diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | 296 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.h | 282 |
4 files changed, 594 insertions, 6 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3b20c7d34..e615b238e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -151,6 +151,8 @@ add_library(video_core STATIC | |||
| 151 | if (ENABLE_VULKAN) | 151 | if (ENABLE_VULKAN) |
| 152 | target_sources(video_core PRIVATE | 152 | target_sources(video_core PRIVATE |
| 153 | renderer_vulkan/declarations.h | 153 | renderer_vulkan/declarations.h |
| 154 | renderer_vulkan/fixed_pipeline_state.cpp | ||
| 155 | renderer_vulkan/fixed_pipeline_state.h | ||
| 154 | renderer_vulkan/maxwell_to_vk.cpp | 156 | renderer_vulkan/maxwell_to_vk.cpp |
| 155 | renderer_vulkan/maxwell_to_vk.h | 157 | renderer_vulkan/maxwell_to_vk.h |
| 156 | renderer_vulkan/vk_buffer_cache.cpp | 158 | renderer_vulkan/vk_buffer_cache.cpp |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 870b359be..a35e7a195 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -711,13 +711,15 @@ public: | |||
| 711 | 711 | ||
| 712 | u32 color_mask_common; | 712 | u32 color_mask_common; |
| 713 | 713 | ||
| 714 | INSERT_UNION_PADDING_WORDS(0x6); | 714 | INSERT_UNION_PADDING_WORDS(0x2); |
| 715 | |||
| 716 | u32 rt_separate_frag_data; | ||
| 717 | 715 | ||
| 718 | f32 depth_bounds[2]; | 716 | f32 depth_bounds[2]; |
| 719 | 717 | ||
| 720 | INSERT_UNION_PADDING_WORDS(0xA); | 718 | INSERT_UNION_PADDING_WORDS(0x2); |
| 719 | |||
| 720 | u32 rt_separate_frag_data; | ||
| 721 | |||
| 722 | INSERT_UNION_PADDING_WORDS(0xC); | ||
| 721 | 723 | ||
| 722 | struct { | 724 | struct { |
| 723 | u32 address_high; | 725 | u32 address_high; |
| @@ -1034,7 +1036,12 @@ public: | |||
| 1034 | BitField<4, 1, u32> depth_clamp_far; | 1036 | BitField<4, 1, u32> depth_clamp_far; |
| 1035 | } view_volume_clip_control; | 1037 | } view_volume_clip_control; |
| 1036 | 1038 | ||
| 1037 | INSERT_UNION_PADDING_WORDS(0x21); | 1039 | INSERT_UNION_PADDING_WORDS(0x1F); |
| 1040 | |||
| 1041 | u32 depth_bounds_enable; | ||
| 1042 | |||
| 1043 | INSERT_UNION_PADDING_WORDS(1); | ||
| 1044 | |||
| 1038 | struct { | 1045 | struct { |
| 1039 | u32 enable; | 1046 | u32 enable; |
| 1040 | LogicOperation operation; | 1047 | LogicOperation operation; |
| @@ -1444,7 +1451,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D6); | |||
| 1444 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D7); | 1451 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D7); |
| 1445 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); | 1452 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); |
| 1446 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | 1453 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); |
| 1447 | ASSERT_REG_POSITION(depth_bounds, 0x3EC); | 1454 | ASSERT_REG_POSITION(depth_bounds, 0x3E7); |
| 1448 | ASSERT_REG_POSITION(zeta, 0x3F8); | 1455 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 1449 | ASSERT_REG_POSITION(clear_flags, 0x43E); | 1456 | ASSERT_REG_POSITION(clear_flags, 0x43E); |
| 1450 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | 1457 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); |
| @@ -1500,6 +1507,7 @@ ASSERT_REG_POSITION(cull, 0x646); | |||
| 1500 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); | 1507 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); |
| 1501 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); | 1508 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); |
| 1502 | ASSERT_REG_POSITION(view_volume_clip_control, 0x64F); | 1509 | ASSERT_REG_POSITION(view_volume_clip_control, 0x64F); |
| 1510 | ASSERT_REG_POSITION(depth_bounds_enable, 0x66F); | ||
| 1503 | ASSERT_REG_POSITION(logic_op, 0x671); | 1511 | ASSERT_REG_POSITION(logic_op, 0x671); |
| 1504 | ASSERT_REG_POSITION(clear_buffers, 0x674); | 1512 | ASSERT_REG_POSITION(clear_buffers, 0x674); |
| 1505 | ASSERT_REG_POSITION(color_mask, 0x680); | 1513 | ASSERT_REG_POSITION(color_mask, 0x680); |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp new file mode 100644 index 000000000..5a490f6ef --- /dev/null +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <tuple> | ||
| 6 | |||
| 7 | #include <boost/functional/hash.hpp> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | ||
| 11 | |||
| 12 | namespace Vulkan { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | |||
| 16 | constexpr FixedPipelineState::DepthStencil GetDepthStencilState(const Maxwell& regs) { | ||
| 17 | const FixedPipelineState::StencilFace front_stencil( | ||
| 18 | regs.stencil_front_op_fail, regs.stencil_front_op_zfail, regs.stencil_front_op_zpass, | ||
| 19 | regs.stencil_front_func_func); | ||
| 20 | const FixedPipelineState::StencilFace back_stencil = | ||
| 21 | regs.stencil_two_side_enable | ||
| 22 | ? FixedPipelineState::StencilFace(regs.stencil_back_op_fail, regs.stencil_back_op_zfail, | ||
| 23 | regs.stencil_back_op_zpass, | ||
| 24 | regs.stencil_back_func_func) | ||
| 25 | : front_stencil; | ||
| 26 | return FixedPipelineState::DepthStencil( | ||
| 27 | regs.depth_test_enable == 1, regs.depth_write_enabled == 1, regs.depth_bounds_enable == 1, | ||
| 28 | regs.stencil_enable == 1, regs.depth_test_func, front_stencil, back_stencil); | ||
| 29 | } | ||
| 30 | |||
| 31 | constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { | ||
| 32 | return FixedPipelineState::InputAssembly( | ||
| 33 | regs.draw.topology, regs.primitive_restart.enabled, | ||
| 34 | regs.draw.topology == Maxwell::PrimitiveTopology::Points ? regs.point_size : 0.0f); | ||
| 35 | } | ||
| 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 | |||
| 50 | if (!regs.independent_blend_enable) { | ||
| 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 | |||
| 60 | if (!regs.blend.enable[render_target]) { | ||
| 61 | return default_blending; | ||
| 62 | } | ||
| 63 | const auto& src = regs.independent_blend[render_target]; | ||
| 64 | return FixedPipelineState::BlendingAttachment( | ||
| 65 | true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a, | ||
| 66 | src.factor_source_a, src.factor_dest_a, components); | ||
| 67 | } | ||
| 68 | |||
| 69 | constexpr FixedPipelineState::ColorBlending GetColorBlendingState(const Maxwell& regs) { | ||
| 70 | return FixedPipelineState::ColorBlending( | ||
| 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, | ||
| 107 | regs.polygon_offset_line_enable, | ||
| 108 | regs.polygon_offset_fill_enable}; | ||
| 109 | const auto topology = static_cast<std::size_t>(regs.draw.topology.Value()); | ||
| 110 | const bool depth_bias_enabled = enabled_lut[PolygonOffsetEnableLUT[topology]]; | ||
| 111 | |||
| 112 | Maxwell::Cull::FrontFace front_face = regs.cull.front_face; | ||
| 113 | if (regs.screen_y_control.triangle_rast_flip != 0 && | ||
| 114 | regs.viewport_transform[0].scale_y > 0.0f) { | ||
| 115 | if (front_face == Maxwell::Cull::FrontFace::CounterClockWise) | ||
| 116 | front_face = Maxwell::Cull::FrontFace::ClockWise; | ||
| 117 | else if (front_face == Maxwell::Cull::FrontFace::ClockWise) | ||
| 118 | front_face = Maxwell::Cull::FrontFace::CounterClockWise; | ||
| 119 | } | ||
| 120 | |||
| 121 | const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; | ||
| 122 | return FixedPipelineState::Rasterizer(regs.cull.enabled, depth_bias_enabled, gl_ndc, | ||
| 123 | regs.cull.cull_face, front_face); | ||
| 124 | } | ||
| 125 | |||
| 126 | } // Anonymous namespace | ||
| 127 | |||
| 128 | std::size_t FixedPipelineState::VertexBinding::Hash() const noexcept { | ||
| 129 | return (index << stride) ^ divisor; | ||
| 130 | } | ||
| 131 | |||
| 132 | bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const noexcept { | ||
| 133 | return std::tie(index, stride, divisor) == std::tie(rhs.index, rhs.stride, rhs.divisor); | ||
| 134 | } | ||
| 135 | |||
| 136 | std::size_t FixedPipelineState::VertexAttribute::Hash() const noexcept { | ||
| 137 | return static_cast<std::size_t>(index) ^ (static_cast<std::size_t>(buffer) << 13) ^ | ||
| 138 | (static_cast<std::size_t>(type) << 22) ^ (static_cast<std::size_t>(size) << 31) ^ | ||
| 139 | (static_cast<std::size_t>(offset) << 36); | ||
| 140 | } | ||
| 141 | |||
| 142 | bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const noexcept { | ||
| 143 | return std::tie(index, buffer, type, size, offset) == | ||
| 144 | std::tie(rhs.index, rhs.buffer, rhs.type, rhs.size, rhs.offset); | ||
| 145 | } | ||
| 146 | |||
| 147 | std::size_t FixedPipelineState::StencilFace::Hash() const noexcept { | ||
| 148 | return static_cast<std::size_t>(action_stencil_fail) ^ | ||
| 149 | (static_cast<std::size_t>(action_depth_fail) << 4) ^ | ||
| 150 | (static_cast<std::size_t>(action_depth_fail) << 20) ^ | ||
| 151 | (static_cast<std::size_t>(action_depth_pass) << 36); | ||
| 152 | } | ||
| 153 | |||
| 154 | bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const noexcept { | ||
| 155 | return std::tie(action_stencil_fail, action_depth_fail, action_depth_pass, test_func) == | ||
| 156 | std::tie(rhs.action_stencil_fail, rhs.action_depth_fail, rhs.action_depth_pass, | ||
| 157 | rhs.test_func); | ||
| 158 | } | ||
| 159 | |||
| 160 | std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { | ||
| 161 | return static_cast<std::size_t>(enable) ^ (static_cast<std::size_t>(rgb_equation) << 5) ^ | ||
| 162 | (static_cast<std::size_t>(src_rgb_func) << 10) ^ | ||
| 163 | (static_cast<std::size_t>(dst_rgb_func) << 15) ^ | ||
| 164 | (static_cast<std::size_t>(a_equation) << 20) ^ | ||
| 165 | (static_cast<std::size_t>(src_a_func) << 25) ^ | ||
| 166 | (static_cast<std::size_t>(dst_a_func) << 30) ^ | ||
| 167 | (static_cast<std::size_t>(components[0]) << 35) ^ | ||
| 168 | (static_cast<std::size_t>(components[1]) << 36) ^ | ||
| 169 | (static_cast<std::size_t>(components[2]) << 37) ^ | ||
| 170 | (static_cast<std::size_t>(components[3]) << 38); | ||
| 171 | } | ||
| 172 | |||
| 173 | bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const | ||
| 174 | noexcept { | ||
| 175 | return std::tie(enable, rgb_equation, src_rgb_func, dst_rgb_func, a_equation, src_a_func, | ||
| 176 | dst_a_func, components) == | ||
| 177 | std::tie(rhs.enable, rhs.rgb_equation, rhs.src_rgb_func, rhs.dst_rgb_func, | ||
| 178 | rhs.a_equation, rhs.src_a_func, rhs.dst_a_func, rhs.components); | ||
| 179 | } | ||
| 180 | |||
| 181 | std::size_t FixedPipelineState::VertexInput::Hash() const noexcept { | ||
| 182 | std::size_t hash = num_bindings ^ (num_attributes << 32); | ||
| 183 | for (std::size_t i = 0; i < num_bindings; ++i) { | ||
| 184 | boost::hash_combine(hash, bindings[i].Hash()); | ||
| 185 | } | ||
| 186 | for (std::size_t i = 0; i < num_attributes; ++i) { | ||
| 187 | boost::hash_combine(hash, attributes[i].Hash()); | ||
| 188 | } | ||
| 189 | return hash; | ||
| 190 | } | ||
| 191 | |||
| 192 | bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const noexcept { | ||
| 193 | return std::equal(bindings.begin(), bindings.begin() + num_bindings, rhs.bindings.begin(), | ||
| 194 | rhs.bindings.begin() + rhs.num_bindings) && | ||
| 195 | std::equal(attributes.begin(), attributes.begin() + num_attributes, | ||
| 196 | rhs.attributes.begin(), rhs.attributes.begin() + rhs.num_attributes); | ||
| 197 | } | ||
| 198 | |||
| 199 | std::size_t FixedPipelineState::InputAssembly::Hash() const noexcept { | ||
| 200 | std::size_t point_size_int = 0; | ||
| 201 | std::memcpy(&point_size_int, &point_size, sizeof(point_size)); | ||
| 202 | return (static_cast<std::size_t>(topology) << 24) ^ (point_size_int << 32) ^ | ||
| 203 | static_cast<std::size_t>(primitive_restart_enable); | ||
| 204 | } | ||
| 205 | |||
| 206 | bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const noexcept { | ||
| 207 | return std::tie(topology, primitive_restart_enable, point_size) == | ||
| 208 | std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size); | ||
| 209 | } | ||
| 210 | |||
| 211 | std::size_t FixedPipelineState::Tessellation::Hash() const noexcept { | ||
| 212 | return static_cast<std::size_t>(patch_control_points) ^ | ||
| 213 | (static_cast<std::size_t>(primitive) << 6) ^ (static_cast<std::size_t>(spacing) << 8) ^ | ||
| 214 | (static_cast<std::size_t>(clockwise) << 10); | ||
| 215 | } | ||
| 216 | |||
| 217 | bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const noexcept { | ||
| 218 | return std::tie(patch_control_points, primitive, spacing, clockwise) == | ||
| 219 | std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise); | ||
| 220 | } | ||
| 221 | |||
| 222 | std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept { | ||
| 223 | return static_cast<std::size_t>(cull_enable) ^ | ||
| 224 | (static_cast<std::size_t>(depth_bias_enable) << 1) ^ | ||
| 225 | (static_cast<std::size_t>(ndc_minus_one_to_one) << 2) ^ | ||
| 226 | (static_cast<std::size_t>(cull_face) << 24) ^ | ||
| 227 | (static_cast<std::size_t>(front_face) << 48); | ||
| 228 | } | ||
| 229 | |||
| 230 | bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept { | ||
| 231 | return std::tie(cull_enable, depth_bias_enable, ndc_minus_one_to_one, cull_face, front_face) == | ||
| 232 | std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.ndc_minus_one_to_one, rhs.cull_face, | ||
| 233 | rhs.front_face); | ||
| 234 | } | ||
| 235 | |||
| 236 | std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { | ||
| 237 | std::size_t hash = static_cast<std::size_t>(depth_test_enable) ^ | ||
| 238 | (static_cast<std::size_t>(depth_write_enable) << 1) ^ | ||
| 239 | (static_cast<std::size_t>(depth_bounds_enable) << 2) ^ | ||
| 240 | (static_cast<std::size_t>(stencil_enable) << 3) ^ | ||
| 241 | (static_cast<std::size_t>(depth_test_function) << 4); | ||
| 242 | boost::hash_combine(hash, front_stencil.Hash()); | ||
| 243 | boost::hash_combine(hash, back_stencil.Hash()); | ||
| 244 | return hash; | ||
| 245 | } | ||
| 246 | |||
| 247 | bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept { | ||
| 248 | return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, | ||
| 249 | stencil_enable, front_stencil, back_stencil) == | ||
| 250 | std::tie(rhs.depth_test_enable, rhs.depth_write_enable, rhs.depth_bounds_enable, | ||
| 251 | rhs.depth_test_function, rhs.stencil_enable, rhs.front_stencil, | ||
| 252 | rhs.back_stencil); | ||
| 253 | } | ||
| 254 | |||
| 255 | std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept { | ||
| 256 | std::size_t hash = attachments_count << 13; | ||
| 257 | for (std::size_t rt = 0; rt < static_cast<std::size_t>(attachments_count); ++rt) { | ||
| 258 | boost::hash_combine(hash, attachments[rt].Hash()); | ||
| 259 | } | ||
| 260 | return hash; | ||
| 261 | } | ||
| 262 | |||
| 263 | bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const noexcept { | ||
| 264 | return std::equal(attachments.begin(), attachments.begin() + attachments_count, | ||
| 265 | rhs.attachments.begin(), rhs.attachments.begin() + rhs.attachments_count); | ||
| 266 | } | ||
| 267 | |||
| 268 | std::size_t FixedPipelineState::Hash() const noexcept { | ||
| 269 | std::size_t hash = 0; | ||
| 270 | boost::hash_combine(hash, vertex_input.Hash()); | ||
| 271 | boost::hash_combine(hash, input_assembly.Hash()); | ||
| 272 | boost::hash_combine(hash, tessellation.Hash()); | ||
| 273 | boost::hash_combine(hash, rasterizer.Hash()); | ||
| 274 | boost::hash_combine(hash, depth_stencil.Hash()); | ||
| 275 | boost::hash_combine(hash, color_blending.Hash()); | ||
| 276 | return hash; | ||
| 277 | } | ||
| 278 | |||
| 279 | bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept { | ||
| 280 | return std::tie(vertex_input, input_assembly, tessellation, rasterizer, depth_stencil, | ||
| 281 | color_blending) == std::tie(rhs.vertex_input, rhs.input_assembly, | ||
| 282 | rhs.tessellation, rhs.rasterizer, rhs.depth_stencil, | ||
| 283 | rhs.color_blending); | ||
| 284 | } | ||
| 285 | |||
| 286 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { | ||
| 287 | FixedPipelineState fixed_state; | ||
| 288 | fixed_state.input_assembly = GetInputAssemblyState(regs); | ||
| 289 | fixed_state.tessellation = GetTessellationState(regs); | ||
| 290 | fixed_state.rasterizer = GetRasterizerState(regs); | ||
| 291 | fixed_state.depth_stencil = GetDepthStencilState(regs); | ||
| 292 | fixed_state.color_blending = GetColorBlendingState(regs); | ||
| 293 | return fixed_state; | ||
| 294 | } | ||
| 295 | |||
| 296 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h new file mode 100644 index 000000000..04152c0d4 --- /dev/null +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -0,0 +1,282 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <type_traits> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | #include "video_core/engines/maxwell_3d.h" | ||
| 13 | #include "video_core/surface.h" | ||
| 14 | |||
| 15 | namespace Vulkan { | ||
| 16 | |||
| 17 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 18 | |||
| 19 | // TODO(Rodrigo): Optimize this structure. | ||
| 20 | |||
| 21 | struct FixedPipelineState { | ||
| 22 | using PixelFormat = VideoCore::Surface::PixelFormat; | ||
| 23 | |||
| 24 | struct VertexBinding { | ||
| 25 | constexpr VertexBinding(u32 index, u32 stride, u32 divisor) | ||
| 26 | : index{index}, stride{stride}, divisor{divisor} {} | ||
| 27 | VertexBinding() = default; | ||
| 28 | |||
| 29 | u32 index; | ||
| 30 | u32 stride; | ||
| 31 | u32 divisor; | ||
| 32 | |||
| 33 | std::size_t Hash() const noexcept; | ||
| 34 | |||
| 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 | |||
| 76 | std::size_t Hash() const noexcept; | ||
| 77 | |||
| 78 | bool operator==(const StencilFace& rhs) const noexcept; | ||
| 79 | |||
| 80 | bool operator!=(const StencilFace& rhs) const noexcept { | ||
| 81 | return !operator==(rhs); | ||
| 82 | } | ||
| 83 | }; | ||
| 84 | |||
| 85 | struct BlendingAttachment { | ||
| 86 | constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation, | ||
| 87 | Maxwell::Blend::Factor src_rgb_func, | ||
| 88 | Maxwell::Blend::Factor dst_rgb_func, | ||
| 89 | Maxwell::Blend::Equation a_equation, | ||
| 90 | Maxwell::Blend::Factor src_a_func, | ||
| 91 | Maxwell::Blend::Factor dst_a_func, | ||
| 92 | std::array<bool, 4> components) | ||
| 93 | : enable{enable}, rgb_equation{rgb_equation}, src_rgb_func{src_rgb_func}, | ||
| 94 | dst_rgb_func{dst_rgb_func}, a_equation{a_equation}, src_a_func{src_a_func}, | ||
| 95 | dst_a_func{dst_a_func}, components{components} {} | ||
| 96 | BlendingAttachment() = default; | ||
| 97 | |||
| 98 | bool enable; | ||
| 99 | Maxwell::Blend::Equation rgb_equation; | ||
| 100 | Maxwell::Blend::Factor src_rgb_func; | ||
| 101 | Maxwell::Blend::Factor dst_rgb_func; | ||
| 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 | |||
| 107 | std::size_t Hash() const noexcept; | ||
| 108 | |||
| 109 | bool operator==(const BlendingAttachment& rhs) const noexcept; | ||
| 110 | |||
| 111 | bool operator!=(const BlendingAttachment& rhs) const noexcept { | ||
| 112 | return !operator==(rhs); | ||
| 113 | } | ||
| 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 | |||
| 124 | bool operator==(const VertexInput& rhs) const noexcept; | ||
| 125 | |||
| 126 | bool operator!=(const VertexInput& rhs) const noexcept { | ||
| 127 | return !operator==(rhs); | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct InputAssembly { | ||
| 132 | constexpr InputAssembly(Maxwell::PrimitiveTopology topology, bool primitive_restart_enable, | ||
| 133 | float point_size) | ||
| 134 | : topology{topology}, primitive_restart_enable{primitive_restart_enable}, | ||
| 135 | point_size{point_size} {} | ||
| 136 | InputAssembly() = default; | ||
| 137 | |||
| 138 | Maxwell::PrimitiveTopology topology; | ||
| 139 | bool primitive_restart_enable; | ||
| 140 | float point_size; | ||
| 141 | |||
| 142 | std::size_t Hash() const noexcept; | ||
| 143 | |||
| 144 | bool operator==(const InputAssembly& rhs) const noexcept; | ||
| 145 | |||
| 146 | bool operator!=(const InputAssembly& rhs) const noexcept { | ||
| 147 | return !operator==(rhs); | ||
| 148 | } | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct Tessellation { | ||
| 152 | constexpr Tessellation(u32 patch_control_points, Maxwell::TessellationPrimitive primitive, | ||
| 153 | Maxwell::TessellationSpacing spacing, bool clockwise) | ||
| 154 | : patch_control_points{patch_control_points}, primitive{primitive}, spacing{spacing}, | ||
| 155 | clockwise{clockwise} {} | ||
| 156 | Tessellation() = default; | ||
| 157 | |||
| 158 | u32 patch_control_points; | ||
| 159 | Maxwell::TessellationPrimitive primitive; | ||
| 160 | Maxwell::TessellationSpacing spacing; | ||
| 161 | bool clockwise; | ||
| 162 | |||
| 163 | std::size_t Hash() const noexcept; | ||
| 164 | |||
| 165 | bool operator==(const Tessellation& rhs) const noexcept; | ||
| 166 | |||
| 167 | bool operator!=(const Tessellation& rhs) const noexcept { | ||
| 168 | return !operator==(rhs); | ||
| 169 | } | ||
| 170 | }; | ||
| 171 | |||
| 172 | struct Rasterizer { | ||
| 173 | constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool ndc_minus_one_to_one, | ||
| 174 | Maxwell::Cull::CullFace cull_face, Maxwell::Cull::FrontFace front_face) | ||
| 175 | : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable}, | ||
| 176 | ndc_minus_one_to_one{ndc_minus_one_to_one}, cull_face{cull_face}, front_face{ | ||
| 177 | front_face} {} | ||
| 178 | Rasterizer() = default; | ||
| 179 | |||
| 180 | bool cull_enable; | ||
| 181 | bool depth_bias_enable; | ||
| 182 | bool ndc_minus_one_to_one; | ||
| 183 | Maxwell::Cull::CullFace cull_face; | ||
| 184 | Maxwell::Cull::FrontFace front_face; | ||
| 185 | |||
| 186 | std::size_t Hash() const noexcept; | ||
| 187 | |||
| 188 | bool operator==(const Rasterizer& rhs) const noexcept; | ||
| 189 | |||
| 190 | bool operator!=(const Rasterizer& rhs) const noexcept { | ||
| 191 | return !operator==(rhs); | ||
| 192 | } | ||
| 193 | }; | ||
| 194 | |||
| 195 | struct DepthStencil { | ||
| 196 | constexpr DepthStencil(bool depth_test_enable, bool depth_write_enable, | ||
| 197 | bool depth_bounds_enable, bool stencil_enable, | ||
| 198 | Maxwell::ComparisonOp depth_test_function, StencilFace front_stencil, | ||
| 199 | StencilFace back_stencil) | ||
| 200 | : depth_test_enable{depth_test_enable}, depth_write_enable{depth_write_enable}, | ||
| 201 | depth_bounds_enable{depth_bounds_enable}, stencil_enable{stencil_enable}, | ||
| 202 | depth_test_function{depth_test_function}, front_stencil{front_stencil}, | ||
| 203 | back_stencil{back_stencil} {} | ||
| 204 | DepthStencil() = default; | ||
| 205 | |||
| 206 | bool depth_test_enable; | ||
| 207 | bool depth_write_enable; | ||
| 208 | bool depth_bounds_enable; | ||
| 209 | bool stencil_enable; | ||
| 210 | Maxwell::ComparisonOp depth_test_function; | ||
| 211 | StencilFace front_stencil; | ||
| 212 | StencilFace back_stencil; | ||
| 213 | |||
| 214 | std::size_t Hash() const noexcept; | ||
| 215 | |||
| 216 | bool operator==(const DepthStencil& rhs) const noexcept; | ||
| 217 | |||
| 218 | bool operator!=(const DepthStencil& rhs) const noexcept { | ||
| 219 | return !operator==(rhs); | ||
| 220 | } | ||
| 221 | }; | ||
| 222 | |||
| 223 | struct ColorBlending { | ||
| 224 | constexpr ColorBlending( | ||
| 225 | std::array<float, 4> blend_constants, std::size_t attachments_count, | ||
| 226 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments) | ||
| 227 | : attachments_count{attachments_count}, attachments{attachments} {} | ||
| 228 | ColorBlending() = default; | ||
| 229 | |||
| 230 | std::size_t attachments_count; | ||
| 231 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments; | ||
| 232 | |||
| 233 | std::size_t Hash() const noexcept; | ||
| 234 | |||
| 235 | bool operator==(const ColorBlending& rhs) const noexcept; | ||
| 236 | |||
| 237 | bool operator!=(const ColorBlending& rhs) const noexcept { | ||
| 238 | return !operator==(rhs); | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | |||
| 242 | std::size_t Hash() const noexcept; | ||
| 243 | |||
| 244 | bool operator==(const FixedPipelineState& rhs) const noexcept; | ||
| 245 | |||
| 246 | bool operator!=(const FixedPipelineState& rhs) const noexcept { | ||
| 247 | return !operator==(rhs); | ||
| 248 | } | ||
| 249 | |||
| 250 | VertexInput vertex_input; | ||
| 251 | InputAssembly input_assembly; | ||
| 252 | Tessellation tessellation; | ||
| 253 | Rasterizer rasterizer; | ||
| 254 | DepthStencil depth_stencil; | ||
| 255 | ColorBlending color_blending; | ||
| 256 | }; | ||
| 257 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexBinding>); | ||
| 258 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexAttribute>); | ||
| 259 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::StencilFace>); | ||
| 260 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>); | ||
| 261 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>); | ||
| 262 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::InputAssembly>); | ||
| 263 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::Tessellation>); | ||
| 264 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::Rasterizer>); | ||
| 265 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::DepthStencil>); | ||
| 266 | static_assert(std::is_trivially_copyable_v<FixedPipelineState::ColorBlending>); | ||
| 267 | static_assert(std::is_trivially_copyable_v<FixedPipelineState>); | ||
| 268 | |||
| 269 | FixedPipelineState GetFixedPipelineState(const Maxwell& regs); | ||
| 270 | |||
| 271 | } // namespace Vulkan | ||
| 272 | |||
| 273 | namespace std { | ||
| 274 | |||
| 275 | template <> | ||
| 276 | struct hash<Vulkan::FixedPipelineState> { | ||
| 277 | std::size_t operator()(const Vulkan::FixedPipelineState& k) const noexcept { | ||
| 278 | return k.Hash(); | ||
| 279 | } | ||
| 280 | }; | ||
| 281 | |||
| 282 | } // namespace std | ||