mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-14 19:26:57 +02:00
[android] Quantization for frames + hints Surface
This commit is contained in:
parent
daf972b517
commit
ebb3cda782
2 changed files with 117 additions and 1 deletions
|
|
@ -7,6 +7,7 @@
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
@ -29,6 +30,10 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||||
m_window_height = 0;
|
m_window_height = 0;
|
||||||
window_info.render_surface = nullptr;
|
window_info.render_surface = nullptr;
|
||||||
m_last_frame_rate_hint = -1.0f;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +64,7 @@ void EmuWindow_Android::OnTouchReleased(int id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuWindow_Android::OnFrameDisplayed() {
|
void EmuWindow_Android::OnFrameDisplayed() {
|
||||||
|
UpdateObservedFrameRate();
|
||||||
UpdateFrameRateHint();
|
UpdateFrameRateHint();
|
||||||
|
|
||||||
if (!m_first_frame) {
|
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 {
|
float EmuWindow_Android::GetFrameRateHint() const {
|
||||||
if (!Settings::values.use_speed_limit.GetValue()) {
|
if (!Settings::values.use_speed_limit.GetValue()) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
@ -89,7 +133,45 @@ float EmuWindow_Android::GetFrameRateHint() const {
|
||||||
return 0.0f;
|
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() {
|
void EmuWindow_Android::UpdateFrameRateHint() {
|
||||||
|
|
@ -100,9 +182,28 @@ void EmuWindow_Android::UpdateFrameRateHint() {
|
||||||
|
|
||||||
const float frame_rate_hint = GetFrameRateHint();
|
const float frame_rate_hint = GetFrameRateHint();
|
||||||
if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) {
|
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;
|
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 =
|
using SetFrameRateWithChangeStrategyFn =
|
||||||
int32_t (*)(ANativeWindow*, float, int8_t, int8_t);
|
int32_t (*)(ANativeWindow*, float, int8_t, int8_t);
|
||||||
static const auto set_frame_rate_with_change_strategy =
|
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_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,
|
EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface,
|
||||||
|
|
|
||||||
|
|
@ -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-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
|
|
@ -50,8 +55,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
void UpdateFrameRateHint();
|
void UpdateFrameRateHint();
|
||||||
|
void UpdateObservedFrameRate();
|
||||||
[[nodiscard]] float GetFrameRateHint() const;
|
[[nodiscard]] float GetFrameRateHint() const;
|
||||||
|
[[nodiscard]] static float QuantizeFrameRateHint(float frame_rate);
|
||||||
|
|
||||||
float m_window_width{};
|
float m_window_width{};
|
||||||
float m_window_height{};
|
float m_window_height{};
|
||||||
|
|
@ -60,4 +69,8 @@ private:
|
||||||
|
|
||||||
bool m_first_frame = false;
|
bool m_first_frame = false;
|
||||||
float m_last_frame_rate_hint = -1.0f;
|
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…
Add table
Add a link
Reference in a new issue