From b85d3ada842b21bb2a12dd1a47ebbad961f00353 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 24 Nov 2025 01:56:59 -0400 Subject: [PATCH] [vk] ExtendedDynamicState impl close to Vulkan specs --- .../renderer_vulkan/vk_pipeline_cache.cpp | 26 +++--- .../renderer_vulkan/vk_rasterizer.cpp | 84 +++++++++++-------- .../vulkan_common/vulkan_device.cpp | 52 +++++++----- 3 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 3bc1efafb1..8b0a5b9623 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -404,30 +404,32 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays); } - const u8 dynamic_state = Settings::values.dyna_state.GetValue(); - - LOG_INFO(Render_Vulkan, "DynamicState value is set to {}", static_cast(dynamic_state)); + LOG_INFO(Render_Vulkan, "DynamicState setting value: {}", Settings::values.dyna_state.GetValue()); dynamic_features = {}; - // EDS1 - Level 1 (all-or-nothing, enabled if driver supports AND setting > 0) + // User granularity enforced in vulkan_device.cpp switch statement: + // Level 0: Core Dynamic States only + // Level 1: Core + EDS1 + // Level 2: Core + EDS1 + EDS2 (accumulative) + // Level 3: Core + EDS1 + EDS2 + EDS3 (accumulative) + // Here we only verify if extensions were successfully loaded by the device + dynamic_features.has_extended_dynamic_state = - device.IsExtExtendedDynamicStateSupported() && dynamic_state > 0; + device.IsExtExtendedDynamicStateSupported(); - // EDS2 - Level 2 (core + granular features, enabled if driver supports AND setting > 1) dynamic_features.has_extended_dynamic_state_2 = - device.IsExtExtendedDynamicState2Supported() && dynamic_state > 1; + device.IsExtExtendedDynamicState2Supported(); dynamic_features.has_extended_dynamic_state_2_logic_op = - device.IsExtExtendedDynamicState2ExtrasSupported() && dynamic_state > 1; + device.IsExtExtendedDynamicState2ExtrasSupported(); dynamic_features.has_extended_dynamic_state_2_patch_control_points = false; - // EDS3 - Level 3 (granular features, enabled if driver supports AND setting > 2) dynamic_features.has_extended_dynamic_state_3_blend = - device.IsExtExtendedDynamicState3BlendingSupported() && dynamic_state > 2; + device.IsExtExtendedDynamicState3BlendingSupported(); dynamic_features.has_extended_dynamic_state_3_enables = - device.IsExtExtendedDynamicState3EnablesSupported() && dynamic_state > 2; + device.IsExtExtendedDynamicState3EnablesSupported(); - // VIDS - Independent toggle (not affected by dyna_state levels) + // VIDS: Independent toggle (not affected by dyna_state levels) dynamic_features.has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported() && Settings::values.vertex_input_dynamic_state.GetValue(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 9e4b504473..ef1f385ca9 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -924,6 +924,8 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info, void RasterizerVulkan::UpdateDynamicStates() { auto& regs = maxwell3d->regs; + + // Core Dynamic States (Vulkan 1.0) - Always active regardless of dyna_state setting UpdateViewportsState(regs); UpdateScissorsState(regs); UpdateDepthBias(regs); @@ -931,6 +933,15 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthBounds(regs); UpdateStencilFaces(regs); UpdateLineWidth(regs); + + // Extended Dynamic States (EDS) - Controlled by dyna_state setting in vulkan_device.cpp + // User granularity levels (accumulative): + // Level 0: Core only + // Level 1: Core + EDS1 + // Level 2: Core + EDS1 + EDS2 + // Level 3: Core + EDS1 + EDS2 + EDS3 + + // EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest if (device.IsExtExtendedDynamicStateSupported()) { UpdateCullMode(regs); UpdateDepthCompareOp(regs); @@ -942,42 +953,49 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthWriteEnable(regs); UpdateStencilTestEnable(regs); } - // EDS2 states must always be set, not just when TouchStateEnable() is true - if (device.IsExtExtendedDynamicState2Supported()) { - UpdatePrimitiveRestartEnable(regs); - UpdateRasterizerDiscardEnable(regs); - UpdateDepthBiasEnable(regs); - } - if (state_tracker.TouchStateEnable()) { - if (device.IsExtExtendedDynamicState3EnablesSupported()) { - using namespace Tegra::Engines; - if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE || device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) { - const auto has_float = std::any_of( - regs.vertex_attrib_format.begin(), - regs.vertex_attrib_format.end(), - [](const auto& attrib) { - return attrib.type == Maxwell3D::Regs::VertexAttribute::Type::Float; - } - ); - if (regs.logic_op.enable) { - regs.logic_op.enable = static_cast(!has_float); - } + } + + // EDS2: PrimitiveRestart, RasterizerDiscard, DepthBias enable/disable + if (device.IsExtExtendedDynamicState2Supported()) { + UpdatePrimitiveRestartEnable(regs); + UpdateRasterizerDiscardEnable(regs); + UpdateDepthBiasEnable(regs); + } + + // EDS2 Extras: LogicOp operation selection + if (device.IsExtExtendedDynamicState2ExtrasSupported()) { + UpdateLogicOp(regs); + } + + // EDS3 Enables: LogicOpEnable, DepthClamp, LineStipple, ConservativeRaster + if (device.IsExtExtendedDynamicState3EnablesSupported()) { + using namespace Tegra::Engines; + // AMD Workaround: LogicOp incompatible with float render targets + if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE || + device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) { + const auto has_float = std::any_of( + regs.vertex_attrib_format.begin(), + regs.vertex_attrib_format.end(), + [](const auto& attrib) { + return attrib.type == Maxwell3D::Regs::VertexAttribute::Type::Float; } - UpdateLogicOpEnable(regs); - UpdateDepthClampEnable(regs); + ); + if (regs.logic_op.enable) { + regs.logic_op.enable = static_cast(!has_float); } } - if (device.IsExtExtendedDynamicState2ExtrasSupported()) { - UpdateLogicOp(regs); - } - if (device.IsExtExtendedDynamicState3BlendingSupported()) { - UpdateBlending(regs); - } - if (device.IsExtExtendedDynamicState3EnablesSupported()) { - UpdateLineStippleEnable(regs); - UpdateConservativeRasterizationMode(regs); - } - } + UpdateLogicOpEnable(regs); + UpdateDepthClampEnable(regs); + UpdateLineStippleEnable(regs); + UpdateConservativeRasterizationMode(regs); + } + + // EDS3 Blending: ColorBlendEnable, ColorBlendEquation, ColorWriteMask + if (device.IsExtExtendedDynamicState3BlendingSupported()) { + UpdateBlending(regs); + } + + // Vertex Input Dynamic State: Independent from EDS levels if (device.IsExtVertexInputDynamicStateSupported()) { if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) { UpdateVertexInput(regs); diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index a561e643c9..916a1cf7c9 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -629,24 +629,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR properties.properties.limits.maxVertexInputBindings = 32; } - if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) { - LOG_INFO(Render_Vulkan, - "Removing extendedDynamicState2 due to missing extendedDynamicState"); - RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, - VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); - } - - if (!extensions.extended_dynamic_state2 && extensions.extended_dynamic_state3) { - LOG_INFO(Render_Vulkan, - "Removing extendedDynamicState3 due to missing extendedDynamicState2"); - RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, - VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); - dynamic_state3_blending = false; - dynamic_state3_enables = false; - } - // Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp - // This slider only controls EXTENDED dynamic states (VK_EXT_extended_dynamic_state 1/2/3) + // This slider controls EXTENDED dynamic states with accumulative levels per Vulkan specs: + // Level 0 = Core Dynamic States only (Vulkan 1.0) + // Level 1 = Core + VK_EXT_extended_dynamic_state + // Level 2 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + // Level 3 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + VK_EXT_extended_dynamic_state3 // Mesa Intel drivers on UHD 620 have broken EDS causing extreme flickering - unknown if it affects other iGPUs // ALSO affects ALL versions of UHD drivers on Windows 10+, seems to cause even worse issues like straight up crashing @@ -659,16 +647,36 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR switch (Settings::values.dyna_state.GetValue()) { case 0: - RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); - [[fallthrough]]; + // Level 0: Disable all extended dynamic state extensions + RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, + VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + dynamic_state3_blending = false; + dynamic_state3_enables = false; + break; case 1: - RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); - [[fallthrough]]; + // Level 1: Enable EDS1, disable EDS2 and EDS3 + RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, + VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); + RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + dynamic_state3_blending = false; + dynamic_state3_enables = false; + break; case 2: - RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); + // Level 2: Enable EDS1 + EDS2, disable EDS3 + RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, + VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); dynamic_state3_blending = false; dynamic_state3_enables = false; break; + case 3: + default: + // Level 3: Enable all (EDS1 + EDS2 + EDS3) + break; } // VK_EXT_vertex_input_dynamic_state is independent from EDS