diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-16 09:33:39 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-16 09:33:39 +0300 |
| commit | a075a2941f8fcdae155495da634cf63368c950b7 (patch) | |
| tree | a33b5636ef7b9e4879cb8ab52220e805a5e30348 /tests/common/test_surface_integration.c | |
| parent | c2832a63547e6328afde25bb3b8145267eadef47 (diff) | |
Pace frame requests by the frame presented after them
A frame request now only records intent. Each loop step resolves it after
the callbacks that present, so a request made before the present waits for
that frame. An animation that asked first got two REFRESH events per frame
on X11 and with GL.
With no frame in flight, the REFRESH comes one refresh interval after the
last present or answer, so a request without a present cannot spin.
Queued events now go before an owed REFRESH. Input reaches the application
before it draws, and a queued REFRESH pays an owed one for the same surface.
The loop prepare only peeks at a lost event, so deliver can report it as a
final loss. A failed push from another thread wakes the loop.
Signals and posts run at the end of a step, after descriptors and timers.
A signal handler now sees the output that came with it.
A render-thread GL swap counts as in flight on Wayland.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/common/test_surface_integration.c')
| -rw-r--r-- | tests/common/test_surface_integration.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c index 7862bfc..6946cf9 100644 --- a/tests/common/test_surface_integration.c +++ b/tests/common/test_surface_integration.c @@ -37,7 +37,8 @@ static void *wrong_thread(void *data) struct callback_state { yasl_loop *loop; yasl_surface *window; - int refreshes; + int refreshes, resizes, refreshes_at_resize, final_losses; + bool animating; int wait_result, shutdown_result; yasl_surface *made; int made_destroy; @@ -45,8 +46,18 @@ struct callback_state { static void on_event(void *userdata, const yasl_event *e) { struct callback_state *st = userdata; + if (e->type == YASL_EVENT_DISPLAY_LOST && e->action == YASL_LOST_FINAL) + st->final_losses++; + if (e->type == YASL_EVENT_WINDOW && e->surface == st->window && + e->window.width == 120 && e->window.height == 80) { + st->resizes++; + st->refreshes_at_resize = st->refreshes; + } if (e->type == YASL_EVENT_REFRESH && e->surface == st->window) { st->refreshes++; + /* An animation asks for its next frame before it presents this one. */ + if (st->animating) + assert(yasl_surface_request_frame(e->surface) == 0); int w = 0, h = 0; uint32_t *pixels = yasl_cpu_pixels(e->surface, &w, &h); assert(pixels && w > 0 && h > 0); @@ -111,6 +122,32 @@ static void test_callback_mode(enum yasl_backend backend) assert(yasl_loop_step(st.loop, 25) >= 0); assert(st.refreshes == before + 1); + /* The frame an animation presents after its request is the frame the + * request waits for: one REFRESH per display refresh, not two. */ + st.animating = true; + assert(yasl_surface_request_frame(st.window) == 0); + before = st.refreshes; + uint64_t start = yasl_time_ns(); + while (yasl_time_ns() - start < 1000000000ull) + assert(yasl_loop_step(st.loop, 50) >= 0); + st.animating = false; + int frames = st.refreshes - before; + fprintf(stderr, "%d REFRESH events in 1 s of animation\n", frames); + assert(frames >= 20 && frames <= 75); + + /* A resize owes one REFRESH, after its WINDOW event. */ + for (int i = 0; i < 6; i++) + assert(yasl_loop_step(st.loop, 25) >= 0); + before = st.refreshes; + assert(yasl_surface_request_size(st.window, 120, 80) == 0); + step_until(&st, &st.resizes, 1); + for (int i = 0; i < 8; i++) + assert(yasl_loop_step(st.loop, 25) >= 0); + fprintf(stderr, "%d REFRESH events for one resize, %d before its WINDOW event\n", + st.refreshes - before, st.refreshes_at_resize - before); + assert(st.resizes == 1 && st.refreshes_at_resize == before); + assert(st.refreshes == before + 1); + /* An idle loop waits instead of spinning. */ int steps = 0; uint64_t end = yasl_time_ns() + 300000000ull; @@ -125,6 +162,13 @@ static void test_callback_mode(enum yasl_backend backend) assert(yasl_loop_step(st.loop, 50) >= 0); assert(st.made_destroy == 0); + /* A lost event ends the session: on_event hears it as a final loss. A + * string event with no text cannot be queued. */ + struct yasl_private_event broken = {.type = YASL_PRIVATE_EVENT_PASTE, .surface = st.window, + .text = {NULL, 1}}; + assert(!yasl_private_events_push(st.window->display, st.window, &broken)); + step_until(&st, &st.final_losses, 1); + assert(yasl_loop_add_timer(st.loop, YASL_PRIVATE_MS_TO_NS(10), quit_in_timer, st.loop)); assert(yasl_loop_run(st.loop) == 0); assert(yasl_shutdown() == 0); |
