diff options
| author | 2021-06-12 05:07:52 -0300 | |
|---|---|---|
| committer | 2021-07-22 21:51:35 -0400 | |
| commit | ea038d66538975319858f792052af1d0fa997fe3 (patch) | |
| tree | 472905d458f31cdcfffcf45a41c276f91094d1b4 /src | |
| parent | shader: Reorder shader cache directories (diff) | |
| download | yuzu-ea038d66538975319858f792052af1d0fa997fe3.tar.gz yuzu-ea038d66538975319858f792052af1d0fa997fe3.tar.xz yuzu-ea038d66538975319858f792052af1d0fa997fe3.zip | |
vulkan: Add VK_EXT_vertex_input_dynamic_state support
Reduces the number of total pipelines generated on Vulkan.
Tested on Super Smash Bros. Ultimate.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | 67 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/fixed_pipeline_state.h | 73 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 107 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 29 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 56 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_state_tracker.cpp | 50 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_state_tracker.h | 8 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.h | 6 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 1 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 8 |
11 files changed, 291 insertions, 116 deletions
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index f121fbf0e..16cef8711 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -50,7 +50,7 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& | |||
| 50 | } // Anonymous namespace | 50 | } // Anonymous namespace |
| 51 | 51 | ||
| 52 | void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | 52 | void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, |
| 53 | bool has_extended_dynamic_state) { | 53 | bool has_extended_dynamic_state, bool has_dynamic_vertex_input) { |
| 54 | const Maxwell& regs = maxwell3d.regs; | 54 | const Maxwell& regs = maxwell3d.regs; |
| 55 | const std::array enabled_lut{ | 55 | const std::array enabled_lut{ |
| 56 | regs.polygon_offset_point_enable, | 56 | regs.polygon_offset_point_enable, |
| @@ -60,7 +60,8 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | |||
| 60 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); | 60 | const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); |
| 61 | 61 | ||
| 62 | raw1 = 0; | 62 | raw1 = 0; |
| 63 | no_extended_dynamic_state.Assign(has_extended_dynamic_state ? 0 : 1); | 63 | extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0); |
| 64 | dynamic_vertex_input.Assign(has_dynamic_vertex_input ? 1 : 0); | ||
| 64 | xfb_enabled.Assign(regs.tfb_enabled != 0); | 65 | xfb_enabled.Assign(regs.tfb_enabled != 0); |
| 65 | primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); | 66 | primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); |
| 66 | depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); | 67 | depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); |
| @@ -73,11 +74,11 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | |||
| 73 | tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); | 74 | tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); |
| 74 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); | 75 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); |
| 75 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); | 76 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); |
| 76 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | ||
| 77 | topology.Assign(regs.draw.topology); | 77 | topology.Assign(regs.draw.topology); |
| 78 | msaa_mode.Assign(regs.multisample_mode); | 78 | msaa_mode.Assign(regs.multisample_mode); |
| 79 | 79 | ||
| 80 | raw2 = 0; | 80 | raw2 = 0; |
| 81 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | ||
| 81 | const auto test_func = | 82 | const auto test_func = |
| 82 | regs.alpha_test_enabled != 0 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; | 83 | regs.alpha_test_enabled != 0 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always; |
| 83 | alpha_test_func.Assign(PackComparisonOp(test_func)); | 84 | alpha_test_func.Assign(PackComparisonOp(test_func)); |
| @@ -93,24 +94,44 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | |||
| 93 | alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); | 94 | alpha_test_ref = Common::BitCast<u32>(regs.alpha_test_ref); |
| 94 | point_size = Common::BitCast<u32>(regs.point_size); | 95 | point_size = Common::BitCast<u32>(regs.point_size); |
| 95 | 96 | ||
| 96 | if (maxwell3d.dirty.flags[Dirty::InstanceDivisors]) { | 97 | if (maxwell3d.dirty.flags[Dirty::VertexInput]) { |
| 97 | maxwell3d.dirty.flags[Dirty::InstanceDivisors] = false; | 98 | if (has_dynamic_vertex_input) { |
| 98 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 99 | // Dirty flag will be reset by the command buffer update |
| 99 | const bool is_enabled = regs.instanced_arrays.IsInstancingEnabled(index); | 100 | static constexpr std::array LUT{ |
| 100 | binding_divisors[index] = is_enabled ? regs.vertex_array[index].divisor : 0; | 101 | 0u, // Invalid |
| 101 | } | 102 | 1u, // SignedNorm |
| 102 | } | 103 | 1u, // UnsignedNorm |
| 103 | if (maxwell3d.dirty.flags[Dirty::VertexAttributes]) { | 104 | 2u, // SignedInt |
| 104 | maxwell3d.dirty.flags[Dirty::VertexAttributes] = false; | 105 | 3u, // UnsignedInt |
| 105 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { | 106 | 1u, // UnsignedScaled |
| 106 | const auto& input = regs.vertex_attrib_format[index]; | 107 | 1u, // SignedScaled |
| 107 | auto& attribute = attributes[index]; | 108 | 1u, // Float |
| 108 | attribute.raw = 0; | 109 | }; |
| 109 | attribute.enabled.Assign(input.IsConstant() ? 0 : 1); | 110 | const auto& attrs = regs.vertex_attrib_format; |
| 110 | attribute.buffer.Assign(input.buffer); | 111 | attribute_types = 0; |
| 111 | attribute.offset.Assign(input.offset); | 112 | for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) { |
| 112 | attribute.type.Assign(static_cast<u32>(input.type.Value())); | 113 | const u32 mask = attrs[i].constant != 0 ? 0 : 3; |
| 113 | attribute.size.Assign(static_cast<u32>(input.size.Value())); | 114 | const u32 type = LUT[static_cast<size_t>(attrs[i].type.Value())]; |
| 115 | attribute_types |= static_cast<u64>(type & mask) << (i * 2); | ||
| 116 | } | ||
| 117 | } else { | ||
| 118 | maxwell3d.dirty.flags[Dirty::VertexInput] = false; | ||
| 119 | enabled_divisors = 0; | ||
| 120 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | ||
| 121 | const bool is_enabled = regs.instanced_arrays.IsInstancingEnabled(index); | ||
| 122 | binding_divisors[index] = is_enabled ? regs.vertex_array[index].divisor : 0; | ||
| 123 | enabled_divisors |= (is_enabled ? u64{1} : 0) << index; | ||
| 124 | } | ||
| 125 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { | ||
| 126 | const auto& input = regs.vertex_attrib_format[index]; | ||
| 127 | auto& attribute = attributes[index]; | ||
| 128 | attribute.raw = 0; | ||
| 129 | attribute.enabled.Assign(input.IsConstant() ? 0 : 1); | ||
| 130 | attribute.buffer.Assign(input.buffer); | ||
| 131 | attribute.offset.Assign(input.offset); | ||
| 132 | attribute.type.Assign(static_cast<u32>(input.type.Value())); | ||
| 133 | attribute.size.Assign(static_cast<u32>(input.size.Value())); | ||
| 134 | } | ||
| 114 | } | 135 | } |
| 115 | } | 136 | } |
| 116 | if (maxwell3d.dirty.flags[Dirty::Blending]) { | 137 | if (maxwell3d.dirty.flags[Dirty::Blending]) { |
| @@ -126,10 +147,10 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | |||
| 126 | return static_cast<u16>(viewport.swizzle.raw); | 147 | return static_cast<u16>(viewport.swizzle.raw); |
| 127 | }); | 148 | }); |
| 128 | } | 149 | } |
| 129 | if (no_extended_dynamic_state != 0) { | 150 | if (!extended_dynamic_state) { |
| 130 | dynamic_state.Refresh(regs); | 151 | dynamic_state.Refresh(regs); |
| 131 | } | 152 | } |
| 132 | if (xfb_enabled != 0) { | 153 | if (xfb_enabled) { |
| 133 | RefreshXfbState(xfb_state, regs); | 154 | RefreshXfbState(xfb_state, regs); |
| 134 | } | 155 | } |
| 135 | } | 156 | } |
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 60adae316..04f34eb97 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -168,44 +168,51 @@ struct FixedPipelineState { | |||
| 168 | 168 | ||
| 169 | union { | 169 | union { |
| 170 | u32 raw1; | 170 | u32 raw1; |
| 171 | BitField<0, 1, u32> no_extended_dynamic_state; | 171 | BitField<0, 1, u32> extended_dynamic_state; |
| 172 | BitField<1, 1, u32> xfb_enabled; | 172 | BitField<1, 1, u32> dynamic_vertex_input; |
| 173 | BitField<2, 1, u32> primitive_restart_enable; | 173 | BitField<2, 1, u32> xfb_enabled; |
| 174 | BitField<3, 1, u32> depth_bias_enable; | 174 | BitField<3, 1, u32> primitive_restart_enable; |
| 175 | BitField<4, 1, u32> depth_clamp_disabled; | 175 | BitField<4, 1, u32> depth_bias_enable; |
| 176 | BitField<5, 1, u32> ndc_minus_one_to_one; | 176 | BitField<5, 1, u32> depth_clamp_disabled; |
| 177 | BitField<6, 2, u32> polygon_mode; | 177 | BitField<6, 1, u32> ndc_minus_one_to_one; |
| 178 | BitField<8, 5, u32> patch_control_points_minus_one; | 178 | BitField<7, 2, u32> polygon_mode; |
| 179 | BitField<13, 2, u32> tessellation_primitive; | 179 | BitField<9, 5, u32> patch_control_points_minus_one; |
| 180 | BitField<15, 2, u32> tessellation_spacing; | 180 | BitField<14, 2, u32> tessellation_primitive; |
| 181 | BitField<17, 1, u32> tessellation_clockwise; | 181 | BitField<16, 2, u32> tessellation_spacing; |
| 182 | BitField<18, 1, u32> logic_op_enable; | 182 | BitField<18, 1, u32> tessellation_clockwise; |
| 183 | BitField<19, 4, u32> logic_op; | 183 | BitField<19, 1, u32> logic_op_enable; |
| 184 | BitField<23, 1, u32> rasterize_enable; | 184 | BitField<20, 4, u32> logic_op; |
| 185 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; | 185 | BitField<24, 4, Maxwell::PrimitiveTopology> topology; |
| 186 | BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; | 186 | BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; |
| 187 | }; | 187 | }; |
| 188 | union { | 188 | union { |
| 189 | u32 raw2; | 189 | u32 raw2; |
| 190 | BitField<0, 3, u32> alpha_test_func; | 190 | BitField<0, 1, u32> rasterize_enable; |
| 191 | BitField<3, 1, u32> early_z; | 191 | BitField<1, 3, u32> alpha_test_func; |
| 192 | BitField<4, 1, u32> depth_enabled; | 192 | BitField<4, 1, u32> early_z; |
| 193 | BitField<5, 5, u32> depth_format; | 193 | BitField<5, 1, u32> depth_enabled; |
| 194 | BitField<10, 1, u32> y_negate; | 194 | BitField<6, 5, u32> depth_format; |
| 195 | BitField<11, 1, u32> provoking_vertex_last; | 195 | BitField<11, 1, u32> y_negate; |
| 196 | BitField<12, 1, u32> provoking_vertex_last; | ||
| 196 | }; | 197 | }; |
| 197 | std::array<u8, Maxwell::NumRenderTargets> color_formats; | 198 | std::array<u8, Maxwell::NumRenderTargets> color_formats; |
| 198 | 199 | ||
| 199 | u32 alpha_test_ref; | 200 | u32 alpha_test_ref; |
| 200 | u32 point_size; | 201 | u32 point_size; |
| 201 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | ||
| 202 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | ||
| 203 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments; | 202 | std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments; |
| 204 | std::array<u16, Maxwell::NumViewports> viewport_swizzles; | 203 | std::array<u16, Maxwell::NumViewports> viewport_swizzles; |
| 204 | union { | ||
| 205 | u64 attribute_types; // Used with VK_EXT_vertex_input_dynamic_state | ||
| 206 | u64 enabled_divisors; | ||
| 207 | }; | ||
| 208 | std::array<VertexAttribute, Maxwell::NumVertexAttributes> attributes; | ||
| 209 | std::array<u32, Maxwell::NumVertexArrays> binding_divisors; | ||
| 210 | |||
| 205 | DynamicState dynamic_state; | 211 | DynamicState dynamic_state; |
| 206 | VideoCommon::TransformFeedbackState xfb_state; | 212 | VideoCommon::TransformFeedbackState xfb_state; |
| 207 | 213 | ||
| 208 | void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, bool has_extended_dynamic_state); | 214 | void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, bool has_extended_dynamic_state, |
| 215 | bool has_dynamic_vertex_input); | ||
| 209 | 216 | ||
| 210 | size_t Hash() const noexcept; | 217 | size_t Hash() const noexcept; |
| 211 | 218 | ||
| @@ -216,16 +223,24 @@ struct FixedPipelineState { | |||
| 216 | } | 223 | } |
| 217 | 224 | ||
| 218 | size_t Size() const noexcept { | 225 | size_t Size() const noexcept { |
| 219 | if (xfb_enabled != 0) { | 226 | if (xfb_enabled) { |
| 220 | // When transform feedback is enabled, use the whole struct | 227 | // When transform feedback is enabled, use the whole struct |
| 221 | return sizeof(*this); | 228 | return sizeof(*this); |
| 222 | } else if (no_extended_dynamic_state != 0) { | 229 | } |
| 223 | // Dynamic state is enabled, we can enable more | 230 | if (dynamic_vertex_input) { |
| 224 | return offsetof(FixedPipelineState, xfb_state); | 231 | // Exclude dynamic state and attributes |
| 225 | } else { | 232 | return offsetof(FixedPipelineState, attributes); |
| 226 | // No XFB, extended dynamic state enabled | 233 | } |
| 234 | if (extended_dynamic_state) { | ||
| 235 | // Exclude dynamic state | ||
| 227 | return offsetof(FixedPipelineState, dynamic_state); | 236 | return offsetof(FixedPipelineState, dynamic_state); |
| 228 | } | 237 | } |
| 238 | // Default | ||
| 239 | return offsetof(FixedPipelineState, xfb_state); | ||
| 240 | } | ||
| 241 | |||
| 242 | u32 DynamicAttributeType(size_t index) const noexcept { | ||
| 243 | return (attribute_types >> (index * 2)) & 0b11; | ||
| 229 | } | 244 | } |
| 230 | }; | 245 | }; |
| 231 | static_assert(std::has_unique_object_representations_v<FixedPipelineState>); | 246 | static_assert(std::has_unique_object_representations_v<FixedPipelineState>); |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 06a80c2ba..ccef71f4c 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -472,39 +472,65 @@ void GraphicsPipeline::ConfigureDraw() { | |||
| 472 | 472 | ||
| 473 | void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | 473 | void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { |
| 474 | FixedPipelineState::DynamicState dynamic{}; | 474 | FixedPipelineState::DynamicState dynamic{}; |
| 475 | if (!device.IsExtExtendedDynamicStateSupported()) { | 475 | if (key.state.extended_dynamic_state) { |
| 476 | dynamic = key.state.dynamic_state; | 476 | dynamic = key.state.dynamic_state; |
| 477 | } | 477 | } |
| 478 | static_vector<VkVertexInputBindingDescription, 32> vertex_bindings; | 478 | static_vector<VkVertexInputBindingDescription, 32> vertex_bindings; |
| 479 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; | 479 | static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors; |
| 480 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | 480 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; |
| 481 | const bool instanced = key.state.binding_divisors[index] != 0; | 481 | if (key.state.dynamic_vertex_input) { |
| 482 | const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | 482 | const auto& input_attributes = stage_infos[0].input_generics; |
| 483 | vertex_bindings.push_back({ | 483 | for (size_t index = 0; index < key.state.attributes.size(); ++index) { |
| 484 | .binding = static_cast<u32>(index), | 484 | const u32 type = key.state.DynamicAttributeType(index); |
| 485 | .stride = dynamic.vertex_strides[index], | 485 | if (!input_attributes[index].used || type == 0) { |
| 486 | .inputRate = rate, | 486 | continue; |
| 487 | }); | 487 | } |
| 488 | if (instanced) { | 488 | vertex_attributes.push_back({ |
| 489 | vertex_binding_divisors.push_back({ | 489 | .location = static_cast<u32>(index), |
| 490 | .binding = 0, | ||
| 491 | .format = type == 1 ? VK_FORMAT_R32_SFLOAT | ||
| 492 | : type == 2 ? VK_FORMAT_R32_SINT | ||
| 493 | : VK_FORMAT_R32_UINT, | ||
| 494 | .offset = 0, | ||
| 495 | }); | ||
| 496 | } | ||
| 497 | if (!vertex_attributes.empty()) { | ||
| 498 | vertex_bindings.push_back({ | ||
| 499 | .binding = 0, | ||
| 500 | .stride = 4, | ||
| 501 | .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, | ||
| 502 | }); | ||
| 503 | } | ||
| 504 | } else { | ||
| 505 | for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) { | ||
| 506 | const bool instanced = key.state.binding_divisors[index] != 0; | ||
| 507 | const auto rate = | ||
| 508 | instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; | ||
| 509 | vertex_bindings.push_back({ | ||
| 490 | .binding = static_cast<u32>(index), | 510 | .binding = static_cast<u32>(index), |
| 491 | .divisor = key.state.binding_divisors[index], | 511 | .stride = dynamic.vertex_strides[index], |
| 512 | .inputRate = rate, | ||
| 492 | }); | 513 | }); |
| 514 | if (instanced) { | ||
| 515 | vertex_binding_divisors.push_back({ | ||
| 516 | .binding = static_cast<u32>(index), | ||
| 517 | .divisor = key.state.binding_divisors[index], | ||
| 518 | }); | ||
| 519 | } | ||
| 493 | } | 520 | } |
| 494 | } | 521 | const auto& input_attributes = stage_infos[0].input_generics; |
| 495 | static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes; | 522 | for (size_t index = 0; index < key.state.attributes.size(); ++index) { |
| 496 | const auto& input_attributes = stage_infos[0].input_generics; | 523 | const auto& attribute = key.state.attributes[index]; |
| 497 | for (size_t index = 0; index < key.state.attributes.size(); ++index) { | 524 | if (!attribute.enabled || !input_attributes[index].used) { |
| 498 | const auto& attribute = key.state.attributes[index]; | 525 | continue; |
| 499 | if (!attribute.enabled || !input_attributes[index].used) { | 526 | } |
| 500 | continue; | 527 | vertex_attributes.push_back({ |
| 528 | .location = static_cast<u32>(index), | ||
| 529 | .binding = attribute.buffer, | ||
| 530 | .format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()), | ||
| 531 | .offset = attribute.offset, | ||
| 532 | }); | ||
| 501 | } | 533 | } |
| 502 | vertex_attributes.push_back({ | ||
| 503 | .location = static_cast<u32>(index), | ||
| 504 | .binding = attribute.buffer, | ||
| 505 | .format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()), | ||
| 506 | .offset = attribute.offset, | ||
| 507 | }); | ||
| 508 | } | 534 | } |
| 509 | VkPipelineVertexInputStateCreateInfo vertex_input_ci{ | 535 | VkPipelineVertexInputStateCreateInfo vertex_input_ci{ |
| 510 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 536 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| @@ -545,27 +571,25 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 545 | .flags = 0, | 571 | .flags = 0, |
| 546 | .patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1, | 572 | .patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1, |
| 547 | }; | 573 | }; |
| 548 | VkPipelineViewportStateCreateInfo viewport_ci{ | 574 | |
| 549 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| 550 | .pNext = nullptr, | ||
| 551 | .flags = 0, | ||
| 552 | .viewportCount = Maxwell::NumViewports, | ||
| 553 | .pViewports = nullptr, | ||
| 554 | .scissorCount = Maxwell::NumViewports, | ||
| 555 | .pScissors = nullptr, | ||
| 556 | }; | ||
| 557 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; | 575 | std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; |
| 558 | std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); | 576 | std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle); |
| 559 | VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ | 577 | const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ |
| 560 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, | 578 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, |
| 561 | .pNext = nullptr, | 579 | .pNext = nullptr, |
| 562 | .flags = 0, | 580 | .flags = 0, |
| 563 | .viewportCount = Maxwell::NumViewports, | 581 | .viewportCount = Maxwell::NumViewports, |
| 564 | .pViewportSwizzles = swizzles.data(), | 582 | .pViewportSwizzles = swizzles.data(), |
| 565 | }; | 583 | }; |
| 566 | if (device.IsNvViewportSwizzleSupported()) { | 584 | const VkPipelineViewportStateCreateInfo viewport_ci{ |
| 567 | viewport_ci.pNext = &swizzle_ci; | 585 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| 568 | } | 586 | .pNext = device.IsNvViewportSwizzleSupported() ? &swizzle_ci : nullptr, |
| 587 | .flags = 0, | ||
| 588 | .viewportCount = Maxwell::NumViewports, | ||
| 589 | .pViewports = nullptr, | ||
| 590 | .scissorCount = Maxwell::NumViewports, | ||
| 591 | .pScissors = nullptr, | ||
| 592 | }; | ||
| 569 | 593 | ||
| 570 | const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provoking_vertex{ | 594 | const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provoking_vertex{ |
| 571 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, | 595 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, |
| @@ -660,13 +684,13 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 660 | .pAttachments = cb_attachments.data(), | 684 | .pAttachments = cb_attachments.data(), |
| 661 | .blendConstants = {}, | 685 | .blendConstants = {}, |
| 662 | }; | 686 | }; |
| 663 | static_vector<VkDynamicState, 17> dynamic_states{ | 687 | static_vector<VkDynamicState, 18> dynamic_states{ |
| 664 | VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, | 688 | VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, |
| 665 | VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, | 689 | VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, |
| 666 | VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, | 690 | VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, |
| 667 | VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, | 691 | VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, |
| 668 | }; | 692 | }; |
| 669 | if (device.IsExtExtendedDynamicStateSupported()) { | 693 | if (key.state.extended_dynamic_state) { |
| 670 | static constexpr std::array extended{ | 694 | static constexpr std::array extended{ |
| 671 | VK_DYNAMIC_STATE_CULL_MODE_EXT, | 695 | VK_DYNAMIC_STATE_CULL_MODE_EXT, |
| 672 | VK_DYNAMIC_STATE_FRONT_FACE_EXT, | 696 | VK_DYNAMIC_STATE_FRONT_FACE_EXT, |
| @@ -678,6 +702,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { | |||
| 678 | VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, | 702 | VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, |
| 679 | VK_DYNAMIC_STATE_STENCIL_OP_EXT, | 703 | VK_DYNAMIC_STATE_STENCIL_OP_EXT, |
| 680 | }; | 704 | }; |
| 705 | if (key.state.dynamic_vertex_input) { | ||
| 706 | dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); | ||
| 707 | } | ||
| 681 | dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); | 708 | dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); |
| 682 | } | 709 | } |
| 683 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | 710 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 6df4088a7..db7da5555 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -109,6 +109,20 @@ static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexA | |||
| 109 | return Shader::AttributeType::Float; | 109 | return Shader::AttributeType::Float; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | Shader::AttributeType AttributeType(const FixedPipelineState& state, size_t index) { | ||
| 113 | switch (state.DynamicAttributeType(index)) { | ||
| 114 | case 0: | ||
| 115 | return Shader::AttributeType::Disabled; | ||
| 116 | case 1: | ||
| 117 | return Shader::AttributeType::Float; | ||
| 118 | case 2: | ||
| 119 | return Shader::AttributeType::SignedInt; | ||
| 120 | case 3: | ||
| 121 | return Shader::AttributeType::UnsignedInt; | ||
| 122 | } | ||
| 123 | return Shader::AttributeType::Disabled; | ||
| 124 | } | ||
| 125 | |||
| 112 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineCacheKey& key, | 126 | Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineCacheKey& key, |
| 113 | const Shader::IR::Program& program) { | 127 | const Shader::IR::Program& program) { |
| 114 | Shader::RuntimeInfo info; | 128 | Shader::RuntimeInfo info; |
| @@ -123,13 +137,19 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineCacheKey& key, | |||
| 123 | if (key.state.topology == Maxwell::PrimitiveTopology::Points) { | 137 | if (key.state.topology == Maxwell::PrimitiveTopology::Points) { |
| 124 | info.fixed_state_point_size = point_size; | 138 | info.fixed_state_point_size = point_size; |
| 125 | } | 139 | } |
| 126 | if (key.state.xfb_enabled != 0) { | 140 | if (key.state.xfb_enabled) { |
| 127 | info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); | 141 | info.xfb_varyings = VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); |
| 128 | } | 142 | } |
| 129 | info.convert_depth_mode = gl_ndc; | 143 | info.convert_depth_mode = gl_ndc; |
| 130 | } | 144 | } |
| 131 | std::ranges::transform(key.state.attributes, info.generic_input_types.begin(), | 145 | if (key.state.dynamic_vertex_input) { |
| 132 | &CastAttributeType); | 146 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { |
| 147 | info.generic_input_types[index] = AttributeType(key.state, index); | ||
| 148 | } | ||
| 149 | } else { | ||
| 150 | std::ranges::transform(key.state.attributes, info.generic_input_types.begin(), | ||
| 151 | &CastAttributeType); | ||
| 152 | } | ||
| 133 | break; | 153 | break; |
| 134 | case Shader::Stage::TessellationEval: | 154 | case Shader::Stage::TessellationEval: |
| 135 | // We have to flip tessellation clockwise for some reason... | 155 | // We have to flip tessellation clockwise for some reason... |
| @@ -298,7 +318,8 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { | |||
| 298 | current_pipeline = nullptr; | 318 | current_pipeline = nullptr; |
| 299 | return nullptr; | 319 | return nullptr; |
| 300 | } | 320 | } |
| 301 | graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported()); | 321 | graphics_key.state.Refresh(maxwell3d, device.IsExtExtendedDynamicStateSupported(), |
| 322 | device.IsExtVertexInputDynamicStateSupported()); | ||
| 302 | 323 | ||
| 303 | if (current_pipeline) { | 324 | if (current_pipeline) { |
| 304 | GraphicsPipeline* const next{current_pipeline->Next(graphics_key)}; | 325 | GraphicsPipeline* const next{current_pipeline->Next(graphics_key)}; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index e339e9739..855c17769 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -551,6 +551,9 @@ void RasterizerVulkan::UpdateDynamicStates() { | |||
| 551 | UpdateFrontFace(regs); | 551 | UpdateFrontFace(regs); |
| 552 | UpdateStencilOp(regs); | 552 | UpdateStencilOp(regs); |
| 553 | UpdateStencilTestEnable(regs); | 553 | UpdateStencilTestEnable(regs); |
| 554 | if (device.IsExtVertexInputDynamicStateSupported()) { | ||
| 555 | UpdateVertexInput(regs); | ||
| 556 | } | ||
| 554 | } | 557 | } |
| 555 | } | 558 | } |
| 556 | 559 | ||
| @@ -780,4 +783,57 @@ void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& | |||
| 780 | }); | 783 | }); |
| 781 | } | 784 | } |
| 782 | 785 | ||
| 786 | void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) { | ||
| 787 | auto& dirty{maxwell3d.dirty.flags}; | ||
| 788 | if (!dirty[Dirty::VertexInput]) { | ||
| 789 | return; | ||
| 790 | } | ||
| 791 | dirty[Dirty::VertexInput] = false; | ||
| 792 | |||
| 793 | boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings; | ||
| 794 | boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes; | ||
| 795 | |||
| 796 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { | ||
| 797 | if (!dirty[Dirty::VertexAttribute0 + index]) { | ||
| 798 | continue; | ||
| 799 | } | ||
| 800 | const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]}; | ||
| 801 | const u32 binding{attribute.buffer}; | ||
| 802 | dirty[Dirty::VertexAttribute0 + index] = false; | ||
| 803 | dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true; | ||
| 804 | |||
| 805 | attributes.push_back({ | ||
| 806 | .sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, | ||
| 807 | .pNext = nullptr, | ||
| 808 | .location = static_cast<u32>(index), | ||
| 809 | .binding = binding, | ||
| 810 | .format = attribute.IsConstant() | ||
| 811 | ? VK_FORMAT_A8B8G8R8_UNORM_PACK32 | ||
| 812 | : MaxwellToVK::VertexFormat(attribute.type, attribute.size), | ||
| 813 | .offset = attribute.offset, | ||
| 814 | }); | ||
| 815 | } | ||
| 816 | for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { | ||
| 817 | if (!dirty[Dirty::VertexBinding0 + index]) { | ||
| 818 | continue; | ||
| 819 | } | ||
| 820 | dirty[Dirty::VertexBinding0 + index] = false; | ||
| 821 | |||
| 822 | const u32 binding{static_cast<u32>(index)}; | ||
| 823 | const auto& input_binding{regs.vertex_array[binding]}; | ||
| 824 | const bool is_instanced{regs.instanced_arrays.IsInstancingEnabled(binding)}; | ||
| 825 | bindings.push_back({ | ||
| 826 | .sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, | ||
| 827 | .pNext = nullptr, | ||
| 828 | .binding = binding, | ||
| 829 | .stride = input_binding.stride, | ||
| 830 | .inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX, | ||
| 831 | .divisor = is_instanced ? input_binding.divisor : 1, | ||
| 832 | }); | ||
| 833 | } | ||
| 834 | scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) { | ||
| 835 | cmdbuf.SetVertexInputEXT(bindings, attributes); | ||
| 836 | }); | ||
| 837 | } | ||
| 838 | |||
| 783 | } // namespace Vulkan | 839 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 1302bed02..c954fa7f8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -135,6 +135,8 @@ private: | |||
| 135 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); | 135 | void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); |
| 136 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); | 136 | void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); |
| 137 | 137 | ||
| 138 | void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); | ||
| 139 | |||
| 138 | Tegra::GPU& gpu; | 140 | Tegra::GPU& gpu; |
| 139 | Tegra::MemoryManager& gpu_memory; | 141 | Tegra::MemoryManager& gpu_memory; |
| 140 | Tegra::Engines::Maxwell3D& maxwell3d; | 142 | Tegra::Engines::Maxwell3D& maxwell3d; |
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index 956f86845..0ebe0473f 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp | |||
| @@ -29,9 +29,10 @@ using Flags = Maxwell3D::DirtyState::Flags; | |||
| 29 | 29 | ||
| 30 | Flags MakeInvalidationFlags() { | 30 | Flags MakeInvalidationFlags() { |
| 31 | static constexpr int INVALIDATION_FLAGS[]{ | 31 | static constexpr int INVALIDATION_FLAGS[]{ |
| 32 | Viewports, Scissors, DepthBias, BlendConstants, DepthBounds, | 32 | Viewports, Scissors, DepthBias, BlendConstants, |
| 33 | StencilProperties, CullMode, DepthBoundsEnable, DepthTestEnable, DepthWriteEnable, | 33 | DepthBounds, StencilProperties, CullMode, DepthBoundsEnable, |
| 34 | DepthCompareOp, FrontFace, StencilOp, StencilTestEnable, VertexBuffers, | 34 | DepthTestEnable, DepthWriteEnable, DepthCompareOp, FrontFace, |
| 35 | StencilOp, StencilTestEnable, VertexBuffers, VertexInput, | ||
| 35 | }; | 36 | }; |
| 36 | Flags flags{}; | 37 | Flags flags{}; |
| 37 | for (const int flag : INVALIDATION_FLAGS) { | 38 | for (const int flag : INVALIDATION_FLAGS) { |
| @@ -40,6 +41,12 @@ Flags MakeInvalidationFlags() { | |||
| 40 | for (int index = VertexBuffer0; index <= VertexBuffer31; ++index) { | 41 | for (int index = VertexBuffer0; index <= VertexBuffer31; ++index) { |
| 41 | flags[index] = true; | 42 | flags[index] = true; |
| 42 | } | 43 | } |
| 44 | for (int index = VertexAttribute0; index <= VertexAttribute31; ++index) { | ||
| 45 | flags[index] = true; | ||
| 46 | } | ||
| 47 | for (int index = VertexBinding0; index <= VertexBinding31; ++index) { | ||
| 48 | flags[index] = true; | ||
| 49 | } | ||
| 43 | return flags; | 50 | return flags; |
| 44 | } | 51 | } |
| 45 | 52 | ||
| @@ -134,31 +141,38 @@ void SetupDirtyBlending(Tables& tables) { | |||
| 134 | FillBlock(tables[0], OFF(independent_blend), NUM(independent_blend), Blending); | 141 | FillBlock(tables[0], OFF(independent_blend), NUM(independent_blend), Blending); |
| 135 | } | 142 | } |
| 136 | 143 | ||
| 137 | void SetupDirtyInstanceDivisors(Tables& tables) { | 144 | void SetupDirtyViewportSwizzles(Tables& tables) { |
| 138 | static constexpr size_t divisor_offset = 3; | 145 | static constexpr size_t swizzle_offset = 6; |
| 139 | for (size_t index = 0; index < Regs::NumVertexArrays; ++index) { | 146 | for (size_t index = 0; index < Regs::NumViewports; ++index) { |
| 140 | tables[0][OFF(instanced_arrays) + index] = InstanceDivisors; | 147 | tables[0][OFF(viewport_transform) + index * NUM(viewport_transform[0]) + swizzle_offset] = |
| 141 | tables[0][OFF(vertex_array) + index * NUM(vertex_array[0]) + divisor_offset] = | 148 | ViewportSwizzles; |
| 142 | InstanceDivisors; | ||
| 143 | } | 149 | } |
| 144 | } | 150 | } |
| 145 | 151 | ||
| 146 | void SetupDirtyVertexAttributes(Tables& tables) { | 152 | void SetupDirtyVertexAttributes(Tables& tables) { |
| 147 | FillBlock(tables[0], OFF(vertex_attrib_format), NUM(vertex_attrib_format), VertexAttributes); | 153 | for (size_t i = 0; i < Regs::NumVertexAttributes; ++i) { |
| 154 | const size_t offset = OFF(vertex_attrib_format) + i * NUM(vertex_attrib_format[0]); | ||
| 155 | FillBlock(tables[0], offset, NUM(vertex_attrib_format[0]), VertexAttribute0 + i); | ||
| 156 | } | ||
| 157 | FillBlock(tables[1], OFF(vertex_attrib_format), Regs::NumVertexAttributes, VertexInput); | ||
| 148 | } | 158 | } |
| 149 | 159 | ||
| 150 | void SetupDirtyViewportSwizzles(Tables& tables) { | 160 | void SetupDirtyVertexBindings(Tables& tables) { |
| 151 | static constexpr size_t swizzle_offset = 6; | 161 | // Do NOT include stride here, it's implicit in VertexBuffer |
| 152 | for (size_t index = 0; index < Regs::NumViewports; ++index) { | 162 | static constexpr size_t divisor_offset = 3; |
| 153 | tables[0][OFF(viewport_transform) + index * NUM(viewport_transform[0]) + swizzle_offset] = | 163 | for (size_t i = 0; i < Regs::NumVertexArrays; ++i) { |
| 154 | ViewportSwizzles; | 164 | const u8 flag = static_cast<u8>(VertexBinding0 + i); |
| 165 | tables[0][OFF(instanced_arrays) + i] = VertexInput; | ||
| 166 | tables[1][OFF(instanced_arrays) + i] = flag; | ||
| 167 | tables[0][OFF(vertex_array) + i * NUM(vertex_array[0]) + divisor_offset] = VertexInput; | ||
| 168 | tables[1][OFF(vertex_array) + i * NUM(vertex_array[0]) + divisor_offset] = flag; | ||
| 155 | } | 169 | } |
| 156 | } | 170 | } |
| 157 | } // Anonymous namespace | 171 | } // Anonymous namespace |
| 158 | 172 | ||
| 159 | StateTracker::StateTracker(Tegra::GPU& gpu) | 173 | StateTracker::StateTracker(Tegra::GPU& gpu) |
| 160 | : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} { | 174 | : flags{gpu.Maxwell3D().dirty.flags}, invalidation_flags{MakeInvalidationFlags()} { |
| 161 | auto& tables = gpu.Maxwell3D().dirty.tables; | 175 | auto& tables{gpu.Maxwell3D().dirty.tables}; |
| 162 | SetupDirtyFlags(tables); | 176 | SetupDirtyFlags(tables); |
| 163 | SetupDirtyViewports(tables); | 177 | SetupDirtyViewports(tables); |
| 164 | SetupDirtyScissors(tables); | 178 | SetupDirtyScissors(tables); |
| @@ -175,9 +189,9 @@ StateTracker::StateTracker(Tegra::GPU& gpu) | |||
| 175 | SetupDirtyStencilOp(tables); | 189 | SetupDirtyStencilOp(tables); |
| 176 | SetupDirtyStencilTestEnable(tables); | 190 | SetupDirtyStencilTestEnable(tables); |
| 177 | SetupDirtyBlending(tables); | 191 | SetupDirtyBlending(tables); |
| 178 | SetupDirtyInstanceDivisors(tables); | ||
| 179 | SetupDirtyVertexAttributes(tables); | ||
| 180 | SetupDirtyViewportSwizzles(tables); | 192 | SetupDirtyViewportSwizzles(tables); |
| 193 | SetupDirtyVertexAttributes(tables); | ||
| 194 | SetupDirtyVertexBindings(tables); | ||
| 181 | } | 195 | } |
| 182 | 196 | ||
| 183 | } // namespace Vulkan | 197 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 84e918a71..1976b7e9b 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h | |||
| @@ -19,6 +19,12 @@ namespace Dirty { | |||
| 19 | enum : u8 { | 19 | enum : u8 { |
| 20 | First = VideoCommon::Dirty::LastCommonEntry, | 20 | First = VideoCommon::Dirty::LastCommonEntry, |
| 21 | 21 | ||
| 22 | VertexInput, | ||
| 23 | VertexAttribute0, | ||
| 24 | VertexAttribute31 = VertexAttribute0 + 31, | ||
| 25 | VertexBinding0, | ||
| 26 | VertexBinding31 = VertexBinding0 + 31, | ||
| 27 | |||
| 22 | Viewports, | 28 | Viewports, |
| 23 | Scissors, | 29 | Scissors, |
| 24 | DepthBias, | 30 | DepthBias, |
| @@ -36,8 +42,6 @@ enum : u8 { | |||
| 36 | StencilTestEnable, | 42 | StencilTestEnable, |
| 37 | 43 | ||
| 38 | Blending, | 44 | Blending, |
| 39 | InstanceDivisors, | ||
| 40 | VertexAttributes, | ||
| 41 | ViewportSwizzles, | 45 | ViewportSwizzles, |
| 42 | 46 | ||
| 43 | Last | 47 | Last |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 37f589612..4fda472b0 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -239,6 +239,11 @@ public: | |||
| 239 | return ext_extended_dynamic_state; | 239 | return ext_extended_dynamic_state; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | /// Returns true if the device supports VK_EXT_vertex_input_dynamic_state. | ||
| 243 | bool IsExtVertexInputDynamicStateSupported() const { | ||
| 244 | return ext_vertex_input_dynamic_state; | ||
| 245 | } | ||
| 246 | |||
| 242 | /// Returns true if the device supports VK_EXT_shader_stencil_export. | 247 | /// Returns true if the device supports VK_EXT_shader_stencil_export. |
| 243 | bool IsExtShaderStencilExportSupported() const { | 248 | bool IsExtShaderStencilExportSupported() const { |
| 244 | return ext_shader_stencil_export; | 249 | return ext_shader_stencil_export; |
| @@ -349,6 +354,7 @@ private: | |||
| 349 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. | 354 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. |
| 350 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. | 355 | bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. |
| 351 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. | 356 | bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. |
| 357 | bool ext_vertex_input_dynamic_state{}; ///< Support for VK_EXT_vertex_input_dynamic_state. | ||
| 352 | bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. | 358 | bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. |
| 353 | bool ext_shader_atomic_int64{}; ///< Support for VK_KHR_shader_atomic_int64. | 359 | bool ext_shader_atomic_int64{}; ///< Support for VK_KHR_shader_atomic_int64. |
| 354 | bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex. | 360 | bool ext_provoking_vertex{}; ///< Support for VK_EXT_provoking_vertex. |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 33fb74bfb..7e13ae8af 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -123,6 +123,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 123 | X(vkCmdSetPrimitiveTopologyEXT); | 123 | X(vkCmdSetPrimitiveTopologyEXT); |
| 124 | X(vkCmdSetStencilOpEXT); | 124 | X(vkCmdSetStencilOpEXT); |
| 125 | X(vkCmdSetStencilTestEnableEXT); | 125 | X(vkCmdSetStencilTestEnableEXT); |
| 126 | X(vkCmdSetVertexInputEXT); | ||
| 126 | X(vkCmdResolveImage); | 127 | X(vkCmdResolveImage); |
| 127 | X(vkCreateBuffer); | 128 | X(vkCreateBuffer); |
| 128 | X(vkCreateBufferView); | 129 | X(vkCreateBufferView); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 3e36d356a..6e5be1186 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -238,6 +238,7 @@ struct DeviceDispatch : InstanceDispatch { | |||
| 238 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; | 238 | PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; |
| 239 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT{}; | 239 | PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT{}; |
| 240 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{}; | 240 | PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{}; |
| 241 | PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT{}; | ||
| 241 | PFN_vkCmdResolveImage vkCmdResolveImage{}; | 242 | PFN_vkCmdResolveImage vkCmdResolveImage{}; |
| 242 | PFN_vkCreateBuffer vkCreateBuffer{}; | 243 | PFN_vkCreateBuffer vkCreateBuffer{}; |
| 243 | PFN_vkCreateBufferView vkCreateBufferView{}; | 244 | PFN_vkCreateBufferView vkCreateBufferView{}; |
| @@ -1203,6 +1204,13 @@ public: | |||
| 1203 | dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); | 1204 | dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); |
| 1204 | } | 1205 | } |
| 1205 | 1206 | ||
| 1207 | void SetVertexInputEXT( | ||
| 1208 | vk::Span<VkVertexInputBindingDescription2EXT> bindings, | ||
| 1209 | vk::Span<VkVertexInputAttributeDescription2EXT> attributes) const noexcept { | ||
| 1210 | dld->vkCmdSetVertexInputEXT(handle, bindings.size(), bindings.data(), attributes.size(), | ||
| 1211 | attributes.data()); | ||
| 1212 | } | ||
| 1213 | |||
| 1206 | void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers, | 1214 | void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers, |
| 1207 | const VkDeviceSize* offsets, | 1215 | const VkDeviceSize* offsets, |
| 1208 | const VkDeviceSize* sizes) const noexcept { | 1216 | const VkDeviceSize* sizes) const noexcept { |