From 3a70dddf8027768bf6bbb4b7ccf7060c72656241 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 1 Feb 2026 02:07:47 -0400 Subject: [PATCH] [vulkan] Adjusting DynamicState functionality + including Static Pipelines Mode --- .../app/src/main/res/values/arrays.xml | 4 +- src/common/settings.h | 4 +- src/common/settings_enums.h | 2 +- .../renderer_vulkan/fixed_pipeline_state.cpp | 1 + .../renderer_vulkan/fixed_pipeline_state.h | 28 ++++++------- .../renderer_vulkan/vk_graphics_pipeline.cpp | 23 +++++++---- .../renderer_vulkan/vk_pipeline_cache.cpp | 8 +--- .../renderer_vulkan/vk_rasterizer.cpp | 25 +++++------- .../vulkan_common/vulkan_device.cpp | 39 +++++++++++-------- src/video_core/vulkan_common/vulkan_device.h | 6 +++ 10 files changed, 76 insertions(+), 64 deletions(-) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 69f1590844..636cb82ac6 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -611,7 +611,8 @@ - @string/disabled + Static + Core ExtendedDynamicState 1 ExtendedDynamicState 2 ExtendedDynamicState 3 @@ -622,6 +623,7 @@ 1 2 3 + 4 diff --git a/src/common/settings.h b/src/common/settings.h index 06837aae5a..5c758e9642 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -535,9 +535,9 @@ struct Values { #elif defined (__FreeBSD__) ExtendedDynamicState::EDS3, #elif defined (ANDROID) - ExtendedDynamicState::Disabled, + ExtendedDynamicState::Static, #elif defined (__APPLE__) - ExtendedDynamicState::Disabled, + ExtendedDynamicState::Static, #else ExtendedDynamicState::EDS2, #endif diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 30d075565b..b009f45675 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -153,7 +153,7 @@ ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge) ENUM(GpuUnswizzle, VeryLow, Low, Normal, Medium, High) ENUM(GpuUnswizzleChunk, VeryLow, Low, Normal, Medium, High) ENUM(TemperatureUnits, Celsius, Fahrenheit) -ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3); +ENUM(ExtendedDynamicState, Static, Core, EDS1, EDS2, EDS3); ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All) template diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 06cbd9e6da..cae8f0f88d 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -57,6 +57,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; raw1 = 0; + dynamic_state_enabled.Assign(features.has_dynamic_state ? 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_2_logic_op.Assign(features.has_extended_dynamic_state_2_logic_op ? 1 : 0); diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index c5bc14f448..eeb9d2df95 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -21,6 +21,7 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; struct DynamicFeatures { + bool has_dynamic_state; bool has_extended_dynamic_state; bool has_extended_dynamic_state_2; bool has_extended_dynamic_state_2_logic_op; @@ -188,19 +189,20 @@ struct FixedPipelineState { union { u32 raw1; - BitField<0, 1, u32> extended_dynamic_state; - BitField<1, 1, u32> extended_dynamic_state_2; - BitField<2, 1, u32> extended_dynamic_state_2_logic_op; - BitField<3, 1, u32> extended_dynamic_state_3_blend; - BitField<4, 1, u32> extended_dynamic_state_3_enables; - BitField<5, 1, u32> dynamic_vertex_input; - BitField<6, 1, u32> xfb_enabled; - BitField<7, 1, u32> ndc_minus_one_to_one; - BitField<8, 2, u32> polygon_mode; - BitField<10, 2, u32> tessellation_primitive; - BitField<12, 2, u32> tessellation_spacing; - BitField<14, 1, u32> tessellation_clockwise; - BitField<15, 5, u32> patch_control_points_minus_one; + BitField<0, 1, u32> dynamic_state_enabled; + BitField<1, 1, u32> extended_dynamic_state; + BitField<2, 1, u32> extended_dynamic_state_2; + BitField<3, 1, u32> extended_dynamic_state_2_logic_op; + BitField<4, 1, u32> extended_dynamic_state_3_blend; + BitField<5, 1, u32> extended_dynamic_state_3_enables; + BitField<6, 1, u32> dynamic_vertex_input; + BitField<7, 1, u32> xfb_enabled; + BitField<8, 1, u32> ndc_minus_one_to_one; + BitField<9, 2, u32> polygon_mode; + BitField<11, 2, u32> tessellation_primitive; + BitField<13, 2, u32> tessellation_spacing; + BitField<15, 1, u32> tessellation_clockwise; + BitField<16, 5, u32> patch_control_points_minus_one; BitField<24, 4, Maxwell::PrimitiveTopology> topology; BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 143d7eee13..06ea1c5b22 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -826,13 +826,22 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { .pAttachments = cb_attachments.data(), .blendConstants = {} }; - 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, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_LINE_WIDTH, - }; + + // Dynamic states configuration based on feature support + static_vector dynamic_states; + + // Core dynamic states (Vulkan 1.0) - Only if not in Static mode + if (key.state.dynamic_state_enabled) { + static constexpr std::array core_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, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_LINE_WIDTH, + }; + dynamic_states.insert(dynamic_states.end(), core_states.begin(), core_states.end()); + } + if (key.state.extended_dynamic_state) { static constexpr std::array extended{ VK_DYNAMIC_STATE_CULL_MODE_EXT, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index f3dd0f90d8..fa2db96879 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -437,13 +437,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, dynamic_features = {}; - // 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_dynamic_state = device.IsCoreDynamicStateSupported(); dynamic_features.has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 1cb4632106..312dac6c1b 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1009,16 +1009,16 @@ 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); - UpdateBlendConstants(regs); - UpdateDepthBounds(regs); - UpdateStencilFaces(regs); - UpdateLineWidth(regs); + if (device.IsCoreDynamicStateSupported()) { + UpdateViewportsState(regs); + UpdateScissorsState(regs); + UpdateDepthBias(regs); + UpdateBlendConstants(regs); + UpdateDepthBounds(regs); + UpdateStencilFaces(regs); + UpdateLineWidth(regs); + } - // EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest if (device.IsExtExtendedDynamicStateSupported()) { UpdateCullMode(regs); UpdateDepthCompareOp(regs); @@ -1032,22 +1032,18 @@ void RasterizerVulkan::UpdateDynamicStates() { } } - // 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( @@ -1069,13 +1065,10 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateAlphaToOneEnable(regs); } - // EDS3 Blending: ColorBlendEnable, ColorBlendEquation, ColorWriteMask - // or VK_EXT_color_write_enable if EDS3 is not available 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 6751973ae1..1d60b3f0e4 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -650,16 +650,21 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR const auto dyna_state = Settings::values.dyna_state.GetValue(); - // Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp - // 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 - switch (dyna_state) { - case Settings::ExtendedDynamicState::Disabled: - // Level 0: Disable all extended dynamic state extensions + case Settings::ExtendedDynamicState::Static: + LOG_INFO(Render_Vulkan, "STATIC Mode (fully static pipelines)"); + 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; + supports_dynamic_state = false; + break; + case Settings::ExtendedDynamicState::Core: + LOG_INFO(Render_Vulkan, "DynamicState - Enabled"); 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, @@ -670,7 +675,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR dynamic_state3_enables = false; break; case Settings::ExtendedDynamicState::EDS1: - // Level 1: Enable EDS1, disable EDS2 and EDS3 + LOG_INFO(Render_Vulkan, "ExtededDynamicState1 - Enabled"); 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, @@ -679,7 +684,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR dynamic_state3_enables = false; break; case Settings::ExtendedDynamicState::EDS2: - // Level 2: Enable EDS1 + EDS2, disable EDS3 + LOG_INFO(Render_Vulkan, "ExtededDynamicState2 - Enabled"); RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); dynamic_state3_blending = false; @@ -687,12 +692,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR break; case Settings::ExtendedDynamicState::EDS3: default: - // Level 3: Enable all (EDS1 + EDS2 + EDS3) + LOG_INFO(Render_Vulkan, "ExtededDynamicState3 - Enabled"); break; } - // VK_EXT_vertex_input_dynamic_state is independent from EDS - // It can be enabled even without extended_dynamic_state if (!Settings::values.vertex_input_dynamic_state.GetValue()) { RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); } @@ -1206,8 +1209,10 @@ bool Device::GetSuitability(bool requires_swapchain) { } } - if (u32(Settings::values.dyna_state.GetValue()) == 0) { - LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features"); + const auto dyna_state_setting = Settings::values.dyna_state.GetValue(); + if (dyna_state_setting == Settings::ExtendedDynamicState::Static) { + LOG_INFO(Render_Vulkan, "Static pipeline mode: All dynamic states disabled"); + supports_dynamic_state = false; features.custom_border_color.customBorderColors = false; features.custom_border_color.customBorderColorWithoutFormat = false; features.extended_dynamic_state.extendedDynamicState = false; @@ -1219,7 +1224,7 @@ bool Device::GetSuitability(bool requires_swapchain) { features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false; } - // Return whether we were suitable. + return suitable; return suitable; } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 999cb709df..666a4fafc3 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -609,6 +609,11 @@ public: return features.custom_border_color.customBorderColorWithoutFormat; } + /// Returns true if the device supports core Vulkan 1.0 dynamic states. + bool IsCoreDynamicStateSupported() const { + return supports_dynamic_state; + } + /// Returns true if the device supports VK_EXT_extended_dynamic_state. bool IsExtExtendedDynamicStateSupported() const { return extensions.extended_dynamic_state; @@ -1067,6 +1072,7 @@ private: bool dynamic_state3_alpha_to_coverage{}; bool dynamic_state3_alpha_to_one{}; bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. + bool supports_dynamic_state{true}; ///< Core Vulkan 1.0 dynamic states size_t sampler_heap_budget{}; ///< Sampler budget for buggy drivers (0 = unlimited). u64 device_access_memory{}; ///< Total size of device local memory in bytes. u32 sets_per_pool{}; ///< Sets per Description Pool