aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt50
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt12
-rw-r--r--src/android/app/src/main/res/values/strings.xml4
-rw-r--r--src/common/settings.h6
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp75
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h4
8 files changed, 155 insertions, 6 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 6644784729..34f417434f 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
@@ -26,7 +26,13 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
SHOW_INPUT_OVERLAY("show_input_overlay"),
TOUCHSCREEN("touchscreen"),
- SHOW_THERMAL_OVERLAY("show_thermal_overlay");
+ SHOW_THERMAL_OVERLAY("show_thermal_overlay"),
+ ENABLE_FRAME_INTERPOLATION("enable_frame_interpolation"),
+ ENABLE_FRAME_SKIPPING("enable_frame_skipping"),
+ CORE_USE_MULTI_CORE("use_multi_core");
+
+ 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 5fdf983185..2780b550e7 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
@@ -172,6 +172,56 @@ abstract class SettingsItem(
override fun reset() = BooleanSetting.USE_DOCKED_MODE.reset()
}
+ val enableInterpolationSetting = object : AbstractBooleanSetting {
+ override val key = BooleanSetting.ENABLE_FRAME_INTERPOLATION.key
+
+ override fun getBoolean(needsGlobal: Boolean): Boolean =
+ BooleanSetting.ENABLE_FRAME_INTERPOLATION.getBoolean(needsGlobal)
+
+ override fun setBoolean(value: Boolean) =
+ BooleanSetting.ENABLE_FRAME_INTERPOLATION.setBoolean(value)
+
+ override val defaultValue = BooleanSetting.ENABLE_FRAME_INTERPOLATION.defaultValue
+
+ override fun getValueAsString(needsGlobal: Boolean): String =
+ BooleanSetting.ENABLE_FRAME_INTERPOLATION.getValueAsString(needsGlobal)
+
+ override fun reset() = BooleanSetting.ENABLE_FRAME_INTERPOLATION.reset()
+ }
+
+ val enableFrameSkippingSetting = object : AbstractBooleanSetting {
+ override val key = BooleanSetting.ENABLE_FRAME_SKIPPING.key
+
+ override fun getBoolean(needsGlobal: Boolean): Boolean =
+ BooleanSetting.ENABLE_FRAME_SKIPPING.getBoolean(needsGlobal)
+
+ override fun setBoolean(value: Boolean) =
+ BooleanSetting.ENABLE_FRAME_SKIPPING.setBoolean(value)
+
+ override val defaultValue = BooleanSetting.ENABLE_FRAME_SKIPPING.defaultValue
+
+ override fun getValueAsString(needsGlobal: Boolean): String =
+ BooleanSetting.ENABLE_FRAME_SKIPPING.getValueAsString(needsGlobal)
+
+ override fun reset() = BooleanSetting.ENABLE_FRAME_SKIPPING.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 7fa22b272f..1af631ce1a 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
@@ -169,6 +169,8 @@ class SettingsFragmentPresenter(
private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
+ add(BooleanSetting.ENABLE_FRAME_INTERPOLATION.key)
+ add(BooleanSetting.ENABLE_FRAME_SKIPPING.key)
add(IntSetting.RENDERER_ACCURACY.key)
add(IntSetting.RENDERER_RESOLUTION.key)
add(IntSetting.RENDERER_VSYNC.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 2c99f6a2ac..e316d96a2a 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
@@ -534,10 +534,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// Calculate used memory
val usedMegs = (mi.totalMem - mi.availMem) / 1048576L // Convert bytes to megabytes
+ val actualFps = perfStats[FPS]
+ val enableFrameInterpolation = BooleanSetting.ENABLE_FRAME_INTERPOLATION.getBoolean()
+ val generatedFpsText = if (enableFrameInterpolation) {
+ val generatedFps = actualFps * 2
+ String.format("(Generated: %.1f)", generatedFps)
+ } else {
+ ""
+ }
if (_binding != null) {
binding.showFpsText.text = String.format(
- "%.1f FPS • %d MB • %s/%s",
- perfStats[FPS], usedMegs, cpuBackend, gpuDriver
+ "%.1f %s FPS • %d MB • %s/%s",
+ actualFps, generatedFpsText, usedMegs, cpuBackend, gpuDriver
)
}
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index bb0b5c58dc..51495df2fc 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -230,6 +230,10 @@
<string name="set_custom_rtc">Set custom RTC</string>
<!-- Graphics settings strings -->
+ <string name="enable_frame_skipping">Enable Frame Skipping</string>
+ <string name="enable_frame_skipping_description">Toggle frame skipping to improve performance by reducing the number of rendered frames.</string>
+ <string name="enable_frame_interpolation">Enable Frame Interpolation</string>
+ <string name="enable_frame_interpolation_description">Toggle frame interpolation to improve visual smoothness by generating intermediate frames.</string>
<string name="renderer_accuracy">Accuracy level</string>
<string name="renderer_resolution">Resolution (Handheld/Docked)</string>
<string name="renderer_vsync">VSync mode</string>
diff --git a/src/common/settings.h b/src/common/settings.h
index cf3579892c..e0788abda6 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -250,7 +250,6 @@ struct Values {
Category::CpuDebug};
Setting<bool> cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts",
Category::CpuDebug};
-
SwitchableSetting<bool> cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma",
Category::CpuUnsafe};
SwitchableSetting<bool> cpuopt_unsafe_reduce_fp_error{
@@ -273,7 +272,10 @@ struct Values {
"shader_backend", Category::Renderer, Specialization::RuntimeList};
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
Specialization::RuntimeList};
-
+ SwitchableSetting<bool> enable_frame_interpolation{linkage, true, "enable_frame_interpolation", Category::Renderer,
+ Specialization::RuntimeList};
+ SwitchableSetting<bool> enable_frame_skipping{linkage, true, "enable_frame_skipping", Category::Renderer,
+ Specialization::RuntimeList};
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
Category::Renderer};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 4a2d4b23ef..3ca69de530 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -35,7 +35,9 @@
#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 <jni.h>
+#endif
namespace Vulkan {
namespace {
@@ -136,11 +138,82 @@ RendererVulkan::~RendererVulkan() {
void(device.GetLogical().WaitIdle());
}
+#ifdef __ANDROID__
+class BooleanSetting {
+ public:
+ static BooleanSetting ENABLE_FRAME_SKIPPING;
+ static BooleanSetting ENABLE_FRAME_INTERPOLATION;
+ explicit BooleanSetting(bool initial_value = false) : value(initial_value) {}
+
+ [[nodiscard]] bool getBoolean() const {
+ return value;
+ }
+
+ void setBoolean(bool new_value) {
+ value = new_value;
+ }
+
+ private:
+ bool value;
+ };
+
+ // Initialize static members
+ BooleanSetting BooleanSetting::ENABLE_FRAME_SKIPPING(false);
+ BooleanSetting BooleanSetting::ENABLE_FRAME_INTERPOLATION(false);
+
+ extern "C" JNIEXPORT jboolean JNICALL
+ Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameSkippingEnabled(JNIEnv* env, jobject /* this */) {
+ return static_cast<jboolean>(BooleanSetting::ENABLE_FRAME_SKIPPING.getBoolean());
+ }
+
+ extern "C" JNIEXPORT jboolean JNICALL
+ Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameInterpolationEnabled(JNIEnv* env, jobject /* this */) {
+ return static_cast<jboolean>(BooleanSetting::ENABLE_FRAME_INTERPOLATION.getBoolean());
+ }
+
+ void RendererVulkan::InterpolateFrames(Frame* prev_frame, Frame* interpolated_frame) {
+ if (prev_frame && interpolated_frame) {
+ *interpolated_frame = std::move(*prev_frame); // Use move assignment to avoid copy issues
+
+ // TODO: Implement actual interpolation logic here
+ }
+ }
+ #endif
+
void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) {
+ #ifdef __ANDROID__
+ static int frame_counter = 0;
+ static int target_fps = 60; // Target FPS (30 or 60)
+ int frame_skip_threshold = 1;
+
+ bool enable_frame_skipping = BooleanSetting::ENABLE_FRAME_SKIPPING.getBoolean();
+ bool enable_frame_interpolation = BooleanSetting::ENABLE_FRAME_INTERPOLATION.getBoolean();
+ #endif
+
if (framebuffers.empty()) {
return;
}
+ #ifdef __ANDROID__
+ if (enable_frame_skipping) {
+ frame_skip_threshold = (target_fps == 30) ? 2 : 2;
+ }
+
+ frame_counter++;
+ if (frame_counter % frame_skip_threshold != 0) {
+ if (enable_frame_interpolation && previous_frame) {
+ Frame* interpolated_frame = present_manager.GetRenderFrame();
+ InterpolateFrames(previous_frame, interpolated_frame);
+ blit_swapchain.DrawToFrame(rasterizer, interpolated_frame, framebuffers,
+ render_window.GetFramebufferLayout(), swapchain.GetImageCount(),
+ swapchain.GetImageViewFormat());
+ scheduler.Flush(*interpolated_frame->render_ready);
+ present_manager.Present(interpolated_frame);
+ }
+ return;
+ }
+ #endif
+
SCOPE_EXIT {
render_window.OnFrameDisplayed();
};
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 0603627a07..fe1f6ce53d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -54,6 +54,10 @@ public:
}
private:
+ void InterpolateFrames(Frame* prev_frame, Frame* curr_frame);
+ Frame* previous_frame = nullptr; // Store the previous frame for interpolation
+ VkCommandBuffer BeginSingleTimeCommands();
+ void EndSingleTimeCommands(VkCommandBuffer command_buffer);
void Report() const;
vk::Buffer RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,