diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | 515 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.h | 374 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 91 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 20 |
6 files changed, 531 insertions, 479 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 5cf6a4cc3..59d5752d2 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -1149,7 +1149,7 @@ public: | |||
| 1149 | 1149 | ||
| 1150 | /// Returns whether the vertex array specified by index is supposed to be | 1150 | /// Returns whether the vertex array specified by index is supposed to be |
| 1151 | /// accessed per instance or not. | 1151 | /// accessed per instance or not. |
| 1152 | bool IsInstancingEnabled(u32 index) const { | 1152 | bool IsInstancingEnabled(std::size_t index) const { |
| 1153 | return is_instanced[index]; | 1153 | return is_instanced[index]; |
| 1154 | } | 1154 | } |
| 1155 | } instanced_arrays; | 1155 | } instanced_arrays; |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 2bb376555..be1c31978 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -2,10 +2,12 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 5 | #include <tuple> | 6 | #include <tuple> |
| 6 | 7 | ||
| 7 | #include <boost/functional/hash.hpp> | 8 | #include <boost/functional/hash.hpp> |
| 8 | 9 | ||
| 10 | #include "common/cityhash.h" | ||
| 9 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 10 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 12 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 11 | 13 | ||
| @@ -13,289 +15,352 @@ namespace Vulkan { | |||
| 13 | 15 | ||
| 14 | namespace { | 16 | namespace { |
| 15 | 17 | ||
| 16 | constexpr FixedPipelineState::DepthStencil GetDepthStencilState(const Maxwell& regs) { | 18 | constexpr std::size_t POINT = 0; |
| 17 | const FixedPipelineState::StencilFace front_stencil( | 19 | constexpr std::size_t LINE = 1; |
| 18 | regs.stencil_front_op_fail, regs.stencil_front_op_zfail, regs.stencil_front_op_zpass, | 20 | constexpr std::size_t POLYGON = 2; |
| 19 | regs.stencil_front_func_func); | 21 | constexpr std::array POLYGON_OFFSET_ENABLE_LUT = { |
| 20 | const FixedPipelineState::StencilFace back_stencil = | 22 | POINT, // Points |
| 21 | regs.stencil_two_side_enable | 23 | LINE, // Lines |
| 22 | ? FixedPipelineState::StencilFace(regs.stencil_back_op_fail, regs.stencil_back_op_zfail, | 24 | LINE, // LineLoop |
| 23 | regs.stencil_back_op_zpass, | 25 | LINE, // LineStrip |
| 24 | regs.stencil_back_func_func) | 26 | POLYGON, // Triangles |
| 25 | : front_stencil; | 27 | POLYGON, // TriangleStrip |
| 26 | return FixedPipelineState::DepthStencil( | 28 | POLYGON, // TriangleFan |
| 27 | regs.depth_test_enable == 1, regs.depth_write_enabled == 1, regs.depth_bounds_enable == 1, | 29 | POLYGON, // Quads |
| 28 | regs.stencil_enable == 1, regs.depth_test_func, front_stencil, back_stencil); | 30 | POLYGON, // QuadStrip |
| 29 | } | 31 | POLYGON, // Polygon |
| 30 | 32 | LINE, // LinesAdjacency | |
| 31 | constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { | 33 | LINE, // LineStripAdjacency |
| 32 | return FixedPipelineState::InputAssembly( | 34 | POLYGON, // TrianglesAdjacency |
| 33 | regs.draw.topology, regs.primitive_restart.enabled, | 35 | POLYGON, // TriangleStripAdjacency |
| 34 | regs.draw.topology == Maxwell::PrimitiveTopology::Points ? regs.point_size : 0.0f); | 36 | POLYGON, // Patches |
| 35 | } | 37 | }; |
| 36 | |||
| 37 | constexpr FixedPipelineState::BlendingAttachment GetBlendingAttachmentState( | ||
| 38 | const Maxwell& regs, std::size_t render_target) { | ||
| 39 | const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : render_target]; | ||
| 40 | const std::array components = {mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0}; | ||
| 41 | |||
| 42 | const FixedPipelineState::BlendingAttachment default_blending( | ||
| 43 | false, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One, | ||
| 44 | Maxwell::Blend::Factor::Zero, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One, | ||
| 45 | Maxwell::Blend::Factor::Zero, components); | ||
| 46 | if (render_target >= regs.rt_control.count) { | ||
| 47 | return default_blending; | ||
| 48 | } | ||
| 49 | 38 | ||
| 50 | if (!regs.independent_blend_enable) { | 39 | } // Anonymous namespace |
| 51 | const auto& src = regs.blend; | ||
| 52 | if (!src.enable[render_target]) { | ||
| 53 | return default_blending; | ||
| 54 | } | ||
| 55 | return FixedPipelineState::BlendingAttachment( | ||
| 56 | true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a, | ||
| 57 | src.factor_source_a, src.factor_dest_a, components); | ||
| 58 | } | ||
| 59 | 40 | ||
| 60 | if (!regs.blend.enable[render_target]) { | 41 | void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept { |
| 61 | return default_blending; | 42 | raw = 0; |
| 43 | front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op_fail)); | ||
| 44 | front.action_depth_fail.Assign(PackStencilOp(regs.stencil_front_op_zfail)); | ||
| 45 | front.action_depth_pass.Assign(PackStencilOp(regs.stencil_front_op_zpass)); | ||
| 46 | front.test_func.Assign(PackComparisonOp(regs.stencil_front_func_func)); | ||
| 47 | if (regs.stencil_two_side_enable) { | ||
| 48 | back.action_stencil_fail.Assign(PackStencilOp(regs.stencil_back_op_fail)); | ||
| 49 | back.action_depth_fail.Assign(PackStencilOp(regs.stencil_back_op_zfail)); | ||
| 50 | back.action_depth_pass.Assign(PackStencilOp(regs.stencil_back_op_zpass)); | ||
| 51 | back.test_func.Assign(PackComparisonOp(regs.stencil_back_func_func)); | ||
| 52 | } else { | ||
| 53 | back.action_stencil_fail.Assign(front.action_stencil_fail); | ||
| 54 | back.action_depth_fail.Assign(front.action_depth_fail); | ||
| 55 | back.action_depth_pass.Assign(front.action_depth_pass); | ||
| 56 | back.test_func.Assign(front.test_func); | ||
| 62 | } | 57 | } |
| 63 | const auto& src = regs.independent_blend[render_target]; | 58 | depth_test_enable.Assign(regs.depth_test_enable); |
| 64 | return FixedPipelineState::BlendingAttachment( | 59 | depth_write_enable.Assign(regs.depth_write_enabled); |
| 65 | true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a, | 60 | depth_bounds_enable.Assign(regs.depth_bounds_enable); |
| 66 | src.factor_source_a, src.factor_dest_a, components); | 61 | stencil_enable.Assign(regs.stencil_enable); |
| 62 | depth_test_func.Assign(PackComparisonOp(regs.depth_test_func)); | ||
| 67 | } | 63 | } |
| 68 | 64 | ||
| 69 | constexpr FixedPipelineState::ColorBlending GetColorBlendingState(const Maxwell& regs) { | 65 | void FixedPipelineState::Rasterizer::Fill(const Maxwell& regs) noexcept { |
| 70 | return FixedPipelineState::ColorBlending( | 66 | const auto& clip = regs.view_volume_clip_control; |
| 71 | {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b, regs.blend_color.a}, | ||
| 72 | regs.rt_control.count, | ||
| 73 | {GetBlendingAttachmentState(regs, 0), GetBlendingAttachmentState(regs, 1), | ||
| 74 | GetBlendingAttachmentState(regs, 2), GetBlendingAttachmentState(regs, 3), | ||
| 75 | GetBlendingAttachmentState(regs, 4), GetBlendingAttachmentState(regs, 5), | ||
| 76 | GetBlendingAttachmentState(regs, 6), GetBlendingAttachmentState(regs, 7)}); | ||
| 77 | } | ||
| 78 | |||
| 79 | constexpr FixedPipelineState::Tessellation GetTessellationState(const Maxwell& regs) { | ||
| 80 | return FixedPipelineState::Tessellation(regs.patch_vertices, regs.tess_mode.prim, | ||
| 81 | regs.tess_mode.spacing, regs.tess_mode.cw != 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | constexpr std::size_t Point = 0; | ||
| 85 | constexpr std::size_t Line = 1; | ||
| 86 | constexpr std::size_t Polygon = 2; | ||
| 87 | constexpr std::array PolygonOffsetEnableLUT = { | ||
| 88 | Point, // Points | ||
| 89 | Line, // Lines | ||
| 90 | Line, // LineLoop | ||
| 91 | Line, // LineStrip | ||
| 92 | Polygon, // Triangles | ||
| 93 | Polygon, // TriangleStrip | ||
| 94 | Polygon, // TriangleFan | ||
| 95 | Polygon, // Quads | ||
| 96 | Polygon, // QuadStrip | ||
| 97 | Polygon, // Polygon | ||
| 98 | Line, // LinesAdjacency | ||
| 99 | Line, // LineStripAdjacency | ||
| 100 | Polygon, // TrianglesAdjacency | ||
| 101 | Polygon, // TriangleStripAdjacency | ||
| 102 | Polygon, // Patches | ||
| 103 | }; | ||
| 104 | |||
| 105 | constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs) { | ||
| 106 | const std::array enabled_lut = {regs.polygon_offset_point_enable, | 67 | const std::array enabled_lut = {regs.polygon_offset_point_enable, |
| 107 | regs.polygon_offset_line_enable, | 68 | regs.polygon_offset_line_enable, |
| 108 | regs.polygon_offset_fill_enable}; | 69 | regs.polygon_offset_fill_enable}; |
| 109 | const auto topology = static_cast<std::size_t>(regs.draw.topology.Value()); | 70 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); |
| 110 | const bool depth_bias_enabled = enabled_lut[PolygonOffsetEnableLUT[topology]]; | ||
| 111 | 71 | ||
| 112 | const auto& clip = regs.view_volume_clip_control; | 72 | u32 packed_front_face = PackFrontFace(regs.front_face); |
| 113 | const bool depth_clamp_enabled = clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1; | ||
| 114 | |||
| 115 | Maxwell::FrontFace front_face = regs.front_face; | ||
| 116 | if (regs.screen_y_control.triangle_rast_flip != 0 && | 73 | if (regs.screen_y_control.triangle_rast_flip != 0 && |
| 117 | regs.viewport_transform[0].scale_y > 0.0f) { | 74 | regs.viewport_transform[0].scale_y > 0.0f) { |
| 118 | if (front_face == Maxwell::FrontFace::CounterClockWise) | 75 | // Flip front face |
| 119 | front_face = Maxwell::FrontFace::ClockWise; | 76 | packed_front_face = 1 - packed_front_face; |
| 120 | else if (front_face == Maxwell::FrontFace::ClockWise) | ||
| 121 | front_face = Maxwell::FrontFace::CounterClockWise; | ||
| 122 | } | 77 | } |
| 123 | 78 | ||
| 124 | const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; | 79 | raw = 0; |
| 125 | return FixedPipelineState::Rasterizer(regs.cull_test_enabled, depth_bias_enabled, | 80 | topology.Assign(topology_index); |
| 126 | depth_clamp_enabled, gl_ndc, regs.cull_face, front_face); | 81 | primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); |
| 82 | cull_enable.Assign(regs.cull_test_enabled != 0 ? 1 : 0); | ||
| 83 | depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); | ||
| 84 | depth_clamp_enable.Assign(clip.depth_clamp_near == 1 || clip.depth_clamp_far == 1 ? 1 : 0); | ||
| 85 | ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0); | ||
| 86 | cull_face.Assign(PackCullFace(regs.cull_face)); | ||
| 87 | front_face.Assign(packed_front_face); | ||
| 88 | polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front)); | ||
| 89 | patch_control_points_minus_one.Assign(regs.patch_vertices - 1); | ||
| 90 | tessellation_primitive.Assign(static_cast<u32>(regs.tess_mode.prim.Value())); | ||
| 91 | tessellation_spacing.Assign(static_cast<u32>(regs.tess_mode.spacing.Value())); | ||
| 92 | tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); | ||
| 93 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); | ||
| 94 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); | ||
| 95 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast | ||
| 127 | } | 96 | } |
| 128 | 97 | ||
| 129 | } // Anonymous namespace | 98 | void FixedPipelineState::ColorBlending::Fill(const Maxwell& regs) noexcept { |
| 130 | 99 | for (std::size_t index = 0; index < std::size(attachments); ++index) { | |
| 131 | std::size_t FixedPipelineState::VertexBinding::Hash() const noexcept { | 100 | attachments[index].Fill(regs, index); |
| 132 | return (index << stride) ^ divisor; | 101 | } |
| 133 | } | 102 | } |
| 134 | 103 | ||
| 135 | bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const noexcept { | 104 | void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size_t index) { |
| 136 | return std::tie(index, stride, divisor) == std::tie(rhs.index, rhs.stride, rhs.divisor); | 105 | const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : index]; |
| 137 | } | 106 | |
| 107 | raw = 0; | ||
| 108 | mask_r.Assign(mask.R); | ||
| 109 | mask_g.Assign(mask.G); | ||
| 110 | mask_b.Assign(mask.B); | ||
| 111 | mask_a.Assign(mask.A); | ||
| 112 | |||
| 113 | // TODO: C++20 Use templated lambda to deduplicate code | ||
| 114 | |||
| 115 | if (!regs.independent_blend_enable) { | ||
| 116 | const auto& src = regs.blend; | ||
| 117 | if (!src.enable[index]) { | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | equation_rgb.Assign(PackBlendEquation(src.equation_rgb)); | ||
| 121 | equation_a.Assign(PackBlendEquation(src.equation_a)); | ||
| 122 | factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb)); | ||
| 123 | factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb)); | ||
| 124 | factor_source_a.Assign(PackBlendFactor(src.factor_source_a)); | ||
| 125 | factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a)); | ||
| 126 | enable.Assign(1); | ||
| 127 | return; | ||
| 128 | } | ||
| 138 | 129 | ||
| 139 | std::size_t FixedPipelineState::VertexAttribute::Hash() const noexcept { | 130 | if (!regs.blend.enable[index]) { |
| 140 | return static_cast<std::size_t>(index) ^ (static_cast<std::size_t>(buffer) << 13) ^ | 131 | return; |
| 141 | (static_cast<std::size_t>(type) << 22) ^ (static_cast<std::size_t>(size) << 31) ^ | 132 | } |
| 142 | (static_cast<std::size_t>(offset) << 36); | 133 | const auto& src = regs.independent_blend[index]; |
| 134 | equation_rgb.Assign(PackBlendEquation(src.equation_rgb)); | ||
| 135 | equation_a.Assign(PackBlendEquation(src.equation_a)); | ||
| 136 | factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb)); | ||
| 137 | factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb)); | ||
| 138 | factor_source_a.Assign(PackBlendFactor(src.factor_source_a)); | ||
| 139 | factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a)); | ||
| 140 | enable.Assign(1); | ||
| 143 | } | 141 | } |
| 144 | 142 | ||
| 145 | bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const noexcept { | 143 | std::size_t FixedPipelineState::Hash() const noexcept { |
| 146 | return std::tie(index, buffer, type, size, offset) == | 144 | const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this); |
| 147 | std::tie(rhs.index, rhs.buffer, rhs.type, rhs.size, rhs.offset); | 145 | return static_cast<std::size_t>(hash); |
| 148 | } | 146 | } |
| 149 | 147 | ||
| 150 | std::size_t FixedPipelineState::StencilFace::Hash() const noexcept { | 148 | bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { |
| 151 | return static_cast<std::size_t>(action_stencil_fail) ^ | 149 | return std::memcmp(this, &rhs, sizeof *this) == 0; |
| 152 | (static_cast<std::size_t>(action_depth_fail) << 4) ^ | ||
| 153 | (static_cast<std::size_t>(action_depth_fail) << 20) ^ | ||
| 154 | (static_cast<std::size_t>(action_depth_pass) << 36); | ||
| 155 | } | 150 | } |
| 156 | 151 | ||
| 157 | bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const noexcept { | 152 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { |
| 158 | return std::tie(action_stencil_fail, action_depth_fail, action_depth_pass, test_func) == | 153 | FixedPipelineState fixed_state; |
| 159 | std::tie(rhs.action_stencil_fail, rhs.action_depth_fail, rhs.action_depth_pass, | 154 | fixed_state.rasterizer.Fill(regs); |
| 160 | rhs.test_func); | 155 | fixed_state.depth_stencil.Fill(regs); |
| 156 | fixed_state.color_blending.Fill(regs); | ||
| 157 | fixed_state.padding = {}; | ||
| 158 | return fixed_state; | ||
| 161 | } | 159 | } |
| 162 | 160 | ||
| 163 | std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { | 161 | u32 FixedPipelineState::PackComparisonOp(Maxwell::ComparisonOp op) noexcept { |
| 164 | return static_cast<std::size_t>(enable) ^ (static_cast<std::size_t>(rgb_equation) << 5) ^ | 162 | // OpenGL enums go from 0x200 to 0x207 and the others from 1 to 8 |
| 165 | (static_cast<std::size_t>(src_rgb_func) << 10) ^ | 163 | // If we substract 0x200 to OpenGL enums and 1 to the others we get a 0-7 range. |
| 166 | (static_cast<std::size_t>(dst_rgb_func) << 15) ^ | 164 | // Perfect for a hash. |
| 167 | (static_cast<std::size_t>(a_equation) << 20) ^ | 165 | const u32 value = static_cast<u32>(op); |
| 168 | (static_cast<std::size_t>(src_a_func) << 25) ^ | 166 | return value - (value >= 0x200 ? 0x200 : 1); |
| 169 | (static_cast<std::size_t>(dst_a_func) << 30) ^ | ||
| 170 | (static_cast<std::size_t>(components[0]) << 35) ^ | ||
| 171 | (static_cast<std::size_t>(components[1]) << 36) ^ | ||
| 172 | (static_cast<std::size_t>(components[2]) << 37) ^ | ||
| 173 | (static_cast<std::size_t>(components[3]) << 38); | ||
| 174 | } | 167 | } |
| 175 | 168 | ||
| 176 | bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const | 169 | Maxwell::ComparisonOp FixedPipelineState::UnpackComparisonOp(u32 packed) noexcept { |
| 177 | noexcept { | 170 | // Read PackComparisonOp for the logic behind this. |
| 178 | return std::tie(enable, rgb_equation, src_rgb_func, dst_rgb_func, a_equation, src_a_func, | 171 | return static_cast<Maxwell::ComparisonOp>(packed + 1); |
| 179 | dst_a_func, components) == | ||
| 180 | std::tie(rhs.enable, rhs.rgb_equation, rhs.src_rgb_func, rhs.dst_rgb_func, | ||
| 181 | rhs.a_equation, rhs.src_a_func, rhs.dst_a_func, rhs.components); | ||
| 182 | } | 172 | } |
| 183 | 173 | ||
| 184 | std::size_t FixedPipelineState::VertexInput::Hash() const noexcept { | 174 | u32 FixedPipelineState::PackStencilOp(Maxwell::StencilOp op) noexcept { |
| 185 | std::size_t hash = num_bindings ^ (num_attributes << 32); | 175 | switch (op) { |
| 186 | for (std::size_t i = 0; i < num_bindings; ++i) { | 176 | case Maxwell::StencilOp::Keep: |
| 187 | boost::hash_combine(hash, bindings[i].Hash()); | 177 | case Maxwell::StencilOp::KeepOGL: |
| 188 | } | 178 | return 0; |
| 189 | for (std::size_t i = 0; i < num_attributes; ++i) { | 179 | case Maxwell::StencilOp::Zero: |
| 190 | boost::hash_combine(hash, attributes[i].Hash()); | 180 | case Maxwell::StencilOp::ZeroOGL: |
| 181 | return 1; | ||
| 182 | case Maxwell::StencilOp::Replace: | ||
| 183 | case Maxwell::StencilOp::ReplaceOGL: | ||
| 184 | return 2; | ||
| 185 | case Maxwell::StencilOp::Incr: | ||
| 186 | case Maxwell::StencilOp::IncrOGL: | ||
| 187 | return 3; | ||
| 188 | case Maxwell::StencilOp::Decr: | ||
| 189 | case Maxwell::StencilOp::DecrOGL: | ||
| 190 | return 4; | ||
| 191 | case Maxwell::StencilOp::Invert: | ||
| 192 | case Maxwell::StencilOp::InvertOGL: | ||
| 193 | return 5; | ||
| 194 | case Maxwell::StencilOp::IncrWrap: | ||
| 195 | case Maxwell::StencilOp::IncrWrapOGL: | ||
| 196 | return 6; | ||
| 197 | case Maxwell::StencilOp::DecrWrap: | ||
| 198 | case Maxwell::StencilOp::DecrWrapOGL: | ||
| 199 | return 7; | ||
| 191 | } | 200 | } |
| 192 | return hash; | 201 | return 0; |
| 193 | } | 202 | } |
| 194 | 203 | ||
| 195 | bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const noexcept { | 204 | Maxwell::StencilOp FixedPipelineState::UnpackStencilOp(u32 packed) noexcept { |
| 196 | return std::equal(bindings.begin(), bindings.begin() + num_bindings, rhs.bindings.begin(), | 205 | static constexpr std::array LUT = {Maxwell::StencilOp::Keep, Maxwell::StencilOp::Zero, |
| 197 | rhs.bindings.begin() + rhs.num_bindings) && | 206 | Maxwell::StencilOp::Replace, Maxwell::StencilOp::Incr, |
| 198 | std::equal(attributes.begin(), attributes.begin() + num_attributes, | 207 | Maxwell::StencilOp::Decr, Maxwell::StencilOp::Invert, |
| 199 | rhs.attributes.begin(), rhs.attributes.begin() + rhs.num_attributes); | 208 | Maxwell::StencilOp::IncrWrap, Maxwell::StencilOp::DecrWrap}; |
| 209 | return LUT[packed]; | ||
| 200 | } | 210 | } |
| 201 | 211 | ||
| 202 | std::size_t FixedPipelineState::InputAssembly::Hash() const noexcept { | 212 | u32 FixedPipelineState::PackCullFace(Maxwell::CullFace cull) noexcept { |
| 203 | std::size_t point_size_int = 0; | 213 | // FrontAndBack is 0x408, by substracting 0x406 in it we get 2. |
| 204 | std::memcpy(&point_size_int, &point_size, sizeof(point_size)); | 214 | // Individual cull faces are in 0x404 and 0x405, substracting 0x404 we get 0 and 1. |
| 205 | return (static_cast<std::size_t>(topology) << 24) ^ (point_size_int << 32) ^ | 215 | const u32 value = static_cast<u32>(cull); |
| 206 | static_cast<std::size_t>(primitive_restart_enable); | 216 | return value - (value == 0x408 ? 0x406 : 0x404); |
| 207 | } | 217 | } |
| 208 | 218 | ||
| 209 | bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const noexcept { | 219 | Maxwell::CullFace FixedPipelineState::UnpackCullFace(u32 packed) noexcept { |
| 210 | return std::tie(topology, primitive_restart_enable, point_size) == | 220 | static constexpr std::array LUT = {Maxwell::CullFace::Front, Maxwell::CullFace::Back, |
| 211 | std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size); | 221 | Maxwell::CullFace::FrontAndBack}; |
| 222 | return LUT[packed]; | ||
| 212 | } | 223 | } |
| 213 | 224 | ||
| 214 | std::size_t FixedPipelineState::Tessellation::Hash() const noexcept { | 225 | u32 FixedPipelineState::PackFrontFace(Maxwell::FrontFace face) noexcept { |
| 215 | return static_cast<std::size_t>(patch_control_points) ^ | 226 | return static_cast<u32>(face) - 0x900; |
| 216 | (static_cast<std::size_t>(primitive) << 6) ^ (static_cast<std::size_t>(spacing) << 8) ^ | ||
| 217 | (static_cast<std::size_t>(clockwise) << 10); | ||
| 218 | } | 227 | } |
| 219 | 228 | ||
| 220 | bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const noexcept { | 229 | Maxwell::FrontFace FixedPipelineState::UnpackFrontFace(u32 packed) noexcept { |
| 221 | return std::tie(patch_control_points, primitive, spacing, clockwise) == | 230 | return static_cast<Maxwell::FrontFace>(packed + 0x900); |
| 222 | std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise); | ||
| 223 | } | 231 | } |
| 224 | 232 | ||
| 225 | std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept { | 233 | u32 FixedPipelineState::PackPolygonMode(Maxwell::PolygonMode mode) noexcept { |
| 226 | return static_cast<std::size_t>(cull_enable) ^ | 234 | return static_cast<u32>(mode) - 0x1B00; |
| 227 | (static_cast<std::size_t>(depth_bias_enable) << 1) ^ | ||
| 228 | (static_cast<std::size_t>(depth_clamp_enable) << 2) ^ | ||
| 229 | (static_cast<std::size_t>(ndc_minus_one_to_one) << 3) ^ | ||
| 230 | (static_cast<std::size_t>(cull_face) << 24) ^ | ||
| 231 | (static_cast<std::size_t>(front_face) << 48); | ||
| 232 | } | 235 | } |
| 233 | 236 | ||
| 234 | bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept { | 237 | Maxwell::PolygonMode FixedPipelineState::UnpackPolygonMode(u32 packed) noexcept { |
| 235 | return std::tie(cull_enable, depth_bias_enable, depth_clamp_enable, ndc_minus_one_to_one, | 238 | return static_cast<Maxwell::PolygonMode>(packed + 0x1B00); |
| 236 | cull_face, front_face) == | ||
| 237 | std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.depth_clamp_enable, | ||
| 238 | rhs.ndc_minus_one_to_one, rhs.cull_face, rhs.front_face); | ||
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { | 241 | u32 FixedPipelineState::PackLogicOp(Maxwell::LogicOperation op) noexcept { |
| 242 | std::size_t hash = static_cast<std::size_t>(depth_test_enable) ^ | 242 | return static_cast<u32>(op) - 0x1500; |
| 243 | (static_cast<std::size_t>(depth_write_enable) << 1) ^ | ||
| 244 | (static_cast<std::size_t>(depth_bounds_enable) << 2) ^ | ||
| 245 | (static_cast<std::size_t>(stencil_enable) << 3) ^ | ||
| 246 | (static_cast<std::size_t>(depth_test_function) << 4); | ||
| 247 | boost::hash_combine(hash, front_stencil.Hash()); | ||
| 248 | boost::hash_combine(hash, back_stencil.Hash()); | ||
| 249 | return hash; | ||
| 250 | } | 243 | } |
| 251 | 244 | ||
| 252 | bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept { | 245 | Maxwell::LogicOperation FixedPipelineState::UnpackLogicOp(u32 packed) noexcept { |
| 253 | return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, | 246 | return static_cast<Maxwell::LogicOperation>(packed + 0x1500); |
| 254 | stencil_enable, front_stencil, back_stencil) == | ||
| 255 | std::tie(rhs.depth_test_enable, rhs.depth_write_enable, rhs.depth_bounds_enable, | ||
| 256 | rhs.depth_test_function, rhs.stencil_enable, rhs.front_stencil, | ||
| 257 | rhs.back_stencil); | ||
| 258 | } | 247 | } |
| 259 | 248 | ||
| 260 | std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept { | 249 | u32 FixedPipelineState::PackBlendEquation(Maxwell::Blend::Equation equation) noexcept { |
| 261 | std::size_t hash = attachments_count << 13; | 250 | switch (equation) { |
| 262 | for (std::size_t rt = 0; rt < static_cast<std::size_t>(attachments_count); ++rt) { | 251 | case Maxwell::Blend::Equation::Add: |
| 263 | boost::hash_combine(hash, attachments[rt].Hash()); | 252 | case Maxwell::Blend::Equation::AddGL: |
| 253 | return 0; | ||
| 254 | case Maxwell::Blend::Equation::Subtract: | ||
| 255 | case Maxwell::Blend::Equation::SubtractGL: | ||
| 256 | return 1; | ||
| 257 | case Maxwell::Blend::Equation::ReverseSubtract: | ||
| 258 | case Maxwell::Blend::Equation::ReverseSubtractGL: | ||
| 259 | return 2; | ||
| 260 | case Maxwell::Blend::Equation::Min: | ||
| 261 | case Maxwell::Blend::Equation::MinGL: | ||
| 262 | return 3; | ||
| 263 | case Maxwell::Blend::Equation::Max: | ||
| 264 | case Maxwell::Blend::Equation::MaxGL: | ||
| 265 | return 4; | ||
| 264 | } | 266 | } |
| 265 | return hash; | 267 | return 0; |
| 266 | } | 268 | } |
| 267 | 269 | ||
| 268 | bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const noexcept { | 270 | Maxwell::Blend::Equation FixedPipelineState::UnpackBlendEquation(u32 packed) noexcept { |
| 269 | return std::equal(attachments.begin(), attachments.begin() + attachments_count, | 271 | static constexpr std::array LUT = { |
| 270 | rhs.attachments.begin(), rhs.attachments.begin() + rhs.attachments_count); | 272 | Maxwell::Blend::Equation::Add, Maxwell::Blend::Equation::Subtract, |
| 271 | } | 273 | Maxwell::Blend::Equation::ReverseSubtract, Maxwell::Blend::Equation::Min, |
| 272 | 274 | Maxwell::Blend::Equation::Max}; | |
| 273 | std::size_t FixedPipelineState::Hash() const noexcept { | 275 | return LUT[packed]; |
| 274 | std::size_t hash = 0; | ||
| 275 | boost::hash_combine(hash, vertex_input.Hash()); | ||
| 276 | boost::hash_combine(hash, input_assembly.Hash()); | ||
| 277 | boost::hash_combine(hash, tessellation.Hash()); | ||
| 278 | boost::hash_combine(hash, rasterizer.Hash()); | ||
| 279 | boost::hash_combine(hash, depth_stencil.Hash()); | ||
| 280 | boost::hash_combine(hash, color_blending.Hash()); | ||
| 281 | return hash; | ||
| 282 | } | 276 | } |
| 283 | 277 | ||
| 284 | bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { | 278 | u32 FixedPipelineState::PackBlendFactor(Maxwell::Blend::Factor factor) noexcept { |
| 285 | return std::tie(vertex_input, input_assembly, tessellation, rasterizer, depth_stencil, | 279 | switch (factor) { |
| 286 | color_blending) == std::tie(rhs.vertex_input, rhs.input_assembly, | 280 | case Maxwell::Blend::Factor::Zero: |
| 287 | rhs.tessellation, rhs.rasterizer, rhs.depth_stencil, | 281 | case Maxwell::Blend::Factor::ZeroGL: |
| 288 | rhs.color_blending); | 282 | return 0; |
| 283 | case Maxwell::Blend::Factor::One: | ||
| 284 | case Maxwell::Blend::Factor::OneGL: | ||
| 285 | return 1; | ||
| 286 | case Maxwell::Blend::Factor::SourceColor: | ||
| 287 | case Maxwell::Blend::Factor::SourceColorGL: | ||
| 288 | return 2; | ||
| 289 | case Maxwell::Blend::Factor::OneMinusSourceColor: | ||
| 290 | case Maxwell::Blend::Factor::OneMinusSourceColorGL: | ||
| 291 | return 3; | ||
| 292 | case Maxwell::Blend::Factor::SourceAlpha: | ||
| 293 | case Maxwell::Blend::Factor::SourceAlphaGL: | ||
| 294 | return 4; | ||
| 295 | case Maxwell::Blend::Factor::OneMinusSourceAlpha: | ||
| 296 | case Maxwell::Blend::Factor::OneMinusSourceAlphaGL: | ||
| 297 | return 5; | ||
| 298 | case Maxwell::Blend::Factor::DestAlpha: | ||
| 299 | case Maxwell::Blend::Factor::DestAlphaGL: | ||
| 300 | return 6; | ||
| 301 | case Maxwell::Blend::Factor::OneMinusDestAlpha: | ||
| 302 | case Maxwell::Blend::Factor::OneMinusDestAlphaGL: | ||
| 303 | return 7; | ||
| 304 | case Maxwell::Blend::Factor::DestColor: | ||
| 305 | case Maxwell::Blend::Factor::DestColorGL: | ||
| 306 | return 8; | ||
| 307 | case Maxwell::Blend::Factor::OneMinusDestColor: | ||
| 308 | case Maxwell::Blend::Factor::OneMinusDestColorGL: | ||
| 309 | return 9; | ||
| 310 | case Maxwell::Blend::Factor::SourceAlphaSaturate: | ||
| 311 | case Maxwell::Blend::Factor::SourceAlphaSaturateGL: | ||
| 312 | return 10; | ||
| 313 | case Maxwell::Blend::Factor::Source1Color: | ||
| 314 | case Maxwell::Blend::Factor::Source1ColorGL: | ||
| 315 | return 11; | ||
| 316 | case Maxwell::Blend::Factor::OneMinusSource1Color: | ||
| 317 | case Maxwell::Blend::Factor::OneMinusSource1ColorGL: | ||
| 318 | return 12; | ||
| 319 | case Maxwell::Blend::Factor::Source1Alpha: | ||
| 320 | case Maxwell::Blend::Factor::Source1AlphaGL: | ||
| 321 | return 13; | ||
| 322 | case Maxwell::Blend::Factor::OneMinusSource1Alpha: | ||
| 323 | case Maxwell::Blend::Factor::OneMinusSource1AlphaGL: | ||
| 324 | return 14; | ||
| 325 | case Maxwell::Blend::Factor::ConstantColor: | ||
| 326 | case Maxwell::Blend::Factor::ConstantColorGL: | ||
| 327 | return 15; | ||
| 328 | case Maxwell::Blend::Factor::OneMinusConstantColor: | ||
| 329 | case Maxwell::Blend::Factor::OneMinusConstantColorGL: | ||
| 330 | return 16; | ||
| 331 | case Maxwell::Blend::Factor::ConstantAlpha: | ||
| 332 | case Maxwell::Blend::Factor::ConstantAlphaGL: | ||
| 333 | return 17; | ||
| 334 | case Maxwell::Blend::Factor::OneMinusConstantAlpha: | ||
| 335 | case Maxwell::Blend::Factor::OneMinusConstantAlphaGL: | ||
| 336 | return 18; | ||
| 337 | } | ||
| 338 | return 0; | ||
| 289 | } | 339 | } |
| 290 | 340 | ||
| 291 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { | 341 | Maxwell::Blend::Factor FixedPipelineState::UnpackBlendFactor(u32 packed) noexcept { |
| 292 | FixedPipelineState fixed_state; | 342 | static constexpr std::array LUT = { |
| 293 | fixed_state.input_assembly = GetInputAssemblyState(regs); | 343 | Maxwell::Blend::Factor::Zero, |
| 294 | fixed_state.tessellation = GetTessellationState(regs); | 344 | Maxwell::Blend::Factor::One, |
| 295 | fixed_state.rasterizer = GetRasterizerState(regs); | 345 | Maxwell::Blend::Factor::SourceColor, |
| 296 | fixed_state.depth_stencil = GetDepthStencilState(regs); | 346 | Maxwell::Blend::Factor::OneMinusSourceColor, |
| 297 | fixed_state.color_blending = GetColorBlendingState(regs); | 347 | Maxwell::Blend::Factor::SourceAlpha, |
| 298 | return fixed_state; | 348 | Maxwell::Blend::Factor::OneMinusSourceAlpha, |
| 349 | Maxwell::Blend::Factor::DestAlpha, | ||
| 350 | Maxwell::Blend::Factor::OneMinusDestAlpha, | ||
| 351 | Maxwell::Blend::Factor::DestColor, | ||
| 352 | Maxwell::Blend::Factor::OneMinusDestColor, | ||
| 353 | Maxwell::Blend::Factor::SourceAlphaSaturate, | ||
| 354 | Maxwell::Blend::Factor::Source1Color, | ||
| 355 | Maxwell::Blend::Factor::OneMinusSource1Color, | ||
| 356 | Maxwell::Blend::Factor::Source1Alpha, | ||
| 357 | Maxwell::Blend::Factor::OneMinusSource1Alpha, | ||
| 358 | Maxwell::Blend::Factor::ConstantColor, | ||
| 359 | Maxwell::Blend::Factor::OneMinusConstantColor, | ||
| 360 | Maxwell::Blend::Factor::ConstantAlpha, | ||
| 361 | Maxwell::Blend::Factor::OneMinusConstantAlpha, | ||
| 362 | }; | ||
| 363 | return LUT[packed]; | ||
| 299 | } | 364 | } |
| 300 | 365 | ||
| 301 | } // namespace Vulkan | 366 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 4c8ba7f90..9fe6bdbf9 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <type_traits> | 8 | #include <type_traits> |
| 9 | 9 | ||
| 10 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| 12 | #include "video_core/engines/maxwell_3d.h" | 13 | #include "video_core/engines/maxwell_3d.h" |
| @@ -16,93 +17,48 @@ namespace Vulkan { | |||
| 16 | 17 | ||
| 17 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 18 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 18 | 19 | ||
| 19 | // TODO(Rodrigo): Optimize this structure. | 20 | struct alignas(32) FixedPipelineState { |
| 21 | static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept; | ||
| 22 | static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept; | ||
| 20 | 23 | ||
| 21 | struct FixedPipelineState { | 24 | static u32 PackStencilOp(Maxwell::StencilOp op) noexcept; |
| 22 | using PixelFormat = VideoCore::Surface::PixelFormat; | 25 | static Maxwell::StencilOp UnpackStencilOp(u32 packed) noexcept; |
| 23 | 26 | ||
| 24 | struct VertexBinding { | 27 | static u32 PackCullFace(Maxwell::CullFace cull) noexcept; |
| 25 | constexpr VertexBinding(u32 index, u32 stride, u32 divisor) | 28 | static Maxwell::CullFace UnpackCullFace(u32 packed) noexcept; |
| 26 | : index{index}, stride{stride}, divisor{divisor} {} | ||
| 27 | VertexBinding() = default; | ||
| 28 | 29 | ||
| 29 | u32 index; | 30 | static u32 PackFrontFace(Maxwell::FrontFace face) noexcept; |
| 30 | u32 stride; | 31 | static Maxwell::FrontFace UnpackFrontFace(u32 packed) noexcept; |
| 31 | u32 divisor; | ||
| 32 | 32 | ||
| 33 | std::size_t Hash() const noexcept; | 33 | static u32 PackPolygonMode(Maxwell::PolygonMode mode) noexcept; |
| 34 | 34 | static Maxwell::PolygonMode UnpackPolygonMode(u32 packed) noexcept; | |
| 35 | bool operator==(const VertexBinding& rhs) const noexcept; | ||
| 36 | |||
| 37 | bool operator!=(const VertexBinding& rhs) const noexcept { | ||
| 38 | return !operator==(rhs); | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct VertexAttribute { | ||
| 43 | constexpr VertexAttribute(u32 index, u32 buffer, Maxwell::VertexAttribute::Type type, | ||
| 44 | Maxwell::VertexAttribute::Size size, u32 offset) | ||
| 45 | : index{index}, buffer{buffer}, type{type}, size{size}, offset{offset} {} | ||
| 46 | VertexAttribute() = default; | ||
| 47 | |||
| 48 | u32 index; | ||
| 49 | u32 buffer; | ||
| 50 | Maxwell::VertexAttribute::Type type; | ||
| 51 | Maxwell::VertexAttribute::Size size; | ||
| 52 | u32 offset; | ||
| 53 | |||
| 54 | std::size_t Hash() const noexcept; | ||
| 55 | |||
| 56 | bool operator==(const VertexAttribute& rhs) const noexcept; | ||
| 57 | |||
| 58 | bool operator!=(const VertexAttribute& rhs) const noexcept { | ||
| 59 | return !operator==(rhs); | ||
| 60 | } | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct StencilFace { | ||
| 64 | constexpr StencilFace(Maxwell::StencilOp action_stencil_fail, | ||
| 65 | Maxwell::StencilOp action_depth_fail, | ||
| 66 | Maxwell::StencilOp action_depth_pass, Maxwell::ComparisonOp test_func) | ||
| 67 | : action_stencil_fail{action_stencil_fail}, action_depth_fail{action_depth_fail}, | ||
| 68 | action_depth_pass{action_depth_pass}, test_func{test_func} {} | ||
| 69 | StencilFace() = default; | ||
| 70 | |||
| 71 | Maxwell::StencilOp action_stencil_fail; | ||
| 72 | Maxwell::StencilOp action_depth_fail; | ||
| 73 | Maxwell::StencilOp action_depth_pass; | ||
| 74 | Maxwell::ComparisonOp test_func; | ||
| 75 | 35 | ||
| 76 | std::size_t Hash() const noexcept; | 36 | static u32 PackLogicOp(Maxwell::LogicOperation op) noexcept; |
| 37 | static Maxwell::LogicOperation UnpackLogicOp(u32 packed) noexcept; | ||
| 77 | 38 | ||
| 78 | bool operator==(const StencilFace& rhs) const noexcept; | 39 | static u32 PackBlendEquation(Maxwell::Blend::Equation equation) noexcept; |
| 40 | static Maxwell::Blend::Equation UnpackBlendEquation(u32 packed) noexcept; | ||
| 79 | 41 | ||
| 80 | bool operator!=(const StencilFace& rhs) const noexcept { | 42 | static u32 PackBlendFactor(Maxwell::Blend::Factor factor) noexcept; |
| 81 | return !operator==(rhs); | 43 | static Maxwell::Blend::Factor UnpackBlendFactor(u32 packed) noexcept; |
| 82 | } | ||
| 83 | }; | ||
| 84 | 44 | ||
| 85 | struct BlendingAttachment { | 45 | struct BlendingAttachment { |
| 86 | constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation, | 46 | union { |
| 87 | Maxwell::Blend::Factor src_rgb_func, | 47 | u32 raw; |
| 88 | Maxwell::Blend::Factor dst_rgb_func, | 48 | BitField<0, 1, u32> mask_r; |
| 89 | Maxwell::Blend::Equation a_equation, | 49 | BitField<1, 1, u32> mask_g; |
| 90 | Maxwell::Blend::Factor src_a_func, | 50 | BitField<2, 1, u32> mask_b; |
| 91 | Maxwell::Blend::Factor dst_a_func, | 51 | BitField<3, 1, u32> mask_a; |
| 92 | std::array<bool, 4> components) | 52 | BitField<4, 3, u32> equation_rgb; |
| 93 | : enable{enable}, rgb_equation{rgb_equation}, src_rgb_func{src_rgb_func}, | 53 | BitField<7, 3, u32> equation_a; |
| 94 | dst_rgb_func{dst_rgb_func}, a_equation{a_equation}, src_a_func{src_a_func}, | 54 | BitField<10, 5, u32> factor_source_rgb; |
| 95 | dst_a_func{dst_a_func}, components{components} {} | 55 | BitField<15, 5, u32> factor_dest_rgb; |
| 96 | BlendingAttachment() = default; | 56 | BitField<20, 5, u32> factor_source_a; |
| 97 | 57 | BitField<25, 5, u32> factor_dest_a; | |
| 98 | bool enable; | 58 | BitField<30, 1, u32> enable; |
| 99 | Maxwell::Blend::Equation rgb_equation; | 59 | }; |
| 100 | Maxwell::Blend::Factor src_rgb_func; | 60 | |
| 101 | Maxwell::Blend::Factor dst_rgb_func; | 61 | void Fill(const Maxwell& regs, std::size_t index); |
| 102 | Maxwell::Blend::Equation a_equation; | ||
| 103 | Maxwell::Blend::Factor src_a_func; | ||
| 104 | Maxwell::Blend::Factor dst_a_func; | ||
| 105 | std::array<bool, 4> components; | ||
| 106 | 62 | ||
| 107 | std::size_t Hash() const noexcept; | 63 | std::size_t Hash() const noexcept; |
| 108 | 64 | ||
| @@ -111,136 +67,178 @@ struct FixedPipelineState { | |||
| 111 | bool operator!=(const BlendingAttachment& rhs) const noexcept { | 67 | bool operator!=(const BlendingAttachment& rhs) const noexcept { |
| 112 | return !operator==(rhs); | 68 | return !operator==(rhs); |
| 113 | } | 69 | } |
| 114 | }; | ||
| 115 | |||
| 116 | struct VertexInput { | ||
| 117 | std::size_t num_bindings = 0; | ||
| 118 | std::size_t num_attributes = 0; | ||
| 119 | std::array<VertexBinding, Maxwell::NumVertexArrays> bindings; | ||
| 120 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | ||
| 121 | |||
| 122 | std::size_t Hash() const noexcept; | ||
| 123 | 70 | ||
| 124 | bool operator==(const VertexInput& rhs) const noexcept; | 71 | constexpr std::array<bool, 4> Mask() const noexcept { |
| 72 | return {mask_r != 0, mask_g != 0, mask_b != 0, mask_a != 0}; | ||
| 73 | } | ||
| 125 | 74 | ||
| 126 | bool operator!=(const VertexInput& rhs) const noexcept { | 75 | Maxwell::Blend::Equation EquationRGB() const noexcept { |
| 127 | return !operator==(rhs); | 76 | return UnpackBlendEquation(equation_rgb.Value()); |
| 128 | } | 77 | } |
| 129 | }; | ||
| 130 | 78 | ||
| 131 | struct InputAssembly { | 79 | Maxwell::Blend::Equation EquationAlpha() const noexcept { |
| 132 | constexpr InputAssembly(Maxwell::PrimitiveTopology topology, bool primitive_restart_enable, | 80 | return UnpackBlendEquation(equation_a.Value()); |
| 133 | float point_size) | 81 | } |
| 134 | : topology{topology}, primitive_restart_enable{primitive_restart_enable}, | ||
| 135 | point_size{point_size} {} | ||
| 136 | InputAssembly() = default; | ||
| 137 | 82 | ||
| 138 | Maxwell::PrimitiveTopology topology; | 83 | Maxwell::Blend::Factor SourceRGBFactor() const noexcept { |
| 139 | bool primitive_restart_enable; | 84 | return UnpackBlendFactor(factor_source_rgb.Value()); |
| 140 | float point_size; | 85 | } |
| 141 | 86 | ||
| 142 | std::size_t Hash() const noexcept; | 87 | Maxwell::Blend::Factor DestRGBFactor() const noexcept { |
| 88 | return UnpackBlendFactor(factor_dest_rgb.Value()); | ||
| 89 | } | ||
| 143 | 90 | ||
| 144 | bool operator==(const InputAssembly& rhs) const noexcept; | 91 | Maxwell::Blend::Factor SourceAlphaFactor() const noexcept { |
| 92 | return UnpackBlendFactor(factor_source_a.Value()); | ||
| 93 | } | ||
| 145 | 94 | ||
| 146 | bool operator!=(const InputAssembly& rhs) const noexcept { | 95 | Maxwell::Blend::Factor DestAlphaFactor() const noexcept { |
| 147 | return !operator==(rhs); | 96 | return UnpackBlendFactor(factor_dest_a.Value()); |
| 148 | } | 97 | } |
| 149 | }; | 98 | }; |
| 150 | 99 | ||
| 151 | struct Tessellation { | 100 | struct VertexInput { |
| 152 | constexpr Tessellation(u32 patch_control_points, Maxwell::TessellationPrimitive primitive, | 101 | union Binding { |
| 153 | Maxwell::TessellationSpacing spacing, bool clockwise) | 102 | u16 raw; |
| 154 | : patch_control_points{patch_control_points}, primitive{primitive}, spacing{spacing}, | 103 | BitField<0, 1, u16> enabled; |
| 155 | clockwise{clockwise} {} | 104 | BitField<1, 12, u16> stride; |
| 156 | Tessellation() = default; | 105 | }; |
| 157 | 106 | ||
| 158 | u32 patch_control_points; | 107 | union Attribute { |
| 159 | Maxwell::TessellationPrimitive primitive; | 108 | u32 raw; |
| 160 | Maxwell::TessellationSpacing spacing; | 109 | BitField<0, 1, u32> enabled; |
| 161 | bool clockwise; | 110 | BitField<1, 5, u32> buffer; |
| 162 | 111 | BitField<6, 14, u32> offset; | |
| 163 | std::size_t Hash() const noexcept; | 112 | BitField<20, 3, u32> type; |
| 164 | 113 | BitField<23, 6, u32> size; | |
| 165 | bool operator==(const Tessellation& rhs) const noexcept; | 114 | |
| 115 | constexpr Maxwell::VertexAttribute::Type Type() const noexcept { | ||
| 116 | return static_cast<Maxwell::VertexAttribute::Type>(type.Value()); | ||
| 117 | } | ||
| 118 | |||
| 119 | constexpr Maxwell::VertexAttribute::Size Size() const noexcept { | ||
| 120 | return static_cast<Maxwell::VertexAttribute::Size>(size.Value()); | ||
| 121 | } | ||
| 122 | }; | ||
| 123 | |||
| 124 | std::array<Binding, Maxwell::NumVertexArrays> bindings; | ||
| 125 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | ||
| 126 | std::array<Attribute, Maxwell::NumVertexAttributes> attributes; | ||
| 127 | |||
| 128 | void SetBinding(std::size_t index, bool enabled, u32 stride, u32 divisor) noexcept { | ||
| 129 | auto& binding = bindings[index]; | ||
| 130 | binding.raw = 0; | ||
| 131 | binding.enabled.Assign(enabled ? 1 : 0); | ||
| 132 | binding.stride.Assign(stride); | ||
| 133 | binding_divisors[index] = divisor; | ||
| 134 | } | ||
| 166 | 135 | ||
| 167 | bool operator!=(const Tessellation& rhs) const noexcept { | 136 | void SetAttribute(std::size_t index, bool enabled, u32 buffer, u32 offset, |
| 168 | return !operator==(rhs); | 137 | Maxwell::VertexAttribute::Type type, |
| 138 | Maxwell::VertexAttribute::Size size) noexcept { | ||
| 139 | auto& attribute = attributes[index]; | ||
| 140 | attribute.raw = 0; | ||
| 141 | attribute.enabled.Assign(enabled ? 1 : 0); | ||
| 142 | attribute.buffer.Assign(buffer); | ||
| 143 | attribute.offset.Assign(offset); | ||
| 144 | attribute.type.Assign(static_cast<u32>(type)); | ||
| 145 | attribute.size.Assign(static_cast<u32>(size)); | ||
| 169 | } | 146 | } |
| 170 | }; | 147 | }; |
| 171 | 148 | ||
| 172 | struct Rasterizer { | 149 | struct Rasterizer { |
| 173 | constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool depth_clamp_enable, | 150 | union { |
| 174 | bool ndc_minus_one_to_one, Maxwell::CullFace cull_face, | 151 | u32 raw; |
| 175 | Maxwell::FrontFace front_face) | 152 | BitField<0, 4, u32> topology; |
| 176 | : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable}, | 153 | BitField<4, 1, u32> primitive_restart_enable; |
| 177 | depth_clamp_enable{depth_clamp_enable}, ndc_minus_one_to_one{ndc_minus_one_to_one}, | 154 | BitField<5, 1, u32> cull_enable; |
| 178 | cull_face{cull_face}, front_face{front_face} {} | 155 | BitField<6, 1, u32> depth_bias_enable; |
| 179 | Rasterizer() = default; | 156 | BitField<7, 1, u32> depth_clamp_enable; |
| 180 | 157 | BitField<8, 1, u32> ndc_minus_one_to_one; | |
| 181 | bool cull_enable; | 158 | BitField<9, 2, u32> cull_face; |
| 182 | bool depth_bias_enable; | 159 | BitField<11, 1, u32> front_face; |
| 183 | bool depth_clamp_enable; | 160 | BitField<12, 2, u32> polygon_mode; |
| 184 | bool ndc_minus_one_to_one; | 161 | BitField<14, 5, u32> patch_control_points_minus_one; |
| 185 | Maxwell::CullFace cull_face; | 162 | BitField<19, 2, u32> tessellation_primitive; |
| 186 | Maxwell::FrontFace front_face; | 163 | BitField<21, 2, u32> tessellation_spacing; |
| 187 | 164 | BitField<23, 1, u32> tessellation_clockwise; | |
| 188 | std::size_t Hash() const noexcept; | 165 | BitField<24, 1, u32> logic_op_enable; |
| 166 | BitField<25, 4, u32> logic_op; | ||
| 167 | }; | ||
| 168 | |||
| 169 | // TODO(Rodrigo): Move this to push constants | ||
| 170 | u32 point_size; | ||
| 171 | |||
| 172 | void Fill(const Maxwell& regs) noexcept; | ||
| 173 | |||
| 174 | constexpr Maxwell::PrimitiveTopology Topology() const noexcept { | ||
| 175 | return static_cast<Maxwell::PrimitiveTopology>(topology.Value()); | ||
| 176 | } | ||
| 189 | 177 | ||
| 190 | bool operator==(const Rasterizer& rhs) const noexcept; | 178 | Maxwell::CullFace CullFace() const noexcept { |
| 179 | return UnpackCullFace(cull_face.Value()); | ||
| 180 | } | ||
| 191 | 181 | ||
| 192 | bool operator!=(const Rasterizer& rhs) const noexcept { | 182 | Maxwell::FrontFace FrontFace() const noexcept { |
| 193 | return !operator==(rhs); | 183 | return UnpackFrontFace(front_face.Value()); |
| 194 | } | 184 | } |
| 195 | }; | 185 | }; |
| 196 | 186 | ||
| 197 | struct DepthStencil { | 187 | struct DepthStencil { |
| 198 | constexpr DepthStencil(bool depth_test_enable, bool depth_write_enable, | 188 | template <std::size_t Position> |
| 199 | bool depth_bounds_enable, bool stencil_enable, | 189 | union StencilFace { |
| 200 | Maxwell::ComparisonOp depth_test_function, StencilFace front_stencil, | 190 | BitField<Position + 0, 3, u32> action_stencil_fail; |
| 201 | StencilFace back_stencil) | 191 | BitField<Position + 3, 3, u32> action_depth_fail; |
| 202 | : depth_test_enable{depth_test_enable}, depth_write_enable{depth_write_enable}, | 192 | BitField<Position + 6, 3, u32> action_depth_pass; |
| 203 | depth_bounds_enable{depth_bounds_enable}, stencil_enable{stencil_enable}, | 193 | BitField<Position + 9, 3, u32> test_func; |
| 204 | depth_test_function{depth_test_function}, front_stencil{front_stencil}, | 194 | |
| 205 | back_stencil{back_stencil} {} | 195 | Maxwell::StencilOp ActionStencilFail() const noexcept { |
| 206 | DepthStencil() = default; | 196 | return UnpackStencilOp(action_stencil_fail); |
| 207 | 197 | } | |
| 208 | bool depth_test_enable; | 198 | |
| 209 | bool depth_write_enable; | 199 | Maxwell::StencilOp ActionDepthFail() const noexcept { |
| 210 | bool depth_bounds_enable; | 200 | return UnpackStencilOp(action_depth_fail); |
| 211 | bool stencil_enable; | 201 | } |
| 212 | Maxwell::ComparisonOp depth_test_function; | 202 | |
| 213 | StencilFace front_stencil; | 203 | Maxwell::StencilOp ActionDepthPass() const noexcept { |
| 214 | StencilFace back_stencil; | 204 | return UnpackStencilOp(action_depth_pass); |
| 215 | 205 | } | |
| 216 | std::size_t Hash() const noexcept; | 206 | |
| 217 | 207 | Maxwell::ComparisonOp TestFunc() const noexcept { | |
| 218 | bool operator==(const DepthStencil& rhs) const noexcept; | 208 | return UnpackComparisonOp(test_func); |
| 219 | 209 | } | |
| 220 | bool operator!=(const DepthStencil& rhs) const noexcept { | 210 | }; |
| 221 | return !operator==(rhs); | 211 | |
| 212 | union { | ||
| 213 | u32 raw; | ||
| 214 | StencilFace<0> front; | ||
| 215 | StencilFace<12> back; | ||
| 216 | BitField<24, 1, u32> depth_test_enable; | ||
| 217 | BitField<25, 1, u32> depth_write_enable; | ||
| 218 | BitField<26, 1, u32> depth_bounds_enable; | ||
| 219 | BitField<27, 1, u32> stencil_enable; | ||
| 220 | BitField<28, 3, u32> depth_test_func; | ||
| 221 | }; | ||
| 222 | |||
| 223 | void Fill(const Maxwell& regs) noexcept; | ||
| 224 | |||
| 225 | Maxwell::ComparisonOp DepthTestFunc() const noexcept { | ||
| 226 | return UnpackComparisonOp(depth_test_func); | ||
| 222 | } | 227 | } |
| 223 | }; | 228 | }; |
| 224 | 229 | ||
| 225 | struct ColorBlending { | 230 | struct ColorBlending { |
| 226 | constexpr ColorBlending( | ||
| 227 | std::array<float, 4> blend_constants, std::size_t attachments_count, | ||
| 228 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments) | ||
| 229 | : attachments_count{attachments_count}, attachments{attachments} {} | ||
| 230 | ColorBlending() = default; | ||
| 231 | |||
| 232 | std::size_t attachments_count; | ||
| 233 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments; | 231 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments; |
| 234 | 232 | ||
| 235 | std::size_t Hash() const noexcept; | 233 | void Fill(const Maxwell& regs) noexcept; |
| 236 | |||
| 237 | bool operator==(const ColorBlending& rhs) const noexcept; | ||
| 238 | |||
| 239 | bool operator!=(const ColorBlending& rhs) const noexcept { | ||
| 240 | return !operator==(rhs); | ||
| 241 | } | ||
| 242 | }; | 234 | }; |
| 243 | 235 | ||
| 236 | VertexInput vertex_input; | ||
| 237 | Rasterizer rasterizer; | ||
| 238 | DepthStencil depth_stencil; | ||
| 239 | ColorBlending color_blending; | ||
| 240 | std::array<u8, 20> padding; | ||
| 241 | |||
| 244 | std::size_t Hash() const noexcept; | 242 | std::size_t Hash() const noexcept; |
| 245 | 243 | ||
| 246 | bool operator==(const FixedPipelineState& rhs) const noexcept; | 244 | bool operator==(const FixedPipelineState& rhs) const noexcept; |
| @@ -248,25 +246,11 @@ struct FixedPipelineState { | |||
| 248 | bool operator!=(const FixedPipelineState& rhs) const noexcept { | 246 | bool operator!=(const FixedPipelineState& rhs) const noexcept { |
| 249 | return !operator==(rhs); | 247 | return !operator==(rhs); |
| 250 | } | 248 | } |
| 251 | |||
| 252 | VertexInput vertex_input; | ||
| 253 | InputAssembly input_assembly; | ||
| 254 | Tessellation tessellation; | ||
| 255 | Rasterizer rasterizer; | ||
| 256 | DepthStencil depth_stencil; | ||
| 257 | ColorBlending color_blending; | ||
| 258 | }; | 249 | }; |
| 259 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexBinding>); | 250 | static_assert(std::has_unique_object_representations_v<FixedPipelineState>); |
| 260 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexAttribute>); | ||
| 261 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::StencilFace>); | ||
| 262 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>); | ||
| 263 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>); | ||
| 264 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::InputAssembly>); | ||
| 265 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::Tessellation>); | ||
| 266 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::Rasterizer>); | ||
| 267 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::DepthStencil>); | ||
| 268 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::ColorBlending>); | ||
| 269 | static_assert(std::is_trivially_copyable_v<FixedPipelineState>); | 251 | static_assert(std::is_trivially_copyable_v<FixedPipelineState>); |
| 252 | static_assert(std::is_trivially_constructible_v<FixedPipelineState>); | ||
| 253 | static_assert(sizeof(FixedPipelineState) % 32 == 0, "Size is not aligned"); | ||
| 270 | 254 | ||
| 271 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs); | 255 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs); |
| 272 | 256 | ||
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index b540b838d..343999cf5 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -26,12 +26,13 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache); | |||
| 26 | 26 | ||
| 27 | namespace { | 27 | namespace { |
| 28 | 28 | ||
| 29 | VkStencilOpState GetStencilFaceState(const FixedPipelineState::StencilFace& face) { | 29 | template <class StencilFace> |
| 30 | VkStencilOpState GetStencilFaceState(const StencilFace& face) { | ||
| 30 | VkStencilOpState state; | 31 | VkStencilOpState state; |
| 31 | state.failOp = MaxwellToVK::StencilOp(face.action_stencil_fail); | 32 | state.failOp = MaxwellToVK::StencilOp(face.ActionStencilFail()); |
| 32 | state.passOp = MaxwellToVK::StencilOp(face.action_depth_pass); | 33 | state.passOp = MaxwellToVK::StencilOp(face.ActionDepthPass()); |
| 33 | state.depthFailOp = MaxwellToVK::StencilOp(face.action_depth_fail); | 34 | state.depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail()); |
| 34 | state.compareOp = MaxwellToVK::ComparisonOp(face.test_func); | 35 | state.compareOp = MaxwellToVK::ComparisonOp(face.TestFunc()); |
| 35 | state.compareMask = 0; | 36 | state.compareMask = 0; |
| 36 | state.writeMask = 0; | 37 | state.writeMask = 0; |
| 37 | state.reference = 0; | 38 | state.reference = 0; |
| @@ -157,43 +158,47 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 157 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, | 158 | vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, |
| 158 | const SPIRVProgram& program) const { | 159 | const SPIRVProgram& program) const { |
| 159 | const auto& vi = fixed_state.vertex_input; | 160 | const auto& vi = fixed_state.vertex_input; |
| 160 | const auto& ia = fixed_state.input_assembly; | ||
| 161 | const auto& ds = fixed_state.depth_stencil; | 161 | const auto& ds = fixed_state.depth_stencil; |
| 162 | const auto& cd = fixed_state.color_blending; | 162 | const auto& cd = fixed_state.color_blending; |
| 163 | const auto& ts = fixed_state.tessellation; | ||
| 164 | const auto& rs = fixed_state.rasterizer; | 163 | const auto& rs = fixed_state.rasterizer; |
| 165 | 164 | ||
| 166 | std::vector<VkVertexInputBindingDescription> vertex_bindings; | 165 | std::vector<VkVertexInputBindingDescription> vertex_bindings; |
| 167 | std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors; | 166 | std::vector<VkVertexInputBindingDivisorDescriptionEXT> vertex_binding_divisors; |
| 168 | for (std::size_t i = 0; i < vi.num_bindings; ++i) { | 167 | for (std::size_t index = 0; index < std::size(vi.bindings); ++index) { |
| 169 | const auto& binding = vi.bindings[i]; | 168 | const auto& binding = vi.bindings[index]; |
| 170 | const bool instanced = binding.divisor != 0; | 169 | if (!binding.enabled) { |
| 170 | continue; | ||
| 171 | } | ||
| 172 | const bool instanced = vi.binding_divisors[index] != 0; | ||
| 171 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | 173 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; |
| 172 | 174 | ||
| 173 | auto& vertex_binding = vertex_bindings.emplace_back(); | 175 | auto& vertex_binding = vertex_bindings.emplace_back(); |
| 174 | vertex_binding.binding = binding.index; | 176 | vertex_binding.binding = static_cast<u32>(index); |
| 175 | vertex_binding.stride = binding.stride; | 177 | vertex_binding.stride = binding.stride; |
| 176 | vertex_binding.inputRate = rate; | 178 | vertex_binding.inputRate = rate; |
| 177 | 179 | ||
| 178 | if (instanced) { | 180 | if (instanced) { |
| 179 | auto& binding_divisor = vertex_binding_divisors.emplace_back(); | 181 | auto& binding_divisor = vertex_binding_divisors.emplace_back(); |
| 180 | binding_divisor.binding = binding.index; | 182 | binding_divisor.binding = static_cast<u32>(index); |
| 181 | binding_divisor.divisor = binding.divisor; | 183 | binding_divisor.divisor = vi.binding_divisors[index]; |
| 182 | } | 184 | } |
| 183 | } | 185 | } |
| 184 | 186 | ||
| 185 | std::vector<VkVertexInputAttributeDescription> vertex_attributes; | 187 | std::vector<VkVertexInputAttributeDescription> vertex_attributes; |
| 186 | const auto& input_attributes = program[0]->entries.attributes; | 188 | const auto& input_attributes = program[0]->entries.attributes; |
| 187 | for (std::size_t i = 0; i < vi.num_attributes; ++i) { | 189 | for (std::size_t index = 0; index < std::size(vi.attributes); ++index) { |
| 188 | const auto& attribute = vi.attributes[i]; | 190 | const auto& attribute = vi.attributes[index]; |
| 189 | if (input_attributes.find(attribute.index) == input_attributes.end()) { | 191 | if (!attribute.enabled) { |
| 192 | continue; | ||
| 193 | } | ||
| 194 | if (input_attributes.find(static_cast<u32>(index)) == input_attributes.end()) { | ||
| 190 | // Skip attributes not used by the vertex shaders. | 195 | // Skip attributes not used by the vertex shaders. |
| 191 | continue; | 196 | continue; |
| 192 | } | 197 | } |
| 193 | auto& vertex_attribute = vertex_attributes.emplace_back(); | 198 | auto& vertex_attribute = vertex_attributes.emplace_back(); |
| 194 | vertex_attribute.location = attribute.index; | 199 | vertex_attribute.location = static_cast<u32>(index); |
| 195 | vertex_attribute.binding = attribute.buffer; | 200 | vertex_attribute.binding = attribute.buffer; |
| 196 | vertex_attribute.format = MaxwellToVK::VertexFormat(attribute.type, attribute.size); | 201 | vertex_attribute.format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()); |
| 197 | vertex_attribute.offset = attribute.offset; | 202 | vertex_attribute.offset = attribute.offset; |
| 198 | } | 203 | } |
| 199 | 204 | ||
| @@ -219,15 +224,15 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 219 | input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | 224 | input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; |
| 220 | input_assembly_ci.pNext = nullptr; | 225 | input_assembly_ci.pNext = nullptr; |
| 221 | input_assembly_ci.flags = 0; | 226 | input_assembly_ci.flags = 0; |
| 222 | input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, ia.topology); | 227 | input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, rs.Topology()); |
| 223 | input_assembly_ci.primitiveRestartEnable = | 228 | input_assembly_ci.primitiveRestartEnable = |
| 224 | ia.primitive_restart_enable && SupportsPrimitiveRestart(input_assembly_ci.topology); | 229 | rs.primitive_restart_enable != 0 && SupportsPrimitiveRestart(input_assembly_ci.topology); |
| 225 | 230 | ||
| 226 | VkPipelineTessellationStateCreateInfo tessellation_ci; | 231 | VkPipelineTessellationStateCreateInfo tessellation_ci; |
| 227 | tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; | 232 | tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; |
| 228 | tessellation_ci.pNext = nullptr; | 233 | tessellation_ci.pNext = nullptr; |
| 229 | tessellation_ci.flags = 0; | 234 | tessellation_ci.flags = 0; |
| 230 | tessellation_ci.patchControlPoints = ts.patch_control_points; | 235 | tessellation_ci.patchControlPoints = rs.patch_control_points_minus_one.Value() + 1; |
| 231 | 236 | ||
| 232 | VkPipelineViewportStateCreateInfo viewport_ci; | 237 | VkPipelineViewportStateCreateInfo viewport_ci; |
| 233 | viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | 238 | viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; |
| @@ -246,8 +251,8 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 246 | rasterization_ci.rasterizerDiscardEnable = VK_FALSE; | 251 | rasterization_ci.rasterizerDiscardEnable = VK_FALSE; |
| 247 | rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; | 252 | rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; |
| 248 | rasterization_ci.cullMode = | 253 | rasterization_ci.cullMode = |
| 249 | rs.cull_enable ? MaxwellToVK::CullFace(rs.cull_face) : VK_CULL_MODE_NONE; | 254 | rs.cull_enable ? MaxwellToVK::CullFace(rs.CullFace()) : VK_CULL_MODE_NONE; |
| 250 | rasterization_ci.frontFace = MaxwellToVK::FrontFace(rs.front_face); | 255 | rasterization_ci.frontFace = MaxwellToVK::FrontFace(rs.FrontFace()); |
| 251 | rasterization_ci.depthBiasEnable = rs.depth_bias_enable; | 256 | rasterization_ci.depthBiasEnable = rs.depth_bias_enable; |
| 252 | rasterization_ci.depthBiasConstantFactor = 0.0f; | 257 | rasterization_ci.depthBiasConstantFactor = 0.0f; |
| 253 | rasterization_ci.depthBiasClamp = 0.0f; | 258 | rasterization_ci.depthBiasClamp = 0.0f; |
| @@ -271,40 +276,38 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 271 | depth_stencil_ci.flags = 0; | 276 | depth_stencil_ci.flags = 0; |
| 272 | depth_stencil_ci.depthTestEnable = ds.depth_test_enable; | 277 | depth_stencil_ci.depthTestEnable = ds.depth_test_enable; |
| 273 | depth_stencil_ci.depthWriteEnable = ds.depth_write_enable; | 278 | depth_stencil_ci.depthWriteEnable = ds.depth_write_enable; |
| 274 | depth_stencil_ci.depthCompareOp = ds.depth_test_enable | 279 | depth_stencil_ci.depthCompareOp = |
| 275 | ? MaxwellToVK::ComparisonOp(ds.depth_test_function) | 280 | ds.depth_test_enable ? MaxwellToVK::ComparisonOp(ds.DepthTestFunc()) : VK_COMPARE_OP_ALWAYS; |
| 276 | : VK_COMPARE_OP_ALWAYS; | ||
| 277 | depth_stencil_ci.depthBoundsTestEnable = ds.depth_bounds_enable; | 281 | depth_stencil_ci.depthBoundsTestEnable = ds.depth_bounds_enable; |
| 278 | depth_stencil_ci.stencilTestEnable = ds.stencil_enable; | 282 | depth_stencil_ci.stencilTestEnable = ds.stencil_enable; |
| 279 | depth_stencil_ci.front = GetStencilFaceState(ds.front_stencil); | 283 | depth_stencil_ci.front = GetStencilFaceState(ds.front); |
| 280 | depth_stencil_ci.back = GetStencilFaceState(ds.back_stencil); | 284 | depth_stencil_ci.back = GetStencilFaceState(ds.back); |
| 281 | depth_stencil_ci.minDepthBounds = 0.0f; | 285 | depth_stencil_ci.minDepthBounds = 0.0f; |
| 282 | depth_stencil_ci.maxDepthBounds = 0.0f; | 286 | depth_stencil_ci.maxDepthBounds = 0.0f; |
| 283 | 287 | ||
| 284 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; | 288 | std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; |
| 285 | const std::size_t num_attachments = | 289 | const std::size_t num_attachments = renderpass_params.color_attachments.size(); |
| 286 | std::min(cd.attachments_count, renderpass_params.color_attachments.size()); | 290 | for (std::size_t index = 0; index < num_attachments; ++index) { |
| 287 | for (std::size_t i = 0; i < num_attachments; ++i) { | 291 | static constexpr std::array COMPONENT_TABLE = { |
| 288 | static constexpr std::array component_table = { | ||
| 289 | VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, | 292 | VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, |
| 290 | VK_COLOR_COMPONENT_A_BIT}; | 293 | VK_COLOR_COMPONENT_A_BIT}; |
| 291 | const auto& blend = cd.attachments[i]; | 294 | const auto& blend = cd.attachments[index]; |
| 292 | 295 | ||
| 293 | VkColorComponentFlags color_components = 0; | 296 | VkColorComponentFlags color_components = 0; |
| 294 | for (std::size_t j = 0; j < component_table.size(); ++j) { | 297 | for (std::size_t i = 0; i < COMPONENT_TABLE.size(); ++i) { |
| 295 | if (blend.components[j]) { | 298 | if (blend.Mask()[i]) { |
| 296 | color_components |= component_table[j]; | 299 | color_components |= COMPONENT_TABLE[i]; |
| 297 | } | 300 | } |
| 298 | } | 301 | } |
| 299 | 302 | ||
| 300 | VkPipelineColorBlendAttachmentState& attachment = cb_attachments[i]; | 303 | VkPipelineColorBlendAttachmentState& attachment = cb_attachments[index]; |
| 301 | attachment.blendEnable = blend.enable; | 304 | attachment.blendEnable = blend.enable != 0; |
| 302 | attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.src_rgb_func); | 305 | attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()); |
| 303 | attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.dst_rgb_func); | 306 | attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()); |
| 304 | attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.rgb_equation); | 307 | attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()); |
| 305 | attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.src_a_func); | 308 | attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()); |
| 306 | attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.dst_a_func); | 309 | attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()); |
| 307 | attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.a_equation); | 310 | attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()); |
| 308 | attachment.colorWriteMask = color_components; | 311 | attachment.colorWriteMask = color_components; |
| 309 | } | 312 | } |
| 310 | 313 | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 90e3a8edd..8fdc6400d 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -329,12 +329,12 @@ VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) { | |||
| 329 | const auto& gpu = system.GPU().Maxwell3D(); | 329 | const auto& gpu = system.GPU().Maxwell3D(); |
| 330 | 330 | ||
| 331 | Specialization specialization; | 331 | Specialization specialization; |
| 332 | if (fixed_state.input_assembly.topology == Maxwell::PrimitiveTopology::Points) { | 332 | if (fixed_state.rasterizer.Topology() == Maxwell::PrimitiveTopology::Points) { |
| 333 | ASSERT(fixed_state.input_assembly.point_size != 0.0f); | 333 | ASSERT(fixed_state.rasterizer.point_size != 0); |
| 334 | specialization.point_size = fixed_state.input_assembly.point_size; | 334 | std::memcpy(&specialization.point_size, &fixed_state.rasterizer.point_size, sizeof(u32)); |
| 335 | } | 335 | } |
| 336 | for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) { | 336 | for (std::size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) { |
| 337 | specialization.attribute_types[i] = fixed_state.vertex_input.attributes[i].type; | 337 | specialization.attribute_types[i] = fixed_state.vertex_input.attributes[i].Type(); |
| 338 | } | 338 | } |
| 339 | specialization.ndc_minus_one_to_one = fixed_state.rasterizer.ndc_minus_one_to_one; | 339 | specialization.ndc_minus_one_to_one = fixed_state.rasterizer.ndc_minus_one_to_one; |
| 340 | 340 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 9bf9e1028..71007bbe8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -807,25 +807,29 @@ void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex | |||
| 807 | BufferBindings& buffer_bindings) { | 807 | BufferBindings& buffer_bindings) { |
| 808 | const auto& regs = system.GPU().Maxwell3D().regs; | 808 | const auto& regs = system.GPU().Maxwell3D().regs; |
| 809 | 809 | ||
| 810 | for (u32 index = 0; index < static_cast<u32>(Maxwell::NumVertexAttributes); ++index) { | 810 | for (std::size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { |
| 811 | const auto& attrib = regs.vertex_attrib_format[index]; | 811 | const auto& attrib = regs.vertex_attrib_format[index]; |
| 812 | if (!attrib.IsValid()) { | 812 | if (!attrib.IsValid()) { |
| 813 | vertex_input.SetAttribute(index, false, 0, 0, {}, {}); | ||
| 813 | continue; | 814 | continue; |
| 814 | } | 815 | } |
| 815 | 816 | ||
| 816 | const auto& buffer = regs.vertex_array[attrib.buffer]; | 817 | [[maybe_unused]] const auto& buffer = regs.vertex_array[attrib.buffer]; |
| 817 | ASSERT(buffer.IsEnabled()); | 818 | ASSERT(buffer.IsEnabled()); |
| 818 | 819 | ||
| 819 | vertex_input.attributes[vertex_input.num_attributes++] = | 820 | vertex_input.SetAttribute(index, true, attrib.buffer, attrib.offset, attrib.type.Value(), |
| 820 | FixedPipelineState::VertexAttribute(index, attrib.buffer, attrib.type, attrib.size, | 821 | attrib.size.Value()); |
| 821 | attrib.offset); | ||
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | for (u32 index = 0; index < static_cast<u32>(Maxwell::NumVertexArrays); ++index) { | 824 | for (std::size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 825 | const auto& vertex_array = regs.vertex_array[index]; | 825 | const auto& vertex_array = regs.vertex_array[index]; |
| 826 | if (!vertex_array.IsEnabled()) { | 826 | if (!vertex_array.IsEnabled()) { |
| 827 | vertex_input.SetBinding(index, false, 0, 0); | ||
| 827 | continue; | 828 | continue; |
| 828 | } | 829 | } |
| 830 | vertex_input.SetBinding( | ||
| 831 | index, true, vertex_array.stride, | ||
| 832 | regs.instanced_arrays.IsInstancingEnabled(index) ? vertex_array.divisor : 0); | ||
| 829 | 833 | ||
| 830 | const GPUVAddr start{vertex_array.StartAddress()}; | 834 | const GPUVAddr start{vertex_array.StartAddress()}; |
| 831 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; | 835 | const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; |
| @@ -833,10 +837,6 @@ void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex | |||
| 833 | ASSERT(end > start); | 837 | ASSERT(end > start); |
| 834 | const std::size_t size{end - start + 1}; | 838 | const std::size_t size{end - start + 1}; |
| 835 | const auto [buffer, offset] = buffer_cache.UploadMemory(start, size); | 839 | const auto [buffer, offset] = buffer_cache.UploadMemory(start, size); |
| 836 | |||
| 837 | vertex_input.bindings[vertex_input.num_bindings++] = FixedPipelineState::VertexBinding( | ||
| 838 | index, vertex_array.stride, | ||
| 839 | regs.instanced_arrays.IsInstancingEnabled(index) ? vertex_array.divisor : 0); | ||
| 840 | buffer_bindings.AddVertexBinding(buffer, offset); | 840 | buffer_bindings.AddVertexBinding(buffer, offset); |
| 841 | } | 841 | } |
| 842 | } | 842 | } |