Publish SDL3 drawable dimensions from pixel-size events

This commit is contained in:
Shokunin
2026-10-21 06:35:46 -07:00
committed by Matthew Stanley
parent 5791ef2a07
commit 779bc43030
3 changed files with 64 additions and 18 deletions
+44 -4
View File
@@ -429,6 +429,34 @@ static int load_modern_gl(void) {
static SDL_Window *s_win = NULL;
static uint64_t s_window_owner;
static _Atomic uint64_t s_drawable_extent;
static uint64_t s_drawable_queries;
#if defined(PSX_SDL3)
static _Atomic uint32_t s_drawable_window_id;
static int s_drawable_watch;
static bool SDLCALL drawable_event_watch(void *unused, SDL_Event *event) {
(void)unused;
if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED &&
event->window.windowID == atomic_load_explicit(&s_drawable_window_id, memory_order_relaxed) &&
event->window.data1 >= 0 && event->window.data2 >= 0)
atomic_store_explicit(&s_drawable_extent,
((uint64_t)(uint32_t)event->window.data1 << 32) | (uint32_t)event->window.data2,
memory_order_release);
return true;
}
#endif
static int drawable_events_enabled(void) {
#if defined(PSX_SDL3)
if (!s_drawable_watch) return 0;
static int enabled = -1;
if (enabled < 0) {
const char *e = getenv("PSX_GL_DRAWABLE_EVENTS");
enabled = !(e && e[0] == '0');
}
return enabled;
#else
return 0; /* SDL2 resize events are logical, not drawable-pixel extents. */
#endif
}
static uint64_t window_thread_id(void) {
#if defined(PSX_SDL3)
return (uint64_t)SDL_GetCurrentThreadID();
@@ -436,17 +464,19 @@ static uint64_t window_thread_id(void) {
return (uint64_t)SDL_ThreadID();
#endif
}
/* SDL3's pixel-size query is main-thread-only. Publish one consistent pair
* before each frame handoff; GL workers never enter the window-system query. */
/* Query only at context creation (or in the legacy control). SDL3 pixel-size
* events publish one consistent pair without taking SDL's window-properties
* lock, which the swapping thread can hold. No worker queries the window. */
static void gl_drawable_refresh(void) {
if (!s_win || window_thread_id() != s_window_owner) return;
int w = 0, h = 0;
SDL_GL_GetDrawableSize(s_win, &w, &h);
s_drawable_queries++;
atomic_store_explicit(&s_drawable_extent,
((uint64_t)(uint32_t)w << 32) | (uint32_t)h, memory_order_release);
}
static void gl_drawable_size(int *w, int *h) {
gl_drawable_refresh();
if (!drawable_events_enabled()) gl_drawable_refresh();
uint64_t extent = atomic_load_explicit(&s_drawable_extent, memory_order_acquire);
if (w) *w = (int)(extent >> 32);
if (h) *h = (int)(uint32_t)extent;
@@ -6791,6 +6821,11 @@ int gl_renderer_init_context(SDL_Window *win) {
s_win = win;
texel_cache_reset();
s_window_owner = window_thread_id();
#if defined(PSX_SDL3)
if (s_drawable_watch) SDL_RemoveEventWatch(drawable_event_watch, NULL);
atomic_store(&s_drawable_window_id, SDL_GetWindowID(win));
s_drawable_watch = SDL_AddEventWatch(drawable_event_watch, NULL) ? 1 : 0;
#endif
gl_drawable_refresh();
s_present_w = 0;
s_present_h = 0;
@@ -6928,6 +6963,11 @@ void gl_renderer_work_stats(GlRenderWorkStats *out) {
void gl_renderer_shutdown(void) {
gl_renderer_render_thread_stop(); /* drains; the context comes back to this thread */
psx_host_set_hud_draw_cb(NULL, NULL);
#if defined(PSX_SDL3)
if (s_drawable_watch) SDL_RemoveEventWatch(drawable_event_watch, NULL);
s_drawable_watch = 0;
atomic_store(&s_drawable_window_id, 0);
#endif
const char *perf = getenv("PSX_RUNTIME_PERF_DIAG");
if (s_ctx && perf && perf[0] && perf[0] != '0')
fprintf(stdout, "psxrecomp: GL work totals: queue_uploads=%llu replay_draws=%llu "
@@ -14996,7 +15036,7 @@ int gl_renderer_render_thread_active(void) { return s_rth_on; }
* to the render thread when the frame may run asynchronously, take it when it
* may not, then close the frame (the in-flight bound applies here). */
void gl_renderer_render_thread_frame_boundary(void) {
gl_drawable_refresh();
if (!drawable_events_enabled()) gl_drawable_refresh();
if (!s_rth_on) return;
fg_note_guest_frame();
if (rt_held()) {
+15 -12
View File
@@ -157,21 +157,24 @@ def main():
ok = False
runs[threaded] = p
if args.wide_present:
for margin, coverage, state, upload, bloom, cache, layers, copy, identity in ((0,0,0,0,0,0,256,1,1), (0,0,1,1,1,1,256,1,1), (0,1,1,1,1,1,256,1,1), (1,0,1,1,1,1,256,1,1), (1,1,1,0,1,1,256,1,1), (1,1,1,1,0,1,256,1,1), (1,1,1,1,1,0,256,1,1), (1,1,1,1,1,1,4,1,1), (1,1,1,1,1,1,256,0,1), (1,1,1,1,1,1,256,1,0)):
reference = run([probe, s, threaded, args.frames, *mode],
{"PSX_GL_WIDE_MARGIN_SCISSOR": str(margin),
"PSX_GL_COVERAGE_FAST": str(coverage),
"PSX_GL_STATE_QUERY_FAST": str(state),
"PSX_GL_QUEUE_UPLOAD_FAST": str(upload),
"PSX_GL_BLOOM_FUSE_EXTEND": str(bloom),
"PSX_GL_TEXEL_CACHE": str(cache),
"PSX_GL_TEXEL_CACHE_LAYERS": str(layers),
"PSX_GL_HIW_COPY_FAST": str(copy),
"PSX_GL_IDENTITY_COPY_FAST": str(identity)})
flags = (
"PSX_GL_WIDE_MARGIN_SCISSOR", "PSX_GL_COVERAGE_FAST",
"PSX_GL_STATE_QUERY_FAST", "PSX_GL_QUEUE_UPLOAD_FAST",
"PSX_GL_BLOOM_FUSE_EXTEND", "PSX_GL_TEXEL_CACHE",
"PSX_GL_HIW_COPY_FAST", "PSX_GL_IDENTITY_COPY_FAST",
"PSX_GL_DRAWABLE_EVENTS", "PSX_RENDER_QUEUE_BATCH")
controls = [{flag: "0" for flag in flags}]
controls += [{flag: "0"} for flag in flags]
controls += [{"PSX_GL_TEXEL_CACHE_LAYERS": "4"}]
for control in controls:
overrides = {flag: "1" for flag in flags}
overrides.update(control)
reference = run([probe, s, threaded, args.frames, *mode], overrides)
baseline = parse(reference.stdout)
if reference.returncode or baseline["failures"] != 0 or any(baseline[k] != p[k] for k in KEYS):
print(f"FAIL scale {s}: margin={margin} coverage={coverage} changed rendered output", baseline, p)
print(f"FAIL scale {s}: controls {control} changed rendered output", baseline, p)
ok = False
for k in KEYS:
if runs[0][k] != runs[1][k]:
print(f"FAIL scale {s}: {k} differs with the render thread on "
+5 -2
View File
@@ -376,6 +376,7 @@ int main(int argc, char **argv) {
}
static const int levels[] = { 2, 1, 3, 1, 4, 2 };
int nsteps = 0, level = scale;
const uint64_t drawable_queries_before = s_drawable_queries;
for (int f = 0; f < frames; f++) {
frame(f, (f & 1) ? 512 : 0);
if (dynres && f % 7 == 6) { /* includes frames held at a sync point */
@@ -507,8 +508,10 @@ int main(int argc, char **argv) {
check(st.acquires >= 2 && st.acquires <= (uint64_t)frames + 4, "acquires bounded");
check(st.bytes > ((uint64_t)32 << 20), "ring wrapped (more than its size recorded)");
}
/* A resize is published at the main-thread handoff and is visible to a
* worker without calling SDL's main-thread-only pixel-size query. */
if (drawable_events_enabled())
check(s_drawable_queries == drawable_queries_before, "no per-frame drawable queries");
/* Pixel-size events publish resizes without querying the window on a
* worker or taking its property lock on every frame boundary. */
for (int k = 0; k < 2; ++k) {
SDL_SetWindowSize(win, 400 + k * 80, 300 + k * 60);
SDL_PumpEvents();