summaryrefslogtreecommitdiff
path: root/tests/common/test_surface_integration.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/common/test_surface_integration.c')
-rw-r--r--tests/common/test_surface_integration.c110
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;
}