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 a412a80a2e..6b50180963 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
@@ -89,11 +89,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
GPU_LOG_MEMORY_TRACKING("gpu_log_memory_tracking"),
GPU_LOG_DRIVER_DEBUG("gpu_log_driver_debug"),
+ ENABLE_FRAME_INTERPOLATION("enable_frame_interpolation"),
+ ENABLE_FRAME_SKIPPING("enable_frame_skipping"),
ENABLE_QUICK_SETTINGS("enable_quick_settings");
-// external fun isFrameSkippingEnabled(): Boolean
- external fun isFrameInterpolationEnabled(): Boolean
-
override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal)
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 f95c53720f..f8ce7d3eea 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
@@ -238,6 +238,22 @@ abstract class SettingsItem(
override fun reset() = BooleanSetting.USE_DOCKED_MODE.reset()
}
+ put(
+ SwitchSetting(
+ BooleanSetting.ENABLE_FRAME_INTERPOLATION,
+ titleId = R.string.enable_frame_interpolation,
+ descriptionId = R.string.enable_frame_interpolation_description
+ )
+ )
+
+ put(
+ SwitchSetting(
+ BooleanSetting.ENABLE_FRAME_SKIPPING,
+ titleId = R.string.enable_frame_skipping,
+ descriptionId = R.string.enable_frame_skipping_description
+ )
+ )
+
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 161579927c..a0ed7a1056 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
@@ -271,6 +271,8 @@ class SettingsFragmentPresenter(
sl.apply {
// add(IntSetting.RENDERER_NVDEC_EMULATION.key)
+ add(BooleanSetting.ENABLE_FRAME_INTERPOLATION.key)
+ add(BooleanSetting.ENABLE_FRAME_SKIPPING.key)
add(IntSetting.RENDERER_RESOLUTION.key)
add(IntSetting.RENDERER_VSYNC.key)
add(IntSetting.RENDERER_SCALING_FILTER.key)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 0069e169b3..61b43a85a8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -1509,6 +1509,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (BooleanSetting.SHOW_FPS.getBoolean(needsGlobal)) {
var fpsText = String.format("FPS: %.1f", actualFps)
+ if (BooleanSetting.ENABLE_FRAME_INTERPOLATION.getBoolean(needsGlobal)) {
+ fpsText += String.format(" (Generated: %.1f)", actualFps * 2)
+ }
sb.append(fpsText)
}
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 77be250537..fd8d00706e 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -465,6 +465,10 @@
Network
+ Enable Frame Skipping
+ Toggle frame skipping to improve performance by reducing the number of rendered frames.
+ Enable Frame Interpolation
+ Toggle frame interpolation to improve visual smoothness by generating intermediate frames.
Resolution (Handheld/Docked)
VSync mode
Window adapting filter
diff --git a/src/common/settings.h b/src/common/settings.h
index 3e14a40a09..6f93ead1bc 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -337,6 +337,10 @@ struct Values {
#endif
"backend", Category::Renderer};
SwitchableSetting vulkan_device{linkage, 0, "vulkan_device", Category::Renderer, Specialization::RuntimeList};
+ SwitchableSetting enable_frame_interpolation{linkage, true, "enable_frame_interpolation",
+ Category::Renderer};
+ SwitchableSetting enable_frame_skipping{linkage, true, "enable_frame_skipping",
+ Category::Renderer};
// Graphics Settings
ResolutionScalingInfo resolution_info{};
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 010cfd225d..0161c53a44 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -38,9 +38,6 @@
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
-#ifdef __ANDROID__
-#include
-#endif
namespace Vulkan {
namespace {
@@ -175,6 +172,16 @@ RendererVulkan::~RendererVulkan() {
}
void RendererVulkan::Composite(std::span framebuffers) {
+#ifdef __ANDROID__
+ static u64 frame_counter = 0;
+ if (Settings::values.enable_frame_skipping.GetValue()) {
+ ++frame_counter;
+ if ((frame_counter % 2) != 0) {
+ return;
+ }
+ }
+#endif
+
SCOPE_EXIT {
render_window.OnFrameDisplayed();
};