diff --git a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt index f0df7c4f8..91166e4e1 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt @@ -30,7 +30,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_THERMAL_OVERLAY("show_thermal_overlay"), SHOW_RAM_METER("show_ram_meter"), SHOW_SHADER_BUILDING_OVERLAY("show_shader_building_overlay"), - SHOW_PERFORMANCE_GRAPH("show_performance_graph"); + SHOW_PERFORMANCE_GRAPH("show_performance_graph"), + USE_CONDITIONAL_RENDERING("use_conditional_rendering"); override fun getBoolean(needsGlobal: Boolean): Boolean = NativeConfig.getBoolean(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/IntSetting.kt index 5f5663986..92298f804 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/IntSetting.kt @@ -38,6 +38,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { ASTC_RECOMPRESSION("astc_recompression"), SHADER_BACKEND("shader_backend"), VRAM_USAGE_MODE("vram_usage_mode"), + EXTENDED_DYNAMIC_STATE("extended_dynamic_state"), // Applet Mode settings CABINET_APPLET_MODE("cabinet_applet_mode"), diff --git a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/ui/SettingsFragmentPresenter.kt index 35811538a..418912c8f 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -1014,6 +1014,8 @@ class SettingsFragmentPresenter( add(HeaderSetting(R.string.advanced_graphics_header)) add(IntSetting.SHADER_BACKEND.key) add(IntSetting.VRAM_USAGE_MODE.key) + add(IntSetting.EXTENDED_DYNAMIC_STATE.key) + add(BooleanSetting.USE_CONDITIONAL_RENDERING.key) add(HeaderSetting(R.string.frame_skipping_header)) add(IntSetting.FRAME_SKIPPING.key) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 66e233a45..9bcb046b3 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -404,6 +404,20 @@ 2 + + Disabled + EDS1 + EDS2 + EDS3 + + + + 0 + 1 + 2 + 3 + + Conservative Aggressive diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index c454f543f..b9d0615d4 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1239,6 +1239,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Controls which shader backend to use for rendering. VRAM Usage Mode Controls how aggressively VRAM is used. Conservative mode limits VRAM usage for better stability. + Extended Dynamic State + Controls which Vulkan Extended Dynamic State features are enabled. EDS3 (default) enables all features for maximum compatibility. EDS2/EDS1 limit features for troubleshooting graphics issues. Disabled turns off all EDS features. Try lower settings if you experience rendering problems in some games. + Use Conditional Rendering + Enables conditional rendering based on query results. Disabling this can fix flickering objects in some games but may impact performance. Try disabling if you see objects appearing and disappearing rapidly. Frame Skipping Skips frames to maintain performance when the system cannot keep up with the target frame rate. Frame Skipping Mode diff --git a/src/citron/configuration/shared_translation.cpp b/src/citron/configuration/shared_translation.cpp index 0fa823e1d..9d8e48701 100644 --- a/src/citron/configuration/shared_translation.cpp +++ b/src/citron/configuration/shared_translation.cpp @@ -230,6 +230,12 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { "unlocked.")); INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"), tr("Improves rendering of transparency effects in specific games.")); + INSERT(Settings, extended_dynamic_state, tr("Extended Dynamic State:"), + tr("Selects the level of Vulkan Extended Dynamic State support.\n" + "EDS3: Enables all Extended Dynamic State features (recommended).\n" + "EDS2: Enables EDS1 and EDS2 features only.\n" + "EDS1: Enables basic Extended Dynamic State features only.\n" + "Disabled: Disables all Extended Dynamic State features (may reduce compatibility).")); INSERT(Settings, use_conditional_rendering, tr("Use conditional rendering"), tr("Enables conditional rendering based on query results.\n" "Disabling this can fix flickering objects in some games but may impact performance.\n" @@ -340,6 +346,13 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(VramUsageMode, HighEnd, tr("High-End GPU (4090/4080+)")), PAIR(VramUsageMode, Insane, tr("Insane (RTX 4090 24GB)")), }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(ExtendedDynamicState, Disabled, tr("Disabled")), + PAIR(ExtendedDynamicState, EDS1, tr("EDS1")), + PAIR(ExtendedDynamicState, EDS2, tr("EDS2")), + PAIR(ExtendedDynamicState, EDS3, tr("EDS3")), + }}); translations->insert({Settings::EnumMetadata::Index(), { #ifdef HAS_OPENGL diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 32a18d90e..f34ee2709 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -42,6 +42,7 @@ SWITCHABLE(AspectRatio, true); SWITCHABLE(AstcDecodeMode, true); SWITCHABLE(AstcRecompression, true); SWITCHABLE(AudioMode, true); +SWITCHABLE(ExtendedDynamicState, true); SWITCHABLE(CpuBackend, true); SWITCHABLE(CpuAccuracy, true); SWITCHABLE(FullscreenMode, true); diff --git a/src/common/settings.h b/src/common/settings.h index da8ae09db..7786f0c70 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -64,6 +64,7 @@ SWITCHABLE(AspectRatio, true); SWITCHABLE(AstcDecodeMode, true); SWITCHABLE(AstcRecompression, true); SWITCHABLE(AudioMode, true); +SWITCHABLE(ExtendedDynamicState, true); SWITCHABLE(CpuBackend, true); SWITCHABLE(CpuAccuracy, true); SWITCHABLE(FullscreenMode, true); @@ -469,6 +470,12 @@ struct Values { Category::RendererAdvanced}; SwitchableSetting barrier_feedback_loops{linkage, true, "barrier_feedback_loops", Category::RendererAdvanced}; + SwitchableSetting extended_dynamic_state{linkage, + ExtendedDynamicState::EDS3, + ExtendedDynamicState::Disabled, + ExtendedDynamicState::EDS3, + "extended_dynamic_state", + Category::RendererAdvanced}; SwitchableSetting use_conditional_rendering{linkage, true, "use_conditional_rendering", Category::RendererAdvanced}; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index efeeb1902..2fcf4b79b 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -853,6 +853,29 @@ inline u32 EnumMetadata::Index() { return 25; } +enum class ExtendedDynamicState : u32 { + Disabled = 0, + EDS1 = 1, + EDS2 = 2, + EDS3 = 3, +}; + +template <> +inline std::vector> +EnumMetadata::Canonicalizations() { + return { + {"Disabled", ExtendedDynamicState::Disabled}, + {"EDS1", ExtendedDynamicState::EDS1}, + {"EDS2", ExtendedDynamicState::EDS2}, + {"EDS3", ExtendedDynamicState::EDS3}, + }; +} + +template <> +inline u32 EnumMetadata::Index() { + return 26; +} + template inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata::Canonicalizations(); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 07b9b2371..fad8c2b51 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -403,13 +403,19 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays); } + // Apply user's Extended Dynamic State setting + const auto eds_setting = Settings::values.extended_dynamic_state.GetValue(); + const bool allow_eds1 = eds_setting >= Settings::ExtendedDynamicState::EDS1; + const bool allow_eds2 = eds_setting >= Settings::ExtendedDynamicState::EDS2; + const bool allow_eds3 = eds_setting >= Settings::ExtendedDynamicState::EDS3; + 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_blend = device.IsExtExtendedDynamicState3BlendingSupported(), - .has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported(), - .has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(), + .has_extended_dynamic_state = allow_eds1 && device.IsExtExtendedDynamicStateSupported(), + .has_extended_dynamic_state_2 = allow_eds2 && device.IsExtExtendedDynamicState2Supported(), + .has_extended_dynamic_state_2_extra = allow_eds2 && device.IsExtExtendedDynamicState2ExtrasSupported(), + .has_extended_dynamic_state_3_blend = allow_eds3 && device.IsExtExtendedDynamicState3BlendingSupported(), + .has_extended_dynamic_state_3_enables = allow_eds3 && device.IsExtExtendedDynamicState3EnablesSupported(), + .has_dynamic_vertex_input = allow_eds3 && device.IsExtVertexInputDynamicStateSupported(), }; }