Browse Source

[android] Quantization for frames + hints Surface

vkexperiments1
CamilleLaVey 1 week ago
parent
commit
ebb3cda782
  1. 105
      src/android/app/src/main/jni/emu_window/emu_window.cpp
  2. 13
      src/android/app/src/main/jni/emu_window/emu_window.h

105
src/android/app/src/main/jni/emu_window/emu_window.cpp

@ -7,6 +7,7 @@
#include <android/native_window_jni.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdint>
#include <dlfcn.h>
@ -29,6 +30,10 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
m_window_height = 0;
window_info.render_surface = nullptr;
m_last_frame_rate_hint = -1.0f;
m_pending_frame_rate_hint = -1.0f;
m_pending_frame_rate_hint_votes = 0;
m_smoothed_present_rate = 0.0f;
m_last_frame_display_time = {};
return;
}
@ -59,6 +64,7 @@ void EmuWindow_Android::OnTouchReleased(int id) {
}
void EmuWindow_Android::OnFrameDisplayed() {
UpdateObservedFrameRate();
UpdateFrameRateHint();
if (!m_first_frame) {
@ -68,6 +74,44 @@ void EmuWindow_Android::OnFrameDisplayed() {
}
}
void EmuWindow_Android::UpdateObservedFrameRate() {
const auto now = Clock::now();
if (m_last_frame_display_time.time_since_epoch().count() != 0) {
const auto frame_time = std::chrono::duration<float>(now - m_last_frame_display_time);
const float seconds = frame_time.count();
if (seconds > 0.0f) {
const float instantaneous_rate = 1.0f / seconds;
if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 10.0f &&
instantaneous_rate <= 240.0f) {
constexpr float SmoothingFactor = 0.15f;
if (m_smoothed_present_rate <= 0.0f) {
m_smoothed_present_rate = instantaneous_rate;
} else {
m_smoothed_present_rate +=
(instantaneous_rate - m_smoothed_present_rate) * SmoothingFactor;
}
}
}
}
m_last_frame_display_time = now;
}
float EmuWindow_Android::QuantizeFrameRateHint(float frame_rate) {
if (!std::isfinite(frame_rate) || frame_rate < 20.0f) {
return 0.0f;
}
constexpr std::array CandidateRates{30.0f, 45.0f, 60.0f, 90.0f, 120.0f};
const auto best = std::min_element(CandidateRates.begin(), CandidateRates.end(),
[frame_rate](float lhs, float rhs) {
return std::fabs(frame_rate - lhs) <
std::fabs(frame_rate - rhs);
});
const float best_rate = *best;
const float tolerance = std::max(best_rate * 0.18f, 5.0f);
return std::fabs(frame_rate - best_rate) <= tolerance ? best_rate : 0.0f;
}
float EmuWindow_Android::GetFrameRateHint() const {
if (!Settings::values.use_speed_limit.GetValue()) {
return 0.0f;
@ -89,7 +133,45 @@ float EmuWindow_Android::GetFrameRateHint() const {
return 0.0f;
}
return desired_rate;
if (m_last_frame_rate_hint > 0.0f && m_smoothed_present_rate > 0.0f) {
const float observed_rate = m_smoothed_present_rate;
switch (static_cast<int>(m_last_frame_rate_hint)) {
case 30:
if (observed_rate < 42.0f) {
return 30.0f;
}
break;
case 45:
if (observed_rate >= 35.0f && observed_rate < 54.0f) {
return 45.0f;
}
break;
case 60:
if (observed_rate >= 48.0f && observed_rate < 75.0f) {
return 60.0f;
}
break;
case 90:
if (observed_rate >= 74.0f && observed_rate < 105.0f) {
return 90.0f;
}
break;
case 120:
if (observed_rate >= 100.0f) {
return 120.0f;
}
break;
default:
break;
}
}
const float observed_hint = QuantizeFrameRateHint(m_smoothed_present_rate);
if (observed_hint > 0.0f) {
return observed_hint;
}
return QuantizeFrameRateHint(desired_rate);
}
void EmuWindow_Android::UpdateFrameRateHint() {
@ -100,9 +182,28 @@ void EmuWindow_Android::UpdateFrameRateHint() {
const float frame_rate_hint = GetFrameRateHint();
if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) {
m_pending_frame_rate_hint = frame_rate_hint;
m_pending_frame_rate_hint_votes = 0;
return;
}
if (frame_rate_hint == 0.0f) {
m_pending_frame_rate_hint = frame_rate_hint;
m_pending_frame_rate_hint_votes = 0;
} else if (m_last_frame_rate_hint >= 0.0f) {
if (std::fabs(frame_rate_hint - m_pending_frame_rate_hint) >= 0.01f) {
m_pending_frame_rate_hint = frame_rate_hint;
m_pending_frame_rate_hint_votes = 1;
return;
}
++m_pending_frame_rate_hint_votes;
constexpr std::uint32_t StableVoteThreshold = 12;
if (m_pending_frame_rate_hint_votes < StableVoteThreshold) {
return;
}
}
using SetFrameRateWithChangeStrategyFn =
int32_t (*)(ANativeWindow*, float, int8_t, int8_t);
static const auto set_frame_rate_with_change_strategy =
@ -123,6 +224,8 @@ void EmuWindow_Android::UpdateFrameRateHint() {
}
m_last_frame_rate_hint = frame_rate_hint;
m_pending_frame_rate_hint = frame_rate_hint;
m_pending_frame_rate_hint_votes = 0;
}
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface,

13
src/android/app/src/main/jni/emu_window/emu_window.h

@ -1,8 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <chrono>
#include <cstdint>
#include <memory>
#include <span>
@ -50,8 +55,12 @@ public:
};
private:
using Clock = std::chrono::steady_clock;
void UpdateFrameRateHint();
void UpdateObservedFrameRate();
[[nodiscard]] float GetFrameRateHint() const;
[[nodiscard]] static float QuantizeFrameRateHint(float frame_rate);
float m_window_width{};
float m_window_height{};
@ -60,4 +69,8 @@ private:
bool m_first_frame = false;
float m_last_frame_rate_hint = -1.0f;
float m_pending_frame_rate_hint = -1.0f;
float m_smoothed_present_rate = 0.0f;
Clock::time_point m_last_frame_display_time{};
std::uint32_t m_pending_frame_rate_hint_votes = 0;
};
Loading…
Cancel
Save