diff options
Diffstat (limited to 'tests/common/test_surface_integration.c')
| -rw-r--r-- | tests/common/test_surface_integration.c | 110 |
1 files changed, 105 insertions, 5 deletions
diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c index f33e35b..7862bfc 100644 --- a/tests/common/test_surface_integration.c +++ b/tests/common/test_surface_integration.c @@ -34,6 +34,102 @@ static void *wrong_thread(void *data) assert(yasl_surface_get_native(data, &native) == -EPERM && !native.wl_display && !native.x11_display); return NULL; } +struct callback_state { + yasl_loop *loop; + yasl_surface *window; + int refreshes; + int wait_result, shutdown_result; + yasl_surface *made; + int made_destroy; +}; +static void on_event(void *userdata, const yasl_event *e) +{ + struct callback_state *st = userdata; + if (e->type == YASL_EVENT_REFRESH && e->surface == st->window) { + st->refreshes++; + int w = 0, h = 0; + uint32_t *pixels = yasl_cpu_pixels(e->surface, &w, &h); + assert(pixels && w > 0 && h > 0); + pixels[0] = 0xff336699u; + assert(yasl_cpu_present(e->surface) == 0); + } + yasl_event inner; + st->wait_result = yasl_wait_event(&inner, 0); + st->shutdown_result = yasl_shutdown(); +} +/* A loop callback runs with the display idle, so surface creation and its + * roundtrips are allowed there. */ +static uint64_t create_in_timer(void *userdata, uint64_t id, uint64_t delay_ns) +{ + (void)id; (void)delay_ns; + struct callback_state *st = userdata; + st->made = yasl_surface_create(&(struct yasl_surface_options){ + .title = "made by a timer", .width = 64, .height = 64}); + assert(st->made); + st->made_destroy = yasl_surface_destroy(st->made); + return 0; +} +static uint64_t quit_in_timer(void *userdata, uint64_t id, uint64_t delay_ns) +{ + (void)id; (void)delay_ns; + yasl_loop_quit(userdata); + return 0; +} +static void step_until(struct callback_state *st, const int *counter, int want) +{ + uint64_t deadline = yasl_time_ns() + 5000000000ull; + while (*counter < want && yasl_time_ns() < deadline) + assert(yasl_loop_step(st->loop, 50) >= 0); + assert(*counter >= want); +} +static void test_callback_mode(enum yasl_backend backend) +{ + struct callback_state st = {.loop = yasl_loop_create()}; + assert(st.loop); + const struct yasl_options options = { + .backend = backend, .loop = st.loop, .on_event = on_event, .userdata = &st}; + assert(yasl_init(&options) == 0); + assert(yasl_init(&options) == -EALREADY); + assert(yasl_loop_destroy(st.loop) == -EBUSY); + yasl_event e; + assert(yasl_wait_event(&e, 0) == -EBUSY); + st.window = yasl_surface_create(&(struct yasl_surface_options){ + .title = "callback mode", .width = 96, .height = 64}); + assert(st.window); + + /* Events reach on_event while the application only steps its loop. */ + step_until(&st, &st.refreshes, 1); + assert(st.wait_result == -EBUSY && st.shutdown_result == -EBUSY); + + /* Frame requests coalesce into one REFRESH, sent once the window can + * show a frame. */ + int before = st.refreshes; + assert(yasl_surface_request_frame(st.window) == 0); + assert(yasl_surface_request_frame(st.window) == 0); + step_until(&st, &st.refreshes, before + 1); + for (int i = 0; i < 4; i++) + assert(yasl_loop_step(st.loop, 25) >= 0); + assert(st.refreshes == before + 1); + + /* An idle loop waits instead of spinning. */ + int steps = 0; + uint64_t end = yasl_time_ns() + 300000000ull; + while (yasl_time_ns() < end) { + assert(yasl_loop_step(st.loop, 100) >= 0); + steps++; + } + assert(steps < 30); + + assert(yasl_loop_add_timer(st.loop, 0, create_in_timer, &st)); + while (!st.made) + assert(yasl_loop_step(st.loop, 50) >= 0); + assert(st.made_destroy == 0); + + 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); + assert(yasl_loop_destroy(st.loop) == 0); +} static void push(yasl_surface *s, struct yasl_private_event event) { event.surface = s; @@ -68,8 +164,11 @@ int main(int argc, char **argv) enum yasl_backend backend = !strcmp(argv[1], "wayland") ? YASL_BACKEND_WAYLAND : !strcmp(argv[1], "x11") ? YASL_BACKEND_X11 : YASL_BACKEND_COCOA; - assert(yasl_init(backend, "org.yasl.surface-test") == 0); - assert(yasl_init(backend, NULL) == -EALREADY); + const struct yasl_options options = {.backend = backend, .app_id = "org.yasl.surface-test"}; + assert(yasl_init(&options) == 0); + assert(yasl_init(&options) == -EALREADY); + /* Other options would need another display. */ + assert(yasl_init(&(struct yasl_options){.backend = backend}) == -EBUSY); assert(yasl_get_backend() == backend); unsigned features = yasl_get_features(); yasl_surface *s = yasl_surface_create( @@ -329,16 +428,17 @@ int main(int argc, char **argv) assert(yasl_surface_destroy(s) == 0); if (popup) assert(!listed(display, popup_id)); - assert(yasl_init(backend, NULL) == -EALREADY); + assert(yasl_init(&options) == -EALREADY); s = yasl_surface_create(&(struct yasl_surface_options){.title = "shared backend remains", .width = 64, .height = 64}); assert(s); yasl_shutdown(); - assert(yasl_init(backend, NULL) == 0); + assert(yasl_init(&(struct yasl_options){.backend = backend}) == 0); s = yasl_surface_create( &(struct yasl_surface_options){.title = "reinitialized", .width = 64, .height = 64}); assert(s); yasl_shutdown(); - puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed"); + test_callback_mode(backend); + puts("public surface lifecycle, pixels, ownership, input, wake, refresh and callback mode passed"); return 0; } |
