From 77da1a32e08102108c35f9b241f9432895d2c780 Mon Sep 17 00:00:00 2001 From: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com> Date: Thu, 14 Aug 2025 20:44:07 +0200 Subject: [PATCH 1/2] [GPU]: Implement a working Frame-Skip into Android --- .../features/settings/model/BooleanSetting.kt | 1 - .../features/settings/model/IntSetting.kt | 1 + .../settings/model/view/SettingsItem.kt | 18 +++---- .../settings/ui/SettingsFragmentPresenter.kt | 1 + .../app/src/main/res/values/arrays.xml | 12 +++++ src/common/settings.h | 2 +- src/video_core/gpu.cpp | 54 +++++++++++++------ src/video_core/gpu.h | 3 ++ 8 files changed, 66 insertions(+), 26 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 119517d99b..f6c222479c 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 @@ -51,7 +51,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { ENABLE_RAII("enable_raii"), FRAME_INTERPOLATION("frame_interpolation"), -// FRAME_SKIPPING("frame_skipping"), PERF_OVERLAY_BACKGROUND("perf_overlay_background"), SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index d53aa46265..9cb1adb581 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -42,6 +42,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { RENDERER_SAMPLE_SHADING_FRACTION("sample_shading_fraction"), FAST_CPU_TIME("fast_cpu_time"), CPU_TICKS("cpu_ticks"), + FRAME_SKIPPING("frame_skipping"), FAST_GPU_TIME("fast_gpu_time"), BAT_TEMPERATURE_UNIT("bat_temperature_unit"), CABINET_APPLET("cabinet_applet_mode"), 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 73834c1184..c2fa66e6ce 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 @@ -242,15 +242,15 @@ abstract class SettingsItem( descriptionId = R.string.frame_interpolation_description ) ) - -// put( -// SwitchSetting( -// BooleanSetting.FRAME_SKIPPING, -// titleId = R.string.frame_skipping, -// descriptionId = R.string.frame_skipping_description -// ) -// ) - + put( + SingleChoiceSetting( + IntSetting.FRAME_SKIPPING, + titleId = R.string.frame_skipping, + descriptionId = R.string.frame_skipping_description, + choicesId = R.array.frameSkippingNames, + valuesId = R.array.frameSkippingValues + ) + ) put( SwitchSetting( dockedModeSetting, 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 28411309e6..ee8140d199 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 @@ -450,6 +450,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.RENDERER_EARLY_RELEASE_FENCES.key) add(BooleanSetting.BUFFER_REORDER_DISABLE.key) add(BooleanSetting.FRAME_INTERPOLATION.key) + add(IntSetting.FRAME_SKIPPING.key) add(BooleanSetting.RENDERER_FAST_GPU.key) add(IntSetting.FAST_GPU_TIME.key) add(IntSetting.RENDERER_SHADER_BACKEND.key) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 602003cf8a..a5ab9bc3d9 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -21,6 +21,18 @@ 1 + + @string/disabled + 1 + 2 + + + + 0 + 1 + 2 + + @string/memory_4gb @string/memory_6gb diff --git a/src/common/settings.h b/src/common/settings.h index faf7210f5d..61f79163b9 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -325,9 +325,9 @@ struct Values { #ifdef __ANDROID__ SwitchableSetting frame_interpolation{linkage, true, "frame_interpolation", Category::Renderer, Specialization::RuntimeList}; +#endif SwitchableSetting frame_skipping{linkage, false, "frame_skipping", Category::Renderer, Specialization::RuntimeList}; -#endif SwitchableSetting use_disk_shader_cache{linkage, true, "use_disk_shader_cache", Category::Renderer}; SwitchableSetting optimize_spirv_output{linkage, diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index d97620ce91..327536661c 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -223,17 +223,23 @@ struct GPU::Impl { system.GetPerfStats().EndGameFrame(); } + void ResetFrameCounter() { + frame_count.store(0, std::memory_order_relaxed); + } + /// Performs any additional setup necessary in order to begin GPU emulation. /// This can be used to launch any necessary threads and register any necessary /// core timing events. void Start() { Settings::UpdateGPUAccuracy(); + ResetFrameCounter(); gpu_thread.StartThread(*renderer, renderer->Context(), *scheduler); } void NotifyShutdown() { std::unique_lock lk{sync_mutex}; shutting_down.store(true, std::memory_order::relaxed); + ResetFrameCounter(); sync_cv.notify_all(); } @@ -291,10 +297,16 @@ struct GPU::Impl { void RequestComposite(std::vector&& layers, std::vector&& fences) { + // Increment frame counter + const u64 current_frame = frame_count.fetch_add(1, std::memory_order_relaxed) + 1; + const u32 frame_skip_value = Settings::values.frame_skipping.GetValue(); + const bool skip_frame = frame_skip_value > 0 && + (current_frame % (static_cast(frame_skip_value) + 1) != 0); + size_t num_fences{fences.size()}; size_t current_request_counter{}; { - std::unique_lock lk(request_swap_mutex); + std::unique_lock lk{request_swap_mutex}; if (free_swap_counters.empty()) { current_request_counter = request_swap_counters.size(); request_swap_counters.emplace_back(num_fences); @@ -305,23 +317,33 @@ struct GPU::Impl { } } const auto wait_fence = - RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences] { + RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences, skip_frame] { auto& syncpoint_manager = host1x.GetSyncpointManager(); if (num_fences == 0) { - renderer->Composite(layers); - } - const auto executer = [this, current_request_counter, layers_copy = layers]() { - { - std::unique_lock lk(request_swap_mutex); - if (--request_swap_counters[current_request_counter] != 0) { - return; - } - free_swap_counters.push_back(current_request_counter); + if (!skip_frame) { + renderer->Composite(layers); + } else { + system.GetPerfStats().EndGameFrame(); + } + } else { + const auto executer = [this, current_request_counter, layers_copy = std::move(layers), skip_frame]() { + { + std::unique_lock lk{request_swap_mutex}; + if (--request_swap_counters[current_request_counter] != 0) { + return; + } + free_swap_counters.push_back(current_request_counter); + } + // Handle frame skipping in executer + if (!skip_frame) { + renderer->Composite(layers_copy); + } else { + system.GetPerfStats().EndGameFrame(); + } + }; + for (size_t i = 0; i < num_fences; i++) { + syncpoint_manager.RegisterGuestAction(fences[i].id, fences[i].value, executer); } - renderer->Composite(layers_copy); - }; - for (size_t i = 0; i < num_fences; i++) { - syncpoint_manager.RegisterGuestAction(fences[i].id, fences[i].value, executer); } }); gpu_thread.TickGPU(); @@ -353,6 +375,8 @@ struct GPU::Impl { /// When true, we are about to shut down emulation session, so terminate outstanding tasks std::atomic_bool shutting_down{}; + std::atomic frame_count{0}; + std::array, Service::Nvidia::MaxSyncPoints> syncpoints{}; std::array, Service::Nvidia::MaxSyncPoints> syncpt_interrupts; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 538c4da85a..b8acd98a60 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -220,6 +220,9 @@ public: std::vector GetAppletCaptureBuffer(); + // Reset frame counter + void ResetFrameCounter(); + /// Performs any additional setup necessary in order to begin GPU emulation. /// This can be used to launch any necessary threads and register any necessary /// core timing events. -- 2.39.5 From d342204e5d9ad15b45d68265872879a9c1fceefd Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 14 Aug 2025 20:17:53 -0400 Subject: [PATCH 2/2] [frontend] fix frame skip setting prsentation Signed-off-by: crueter --- .../features/settings/model/BooleanSetting.kt | 1 + .../features/settings/model/IntSetting.kt | 1 - .../settings/model/view/SettingsItem.kt | 6 ++---- .../settings/ui/SettingsFragmentPresenter.kt | 2 +- src/android/app/src/main/res/values/arrays.xml | 12 ------------ .../app/src/main/res/values/strings.xml | 4 ++-- src/common/settings.h | 3 +-- src/yuzu/configuration/shared_translation.cpp | 18 ++++++++++++------ 8 files changed, 19 insertions(+), 28 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 f6c222479c..3af07c6c02 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 @@ -32,6 +32,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_DESCRIPTOR_INDEXING("descriptor_indexing"), RENDERER_SAMPLE_SHADING("sample_shading"), PICTURE_IN_PICTURE("picture_in_picture"), + FRAME_SKIPPING("frame_skipping"), USE_CUSTOM_RTC("custom_rtc_enabled"), BLACK_BACKGROUNDS("black_backgrounds"), JOYSTICK_REL_CENTER("joystick_rel_center"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index 9cb1adb581..d53aa46265 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -42,7 +42,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { RENDERER_SAMPLE_SHADING_FRACTION("sample_shading_fraction"), FAST_CPU_TIME("fast_cpu_time"), CPU_TICKS("cpu_ticks"), - FRAME_SKIPPING("frame_skipping"), FAST_GPU_TIME("fast_gpu_time"), BAT_TEMPERATURE_UNIT("bat_temperature_unit"), CABINET_APPLET("cabinet_applet_mode"), 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 c2fa66e6ce..a940d2fca2 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 @@ -243,12 +243,10 @@ abstract class SettingsItem( ) ) put( - SingleChoiceSetting( - IntSetting.FRAME_SKIPPING, + SwitchSetting( + BooleanSetting.FRAME_SKIPPING, titleId = R.string.frame_skipping, descriptionId = R.string.frame_skipping_description, - choicesId = R.array.frameSkippingNames, - valuesId = R.array.frameSkippingValues ) ) put( 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 ee8140d199..a5daa9027f 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 @@ -450,7 +450,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.RENDERER_EARLY_RELEASE_FENCES.key) add(BooleanSetting.BUFFER_REORDER_DISABLE.key) add(BooleanSetting.FRAME_INTERPOLATION.key) - add(IntSetting.FRAME_SKIPPING.key) + add(BooleanSetting.FRAME_SKIPPING.key) add(BooleanSetting.RENDERER_FAST_GPU.key) add(IntSetting.FAST_GPU_TIME.key) add(IntSetting.RENDERER_SHADER_BACKEND.key) diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index a5ab9bc3d9..602003cf8a 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -21,18 +21,6 @@ 1 - - @string/disabled - 1 - 2 - - - - 0 - 1 - 2 - - @string/memory_4gb @string/memory_6gb diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index d649ba08ac..fa54f9cfa7 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -482,8 +482,8 @@ Display Post-Processing - WIP: Frameskip - Toggle frame skipping to improve performance by reducing the number of rendered frames. This feature is still being worked on and will be enabled in future releases. + Frame Skipping + Toggle frame skipping to improve performance by reducing the number of rendered frames. Accuracy level Resolution (Handheld/Docked) VSync mode diff --git a/src/common/settings.h b/src/common/settings.h index 61f79163b9..5a089507f6 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -326,8 +326,7 @@ struct Values { SwitchableSetting frame_interpolation{linkage, true, "frame_interpolation", Category::Renderer, Specialization::RuntimeList}; #endif - SwitchableSetting frame_skipping{linkage, false, "frame_skipping", Category::Renderer, - Specialization::RuntimeList}; + SwitchableSetting frame_skipping{linkage, false, "frame_skipping", Category::Renderer}; SwitchableSetting use_disk_shader_cache{linkage, true, "use_disk_shader_cache", Category::Renderer}; SwitchableSetting optimize_spirv_output{linkage, diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 22f1921dbf..dbc6b35ddd 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -269,6 +269,18 @@ std::unique_ptr InitializeTranslations(QWidget* parent) INSERT(Settings, bg_blue, QString(), QString()); // Renderer (Advanced Graphics) + INSERT(Settings, + enable_raii, + tr("RAII"), + tr("A method of automatic resource management in Vulkan " + "that ensures proper release of resources " + "when they are no longer needed, but may cause crashes in bundled games.")); + INSERT(Settings, + frame_skipping, + tr("Frame Skipping"), + tr("Skips rendering every other frame while still presenting " + "the frame as rendered.\nThis cuts the effective FPS in half, but can make " + "games run stable at the game's target FPS on weaker hardware.")); INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"), @@ -335,12 +347,6 @@ std::unique_ptr InitializeTranslations(QWidget* parent) tr("Improves rendering of transparency effects in specific games.")); // Renderer (Extensions) - INSERT(Settings, - enable_raii, - tr("RAII"), - tr("A method of automatic resource management in Vulkan " - "that ensures proper release of resources " - "when they are no longer needed, but may cause crashes in bundled games.")); INSERT(Settings, dyna_state, tr("Extended Dynamic State"), -- 2.39.5