From d8963106929f35a98d754fe113be1563f8ff9d2c Mon Sep 17 00:00:00 2001 From: xbzk Date: Wed, 30 Sep 2026 23:44:31 -0300 Subject: [PATCH] [settings] add PR4490 & PR4492 toggles --- .../features/settings/model/BooleanSetting.kt | 2 + .../settings/model/view/SettingsItem.kt | 14 +++++++ .../settings/ui/SettingsFragmentPresenter.kt | 2 + .../app/src/main/res/values/strings.xml | 4 ++ src/common/settings.h | 4 ++ src/core/hle/service/ro/ro.cpp | 38 ++++++++++--------- src/qt_common/config/shared_translation.cpp | 8 ++++ src/video_core/gpu.cpp | 20 +++++----- 8 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 97be7f1bd9..239d56837c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -16,6 +16,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_USE_SPEED_LIMIT("use_speed_limit"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), + NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"), + NCE_RUNTIME_NRO_PATCH("nce_runtime_nro_patch"), FIX_BLOOM_EFFECTS("fix_bloom_effects"), EMULATE_BGR565("emulate_bgr565"), RESCALE_HACK("rescale_hack"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 366d3a8b3b..ef52b23053 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -866,6 +866,20 @@ abstract class SettingsItem( descriptionId = R.string.skip_cpu_inner_invalidation_description ) ) + put( + SwitchSetting( + BooleanSetting.NCE_INVALIDATION_GPU_READBACK, + titleId = R.string.nce_invalidation_gpu_readback, + descriptionId = R.string.nce_invalidation_gpu_readback_description + ) + ) + put( + SwitchSetting( + BooleanSetting.NCE_RUNTIME_NRO_PATCH, + titleId = R.string.nce_runtime_nro_patch, + descriptionId = R.string.nce_runtime_nro_patch_description + ) + ) put( SwitchSetting( BooleanSetting.FIX_BLOOM_EFFECTS, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index e9f818d9bc..dccc8b859a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -554,6 +554,8 @@ class SettingsFragmentPresenter( add(HeaderSetting(R.string.hacks)) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) + add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key) + add(BooleanSetting.NCE_RUNTIME_NRO_PATCH.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5a587be351..e48319f483 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -595,6 +595,10 @@ Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks. Skip CPU Inner Invalidation Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games. + GPU Readback Before NCE Invalidation + Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress. + Patch Runtime NROs for NCE + Temporary. Fix Biomutant boot. May impact performance. Improvement in progress. Fix Bloom Effects Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games. Emulate BGR565 diff --git a/src/common/settings.h b/src/common/settings.h index 5d66f49ebd..d4c445c27c 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -639,6 +639,10 @@ struct Values { Specialization::Default, true, true}; + SwitchableSetting nce_invalidation_gpu_readback{ + linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks}; + SwitchableSetting nce_runtime_nro_patch{ + linkage, false, "nce_runtime_nro_patch", Category::RendererHacks}; SwitchableSetting async_presentation{linkage, #ifdef __ANDROID__ false, diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index b847811fe5..167bf04c9a 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -426,28 +426,30 @@ public: std::addressof(ro_size), std::addressof(rw_size), nro_info->base_address, nro_size, bss_size)); #ifdef HAS_NCE - if (Settings::IsNceEnabled()) { - auto* process = context->GetProcess(); - auto& memory = process->GetMemory(); + if (Settings::values.nce_runtime_nro_patch.GetValue()) { + if (Settings::IsNceEnabled()) { + auto* process = context->GetProcess(); + auto& memory = process->GetMemory(); - std::vector image(total_size); - memory.ReadBlock(nro_info->base_address, image.data(), rx_size); + std::vector image(total_size); + memory.ReadBlock(nro_info->base_address, image.data(), rx_size); - Kernel::CodeSet::Segment code{.size = static_cast(rx_size)}; - Core::NCE::Patcher patch; - patch.PatchText(image, code); - patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr); + Kernel::CodeSet::Segment code{.size = static_cast(rx_size)}; + Core::NCE::Patcher patch; + patch.PatchText(image, code); + patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr); - const u64 patch_address = nro_info->base_address + total_size; - const size_t patch_size = patch.GetSectionSize(); - constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute; + const u64 patch_address = nro_info->base_address + total_size; + const size_t patch_size = patch.GetSectionSize(); + constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute; - auto* patch_memory = Kernel::KSharedMemory::Create(kernel); - R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size)); - std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size); - R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size)); - R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission)); - memory.WriteBlock(nro_info->base_address, image.data(), rx_size); + auto* patch_memory = Kernel::KSharedMemory::Create(kernel); + R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size)); + std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size); + R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size)); + R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission)); + memory.WriteBlock(nro_info->base_address, image.data(), rx_size); + } } #endif // Set NRO perms. diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index 29fbd32de5..0fe2366dfc 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -194,6 +194,14 @@ std::unique_ptr InitializeTranslations(QObject* parent) { INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"), tr("Skips certain cache invalidations during memory updates, reducing CPU usage and " "improving latency. This may cause soft-crashes.")); + INSERT(Settings, nce_invalidation_gpu_readback, + tr("GPU Readback Before NCE Invalidation"), + tr("Flushes GPU buffer data back to guest memory before NCE invalidates the whole " + "guest page, preserving it while the CPU store proceeds.")); + INSERT(Settings, nce_runtime_nro_patch, + tr("Patch Runtime NROs for NCE"), + tr("Applies NCE code patches to runtime-loaded NRO modules." + "This is required for some games to run correctly.")); INSERT(Settings, vsync_mode, tr("VSync Mode:"), tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " "refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n" diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 6aa7f9abd8..4e36d086e6 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -227,15 +227,17 @@ struct GPU::Impl { /// Notify rasterizer that any caches of the specified region should be invalidated void InvalidateRegion(DAddr addr, u64 size, bool preserve_gpu_writes) { - VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer(); - if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) { - const u64 fence = RequestSyncOperation([rasterizer, addr, size] { - rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache); - rasterizer->OnCacheInvalidation(addr, size); - }); - gpu_thread.TickGPU(is_async); - WaitForSyncOperation(fence); - return; + if (Settings::values.nce_invalidation_gpu_readback.GetValue()) { + VideoCore::RasterizerInterface* rasterizer = renderer->ReadRasterizer(); + if (preserve_gpu_writes && rasterizer->MustFlushRegion(addr, size, VideoCommon::CacheType::BufferCache)) { + const u64 fence = RequestSyncOperation([rasterizer, addr, size] { + rasterizer->FlushRegion(addr, size, VideoCommon::CacheType::BufferCache); + rasterizer->OnCacheInvalidation(addr, size); + }); + gpu_thread.TickGPU(is_async); + WaitForSyncOperation(fence); + return; + } } gpu_thread.InvalidateRegion(addr, size); }