|
|
|
@ -2,10 +2,12 @@ |
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
#include <boost/functional/hash.hpp>
|
|
|
|
|
|
|
|
#include "common/cityhash.h"
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
|
|
|
|
|
|
|
@ -13,289 +15,352 @@ namespace Vulkan { |
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
constexpr FixedPipelineState::DepthStencil GetDepthStencilState(const Maxwell& regs) { |
|
|
|
const FixedPipelineState::StencilFace front_stencil( |
|
|
|
regs.stencil_front_op_fail, regs.stencil_front_op_zfail, regs.stencil_front_op_zpass, |
|
|
|
regs.stencil_front_func_func); |
|
|
|
const FixedPipelineState::StencilFace back_stencil = |
|
|
|
regs.stencil_two_side_enable |
|
|
|
? FixedPipelineState::StencilFace(regs.stencil_back_op_fail, regs.stencil_back_op_zfail, |
|
|
|
regs.stencil_back_op_zpass, |
|
|
|
regs.stencil_back_func_func) |
|
|
|
: front_stencil; |
|
|
|
return FixedPipelineState::DepthStencil( |
|
|
|
regs.depth_test_enable == 1, regs.depth_write_enabled == 1, regs.depth_bounds_enable == 1, |
|
|
|
regs.stencil_enable == 1, regs.depth_test_func, front_stencil, back_stencil); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { |
|
|
|
return FixedPipelineState::InputAssembly( |
|
|
|
regs.draw.topology, regs.primitive_restart.enabled, |
|
|
|
regs.draw.topology == Maxwell::PrimitiveTopology::Points ? regs.point_size : 0.0f); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr FixedPipelineState::BlendingAttachment GetBlendingAttachmentState( |
|
|
|
const Maxwell& regs, std::size_t render_target) { |
|
|
|
const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : render_target]; |
|
|
|
const std::array components = {mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0}; |
|
|
|
|
|
|
|
const FixedPipelineState::BlendingAttachment default_blending( |
|
|
|
false, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One, |
|
|
|
Maxwell::Blend::Factor::Zero, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One, |
|
|
|
Maxwell::Blend::Factor::Zero, components); |
|
|
|
if (render_target >= regs.rt_control.count) { |
|
|
|
return default_blending; |
|
|
|
} |
|
|
|
constexpr std::size_t POINT = 0; |
|
|
|
constexpr std::size_t LINE = 1; |
|
|
|
constexpr std::size_t POLYGON = 2; |
|
|
|
constexpr std::array POLYGON_OFFSET_ENABLE_LUT = { |
|
|
|
POINT, // Points
|
|
|
|
LINE, // Lines
|
|
|
|
LINE, // LineLoop
|
|
|
|
LINE, // LineStrip
|
|
|
|
POLYGON, // Triangles
|
|
|
|
POLYGON, // TriangleStrip
|
|
|
|
POLYGON, // TriangleFan
|
|
|
|
POLYGON, // Quads
|
|
|
|
POLYGON, // QuadStrip
|
|
|
|
POLYGON, // Polygon
|
|
|
|
LINE, // LinesAdjacency
|
|
|
|
LINE, // LineStripAdjacency
|
|
|
|
POLYGON, // TrianglesAdjacency
|
|
|
|
POLYGON, // TriangleStripAdjacency
|
|
|
|
POLYGON, // Patches
|
|
|
|
}; |
|
|
|
|
|
|
|
if (!regs.independent_blend_enable) { |
|
|
|
const auto& src = regs.blend; |
|
|
|
if (!src.enable[render_target]) { |
|
|
|
return default_blending; |
|
|
|
} |
|
|
|
return FixedPipelineState::BlendingAttachment( |
|
|
|
true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a, |
|
|
|
src.factor_source_a, src.factor_dest_a, components); |
|
|
|
} |
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
if (!regs.blend.enable[render_target]) { |
|
|
|
return default_blending; |
|
|
|
void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept { |
|
|
|
raw = 0; |
|
|
|
front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op_fail)); |
|
|
|
front.action_depth_fail.Assign(PackStencilOp(regs.stencil_front_op_zfail)); |
|
|
|
front.action_depth_pass.Assign(PackStencilOp(regs.stencil_front_op_zpass)); |
|
|
|
front.test_func.Assign(PackComparisonOp(regs.stencil_front_func_func)); |
|
|
|
if (regs.stencil_two_side_enable) { |
|
|
|
back.action_stencil_fail.Assign(PackStencilOp(regs.stencil_back_op_fail)); |
|
|
|
back.action_depth_fail.Assign(PackStencilOp(regs.stencil_back_op_zfail)); |
|
|
|
back.action_depth_pass.Assign(PackStencilOp(regs.stencil_back_op_zpass)); |
|
|
|
back.test_func.Assign(PackComparisonOp(regs.stencil_back_func_func)); |
|
|
|
} else { |
|
|
|
back.action_stencil_fail.Assign(front.action_stencil_fail); |
|
|
|
back.action_depth_fail.Assign(front.action_depth_fail); |
|
|
|
back.action_depth_pass.Assign(front.action_depth_pass); |
|
|
|
back.test_func.Assign(front.test_func); |
|
|
|
} |
|
|
|
const auto& src = regs.independent_blend[render_target]; |
|
|
|
return FixedPipelineState::BlendingAttachment( |
|
|
|
true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a, |
|
|
|
src.factor_source_a, src.factor_dest_a, components); |
|
|
|
depth_test_enable.Assign(regs.depth_test_enable); |
|
|
|
depth_write_enable.Assign(regs.depth_write_enabled); |
|
|
|
depth_bounds_enable.Assign(regs.depth_bounds_enable); |
|
|
|
stencil_enable.Assign(regs.stencil_enable); |
|
|
|
depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr FixedPipelineState::ColorBlending GetColorBlendingState(const Maxwell& regs) { |
|
|
|
return FixedPipelineState::ColorBlending( |
|
|
|
{regs.blend_color.r, regs.blend_color.g, regs.blend_color.b, regs.blend_color.a}, |
|
|
|
regs.rt_control.count, |
|
|
|
{GetBlendingAttachmentState(regs, 0), GetBlendingAttachmentState(regs, 1), |
|
|
|
GetBlendingAttachmentState(regs, 2), GetBlendingAttachmentState(regs, 3), |
|
|
|
GetBlendingAttachmentState(regs, 4), GetBlendingAttachmentState(regs, 5), |
|
|
|
GetBlendingAttachmentState(regs, 6), GetBlendingAttachmentState(regs, 7)}); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr FixedPipelineState::Tessellation GetTessellationState(const Maxwell& regs) { |
|
|
|
return FixedPipelineState::Tessellation(regs.patch_vertices, regs.tess_mode.prim, |
|
|
|
regs.tess_mode.spacing, regs.tess_mode.cw != 0); |
|
|
|
} |
|
|
|
|
|
|
|
constexpr std::size_t Point = 0; |
|
|
|
constexpr std::size_t Line = 1; |
|
|
|
constexpr std::size_t Polygon = 2; |
|
|
|
constexpr std::array PolygonOffsetEnableLUT = { |
|
|
|
Point, // Points
|
|
|
|
Line, // Lines
|
|
|
|
Line, // LineLoop
|
|
|
|
Line, // LineStrip
|
|
|
|
Polygon, // Triangles
|
|
|
|
Polygon, // TriangleStrip
|
|
|
|
Polygon, // TriangleFan
|
|
|
|
Polygon, // Quads
|
|
|
|
Polygon, // QuadStrip
|
|
|
|
Polygon, // Polygon
|
|
|
|
Line, // LinesAdjacency
|
|
|
|
Line, // LineStripAdjacency
|
|
|
|
Polygon, // TrianglesAdjacency
|
|
|
|
Polygon, // TriangleStripAdjacency
|
|
|
|
Polygon, // Patches
|
|
|
|
}; |
|
|
|
|
|
|
|
constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs) { |
|
|
|
void FixedPipelineState::Rasterizer::Fill(const Maxwell& regs) noexcept { |
|
|
|
const auto& clip = regs.view_volume_clip_control; |
|
|
|
const std::array enabled_lut = {regs.polygon_offset_point_enable, |
|
|
|
regs.polygon_offset_line_enable, |
|
|
|
regs.polygon_offset_fill_enable}; |
|
|
|
const auto topology = static_cast<std::size_t>(regs.draw.topology.Value()); |
|
|
|
const bool depth_bias_enabled = enabled_lut[PolygonOffsetEnableLUT[topology]]; |
|
|
|
const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); |
|
|
|
|
|
|
|
const auto& clip = regs.view_volume_clip_control; |
|
|
|
const bool depth_clamp_enabled = clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1; |
|
|
|
|
|
|
|
Maxwell::FrontFace front_face = regs.front_face; |
|
|
|
u32 packed_front_face = PackFrontFace(regs.front_face); |
|
|
|
if (regs.screen_y_control.triangle_rast_flip != 0 && |
|
|
|
regs.viewport_transform[0].scale_y > 0.0f) { |
|
|
|
if (front_face == Maxwell::FrontFace::CounterClockWise) |
|
|
|
front_face = Maxwell::FrontFace::ClockWise; |
|
|
|
else if (front_face == Maxwell::FrontFace::ClockWise) |
|
|
|
front_face = Maxwell::FrontFace::CounterClockWise; |
|
|
|
// Flip front face
|
|
|
|
packed_front_face = 1 - packed_front_face; |
|
|
|
} |
|
|
|
|
|
|
|
const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; |
|
|
|
return FixedPipelineState::Rasterizer(regs.cull_test_enabled, depth_bias_enabled, |
|
|
|
depth_clamp_enabled, gl_ndc, regs.cull_face, front_face); |
|
|
|
raw = 0; |
|
|
|
topology.Assign(topology_index); |
|
|
|
primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); |
|
|
|
cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); |
|
|
|
depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); |
|
|
|
depth_clamp_enable.Assign(clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1 ? 1 : 0); |
|
|
|
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0); |
|
|
|
cull_face.Assign(PackCullFace(regs.cull_face)); |
|
|
|
front_face.Assign(packed_front_face); |
|
|
|
polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front)); |
|
|
|
patch_control_points_minus_one.Assign(regs.patch_vertices - 1); |
|
|
|
tessellation_primitive.Assign(static_cast<u32>(regs.tess_mode.prim.Value())); |
|
|
|
tessellation_spacing.Assign(static_cast<u32>(regs.tess_mode.spacing.Value())); |
|
|
|
tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); |
|
|
|
logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); |
|
|
|
logic_op.Assign(PackLogicOp(regs.logic_op.operation)); |
|
|
|
std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
|
|
|
|
} |
|
|
|
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
std::size_t FixedPipelineState::VertexBinding::Hash() const noexcept { |
|
|
|
return (index << stride) ^ divisor; |
|
|
|
void FixedPipelineState::ColorBlending::Fill(const Maxwell& regs) noexcept { |
|
|
|
for (std::size_t index = 0; index < std::size(attachments); ++index) { |
|
|
|
attachments[index].Fill(regs, index); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const noexcept { |
|
|
|
return std::tie(index, stride, divisor) == std::tie(rhs.index, rhs.stride, rhs.divisor); |
|
|
|
} |
|
|
|
void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size_t index) { |
|
|
|
const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : index]; |
|
|
|
|
|
|
|
raw = 0; |
|
|
|
mask_r.Assign(mask.R); |
|
|
|
mask_g.Assign(mask.G); |
|
|
|
mask_b.Assign(mask.B); |
|
|
|
mask_a.Assign(mask.A); |
|
|
|
|
|
|
|
// TODO: C++20 Use templated lambda to deduplicate code
|
|
|
|
|
|
|
|
if (!regs.independent_blend_enable) { |
|
|
|
const auto& src = regs.blend; |
|
|
|
if (!src.enable[index]) { |
|
|
|
return; |
|
|
|
} |
|
|
|
equation_rgb.Assign(PackBlendEquation(src.equation_rgb)); |
|
|
|
equation_a.Assign(PackBlendEquation(src.equation_a)); |
|
|
|
factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb)); |
|
|
|
factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb)); |
|
|
|
factor_source_a.Assign(PackBlendFactor(src.factor_source_a)); |
|
|
|
factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a)); |
|
|
|
enable.Assign(1); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::VertexAttribute::Hash() const noexcept { |
|
|
|
return static_cast<std::size_t>(index) ^ (static_cast<std::size_t>(buffer) << 13) ^ |
|
|
|
(static_cast<std::size_t>(type) << 22) ^ (static_cast<std::size_t>(size) << 31) ^ |
|
|
|
(static_cast<std::size_t>(offset) << 36); |
|
|
|
if (!regs.blend.enable[index]) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const auto& src = regs.independent_blend[index]; |
|
|
|
equation_rgb.Assign(PackBlendEquation(src.equation_rgb)); |
|
|
|
equation_a.Assign(PackBlendEquation(src.equation_a)); |
|
|
|
factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb)); |
|
|
|
factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb)); |
|
|
|
factor_source_a.Assign(PackBlendFactor(src.factor_source_a)); |
|
|
|
factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a)); |
|
|
|
enable.Assign(1); |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const noexcept { |
|
|
|
return std::tie(index, buffer, type, size, offset) == |
|
|
|
std::tie(rhs.index, rhs.buffer, rhs.type, rhs.size, rhs.offset); |
|
|
|
std::size_t FixedPipelineState::Hash() const noexcept { |
|
|
|
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this); |
|
|
|
return static_cast<std::size_t>(hash); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::StencilFace::Hash() const noexcept { |
|
|
|
return static_cast<std::size_t>(action_stencil_fail) ^ |
|
|
|
(static_cast<std::size_t>(action_depth_fail) << 4) ^ |
|
|
|
(static_cast<std::size_t>(action_depth_fail) << 20) ^ |
|
|
|
(static_cast<std::size_t>(action_depth_pass) << 36); |
|
|
|
bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { |
|
|
|
return std::memcmp(this, &rhs, sizeof *this) == 0; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const noexcept { |
|
|
|
return std::tie(action_stencil_fail, action_depth_fail, action_depth_pass, test_func) == |
|
|
|
std::tie(rhs.action_stencil_fail, rhs.action_depth_fail, rhs.action_depth_pass, |
|
|
|
rhs.test_func); |
|
|
|
FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { |
|
|
|
FixedPipelineState fixed_state; |
|
|
|
fixed_state.rasterizer.Fill(regs); |
|
|
|
fixed_state.depth_stencil.Fill(regs); |
|
|
|
fixed_state.color_blending.Fill(regs); |
|
|
|
fixed_state.padding = {}; |
|
|
|
return fixed_state; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { |
|
|
|
return static_cast<std::size_t>(enable) ^ (static_cast<std::size_t>(rgb_equation) << 5) ^ |
|
|
|
(static_cast<std::size_t>(src_rgb_func) << 10) ^ |
|
|
|
(static_cast<std::size_t>(dst_rgb_func) << 15) ^ |
|
|
|
(static_cast<std::size_t>(a_equation) << 20) ^ |
|
|
|
(static_cast<std::size_t>(src_a_func) << 25) ^ |
|
|
|
(static_cast<std::size_t>(dst_a_func) << 30) ^ |
|
|
|
(static_cast<std::size_t>(components[0]) << 35) ^ |
|
|
|
(static_cast<std::size_t>(components[1]) << 36) ^ |
|
|
|
(static_cast<std::size_t>(components[2]) << 37) ^ |
|
|
|
(static_cast<std::size_t>(components[3]) << 38); |
|
|
|
u32 FixedPipelineState::PackComparisonOp(Maxwell::ComparisonOp op) noexcept { |
|
|
|
// OpenGL enums go from 0x200 to 0x207 and the others from 1 to 8
|
|
|
|
// If we substract 0x200 to OpenGL enums and 1 to the others we get a 0-7 range.
|
|
|
|
// Perfect for a hash.
|
|
|
|
const u32 value = static_cast<u32>(op); |
|
|
|
return value - (value >= 0x200 ? 0x200 : 1); |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const |
|
|
|
noexcept { |
|
|
|
return std::tie(enable, rgb_equation, src_rgb_func, dst_rgb_func, a_equation, src_a_func, |
|
|
|
dst_a_func, components) == |
|
|
|
std::tie(rhs.enable, rhs.rgb_equation, rhs.src_rgb_func, rhs.dst_rgb_func, |
|
|
|
rhs.a_equation, rhs.src_a_func, rhs.dst_a_func, rhs.components); |
|
|
|
Maxwell::ComparisonOp FixedPipelineState::UnpackComparisonOp(u32 packed) noexcept { |
|
|
|
// Read PackComparisonOp for the logic behind this.
|
|
|
|
return static_cast<Maxwell::ComparisonOp>(packed + 1); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::VertexInput::Hash() const noexcept { |
|
|
|
std::size_t hash = num_bindings ^ (num_attributes << 32); |
|
|
|
for (std::size_t i = 0; i < num_bindings; ++i) { |
|
|
|
boost::hash_combine(hash, bindings[i].Hash()); |
|
|
|
} |
|
|
|
for (std::size_t i = 0; i < num_attributes; ++i) { |
|
|
|
boost::hash_combine(hash, attributes[i].Hash()); |
|
|
|
u32 FixedPipelineState::PackStencilOp(Maxwell::StencilOp op) noexcept { |
|
|
|
switch (op) { |
|
|
|
case Maxwell::StencilOp::Keep: |
|
|
|
case Maxwell::StencilOp::KeepOGL: |
|
|
|
return 0; |
|
|
|
case Maxwell::StencilOp::Zero: |
|
|
|
case Maxwell::StencilOp::ZeroOGL: |
|
|
|
return 1; |
|
|
|
case Maxwell::StencilOp::Replace: |
|
|
|
case Maxwell::StencilOp::ReplaceOGL: |
|
|
|
return 2; |
|
|
|
case Maxwell::StencilOp::Incr: |
|
|
|
case Maxwell::StencilOp::IncrOGL: |
|
|
|
return 3; |
|
|
|
case Maxwell::StencilOp::Decr: |
|
|
|
case Maxwell::StencilOp::DecrOGL: |
|
|
|
return 4; |
|
|
|
case Maxwell::StencilOp::Invert: |
|
|
|
case Maxwell::StencilOp::InvertOGL: |
|
|
|
return 5; |
|
|
|
case Maxwell::StencilOp::IncrWrap: |
|
|
|
case Maxwell::StencilOp::IncrWrapOGL: |
|
|
|
return 6; |
|
|
|
case Maxwell::StencilOp::DecrWrap: |
|
|
|
case Maxwell::StencilOp::DecrWrapOGL: |
|
|
|
return 7; |
|
|
|
} |
|
|
|
return hash; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const noexcept { |
|
|
|
return std::equal(bindings.begin(), bindings.begin() + num_bindings, rhs.bindings.begin(), |
|
|
|
rhs.bindings.begin() + rhs.num_bindings) && |
|
|
|
std::equal(attributes.begin(), attributes.begin() + num_attributes, |
|
|
|
rhs.attributes.begin(), rhs.attributes.begin() + rhs.num_attributes); |
|
|
|
Maxwell::StencilOp FixedPipelineState::UnpackStencilOp(u32 packed) noexcept { |
|
|
|
static constexpr std::array LUT = {Maxwell::StencilOp::Keep, Maxwell::StencilOp::Zero, |
|
|
|
Maxwell::StencilOp::Replace, Maxwell::StencilOp::Incr, |
|
|
|
Maxwell::StencilOp::Decr, Maxwell::StencilOp::Invert, |
|
|
|
Maxwell::StencilOp::IncrWrap, Maxwell::StencilOp::DecrWrap}; |
|
|
|
return LUT[packed]; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::InputAssembly::Hash() const noexcept { |
|
|
|
std::size_t point_size_int = 0; |
|
|
|
std::memcpy(&point_size_int, &point_size, sizeof(point_size)); |
|
|
|
return (static_cast<std::size_t>(topology) << 24) ^ (point_size_int << 32) ^ |
|
|
|
static_cast<std::size_t>(primitive_restart_enable); |
|
|
|
u32 FixedPipelineState::PackCullFace(Maxwell::CullFace cull) noexcept { |
|
|
|
// FrontAndBack is 0x408, by substracting 0x406 in it we get 2.
|
|
|
|
// Individual cull faces are in 0x404 and 0x405, substracting 0x404 we get 0 and 1.
|
|
|
|
const u32 value = static_cast<u32>(cull); |
|
|
|
return value - (value == 0x408 ? 0x406 : 0x404); |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const noexcept { |
|
|
|
return std::tie(topology, primitive_restart_enable, point_size) == |
|
|
|
std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size); |
|
|
|
Maxwell::CullFace FixedPipelineState::UnpackCullFace(u32 packed) noexcept { |
|
|
|
static constexpr std::array LUT = {Maxwell::CullFace::Front, Maxwell::CullFace::Back, |
|
|
|
Maxwell::CullFace::FrontAndBack}; |
|
|
|
return LUT[packed]; |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::Tessellation::Hash() const noexcept { |
|
|
|
return static_cast<std::size_t>(patch_control_points) ^ |
|
|
|
(static_cast<std::size_t>(primitive) << 6) ^ (static_cast<std::size_t>(spacing) << 8) ^ |
|
|
|
(static_cast<std::size_t>(clockwise) << 10); |
|
|
|
u32 FixedPipelineState::PackFrontFace(Maxwell::FrontFace face) noexcept { |
|
|
|
return static_cast<u32>(face) - 0x900; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const noexcept { |
|
|
|
return std::tie(patch_control_points, primitive, spacing, clockwise) == |
|
|
|
std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise); |
|
|
|
Maxwell::FrontFace FixedPipelineState::UnpackFrontFace(u32 packed) noexcept { |
|
|
|
return static_cast<Maxwell::FrontFace>(packed + 0x900); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept { |
|
|
|
return static_cast<std::size_t>(cull_enable) ^ |
|
|
|
(static_cast<std::size_t>(depth_bias_enable) << 1) ^ |
|
|
|
(static_cast<std::size_t>(depth_clamp_enable) << 2) ^ |
|
|
|
(static_cast<std::size_t>(ndc_minus_one_to_one) << 3) ^ |
|
|
|
(static_cast<std::size_t>(cull_face) << 24) ^ |
|
|
|
(static_cast<std::size_t>(front_face) << 48); |
|
|
|
u32 FixedPipelineState::PackPolygonMode(Maxwell::PolygonMode mode) noexcept { |
|
|
|
return static_cast<u32>(mode) - 0x1B00; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept { |
|
|
|
return std::tie(cull_enable, depth_bias_enable, depth_clamp_enable, ndc_minus_one_to_one, |
|
|
|
cull_face, front_face) == |
|
|
|
std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.depth_clamp_enable, |
|
|
|
rhs.ndc_minus_one_to_one, rhs.cull_face, rhs.front_face); |
|
|
|
Maxwell::PolygonMode FixedPipelineState::UnpackPolygonMode(u32 packed) noexcept { |
|
|
|
return static_cast<Maxwell::PolygonMode>(packed + 0x1B00); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { |
|
|
|
std::size_t hash = static_cast<std::size_t>(depth_test_enable) ^ |
|
|
|
(static_cast<std::size_t>(depth_write_enable) << 1) ^ |
|
|
|
(static_cast<std::size_t>(depth_bounds_enable) << 2) ^ |
|
|
|
(static_cast<std::size_t>(stencil_enable) << 3) ^ |
|
|
|
(static_cast<std::size_t>(depth_test_function) << 4); |
|
|
|
boost::hash_combine(hash, front_stencil.Hash()); |
|
|
|
boost::hash_combine(hash, back_stencil.Hash()); |
|
|
|
return hash; |
|
|
|
u32 FixedPipelineState::PackLogicOp(Maxwell::LogicOperation op) noexcept { |
|
|
|
return static_cast<u32>(op) - 0x1500; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept { |
|
|
|
return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, |
|
|
|
stencil_enable, front_stencil, back_stencil) == |
|
|
|
std::tie(rhs.depth_test_enable, rhs.depth_write_enable, rhs.depth_bounds_enable, |
|
|
|
rhs.depth_test_function, rhs.stencil_enable, rhs.front_stencil, |
|
|
|
rhs.back_stencil); |
|
|
|
Maxwell::LogicOperation FixedPipelineState::UnpackLogicOp(u32 packed) noexcept { |
|
|
|
return static_cast<Maxwell::LogicOperation>(packed + 0x1500); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept { |
|
|
|
std::size_t hash = attachments_count << 13; |
|
|
|
for (std::size_t rt = 0; rt < static_cast<std::size_t>(attachments_count); ++rt) { |
|
|
|
boost::hash_combine(hash, attachments[rt].Hash()); |
|
|
|
u32 FixedPipelineState::PackBlendEquation(Maxwell::Blend::Equation equation) noexcept { |
|
|
|
switch (equation) { |
|
|
|
case Maxwell::Blend::Equation::Add: |
|
|
|
case Maxwell::Blend::Equation::AddGL: |
|
|
|
return 0; |
|
|
|
case Maxwell::Blend::Equation::Subtract: |
|
|
|
case Maxwell::Blend::Equation::SubtractGL: |
|
|
|
return 1; |
|
|
|
case Maxwell::Blend::Equation::ReverseSubtract: |
|
|
|
case Maxwell::Blend::Equation::ReverseSubtractGL: |
|
|
|
return 2; |
|
|
|
case Maxwell::Blend::Equation::Min: |
|
|
|
case Maxwell::Blend::Equation::MinGL: |
|
|
|
return 3; |
|
|
|
case Maxwell::Blend::Equation::Max: |
|
|
|
case Maxwell::Blend::Equation::MaxGL: |
|
|
|
return 4; |
|
|
|
} |
|
|
|
return hash; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const noexcept { |
|
|
|
return std::equal(attachments.begin(), attachments.begin() + attachments_count, |
|
|
|
rhs.attachments.begin(), rhs.attachments.begin() + rhs.attachments_count); |
|
|
|
} |
|
|
|
|
|
|
|
std::size_t FixedPipelineState::Hash() const noexcept { |
|
|
|
std::size_t hash = 0; |
|
|
|
boost::hash_combine(hash, vertex_input.Hash()); |
|
|
|
boost::hash_combine(hash, input_assembly.Hash()); |
|
|
|
boost::hash_combine(hash, tessellation.Hash()); |
|
|
|
boost::hash_combine(hash, rasterizer.Hash()); |
|
|
|
boost::hash_combine(hash, depth_stencil.Hash()); |
|
|
|
boost::hash_combine(hash, color_blending.Hash()); |
|
|
|
return hash; |
|
|
|
Maxwell::Blend::Equation FixedPipelineState::UnpackBlendEquation(u32 packed) noexcept { |
|
|
|
static constexpr std::array LUT = { |
|
|
|
Maxwell::Blend::Equation::Add, Maxwell::Blend::Equation::Subtract, |
|
|
|
Maxwell::Blend::Equation::ReverseSubtract, Maxwell::Blend::Equation::Min, |
|
|
|
Maxwell::Blend::Equation::Max}; |
|
|
|
return LUT[packed]; |
|
|
|
} |
|
|
|
|
|
|
|
bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { |
|
|
|
return std::tie(vertex_input, input_assembly, tessellation, rasterizer, depth_stencil, |
|
|
|
color_blending) == std::tie(rhs.vertex_input, rhs.input_assembly, |
|
|
|
rhs.tessellation, rhs.rasterizer, rhs.depth_stencil, |
|
|
|
rhs.color_blending); |
|
|
|
u32 FixedPipelineState::PackBlendFactor(Maxwell::Blend::Factor factor) noexcept { |
|
|
|
switch (factor) { |
|
|
|
case Maxwell::Blend::Factor::Zero: |
|
|
|
case Maxwell::Blend::Factor::ZeroGL: |
|
|
|
return 0; |
|
|
|
case Maxwell::Blend::Factor::One: |
|
|
|
case Maxwell::Blend::Factor::OneGL: |
|
|
|
return 1; |
|
|
|
case Maxwell::Blend::Factor::SourceColor: |
|
|
|
case Maxwell::Blend::Factor::SourceColorGL: |
|
|
|
return 2; |
|
|
|
case Maxwell::Blend::Factor::OneMinusSourceColor: |
|
|
|
case Maxwell::Blend::Factor::OneMinusSourceColorGL: |
|
|
|
return 3; |
|
|
|
case Maxwell::Blend::Factor::SourceAlpha: |
|
|
|
case Maxwell::Blend::Factor::SourceAlphaGL: |
|
|
|
return 4; |
|
|
|
case Maxwell::Blend::Factor::OneMinusSourceAlpha: |
|
|
|
case Maxwell::Blend::Factor::OneMinusSourceAlphaGL: |
|
|
|
return 5; |
|
|
|
case Maxwell::Blend::Factor::DestAlpha: |
|
|
|
case Maxwell::Blend::Factor::DestAlphaGL: |
|
|
|
return 6; |
|
|
|
case Maxwell::Blend::Factor::OneMinusDestAlpha: |
|
|
|
case Maxwell::Blend::Factor::OneMinusDestAlphaGL: |
|
|
|
return 7; |
|
|
|
case Maxwell::Blend::Factor::DestColor: |
|
|
|
case Maxwell::Blend::Factor::DestColorGL: |
|
|
|
return 8; |
|
|
|
case Maxwell::Blend::Factor::OneMinusDestColor: |
|
|
|
case Maxwell::Blend::Factor::OneMinusDestColorGL: |
|
|
|
return 9; |
|
|
|
case Maxwell::Blend::Factor::SourceAlphaSaturate: |
|
|
|
case Maxwell::Blend::Factor::SourceAlphaSaturateGL: |
|
|
|
return 10; |
|
|
|
case Maxwell::Blend::Factor::Source1Color: |
|
|
|
case Maxwell::Blend::Factor::Source1ColorGL: |
|
|
|
return 11; |
|
|
|
case Maxwell::Blend::Factor::OneMinusSource1Color: |
|
|
|
case Maxwell::Blend::Factor::OneMinusSource1ColorGL: |
|
|
|
return 12; |
|
|
|
case Maxwell::Blend::Factor::Source1Alpha: |
|
|
|
case Maxwell::Blend::Factor::Source1AlphaGL: |
|
|
|
return 13; |
|
|
|
case Maxwell::Blend::Factor::OneMinusSource1Alpha: |
|
|
|
case Maxwell::Blend::Factor::OneMinusSource1AlphaGL: |
|
|
|
return 14; |
|
|
|
case Maxwell::Blend::Factor::ConstantColor: |
|
|
|
case Maxwell::Blend::Factor::ConstantColorGL: |
|
|
|
return 15; |
|
|
|
case Maxwell::Blend::Factor::OneMinusConstantColor: |
|
|
|
case Maxwell::Blend::Factor::OneMinusConstantColorGL: |
|
|
|
return 16; |
|
|
|
case Maxwell::Blend::Factor::ConstantAlpha: |
|
|
|
case Maxwell::Blend::Factor::ConstantAlphaGL: |
|
|
|
return 17; |
|
|
|
case Maxwell::Blend::Factor::OneMinusConstantAlpha: |
|
|
|
case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: |
|
|
|
return 18; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { |
|
|
|
FixedPipelineState fixed_state; |
|
|
|
fixed_state.input_assembly = GetInputAssemblyState(regs); |
|
|
|
fixed_state.tessellation = GetTessellationState(regs); |
|
|
|
fixed_state.rasterizer = GetRasterizerState(regs); |
|
|
|
fixed_state.depth_stencil = GetDepthStencilState(regs); |
|
|
|
fixed_state.color_blending = GetColorBlendingState(regs); |
|
|
|
return fixed_state; |
|
|
|
Maxwell::Blend::Factor FixedPipelineState::UnpackBlendFactor(u32 packed) noexcept { |
|
|
|
static constexpr std::array LUT = { |
|
|
|
Maxwell::Blend::Factor::Zero, |
|
|
|
Maxwell::Blend::Factor::One, |
|
|
|
Maxwell::Blend::Factor::SourceColor, |
|
|
|
Maxwell::Blend::Factor::OneMinusSourceColor, |
|
|
|
Maxwell::Blend::Factor::SourceAlpha, |
|
|
|
Maxwell::Blend::Factor::OneMinusSourceAlpha, |
|
|
|
Maxwell::Blend::Factor::DestAlpha, |
|
|
|
Maxwell::Blend::Factor::OneMinusDestAlpha, |
|
|
|
Maxwell::Blend::Factor::DestColor, |
|
|
|
Maxwell::Blend::Factor::OneMinusDestColor, |
|
|
|
Maxwell::Blend::Factor::SourceAlphaSaturate, |
|
|
|
Maxwell::Blend::Factor::Source1Color, |
|
|
|
Maxwell::Blend::Factor::OneMinusSource1Color, |
|
|
|
Maxwell::Blend::Factor::Source1Alpha, |
|
|
|
Maxwell::Blend::Factor::OneMinusSource1Alpha, |
|
|
|
Maxwell::Blend::Factor::ConstantColor, |
|
|
|
Maxwell::Blend::Factor::OneMinusConstantColor, |
|
|
|
Maxwell::Blend::Factor::ConstantAlpha, |
|
|
|
Maxwell::Blend::Factor::OneMinusConstantAlpha, |
|
|
|
}; |
|
|
|
return LUT[packed]; |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace Vulkan
|