diff --git a/runtime/include/gpu_gl_renderer.h b/runtime/include/gpu_gl_renderer.h index 4a27bdb2..96a08292 100644 --- a/runtime/include/gpu_gl_renderer.h +++ b/runtime/include/gpu_gl_renderer.h @@ -607,6 +607,7 @@ int gl_renderer_get_texture_window_batching(void); int gl_renderer_render_thread_start(int max_frames); void gl_renderer_render_thread_stop(void); int gl_renderer_render_thread_active(void); +int gl_renderer_vendor_is_nvidia(void); void gl_renderer_render_thread_frame_boundary(void); void gl_renderer_render_thread_sync(const char *reason); int gl_renderer_render_thread_json(char *out, size_t cap); diff --git a/runtime/src/gpu_gl_renderer.c b/runtime/src/gpu_gl_renderer.c index dab81837..62b9886b 100644 --- a/runtime/src/gpu_gl_renderer.c +++ b/runtime/src/gpu_gl_renderer.c @@ -397,6 +397,8 @@ static int load_modern_gl(void) { static SDL_Window *s_win = NULL; static SDL_GLContext s_ctx = NULL; static uint16_t *s_vram = NULL; /* CPU VRAM array (gpu.c's storage) */ +/* GL_VENDOR names NVIDIA (captured at context creation). */ +static int s_vendor_nvidia = 0; static int s_swap_interval = 1; /* SDL_GL swap interval (vsync mode) */ /* ---- render thread ([video] render_thread, docs/RENDER_THREAD.md) -------- @@ -6450,6 +6452,10 @@ int gl_renderer_init_context(SDL_Window *win) { const char *gpu = (const char *)glGetString(0x1F01 /* GL_RENDERER */); fprintf(stdout, "psxrecomp: OpenGL context created (%s; %s)\n", ver ? ver : "?", gpu ? gpu : "?"); + { + const char *vendor = (const char *)glGetString(0x1F00 /* GL_VENDOR */); + s_vendor_nvidia = (vendor && strstr(vendor, "NVIDIA")) ? 1 : 0; + } /* All-or-nothing: any missing entry point / failed shader / bad FBO means * the whole GL renderer is unavailable and the runtime stays on the pure @@ -14152,6 +14158,8 @@ void gl_renderer_render_thread_stop(void) { gr_refresh_backend(); } +int gl_renderer_vendor_is_nvidia(void) { return s_vendor_nvidia; } + int gl_renderer_render_thread_active(void) { return s_rth_on; } /* Frame boundary (once per vblank, after the present): hand the context back diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 221c3194..b91d724d 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -3958,11 +3958,18 @@ static int host_driver_vsync_unreliable(void) { * then costs a whole refresh (16.7 ms "GPU" at any internal scale, * render_busy 100 %), back-pressure slows the guest to 52-57 Hz, and * dynamic resolution drops for nothing. Swap interval 0 under the - * wall-clock pacer: 60.0 Hz, 4.4 ms. Exclusive fullscreen (2) keeps - * driver vsync. PSX_TRUST_DRIVER_VSYNC=1 restores it everywhere. */ + * wall-clock pacer: 60.0 Hz, 4.4 ms. + * + * Scope is the measured case only: GL renderer active, the render thread + * running, GL_VENDOR NVIDIA, and not exclusive fullscreen (2). Other + * driver families, the unthreaded path and exclusive fullscreen keep + * driver vsync. Re-evaluated per call, so runtime fullscreen/renderer + * changes take effect. PSX_TRUST_DRIVER_VSYNC=1 keeps driver vsync. */ if (const char *e = std::getenv("PSX_TRUST_DRIVER_VSYNC"); e && e[0] && e[0] != '0') return 0; - return (g_video_renderer == 1 && g_fullscreen != 2) ? 1 : 0; + return (g_video_renderer == 1 && g_gl_active && g_fullscreen != 2 && + gl_renderer_render_thread_active() && + gl_renderer_vendor_is_nvidia()) ? 1 : 0; #else static int cached = -1; if (cached >= 0) @@ -4076,7 +4083,7 @@ static void log_present_cadence(void) { "(%.4f ms/frame); driver vsync off (%s)\n", g_frame_period_ms, #ifdef _WIN32 - "Windows GL: DWM composes" + "Windows GL, NVIDIA render thread: DWM composes" #else "under WSL" #endif