mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
VRR present mode: [video] vsync = "vrr"
Variable refresh (G-Sync/FreeSync, ProMotion): present each frame when it is ready (swap interval 0). Smooth motion targets the panel's maximum refresh at the current size (psx_sdl_display_max_refresh) and never exceeds it. PSX_HOST_REFRESH_HZ / PSX_HOST_REFRESH_MAX_HZ simulate a display for headless tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -867,8 +867,12 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path&
|
||||
if (mode == "on" || mode == "vsync") rt.video_vsync = 1;
|
||||
else if (mode == "off" || mode == "immediate") rt.video_vsync = 0;
|
||||
else if (mode == "adaptive") rt.video_vsync = -1;
|
||||
// vrr: variable refresh (G-Sync/FreeSync, ProMotion): present
|
||||
// each frame when it is ready (swap interval 0), Smooth motion
|
||||
// targets the panel's maximum refresh and never exceeds it.
|
||||
else if (mode == "vrr") rt.video_vsync = 2;
|
||||
else throw std::runtime_error(fmt::format(
|
||||
"[video] vsync must be \"on\"|\"off\"|\"immediate\"|\"adaptive\": {}", mode));
|
||||
"[video] vsync must be \"on\"|\"off\"|\"immediate\"|\"adaptive\"|\"vrr\": {}", mode));
|
||||
}
|
||||
if (video.contains("frame_interpolation")) {
|
||||
rt.video_frame_interpolation =
|
||||
|
||||
@@ -137,6 +137,25 @@ static inline int psx_sdl_get_current_display_mode(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The highest refresh the display offers at the current mode's size (a VRR
|
||||
* or ProMotion panel's maximum); 0 when unknown. */
|
||||
static inline double psx_sdl_display_max_refresh(SDL_DisplayID display)
|
||||
{
|
||||
if (!display) display = SDL_GetPrimaryDisplay();
|
||||
const SDL_DisplayMode *cur = SDL_GetCurrentDisplayMode(display);
|
||||
double best = cur ? (double)cur->refresh_rate : 0.0;
|
||||
int count = 0;
|
||||
SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &count);
|
||||
if (modes) {
|
||||
for (int i = 0; i < count; ++i)
|
||||
if (modes[i] && cur && modes[i]->w == cur->w && modes[i]->h == cur->h &&
|
||||
(double)modes[i]->refresh_rate > best)
|
||||
best = (double)modes[i]->refresh_rate;
|
||||
SDL_free(modes);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/* Opt-in high-pixel-density game window. Without it, SDL3 on a Retina Mac
|
||||
* gives the GL context a drawable in POINTS (half the panel resolution) and
|
||||
* the compositor stretches it, so any internal resolution above that is
|
||||
@@ -269,4 +288,17 @@ static inline int psx_sdl_display_pixel_height(SDL_Window *window)
|
||||
return mode.h;
|
||||
}
|
||||
|
||||
static inline double psx_sdl_display_max_refresh(int display)
|
||||
{
|
||||
SDL_DisplayMode cur, m;
|
||||
if (display < 0) display = 0;
|
||||
if (SDL_GetCurrentDisplayMode(display, &cur) != 0) return 0.0;
|
||||
double best = (double)cur.refresh_rate;
|
||||
const int n = SDL_GetNumDisplayModes(display);
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (SDL_GetDisplayMode(display, i, &m) == 0 && m.w == cur.w && m.h == cur.h &&
|
||||
(double)m.refresh_rate > best)
|
||||
best = (double)m.refresh_rate;
|
||||
return best;
|
||||
}
|
||||
#endif
|
||||
|
||||
+19
-3
@@ -1505,6 +1505,7 @@ static_assert((int)PSX_MOD_CONTROLLER_ANALOG ==
|
||||
static_assert((int)PSX_MOD_CONTROLLER_DIGITAL ==
|
||||
(int)PSXRecompV4::PAD_MODE_DIGITAL);
|
||||
static double g_host_refresh_hz = 0.0;
|
||||
static double g_host_refresh_max_hz = 0.0; /* panel maximum (VRR) */
|
||||
static constexpr double PSX_FRAME_PERIOD_MS = 1000.0 / 59.94;
|
||||
static double g_guest_frame_period_ms = PSX_FRAME_PERIOD_MS;
|
||||
static double g_frame_period_ms = PSX_FRAME_PERIOD_MS;
|
||||
@@ -3455,14 +3456,28 @@ static void refresh_host_display_cadence(int force_log, int force_probe) {
|
||||
}
|
||||
g_host_refresh_last_probe_ms = now_ms ? now_ms : 1ull;
|
||||
|
||||
double host_hz = 0.0;
|
||||
double host_hz = 0.0, max_hz = 0.0;
|
||||
if (disp_idx >= 0) {
|
||||
SDL_DisplayMode dm;
|
||||
if (SDL_GetCurrentDisplayMode(disp_idx, &dm) == 0 &&
|
||||
dm.refresh_rate > 0) {
|
||||
host_hz = (double)dm.refresh_rate;
|
||||
/* The panel's maximum refresh at this size (VRR targets it). */
|
||||
max_hz = psx_sdl_display_max_refresh(disp_idx);
|
||||
}
|
||||
}
|
||||
/* Simulated displays (headless tests): PSX_HOST_REFRESH_HZ and
|
||||
* PSX_HOST_REFRESH_MAX_HZ override what SDL reports. */
|
||||
if (const char* e = std::getenv("PSX_HOST_REFRESH_HZ")) {
|
||||
const double v = std::atof(e);
|
||||
if (v > 0.0) host_hz = v;
|
||||
}
|
||||
if (const char* e = std::getenv("PSX_HOST_REFRESH_MAX_HZ")) {
|
||||
const double v = std::atof(e);
|
||||
if (v > 0.0) max_hz = v;
|
||||
}
|
||||
if (max_hz < host_hz) max_hz = host_hz;
|
||||
g_host_refresh_max_hz = max_hz;
|
||||
|
||||
const int display_changed = (disp_idx != g_host_refresh_display_idx);
|
||||
const int refresh_changed =
|
||||
@@ -3564,7 +3579,7 @@ static int host_driver_vsync_unreliable(void) {
|
||||
}
|
||||
|
||||
static int present_vsync_owns_cadence(void) {
|
||||
if (g_video_vsync == 0 || g_present_vsync_disabled)
|
||||
if (g_video_vsync == 0 || g_video_vsync == 2 || g_present_vsync_disabled)
|
||||
return 0;
|
||||
if (host_driver_vsync_unreliable())
|
||||
return 0;
|
||||
@@ -9290,7 +9305,8 @@ static void render_thread_vblank(void) {
|
||||
std::fflush(stdout);
|
||||
}
|
||||
if (g_frame_generation)
|
||||
gl_renderer_frame_gen_configure(g_host_refresh_hz,
|
||||
gl_renderer_frame_gen_configure(g_video_vsync == 2 && g_host_refresh_max_hz > 0.0
|
||||
? g_host_refresh_max_hz : g_host_refresh_hz,
|
||||
g_guest_frame_period_ms > 0.0
|
||||
? 1000.0 / g_guest_frame_period_ms : 0.0);
|
||||
gl_renderer_render_thread_frame_boundary();
|
||||
|
||||
Reference in New Issue
Block a user