ui: log guest present cadence statistics behind a debug cvar
This commit is contained in:
parent
134a1c8f5e
commit
79761cbdd5
1 changed files with 42 additions and 0 deletions
|
|
@ -13,6 +13,7 @@
|
|||
#include <atomic>
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
#include <rex/assert.h>
|
||||
|
|
@ -45,6 +46,13 @@ REXCVAR_DEFINE_INT32(presenter_strict_guest_output_backpressure_timeout_ms, 100,
|
|||
.range(0, 1000)
|
||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||
|
||||
REXCVAR_DEFINE_BOOL(presenter_present_cadence_log, false, "UI/Presenter",
|
||||
"Log guest present cadence statistics every 600 swaps: average/max "
|
||||
"swap-to-swap interval, standard deviation, and frame-to-frame jitter "
|
||||
"(mean absolute successive difference). Attributes perceived judder to "
|
||||
"irregular present timing versus low frame rate.")
|
||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||
|
||||
REXCVAR_DEFINE_BOOL(present_letterbox, true, "UI/Presenter",
|
||||
"Enable letterboxing for non-native aspect ratios");
|
||||
|
||||
|
|
@ -585,6 +593,40 @@ bool Presenter::RefreshGuestOutput(
|
|||
return false;
|
||||
}
|
||||
guest_output_active_last_refresh_ = true;
|
||||
// Present-cadence telemetry: the interval between guest output refreshes
|
||||
// is the cadence the host presents at (painting is triggered per
|
||||
// refresh), which VRR displays turn directly into perceived smoothness.
|
||||
// jitter = mean absolute successive frame-to-frame difference, the
|
||||
// judder-relevant metric; sd and max catch slow drift and hitches.
|
||||
if (REXCVAR_GET(presenter_present_cadence_log)) {
|
||||
static std::chrono::steady_clock::time_point s_cad_prev{};
|
||||
static double s_cad_sum = 0, s_cad_sumsq = 0, s_cad_max = 0;
|
||||
static double s_cad_jitter_sum = 0, s_cad_last = 0;
|
||||
static uint32_t s_cad_n = 0;
|
||||
const auto cad_now = std::chrono::steady_clock::now();
|
||||
if (s_cad_prev.time_since_epoch().count() != 0) {
|
||||
const double ms =
|
||||
std::chrono::duration<double, std::milli>(cad_now - s_cad_prev).count();
|
||||
s_cad_sum += ms;
|
||||
s_cad_sumsq += ms * ms;
|
||||
s_cad_max = std::max(s_cad_max, ms);
|
||||
if (s_cad_n != 0) {
|
||||
s_cad_jitter_sum += std::abs(ms - s_cad_last);
|
||||
}
|
||||
s_cad_last = ms;
|
||||
if (++s_cad_n >= 600) {
|
||||
const double avg = s_cad_sum / s_cad_n;
|
||||
const double var = std::max(0.0, s_cad_sumsq / s_cad_n - avg * avg);
|
||||
REXLOG_INFO(
|
||||
"present-cadence: avg={:.2f}ms sd={:.2f} jitter={:.3f} max={:.2f} "
|
||||
"(600 swaps)",
|
||||
avg, std::sqrt(var), s_cad_jitter_sum / (s_cad_n - 1), s_cad_max);
|
||||
s_cad_sum = s_cad_sumsq = s_cad_max = s_cad_jitter_sum = s_cad_last = 0;
|
||||
s_cad_n = 0;
|
||||
}
|
||||
}
|
||||
s_cad_prev = cad_now;
|
||||
}
|
||||
if (GuestFrameStatsEnabled()) {
|
||||
std::lock_guard<std::mutex> stats_lock(guest_frame_stats_mutex_);
|
||||
guest_frame_timestamps_[guest_frame_timestamp_next_] = std::chrono::steady_clock::now();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue