Add "SWP" frame time information (#1173)

This commit is contained in:
PabloMK7 2025-06-20 19:26:12 +02:00 committed by GitHub
parent 2b51691d57
commit 0deb0f50b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 46 additions and 22 deletions

View File

@ -1183,7 +1183,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
val TIME_SVC = 4
val TIME_IPC = 5
val TIME_GPU = 6
val TIME_REM = 7
val TIME_SWAP = 7
val TIME_REM = 8
perfStatsUpdater = Runnable {
val sb = StringBuilder()
val perfStats = NativeLibrary.getPerfStats()
@ -1197,9 +1198,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
if (sb.isNotEmpty()) sb.append(dividerString)
sb.append(
String.format(
"Frame:\u00A0%.1fms (GPU:\u00A0%.1fms IPC:\u00A0%.1fms SVC:\u00A0%.1fms Rem:\u00A0%.1fms)",
"Frame:\u00A0%.1fms (GPU: [CMD:\u00A0%.1fms SWP:\u00A0%.1fms] IPC:\u00A0%.1fms SVC:\u00A0%.1fms Rem:\u00A0%.1fms)",
(perfStats[FRAMETIME] * 1000.0f).toFloat(),
(perfStats[TIME_GPU] * 1000.0f).toFloat(),
(perfStats[TIME_SWAP] * 1000.0f).toFloat(),
(perfStats[TIME_IPC] * 1000.0f).toFloat(),
(perfStats[TIME_SVC] * 1000.0f).toFloat(),
(perfStats[TIME_REM] * 1000.0f).toFloat(),

View File

@ -644,18 +644,19 @@ void Java_org_citra_citra_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNI
jdoubleArray Java_org_citra_citra_1emu_NativeLibrary_getPerfStats(JNIEnv* env,
[[maybe_unused]] jobject obj) {
auto& core = Core::System::GetInstance();
jdoubleArray j_stats = env->NewDoubleArray(8);
jdoubleArray j_stats = env->NewDoubleArray(9);
if (core.IsPoweredOn()) {
auto results = core.GetAndResetPerfStats();
// Converting the structure into an array makes it easier to pass it to the frontend
double stats[8] = {results.system_fps, results.game_fps,
double stats[9] = {results.system_fps, results.game_fps,
results.emulation_speed, results.time_vblank_interval,
results.time_hle_svc, results.time_hle_ipc,
results.time_gpu, results.time_remaining};
results.time_gpu, results.time_swap,
results.time_remaining};
env->SetDoubleArrayRegion(j_stats, 0, 8, stats);
env->SetDoubleArrayRegion(j_stats, 0, 9, stats);
}
return j_stats;

View File

@ -3232,9 +3232,10 @@ void GMainWindow::UpdateStatusBar() {
game_fps_label->setText(tr("App: %1 FPS").arg(results.game_fps, 0, 'f', 0));
if (UISettings::values.show_advanced_frametime_info) {
emu_frametime_label->setText(
tr("Frame: %1 ms (GPU: %2 ms, IPC: %3 ms, SVC: %4 ms, Rem: %5 ms)")
tr("Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms)")
.arg(results.time_vblank_interval * 1000.0, 2, 'f', 2)
.arg(results.time_gpu * 1000.0, 2, 'f', 2)
.arg(results.time_swap * 1000.0, 2, 'f', 2)
.arg(results.time_hle_ipc * 1000.0, 2, 'f', 2)
.arg(results.time_hle_svc * 1000.0, 2, 'f', 2)
.arg(results.time_remaining * 1000.0, 2, 'f', 2));

View File

@ -72,6 +72,14 @@ void PerfStats::EndGPUProcessing() {
accumulated_gpu_time += (Clock::now() - start_gpu_time);
}
void PerfStats::StartSwap() {
start_swap_time = Clock::now();
}
void PerfStats::EndSwap() {
accumulated_swap_time += (Clock::now() - start_swap_time);
}
void PerfStats::BeginSystemFrame() {
std::scoped_lock lock{object_mutex};
@ -143,11 +151,17 @@ PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_
last_stats.time_gpu = system_frames ? (duration_cast<DoubleSecs>(accumulated_gpu_time).count() /
static_cast<double>(system_frames))
: 0;
last_stats.time_swap = system_frames
? (duration_cast<DoubleSecs>(accumulated_swap_time).count() /
static_cast<double>(system_frames))
: 0;
last_stats.time_remaining =
system_frames
? (duration_cast<DoubleSecs>(accumulated_frametime - accumulated_svc_time).count() /
static_cast<double>(system_frames))
: 0;
system_frames ? (duration_cast<DoubleSecs>((accumulated_frametime - accumulated_svc_time) -
accumulated_swap_time)
.count() /
static_cast<double>(system_frames))
: 0;
last_stats.emulation_speed = system_us_per_second.count() / 1'000'000.0;
last_stats.artic_transmitted = static_cast<double>(artic_transmitted) / interval;
last_stats.artic_events.raw = artic_events.raw | prev_artic_event.raw;
@ -158,11 +172,9 @@ PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_
accumulated_frametime = Clock::duration::zero();
system_frames = 0;
accumulated_svc_time = Clock::duration::zero();
svc_processing_times = 0;
accumulated_ipc_time = Clock::duration::zero();
ipc_processing_times = 0;
accumulated_gpu_time = Clock::duration::zero();
gpu_processing_times = 0;
accumulated_swap_time = Clock::duration::zero();
game_frames = 0;
artic_transmitted = 0;
prev_artic_event.raw &= artic_events.raw;

View File

@ -62,7 +62,10 @@ public:
double time_hle_ipc;
// Walltime in seconds of the vblank interval spent in GPU command processing
double time_gpu;
// Walltime in seconds of teh vblank interval spent in other operations
// Walltime in seconds of the vblank interval spent in Renderer::SwapBuffers (includes
// waiting for host GPU to finish)
double time_swap;
// Walltime in seconds of the vblank interval spent in other operations
double time_remaining;
/// Ratio of walltime / emulated time elapsed
double emulation_speed;
@ -78,6 +81,8 @@ public:
void EndIPCProcessing();
void BeginGPUProcessing();
void EndGPUProcessing();
void StartSwap();
void EndSwap();
void BeginSystemFrame();
void EndSystemFrame();
void EndGameFrame();
@ -155,19 +160,16 @@ private:
Clock::duration previous_previous_frame_length = Clock::duration::zero();
Clock::time_point start_svc_time = reset_point;
Clock::duration accumulated_svc_time = Clock::duration::zero();
u32 svc_processing_times = 0;
Clock::time_point start_ipc_time = reset_point;
Clock::duration accumulated_ipc_time = Clock::duration::zero();
u32 ipc_processing_times = 0;
Clock::time_point start_gpu_time = reset_point;
Clock::duration accumulated_gpu_time = Clock::duration::zero();
u32 gpu_processing_times = 0;
Clock::time_point start_swap_time = reset_point;
Clock::duration accumulated_swap_time = Clock::duration::zero();
/// Last recorded performance statistics.
Results last_stats;

View File

@ -89,6 +89,7 @@ RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
RendererOpenGL::~RendererOpenGL() = default;
void RendererOpenGL::SwapBuffers() {
system.perf_stats->StartSwap();
// Maintain the rasterizer's state as a priority
OpenGLState prev_state = OpenGLState::GetCurState();
state.Apply();
@ -115,6 +116,7 @@ void RendererOpenGL::SwapBuffers() {
}
}
system.perf_stats->EndSwap();
EndFrame();
prev_state.Apply();
rasterizer.TickFrame();

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -18,7 +18,9 @@ RendererSoftware::RendererSoftware(Core::System& system, Pica::PicaCore& pica_,
RendererSoftware::~RendererSoftware() = default;
void RendererSoftware::SwapBuffers() {
system.perf_stats->StartSwap();
PrepareRenderTarget();
system.perf_stats->EndSwap();
EndFrame();
}

View File

@ -832,6 +832,7 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
}
void RendererVulkan::SwapBuffers() {
system.perf_stats->StartSwap();
const Layout::FramebufferLayout& layout = render_window.GetFramebufferLayout();
PrepareRendertarget();
RenderScreenshot();
@ -847,6 +848,7 @@ void RendererVulkan::SwapBuffers() {
secondary_window->PollEvents();
}
#endif
system.perf_stats->EndSwap();
rasterizer.TickFrame();
EndFrame();
}