diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index c38c07c76b..8371440b23 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -131,15 +131,11 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe } dynamic_state.raw1 = 0; dynamic_state.raw2 = 0; - if (!extended_dynamic_state) { - dynamic_state.Refresh(regs); - } + dynamic_state.Refresh(regs); std::ranges::transform(regs.vertex_streams, vertex_strides.begin(), [](const auto& array) { return static_cast(array.stride.Value()); }); - if (!extended_dynamic_state_2) { - dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2); - } + dynamic_state.Refresh2(regs, topology_, false); if (maxwell3d.dirty.flags[Dirty::Blending]) { maxwell3d.dirty.flags[Dirty::Blending] = false; for (size_t index = 0; index < attachments.size(); ++index) { diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 030c62a883..77d44e6d49 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -254,11 +254,9 @@ struct FixedPipelineState { // When transform feedback is enabled, use the whole struct return sizeof(*this); } - if (extended_dynamic_state) { - // Exclude dynamic state - return offsetof(FixedPipelineState, vertex_strides); - } - // Default + // Always include the cached dynamic-state payload in the key. Some members of + // `dynamic_state` still feed static pipeline state even when EDS is enabled, + // and excluding the whole block causes incorrect pipeline reuse. 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 8a96a11a22..7fb7ab9ba7 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -531,12 +531,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling, } const void* const descriptor_data{guest_descriptor_queue.UpdateData()}; - FixedPipelineState::DynamicState dynamic_state{}; - if (!key.state.extended_dynamic_state) { - dynamic_state = key.state.dynamic_state; - } else { - dynamic_state.raw1 = key.state.dynamic_state.raw1; - } + const FixedPipelineState::DynamicState dynamic_state{key.state.dynamic_state}; scheduler.Record([this, descriptor_data, bind_pipeline, rescaling_data = rescaling.Data(), is_rescaling, update_rescaling, uses_render_area = render_area.uses_render_area, @@ -687,9 +682,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .pNext = nullptr, .flags = 0, - .viewportCount = num_viewports, + .viewportCount = key.state.extended_dynamic_state ? 0u : num_viewports, .pViewports = nullptr, - .scissorCount = num_viewports, + .scissorCount = key.state.extended_dynamic_state ? 0u : num_viewports, .pScissors = nullptr, }; if (device.IsNvViewportSwizzleSupported()) { @@ -901,6 +896,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { } if (key.state.extended_dynamic_state) { static constexpr std::array extended{ + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT, + VK_DYNAMIC_STATE_CULL_MODE_EXT, + VK_DYNAMIC_STATE_FRONT_FACE_EXT, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, @@ -914,11 +914,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); } - if (key.state.extended_dynamic_state) { - dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); - dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); - } - // EDS2 - Core (3 states) if (key.state.extended_dynamic_state_2) { static constexpr std::array extended2{ diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a8bbaadc33..0002fceec6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -277,8 +277,9 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { if (!pipeline->Configure(is_indexed)) return; - if (pipeline->UsesExtendedDynamicState()) { - state_tracker.InvalidateStateEnableFlag(); + if (pipeline->UsesExtendedDynamicState() || pipeline->UsesExtendedDynamicState2() || + pipeline->UsesExtendedDynamicState2LogicOp()) { + state_tracker.InvalidateExtendedDynamicStates(); } HandleTransformFeedback(); @@ -1078,16 +1079,18 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateLineWidth(regs); UpdateLineStipple(regs); - // EDS1: DepthCompare, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest + // EDS1: CullMode, DepthCompare, FrontFace, PrimitiveTopology, StencilOp, + // DepthBoundsTest, DepthTest, DepthWrite, StencilTest if (device.IsExtExtendedDynamicStateSupported() && pipeline && pipeline->UsesExtendedDynamicState()) { + UpdateCullMode(regs); UpdateDepthCompareOp(regs); + UpdateFrontFace(regs); + UpdatePrimitiveTopology(regs); UpdateStencilOp(regs); - if (state_tracker.TouchStateEnable()) { - UpdateDepthBoundsTestEnable(regs); - UpdateDepthTestEnable(regs); - UpdateDepthWriteEnable(regs); - UpdateStencilTestEnable(regs); - } + UpdateDepthBoundsTestEnable(regs); + UpdateDepthTestEnable(regs); + UpdateDepthWriteEnable(regs); + UpdateStencilTestEnable(regs); } UpdateStencilFaces(regs); @@ -1157,8 +1160,16 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg .minDepth = 0.0f, .maxDepth = 1.0f, }; - scheduler.Record([viewport](vk::CommandBuffer cmdbuf) { - cmdbuf.SetViewport(0, viewport); + GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline(); + const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported() && + pipeline && pipeline->UsesExtendedDynamicState(); + scheduler.Record([viewport, use_viewport_with_count](vk::CommandBuffer cmdbuf) { + if (use_viewport_with_count) { + std::array viewports{viewport}; + cmdbuf.SetViewportWithCountEXT(viewports); + } else { + cmdbuf.SetViewport(0, viewport); + } }); return; } @@ -1174,10 +1185,17 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), }; - scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) { + GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline(); + const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported() && + pipeline && pipeline->UsesExtendedDynamicState(); + scheduler.Record([this, viewport_list, use_viewport_with_count](vk::CommandBuffer cmdbuf) { const u32 num_viewports = std::min(device.GetMaxViewports(), Maxwell::NumViewports); const vk::Span viewports(viewport_list.data(), num_viewports); - cmdbuf.SetViewport(0, viewports); + if (use_viewport_with_count) { + cmdbuf.SetViewportWithCountEXT(viewports); + } else { + cmdbuf.SetViewport(0, viewports); + } }); } @@ -1198,8 +1216,16 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs scissor.offset.y = static_cast(y); scissor.extent.width = width; scissor.extent.height = height; - scheduler.Record([scissor](vk::CommandBuffer cmdbuf) { - cmdbuf.SetScissor(0, scissor); + GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline(); + const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported() && + pipeline && pipeline->UsesExtendedDynamicState(); + scheduler.Record([scissor, use_scissor_with_count](vk::CommandBuffer cmdbuf) { + if (use_scissor_with_count) { + std::array scissors{scissor}; + cmdbuf.SetScissorWithCountEXT(scissors); + } else { + cmdbuf.SetScissor(0, scissor); + } }); return; } @@ -1227,10 +1253,17 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs GetScissorState(regs, 14, up_scale, down_shift), GetScissorState(regs, 15, up_scale, down_shift), }; - scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) { + GraphicsPipeline* pipeline = pipeline_cache.CurrentGraphicsPipeline(); + const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported() && + pipeline && pipeline->UsesExtendedDynamicState(); + scheduler.Record([this, scissor_list, use_scissor_with_count](vk::CommandBuffer cmdbuf) { const u32 num_scissors = std::min(device.GetMaxViewports(), Maxwell::NumViewports); const vk::Span scissors(scissor_list.data(), num_scissors); - cmdbuf.SetScissor(0, scissors); + if (use_scissor_with_count) { + cmdbuf.SetScissorWithCountEXT(scissors); + } else { + cmdbuf.SetScissor(0, scissors); + } }); } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index dba18a91cb..d3ed9c50a6 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -154,9 +154,11 @@ void Scheduler::RequestOutsideRenderPassOperationContext() { bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { if (state.graphics_pipeline == pipeline) { - if (pipeline && pipeline->UsesExtendedDynamicState() && + if (pipeline && + (pipeline->UsesExtendedDynamicState() || pipeline->UsesExtendedDynamicState2() || + pipeline->UsesExtendedDynamicState2LogicOp()) && state.needs_state_enable_refresh) { - state_tracker.InvalidateStateEnableFlag(); + state_tracker.InvalidateExtendedDynamicStates(); state.needs_state_enable_refresh = false; } return false; @@ -173,10 +175,11 @@ bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) { state_tracker.InvalidateExtendedDynamicStates(); } - if (!pipeline->UsesExtendedDynamicState()) { + if (!pipeline->UsesExtendedDynamicState() && !pipeline->UsesExtendedDynamicState2() && + !pipeline->UsesExtendedDynamicState2LogicOp()) { state.needs_state_enable_refresh = true; } else if (state.needs_state_enable_refresh) { - state_tracker.InvalidateStateEnableFlag(); + state_tracker.InvalidateExtendedDynamicStates(); state.needs_state_enable_refresh = false; } diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index 47948ddc64..610dee618e 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -98,9 +98,13 @@ public: (*flags)[Dirty::Viewports] = true; (*flags)[Dirty::Scissors] = true; (*flags)[Dirty::CullMode] = true; + (*flags)[Dirty::DepthBoundsEnable] = true; + (*flags)[Dirty::DepthTestEnable] = true; + (*flags)[Dirty::DepthWriteEnable] = true; (*flags)[Dirty::DepthCompareOp] = true; (*flags)[Dirty::FrontFace] = true; (*flags)[Dirty::StencilOp] = true; + (*flags)[Dirty::StencilTestEnable] = true; (*flags)[Dirty::StateEnable] = true; (*flags)[Dirty::PrimitiveRestartEnable] = true; (*flags)[Dirty::RasterizerDiscardEnable] = true;