From c897c55e3cf007b771351267ff61114d36011ac6 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 5 Dec 2022 15:44:10 +0100 Subject: [PATCH] Vulkan: Implement Dynamic States 2 --- .../renderer_vulkan/fixed_pipeline_state.cpp | 46 +++++++----- .../renderer_vulkan/fixed_pipeline_state.h | 43 ++++++++---- .../renderer_vulkan/vk_graphics_pipeline.cpp | 19 +++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 22 ++++-- .../renderer_vulkan/vk_pipeline_cache.h | 1 + .../renderer_vulkan/vk_rasterizer.cpp | 70 +++++++++++++++++-- .../renderer_vulkan/vk_rasterizer.h | 3 + .../renderer_vulkan/vk_state_tracker.cpp | 58 +++++++++------ .../renderer_vulkan/vk_state_tracker.h | 20 ++++++ .../vulkan_common/vulkan_device.cpp | 64 +++++++++++++++++ src/video_core/vulkan_common/vulkan_device.h | 17 +++++ .../vulkan_common/vulkan_wrapper.cpp | 3 + src/video_core/vulkan_common/vulkan_wrapper.h | 15 ++++ 13 files changed, 315 insertions(+), 66 deletions(-) diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index df229f41b8..f13ff09c69 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -48,23 +48,16 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& } } // Anonymous namespace -void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, - bool has_extended_dynamic_state, bool has_dynamic_vertex_input) { +void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features) { const Maxwell& regs = maxwell3d.regs; const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; - const std::array enabled_lut{ - regs.polygon_offset_point_enable, - regs.polygon_offset_line_enable, - regs.polygon_offset_fill_enable, - }; - const u32 topology_index = static_cast(topology_); raw1 = 0; - extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0); - dynamic_vertex_input.Assign(has_dynamic_vertex_input ? 1 : 0); + extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0); + extended_dynamic_state_2.Assign(features.has_extended_dynamic_state_2 ? 1 : 0); + extended_dynamic_state_3.Assign(features.has_extended_dynamic_state_3 ? 1 : 0); + dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0); xfb_enabled.Assign(regs.transform_feedback_enabled != 0); - primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); - depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); depth_clamp_disabled.Assign(regs.viewport_clip_control.geometry_clip == Maxwell::ViewportClipControl::GeometryClip::Passthrough || regs.viewport_clip_control.geometry_clip == @@ -84,7 +77,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, msaa_mode.Assign(regs.anti_alias_samples_mode); raw2 = 0; - rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); + const auto test_func = regs.alpha_test_enabled != 0 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always_GL; alpha_test_func.Assign(PackComparisonOp(test_func)); @@ -106,7 +99,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, point_size = Common::BitCast(regs.point_size); if (maxwell3d.dirty.flags[Dirty::VertexInput]) { - if (has_dynamic_vertex_input) { + if (features.has_dynamic_vertex_input) { // Dirty flag will be reset by the command buffer update static constexpr std::array LUT{ 0u, // Invalid @@ -158,9 +151,17 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, return static_cast(viewport.swizzle.raw); }); } + dynamic_state.raw1 = 0; + dynamic_state.raw2 = 0; if (!extended_dynamic_state) { dynamic_state.Refresh(regs); } + if (!extended_dynamic_state_2) { + dynamic_state.Refresh2(regs, topology); + } + if (!extended_dynamic_state_3) { + dynamic_state.Refresh3(regs); + } if (xfb_enabled) { RefreshXfbState(xfb_state, regs); } @@ -212,8 +213,6 @@ void FixedPipelineState::DynamicState::Refresh(const Maxwell& regs) { packed_front_face = 1 - packed_front_face; } - raw1 = 0; - raw2 = 0; front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op.fail)); front.action_depth_fail.Assign(PackStencilOp(regs.stencil_front_op.zfail)); front.action_depth_pass.Assign(PackStencilOp(regs.stencil_front_op.zpass)); @@ -242,6 +241,21 @@ void FixedPipelineState::DynamicState::Refresh(const Maxwell& regs) { }); } +void FixedPipelineState::DynamicState::Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology_) { + const std::array enabled_lut{ + regs.polygon_offset_point_enable, + regs.polygon_offset_line_enable, + regs.polygon_offset_fill_enable, + }; + const u32 topology_index = static_cast(topology_); + + rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); + primitive_restart_enable.Assign(regs.primitive_restart.enabled != 0 ? 1 : 0); + depth_bias_enable.Assign(enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]] != 0 ? 1 : 0); +} + +void FixedPipelineState::DynamicState::Refresh3(const Maxwell&) {} + size_t FixedPipelineState::Hash() const noexcept { const u64 hash = Common::CityHash64(reinterpret_cast(this), Size()); return static_cast(hash); diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 03bf64b575..ac2ec3edc0 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -17,6 +17,14 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; +struct DynamicFeatures { + bool has_extended_dynamic_state; + bool has_extended_dynamic_state_2; + bool has_extended_dynamic_state_2_extra; + bool has_extended_dynamic_state_3; + bool has_dynamic_vertex_input; +}; + struct FixedPipelineState { static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept; static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept; @@ -133,6 +141,14 @@ struct FixedPipelineState { struct DynamicState { union { u32 raw1; + BitField<0, 2, u32> cull_face; + BitField<2, 1, u32> cull_enable; + BitField<3, 1, u32> primitive_restart_enable; + BitField<4, 1, u32> depth_bias_enable; + BitField<5, 1, u32> rasterize_enable; + }; + union { + u32 raw2; StencilFace<0> front; StencilFace<12> back; BitField<24, 1, u32> stencil_enable; @@ -142,15 +158,12 @@ struct FixedPipelineState { BitField<28, 1, u32> front_face; BitField<29, 3, u32> depth_test_func; }; - union { - u32 raw2; - BitField<0, 2, u32> cull_face; - BitField<2, 1, u32> cull_enable; - }; // Vertex stride is a 12 bits value, we have 4 bits to spare per element std::array vertex_strides; void Refresh(const Maxwell& regs); + void Refresh2(const Maxwell& regs, Maxwell::PrimitiveTopology topology); + void Refresh3(const Maxwell& regs); Maxwell::ComparisonOp DepthTestFunc() const noexcept { return UnpackComparisonOp(depth_test_func); @@ -168,10 +181,10 @@ struct FixedPipelineState { union { u32 raw1; BitField<0, 1, u32> extended_dynamic_state; - BitField<1, 1, u32> dynamic_vertex_input; - BitField<2, 1, u32> xfb_enabled; - BitField<3, 1, u32> primitive_restart_enable; - BitField<4, 1, u32> depth_bias_enable; + BitField<1, 1, u32> extended_dynamic_state_2; + BitField<2, 1, u32> extended_dynamic_state_3; + BitField<3, 1, u32> dynamic_vertex_input; + BitField<4, 1, u32> xfb_enabled; BitField<5, 1, u32> depth_clamp_disabled; BitField<6, 1, u32> ndc_minus_one_to_one; BitField<7, 2, u32> polygon_mode; @@ -186,7 +199,6 @@ struct FixedPipelineState { }; union { u32 raw2; - BitField<0, 1, u32> rasterize_enable; BitField<1, 3, u32> alpha_test_func; BitField<4, 1, u32> early_z; BitField<5, 1, u32> depth_enabled; @@ -215,8 +227,7 @@ struct FixedPipelineState { DynamicState dynamic_state; VideoCommon::TransformFeedbackState xfb_state; - void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, bool has_extended_dynamic_state, - bool has_dynamic_vertex_input); + void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features); size_t Hash() const noexcept; @@ -231,14 +242,18 @@ struct FixedPipelineState { // When transform feedback is enabled, use the whole struct return sizeof(*this); } - if (dynamic_vertex_input) { + if (dynamic_vertex_input && extended_dynamic_state_2) { // Exclude dynamic state and attributes return offsetof(FixedPipelineState, attributes); } - if (extended_dynamic_state) { + if (extended_dynamic_state_2) { // Exclude dynamic state return offsetof(FixedPipelineState, dynamic_state); } + if (extended_dynamic_state) { + // Exclude dynamic state + return offsetof(FixedPipelineState, dynamic_state.raw2); + } // Default return offsetof(FixedPipelineState, xfb_state); } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 515d8d8695..d21d5aaf4c 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -525,6 +525,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { if (!key.state.extended_dynamic_state) { dynamic = key.state.dynamic_state; } + if (!key.state.extended_dynamic_state_2) { + dynamic.raw2 = key.state.dynamic_state.raw2; + } static_vector vertex_bindings; static_vector vertex_binding_divisors; static_vector vertex_attributes; @@ -625,7 +628,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pNext = nullptr, .flags = 0, .topology = input_assembly_topology, - .primitiveRestartEnable = key.state.primitive_restart_enable != 0 && + .primitiveRestartEnable = key.state.dynamic_state.primitive_restart_enable != 0 && ((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && device.IsTopologyListPrimitiveRestartSupported()) || SupportsPrimitiveRestart(input_assembly_topology) || @@ -674,13 +677,13 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .depthClampEnable = static_cast(key.state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), .rasterizerDiscardEnable = - static_cast(key.state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), + static_cast(dynamic.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), .polygonMode = MaxwellToVK::PolygonMode(FixedPipelineState::UnpackPolygonMode(key.state.polygon_mode)), .cullMode = static_cast( dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE), .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), - .depthBiasEnable = key.state.depth_bias_enable, + .depthBiasEnable = (dynamic.depth_bias_enable == 0 ? VK_TRUE : VK_FALSE), .depthBiasConstantFactor = 0.0f, .depthBiasClamp = 0.0f, .depthBiasSlopeFactor = 0.0f, @@ -788,7 +791,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pAttachments = cb_attachments.data(), .blendConstants = {}, }; - static_vector dynamic_states{ + static_vector dynamic_states{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, @@ -811,6 +814,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT); } dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); + if (key.state.extended_dynamic_state_2) { + static constexpr std::array extended2{ + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT, + }; + dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end()); + } } const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 58b955821e..1292b6bdff 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -351,6 +351,14 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device LOG_WARNING(Render_Vulkan, "maxVertexInputBindings is too low: {} < {}", device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays); } + + dynamic_features = DynamicFeatures{ + .has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported(), + .has_extended_dynamic_state_2 = device.IsExtExtendedDynamicState2Supported(), + .has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported(), + .has_extended_dynamic_state_3 = device.IsExtExtendedDynamicState3Supported(), + .has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(), + }; } PipelineCache::~PipelineCache() = default; @@ -362,8 +370,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { current_pipeline = nullptr; return nullptr; } - graphics_key.state.Refresh(*maxwell3d, device.IsExtExtendedDynamicStateSupported(), - device.IsExtVertexInputDynamicStateSupported()); + graphics_key.state.Refresh(*maxwell3d, dynamic_features); if (current_pipeline) { GraphicsPipeline* const next{current_pipeline->Next(graphics_key)}; @@ -439,14 +446,17 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading }); ++state.total; }}; - const bool extended_dynamic_state = device.IsExtExtendedDynamicStateSupported(); - const bool dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(); const auto load_graphics{[&](std::ifstream& file, std::vector envs) { GraphicsPipelineCacheKey key; file.read(reinterpret_cast(&key), sizeof(key)); - if ((key.state.extended_dynamic_state != 0) != extended_dynamic_state || - (key.state.dynamic_vertex_input != 0) != dynamic_vertex_input) { + if ((key.state.extended_dynamic_state != 0) != + dynamic_features.has_extended_dynamic_state || + (key.state.extended_dynamic_state_2 != 0) != + dynamic_features.has_extended_dynamic_state_2 || + (key.state.extended_dynamic_state_3 != 0) != + dynamic_features.has_extended_dynamic_state_3 || + (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { return; } workers.QueueWork([this, key, envs = std::move(envs), &state, &callback]() mutable { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 61f9e9366a..b4f593ef54 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -160,6 +160,7 @@ private: Common::ThreadWorker workers; Common::ThreadWorker serialization_thread; + DynamicFeatures dynamic_features; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6f1adc97ff..f52cebc222 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -680,16 +680,26 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateLineWidth(regs); if (device.IsExtExtendedDynamicStateSupported()) { UpdateCullMode(regs); - UpdateDepthBoundsTestEnable(regs); - UpdateDepthTestEnable(regs); - UpdateDepthWriteEnable(regs); + UpdateDepthCompareOp(regs); UpdateFrontFace(regs); UpdateStencilOp(regs); - UpdateStencilTestEnable(regs); + if (device.IsExtVertexInputDynamicStateSupported()) { UpdateVertexInput(regs); } + + if (state_tracker.TouchStateEnable()) { + UpdateDepthBoundsTestEnable(regs); + UpdateDepthTestEnable(regs); + UpdateDepthWriteEnable(regs); + UpdateStencilTestEnable(regs); + if (device.IsExtExtendedDynamicState2Supported()) { + UpdatePrimitiveRestartEnable(regs); + UpdateRasterizerDiscardEnable(regs); + UpdateDepthBiasEnable(regs); + } + } } } @@ -909,6 +919,58 @@ void RasterizerVulkan::UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& r }); } +void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs) { + if (!state_tracker.TouchPrimitiveRestartEnable()) { + return; + } + scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) { + cmdbuf.SetPrimitiveRestartEnableEXT(enable); + }); +} + +void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs) { + if (!state_tracker.TouchRasterizerDiscardEnable()) { + return; + } + scheduler.Record([disable = regs.rasterize_enable](vk::CommandBuffer cmdbuf) { + cmdbuf.SetRasterizerDiscardEnableEXT(disable == 0); + }); +} + +void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs) { + if (!state_tracker.TouchDepthBiasEnable()) { + return; + } + constexpr size_t POINT = 0; + constexpr size_t LINE = 1; + constexpr size_t POLYGON = 2; + constexpr std::array POLYGON_OFFSET_ENABLE_LUT = { + POINT, // Points + LINE, // Lines + LINE, // LineLoop + LINE, // LineStrip + POLYGON, // Triangles + POLYGON, // TriangleStrip + POLYGON, // TriangleFan + POLYGON, // Quads + POLYGON, // QuadStrip + POLYGON, // Polygon + LINE, // LinesAdjacency + LINE, // LineStripAdjacency + POLYGON, // TrianglesAdjacency + POLYGON, // TriangleStripAdjacency + POLYGON, // Patches + }; + const std::array enabled_lut{ + regs.polygon_offset_point_enable, + regs.polygon_offset_line_enable, + regs.polygon_offset_fill_enable, + }; + const u32 topology_index = static_cast(maxwell3d->draw_manager->GetDrawState().topology); + const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]]; + scheduler.Record([enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable); }); +} + void RasterizerVulkan::UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs) { if (!state_tracker.TouchDepthCompareOp()) { return; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 43a210da0b..c09415a6ad 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -139,6 +139,9 @@ private: void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs); + void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs); + void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs); + void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs); void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs); diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index edb41b171e..339679ff92 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -27,10 +27,27 @@ using Flags = Maxwell3D::DirtyState::Flags; Flags MakeInvalidationFlags() { static constexpr int INVALIDATION_FLAGS[]{ - Viewports, Scissors, DepthBias, BlendConstants, DepthBounds, - StencilProperties, LineWidth, CullMode, DepthBoundsEnable, DepthTestEnable, - DepthWriteEnable, DepthCompareOp, FrontFace, StencilOp, StencilTestEnable, - VertexBuffers, VertexInput, + Viewports, + Scissors, + DepthBias, + BlendConstants, + DepthBounds, + StencilProperties, + LineWidth, + CullMode, + DepthBoundsEnable, + DepthTestEnable, + DepthWriteEnable, + DepthCompareOp, + FrontFace, + StencilOp, + StencilTestEnable, + VertexBuffers, + VertexInput, + StateEnable, + PrimitiveRestartEnable, + RasterizerDiscardEnable, + DepthBiasEnable, }; Flags flags{}; for (const int flag : INVALIDATION_FLAGS) { @@ -96,16 +113,20 @@ void SetupDirtyCullMode(Tables& tables) { table[OFF(gl_cull_test_enabled)] = CullMode; } -void SetupDirtyDepthBoundsEnable(Tables& tables) { - tables[0][OFF(depth_bounds_enable)] = DepthBoundsEnable; -} - -void SetupDirtyDepthTestEnable(Tables& tables) { - tables[0][OFF(depth_test_enable)] = DepthTestEnable; -} - -void SetupDirtyDepthWriteEnable(Tables& tables) { - tables[0][OFF(depth_write_enabled)] = DepthWriteEnable; +void SetupDirtyStateEnable(Tables& tables) { + const auto setup = [&](size_t position, u8 flag) { + tables[0][position] = flag; + tables[1][position] = StateEnable; + }; + setup(OFF(depth_bounds_enable), DepthBoundsEnable); + setup(OFF(depth_test_enable), DepthTestEnable); + setup(OFF(depth_write_enabled), DepthWriteEnable); + setup(OFF(stencil_enable), StencilTestEnable); + setup(OFF(primitive_restart.enabled), PrimitiveRestartEnable); + setup(OFF(rasterize_enable), RasterizerDiscardEnable); + setup(OFF(polygon_offset_point_enable), DepthBiasEnable); + setup(OFF(polygon_offset_line_enable), DepthBiasEnable); + setup(OFF(polygon_offset_fill_enable), DepthBiasEnable); } void SetupDirtyDepthCompareOp(Tables& tables) { @@ -133,10 +154,6 @@ void SetupDirtyStencilOp(Tables& tables) { tables[1][OFF(stencil_two_side_enable)] = StencilOp; } -void SetupDirtyStencilTestEnable(Tables& tables) { - tables[0][OFF(stencil_enable)] = StencilTestEnable; -} - void SetupDirtyBlending(Tables& tables) { tables[0][OFF(color_mask_common)] = Blending; tables[0][OFF(blend_per_target_enabled)] = Blending; @@ -185,13 +202,10 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) { SetupDirtyStencilProperties(tables); SetupDirtyLineWidth(tables); SetupDirtyCullMode(tables); - SetupDirtyDepthBoundsEnable(tables); - SetupDirtyDepthTestEnable(tables); - SetupDirtyDepthWriteEnable(tables); + SetupDirtyStateEnable(tables); SetupDirtyDepthCompareOp(tables); SetupDirtyFrontFace(tables); SetupDirtyStencilOp(tables); - SetupDirtyStencilTestEnable(tables); SetupDirtyBlending(tables); SetupDirtyViewportSwizzles(tables); SetupDirtyVertexAttributes(tables); diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 2296dea602..583bfe1350 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -45,6 +45,10 @@ enum : u8 { FrontFace, StencilOp, StencilTestEnable, + PrimitiveRestartEnable, + RasterizerDiscardEnable, + DepthBiasEnable, + StateEnable, Blending, ViewportSwizzles, @@ -111,6 +115,10 @@ public: return Exchange(Dirty::CullMode, false); } + bool TouchStateEnable() { + return Exchange(Dirty::StateEnable, false); + } + bool TouchDepthBoundsTestEnable() { return Exchange(Dirty::DepthBoundsEnable, false); } @@ -123,6 +131,18 @@ public: return Exchange(Dirty::DepthWriteEnable, false); } + bool TouchPrimitiveRestartEnable() { + return Exchange(Dirty::PrimitiveRestartEnable, false); + } + + bool TouchRasterizerDiscardEnable() { + return Exchange(Dirty::RasterizerDiscardEnable, false); + } + + bool TouchDepthBiasEnable() { + return Exchange(Dirty::DepthBiasEnable, false); + } + bool TouchDepthCompareOp() { return Exchange(Dirty::DepthCompareOp, false); } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 207fae8c91..9a420a2934 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -569,6 +569,34 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); } + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2; + if (ext_extended_dynamic_state2) { + dynamic_state2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT, + .pNext = nullptr, + .extendedDynamicState2 = VK_TRUE, + .extendedDynamicState2LogicOp = ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE, + .extendedDynamicState2PatchControlPoints = + ext_extended_dynamic_state2_extra ? VK_TRUE : VK_FALSE, + }; + SetNext(next, dynamic_state2); + } else { + LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 2"); + } + + VkPhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state3; + if (ext_extended_dynamic_state3) { + dynamic_state3 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT, + .pNext = nullptr, + .extendedDynamicState3ColorBlendEnable = VK_TRUE, + .extendedDynamicState3ColorBlendEquation = VK_TRUE, + }; + SetNext(next, dynamic_state3); + } else { + LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state 3"); + } + VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster; if (ext_line_rasterization) { line_raster = { @@ -1091,6 +1119,8 @@ std::vector Device::LoadExtensions(bool requires_surface) { bool has_ext_transform_feedback{}; bool has_ext_custom_border_color{}; bool has_ext_extended_dynamic_state{}; + bool has_ext_extended_dynamic_state2{}; + bool has_ext_extended_dynamic_state3{}; bool has_ext_shader_atomic_int64{}; bool has_ext_provoking_vertex{}; bool has_ext_vertex_input_dynamic_state{}; @@ -1135,6 +1165,10 @@ std::vector Device::LoadExtensions(bool requires_surface) { test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); + test(has_ext_extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, + false); + test(has_ext_extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME, + false); test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, true); test(has_ext_provoking_vertex, VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, false); test(has_ext_vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME, @@ -1284,6 +1318,36 @@ std::vector Device::LoadExtensions(bool requires_surface) { ext_extended_dynamic_state = true; } } + if (has_ext_extended_dynamic_state2) { + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extended_dynamic_state2; + extended_dynamic_state2.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + extended_dynamic_state2.pNext = nullptr; + features.pNext = &extended_dynamic_state2; + physical.GetFeatures2(features); + + if (extended_dynamic_state2.extendedDynamicState2) { + extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + ext_extended_dynamic_state2 = true; + ext_extended_dynamic_state2_extra = + extended_dynamic_state2.extendedDynamicState2LogicOp && + extended_dynamic_state2.extendedDynamicState2PatchControlPoints; + } + } + if (has_ext_extended_dynamic_state3) { + VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extended_dynamic_state3; + extended_dynamic_state3.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; + extended_dynamic_state3.pNext = nullptr; + features.pNext = &extended_dynamic_state3; + physical.GetFeatures2(features); + + if (extended_dynamic_state3.extendedDynamicState3ColorBlendEnable && + extended_dynamic_state3.extendedDynamicState3ColorBlendEquation) { + extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + ext_extended_dynamic_state3 = true; + } + } if (has_ext_line_rasterization) { VkPhysicalDeviceLineRasterizationFeaturesEXT line_raster; line_raster.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d0d7c2299f..51b049c0d1 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -286,6 +286,20 @@ public: return ext_extended_dynamic_state; } + /// Returns true if the device supports VK_EXT_extended_dynamic_state2. + bool IsExtExtendedDynamicState2Supported() const { + return ext_extended_dynamic_state2; + } + + bool IsExtExtendedDynamicState2ExtrasSupported() const { + return ext_extended_dynamic_state2_extra; + } + + /// Returns true if the device supports VK_EXT_extended_dynamic_state3. + bool IsExtExtendedDynamicState3Supported() const { + return ext_extended_dynamic_state3; + } + /// Returns true if the device supports VK_EXT_line_rasterization. bool IsExtLineRasterizationSupported() const { return ext_line_rasterization; @@ -468,6 +482,9 @@ private: bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. + bool ext_extended_dynamic_state2{}; ///< Support for VK_EXT_extended_dynamic_state2. + bool ext_extended_dynamic_state2_extra{}; ///< Support for VK_EXT_extended_dynamic_state2. + bool ext_extended_dynamic_state3{}; ///< Support for VK_EXT_extended_dynamic_state3. bool ext_line_rasterization{}; ///< Support for VK_EXT_line_rasterization. bool ext_vertex_input_dynamic_state{}; ///< Support for VK_EXT_vertex_input_dynamic_state. bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index f8f8ed9f88..4dde325ffb 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -122,6 +122,9 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { X(vkCmdSetDepthCompareOpEXT); X(vkCmdSetDepthTestEnableEXT); X(vkCmdSetDepthWriteEnableEXT); + X(vkCmdSetPrimitiveRestartEnableEXT); + X(vkCmdSetRasterizerDiscardEnableEXT); + X(vkCmdSetDepthBiasEnableEXT); X(vkCmdSetFrontFaceEXT); X(vkCmdSetLineWidth); X(vkCmdSetPrimitiveTopologyEXT); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 493a48573f..0d3f71460a 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -234,6 +234,9 @@ struct DeviceDispatch : InstanceDispatch { PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{}; PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{}; PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{}; + PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{}; + PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{}; + PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{}; PFN_vkCmdSetEvent vkCmdSetEvent{}; PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{}; PFN_vkCmdSetLineWidth vkCmdSetLineWidth{}; @@ -1219,6 +1222,18 @@ public: dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); } + void SetPrimitiveRestartEnableEXT(bool enable) const noexcept { + dld->vkCmdSetPrimitiveRestartEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetRasterizerDiscardEnableEXT(bool enable) const noexcept { + dld->vkCmdSetRasterizerDiscardEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetDepthBiasEnableEXT(bool enable) const noexcept { + dld->vkCmdSetDepthBiasEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + void SetFrontFaceEXT(VkFrontFace front_face) const noexcept { dld->vkCmdSetFrontFaceEXT(handle, front_face); }