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 cabea73353..73a977bb1f 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 @@ -647,15 +647,6 @@ abstract class SettingsItem( valuesId = R.array.dmaAccuracyValues ) ) - put( - SingleChoiceSetting( - IntSetting.FRAME_PACING_MODE, - titleId = R.string.frame_pacing_mode, - descriptionId = R.string.frame_pacing_mode_description, - choicesId = R.array.framePacingModeNames, - valuesId = R.array.framePacingModeValues - ) - ) put( SwitchSetting( BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, 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 c43de4d5c7..6d769b2e15 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 @@ -267,7 +267,6 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_ACCURACY.key) add(IntSetting.DMA_ACCURACY.key) - add(IntSetting.FRAME_PACING_MODE.key) add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.RENDERER_VRAM_USAGE_MODE.key) add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 4e90cad570..36615f9d96 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -6,8 +6,14 @@ #include +#include +#include +#include +#include + #include "common/android/id_cache.h" #include "common/logging/log.h" +#include "common/settings.h" #include "input_common/drivers/android.h" #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/virtual_amiibo.h" @@ -22,6 +28,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { m_window_width = 0; m_window_height = 0; window_info.render_surface = nullptr; + m_last_frame_rate_hint = -1.0f; return; } @@ -32,6 +39,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { UpdateCurrentFramebufferLayout(m_window_width, m_window_height); window_info.render_surface = reinterpret_cast(surface); + UpdateFrameRateHint(); } void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { @@ -51,6 +59,8 @@ void EmuWindow_Android::OnTouchReleased(int id) { } void EmuWindow_Android::OnFrameDisplayed() { + UpdateFrameRateHint(); + if (!m_first_frame) { Common::Android::RunJNIOnFiber( [&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); }); @@ -58,6 +68,63 @@ void EmuWindow_Android::OnFrameDisplayed() { } } +float EmuWindow_Android::GetFrameRateHint() const { + if (!Settings::values.use_speed_limit.GetValue()) { + return 0.0f; + } + + const u16 speed_limit = Settings::SpeedLimit(); + if (speed_limit == 0) { + return 0.0f; + } + + if (speed_limit > 100) { + return 0.0f; + } + + constexpr float NominalFrameRate = 60.0f; + const float desired_rate = NominalFrameRate * (static_cast(speed_limit) / 100.0f); + + if (desired_rate < 20.0f) { + return 0.0f; + } + + return desired_rate; +} + +void EmuWindow_Android::UpdateFrameRateHint() { + auto* const surface = reinterpret_cast(window_info.render_surface); + if (!surface) { + return; + } + + const float frame_rate_hint = GetFrameRateHint(); + if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) { + return; + } + + using SetFrameRateWithChangeStrategyFn = + int32_t (*)(ANativeWindow*, float, int8_t, int8_t); + static const auto set_frame_rate_with_change_strategy = + reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRateWithChangeStrategy")); + + if (!set_frame_rate_with_change_strategy) { + return; + } + + const auto result = set_frame_rate_with_change_strategy( + surface, frame_rate_hint, + static_cast(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + static_cast(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS)); + if (result != 0) { + LOG_DEBUG(Frontend, "Failed to update Android surface frame rate hint: {}", result); + return; + } + + m_last_frame_rate_hint = frame_rate_hint; +} + EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, std::shared_ptr driver_library) : m_driver_library{driver_library} { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index d7b5fc6dac..b2210e0b20 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -50,10 +50,14 @@ public: }; private: + void UpdateFrameRateHint(); + [[nodiscard]] float GetFrameRateHint() const; + float m_window_width{}; float m_window_height{}; std::shared_ptr m_driver_library; bool m_first_frame = false; + float m_last_frame_rate_hint = -1.0f; }; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index cd8f948d8b..46b98f6cc1 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -170,6 +170,9 @@ bool Swapchain::AcquireNextImage() { break; } +#ifdef __ANDROID__ + scheduler.Wait(resource_ticks[image_index]); +#else switch (Settings::values.frame_pacing_mode.GetValue()) { case Settings::FramePacingMode::Target_Auto: scheduler.Wait(resource_ticks[image_index]); @@ -187,6 +190,7 @@ bool Swapchain::AcquireNextImage() { scheduler.Wait(resource_ticks[image_index], 120.0); break; } +#endif resource_ticks[image_index] = scheduler.CurrentTick();