From 1ab3e5a123109704789c2768e11a4f9af515821d Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Wed, 14 Oct 2026 13:13:52 +0300 Subject: Redefine public and rendering APIs with explicit contracts --- tests/common/test_surface_integration.c | 302 ++++++++++++++++++++++++-------- 1 file changed, 229 insertions(+), 73 deletions(-) (limited to 'tests/common/test_surface_integration.c') diff --git a/tests/common/test_surface_integration.c b/tests/common/test_surface_integration.c index 7cc938a..1f18f23 100644 --- a/tests/common/test_surface_integration.c +++ b/tests/common/test_surface_integration.c @@ -2,6 +2,16 @@ #include #include #include +#include +#if YASL_HAS_WAYLAND +#include +#endif +#if YASL_HAS_X11 +#include +#endif +#if YASL_HAS_COCOA +#include +#endif #include "common/backend.h" #include #include @@ -14,95 +24,241 @@ void yasl_test_frame_tick(struct yasl_surface *surface); #endif static void drain(void) { - yasl_event e;int n=0; - while(yasl_wait_event(&e,0)>0)assert(++n<1000); + yasl_event e; + int n = 0; + while (yasl_wait_event(&e, 0) > 0) + assert(++n < 1000); } static void *wake_thread(void *unused) -{ (void)unused;struct timespec delay={0,20000000};nanosleep(&delay,NULL);yasl_wake();return NULL; } +{ + (void)unused; + struct timespec delay = {0, 20000000}; + nanosleep(&delay, NULL); + yasl_wake(); + return NULL; +} static void *wrong_thread(void *data) -{ assert(!yasl_surface_set_title(data,"wrong"));assert(yasl_get_error(NULL)==YASL_ERROR_WRONG_THREAD);return NULL; } +{ + assert(yasl_surface_set_title(data, "wrong") == -EPERM); + struct yasl_cpu_buffer buffer; + assert(yasl_cpu_acquire(data, &buffer) == -EPERM && !buffer.pixels); +#if YASL_HAS_WAYLAND + struct yasl_wayland_handles native; + assert(yasl_wayland_get_native(data, &native) == -EPERM && !native.display && !native.surface); +#endif + return NULL; +} static int refreshes; -static void refresh(yasl_surface *s,void *ud) +static void refresh(yasl_surface *s, void *ud) { - (void)ud;refreshes++; - yasl_event e;assert(yasl_wait_event(&e,0)==-1);assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); - yasl_surface_destroy(s);assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); + (void)ud; + refreshes++; + yasl_event e; + assert(yasl_wait_event(&e, 0) == -EBUSY); + assert(errno == EBUSY); + assert(yasl_surface_destroy(s) == -EBUSY); + struct yasl_surface_options options = {.width = 32, .height = 32}; + assert(!yasl_surface_create(&options) && errno == EBUSY); + assert(!yasl_gl_surface_create(&options, NULL) && errno == EBUSY); } -int main(int argc,char **argv) +int main(int argc, char **argv) { - assert(argc==2); - enum yasl_backend backend=!strcmp(argv[1],"wayland")?YASL_BACKEND_WAYLAND:!strcmp(argv[1],"x11")?YASL_BACKEND_X11:YASL_BACKEND_COCOA; - assert(yasl_set_backend(backend));assert(yasl_set_app_id("org.yasl.surface-test")); - yasl_surface *s=yasl_surface_create("CPU contract",96,80,YASL_SURFACE_CPU); - if(!s){const char *why;yasl_get_error(&why);fprintf(stderr,"surface: %s native=%d\n",why,yasl_get_native_error());return 1;} - assert(yasl_surface_backend(s)==backend); - if(backend==YASL_BACKEND_COCOA) { - assert(!(yasl_surface_features(s)&YASL_CAP_OPENGL)); - assert(!yasl_gl_surface_create("unsupported GL",64,64,0,NULL,NULL)); - assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); - assert(!yasl_gl_make_current(NULL)); - assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); + assert(argc == 2); + enum yasl_backend backend = !strcmp(argv[1], "wayland") ? YASL_BACKEND_WAYLAND + : !strcmp(argv[1], "x11") ? YASL_BACKEND_X11 + : YASL_BACKEND_COCOA; + assert(yasl_init( + &(struct yasl_options){.backend = backend, .app_id = "org.yasl.surface-test"}) == 0); + yasl_surface *s = yasl_surface_create(&(struct yasl_surface_options){ + .title = "CPU contract", .width = 96, .height = 80, .type = YASL_SURFACE_CPU, .flags = 0}); + if (!s) { + const char *why; + why = strerror(errno); + fprintf(stderr, "surface: %s native=%d\n", why, errno); + return 1; + } + assert(yasl_surface_get_backend(s) == backend); + assert(yasl_surface_set_userdata(s, &backend) == 0); + assert(yasl_surface_get_userdata(s) == &backend); +#if YASL_HAS_WAYLAND + struct yasl_wayland_handles wl; + int wl_result = yasl_wayland_get_native(s, &wl); + assert(wl_result == (backend == YASL_BACKEND_WAYLAND ? 0 : -ENOTSUP)); + assert(backend == YASL_BACKEND_WAYLAND ? wl.display && wl.surface : !wl.display && !wl.surface); + assert(yasl_wayland_get_native(s, NULL) == -EINVAL); +#endif +#if YASL_HAS_X11 + struct yasl_x11_handles x; + int x_result = yasl_x11_get_native(s, &x); + assert(x_result == (backend == YASL_BACKEND_X11 ? 0 : -ENOTSUP)); + assert(backend == YASL_BACKEND_X11 ? x.display && x.window : !x.display && !x.window); +#endif +#if YASL_HAS_COCOA + struct yasl_cocoa_handles cocoa; + assert(yasl_cocoa_get_native(s, &cocoa) == 0 && cocoa.application && cocoa.window && + cocoa.view); +#endif + CAMetalLayer *layer = NULL; + assert(yasl_metal_get_layer(s, &layer) == -EBUSY && !layer); + assert(yasl_surface_set_ime_caret(s, 1e300, 0, 1, 1) == -EOVERFLOW); + if (backend == YASL_BACKEND_COCOA) { + assert(!(yasl_surface_get_features(s) & YASL_CAP_OPENGL)); + assert(!yasl_gl_surface_create(&(struct yasl_surface_options){.title = "unsupported GL", + .width = 64, + .height = 64, + .type = YASL_SURFACE_NATIVE, + .flags = 0}, + NULL)); + assert(errno == ENOTSUP); + assert((yasl_gl_make_current(NULL) < 0)); + assert(errno == ENOTSUP); assert(!yasl_gl_get_proc_address("glClear")); - assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); + assert(errno == ENOTSUP); } /* The first events report the window size, then ask for a frame. */ - yasl_event e;int fw=0,fh=0;bool window=false; - for(int i=0;i<1000;i++) { - assert(yasl_wait_event(&e,i?20:0)>=0); - if(e.type==YASL_EVENT_WINDOW){window=true;fw=e.window.pixel_width;fh=e.window.pixel_height;} - if(e.type==YASL_EVENT_REFRESH){assert(window&&fw>0&&fh>0&&e.surface==s);break;} + yasl_event e; + int fw = 0, fh = 0; + bool window = false; + for (int i = 0; i < 1000; i++) { + assert(yasl_wait_event(&e, i ? 20 : 0) >= 0); + if (e.type == YASL_EVENT_WINDOW) { + window = true; + fw = e.window.pixel_width; + fh = e.window.pixel_height; + } + if (e.type == YASL_EVENT_REFRESH) { + assert(window && fw > 0 && fh > 0 && e.surface == s); + break; + } } - assert(e.type==YASL_EVENT_REFRESH); - int w,h;yasl_surface_get_framebuffer_size(s,&w,&h);assert(w==fw&&h==fh); - assert(!yasl_set_backend(backend));assert(yasl_get_error(NULL)==YASL_ERROR_BUSY); - int pw,ph;uint32_t *pixels=yasl_cpu_pixels(s,&pw,&ph);assert(pixels&&pw==w&&ph==h); - assert(pixels[0]==0&&pixels[(size_t)w*h-1]==0); - for(size_t i=0;i<(size_t)w*h;i++)pixels[i]=0xff102030u; - pixels[(size_t)3*w+2]=0xffaabbccu; - assert(yasl_cpu_present(s)); - assert(yasl_cpu_pixels(s,&pw,&ph)==pixels&&pixels[0]==0xff102030u&&pixels[(size_t)3*w+2]==0xffaabbccu); + assert(e.type == YASL_EVENT_REFRESH); + int w, h; + yasl_surface_get_framebuffer_size(s, &w, &h); + assert(w == fw && h == fh); + assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0)); + assert(errno == EALREADY); + struct yasl_cpu_buffer buffer, other; + assert(yasl_cpu_acquire(s, &buffer) == 0); + uint32_t *pixels = buffer.pixels; + assert(buffer.width == w && buffer.height == h && buffer.stride_bytes == (size_t)w * 4); + assert(pixels[0] == 0 && pixels[(size_t)w * h - 1] == 0); + assert(yasl_cpu_acquire(s, &other) == -EBUSY && !other.pixels); + for (size_t i = 0; i < (size_t)w * h; i++) + pixels[i] = 0xff102030u; + pixels[(size_t)3 * w + 2] = 0xffaabbccu; + other = buffer; + other.stride_bytes++; + assert(yasl_cpu_present(s, &other) == -EINVAL); + assert(yasl_cpu_present(s, &buffer) == 0); + assert(yasl_cpu_present(s, &buffer) == -ESTALE); + assert(yasl_cpu_acquire(s, &buffer) == 0); + assert(buffer.pixels[0] == 0xff102030u && buffer.pixels[(size_t)3 * w + 2] == 0xffaabbccu); + buffer.pixels[0] = 0xffffffffu; + assert(s->committed_pixels[0] == 0xff102030u); + assert(yasl_cpu_discard(s, &buffer) == 0); + assert(yasl_cpu_discard(s, &buffer) == -ESTALE); + assert(yasl_cpu_acquire(s, &buffer) == 0 && buffer.pixels[0] == 0xff102030u); drain(); - pthread_t thread;assert(!pthread_create(&thread,NULL,wrong_thread,s));pthread_join(thread,NULL); - assert(!pthread_create(&thread,NULL,wake_thread,NULL)); - int n=yasl_wait_event(&e,500);assert(n>=0);pthread_join(thread,NULL); - bool ime=yasl_surface_set_text_input(s,true,YASL_TEXT_NORMAL); - if(!ime)assert(yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); - bool snapshot=yasl_surface_set_surrounding_text(s,"a\xc3\xa9z",4,1,3,7); - if(ime)assert(snapshot); - else assert(!snapshot&&yasl_get_error(NULL)==YASL_ERROR_UNSUPPORTED); - assert(!yasl_surface_set_surrounding_text(s,"a\xc3\xa9z",4,2,3,8)); - assert(!yasl_surface_set_surrounding_text(s,"\xc0\xaf",2,0,2,8)); + assert(yasl_cpu_present(s, &buffer) == -ESTALE); + yasl_surface *second = yasl_surface_create(&(struct yasl_surface_options){ + .width = 32, .height = 32, .type = YASL_SURFACE_CPU, .userdata = &backend}); + assert(second && yasl_surface_get_userdata(second) == &backend); + assert(yasl_cpu_acquire(s, &buffer) == 0); + assert(yasl_cpu_acquire(second, &other) == 0); + assert(yasl_cpu_present(second, &buffer) == -ESTALE); + assert(yasl_cpu_discard(second, &other) == 0); + assert(yasl_surface_destroy(second) == 0); + assert(yasl_cpu_discard(s, &buffer) == 0); + pthread_t thread; + assert(!pthread_create(&thread, NULL, wrong_thread, s)); + pthread_join(thread, NULL); + assert(!pthread_create(&thread, NULL, wake_thread, NULL)); + int n = yasl_wait_event(&e, 500); + assert(n >= 0); + pthread_join(thread, NULL); + bool ime = (yasl_surface_set_text_input(s, true, YASL_TEXT_NORMAL) == 0); + if (!ime) + assert(errno == ENOTSUP); + bool snapshot = (yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 1, 3, 7) == 0); + if (ime) + assert(snapshot); + else + assert(!snapshot && errno == ENOTSUP); + assert((yasl_surface_set_surrounding_text(s, "a\xc3\xa9z", 4, 2, 3, 8) < 0)); + assert((yasl_surface_set_surrounding_text(s, "\xc0\xaf", 2, 0, 2, 8) < 0)); drain(); - struct yasl_private_event pen={.type=YASL_PRIVATE_EVENT_PEN,.surface=s, - .pen={.device_id=10,.tool_id=20,.x=12.5,.y=9.25,.pressure=0.3, - .axes_valid=YASL_PRIVATE_PEN_PRESSURE,.action=YASL_PRIVATE_PEN_DOWN,.in_contact=true}}; - assert(yasl_private_events_push(s->display,s,&pen)); - assert(yasl_wait_event(&e,0)==1&&e.type==YASL_EVENT_PEN&&e.pen.device_id==10&&e.pen.pressure==0.3&&e.pen.in_contact); - struct yasl_private_event text={.type=YASL_PRIVATE_EVENT_TEXT,.surface=s,.text={.data="owned",.len=5}}; - assert(yasl_private_events_push(s->display,s,&text));assert(yasl_wait_event(&e,0)==1&&e.type==YASL_EVENT_TEXT); - assert(e.text.length==5&&!strcmp(e.text.data,"owned")); + struct yasl_private_event pen = {.type = YASL_PRIVATE_EVENT_PEN, + .surface = s, + .pen = {.device_id = 10, + .tool_id = 20, + .x = 12.5, + .y = 9.25, + .pressure = 0.3, + .axes_valid = YASL_PRIVATE_PEN_PRESSURE, + .action = YASL_PRIVATE_PEN_DOWN, + .in_contact = true}}; + assert(yasl_private_events_push(s->display, s, &pen)); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_PEN && e.pen.device_id == 10 && + e.pen.pressure == 0.3 && e.pen.in_contact); + struct yasl_private_event text = { + .type = YASL_PRIVATE_EVENT_TEXT, .surface = s, .text = {.data = "owned", .len = 5}}; + assert(yasl_private_events_push(s->display, s, &text)); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_TEXT); + assert(e.text.length == 5 && !strcmp(e.text.data, "owned")); /* Unchanged focus folds into no event; a change reports the activated state. */ - unsigned active=yasl_surface_state(s)&YASL_STATE_ACTIVATED; - struct yasl_private_event focus={.type=YASL_PRIVATE_EVENT_FOCUS,.surface=s,.focus={.focused=!active}}; - assert(yasl_private_events_push(s->display,s,&focus));assert(yasl_wait_event(&e,0)==1&&e.type==YASL_EVENT_WINDOW); - assert((e.window.state&YASL_STATE_ACTIVATED)==(active?0u:YASL_STATE_ACTIVATED)&&e.window.pixel_width==w); - assert(yasl_private_events_push(s->display,s,&focus));assert(yasl_wait_event(&e,0)==0&&e.type==YASL_EVENT_NONE); - struct yasl_private_event hover={.type=YASL_PRIVATE_EVENT_DROP_HOVER,.surface=s,.drop={YASL_PRIVATE_DROP_LEAVE,{0,0}}}; - assert(yasl_private_events_push(s->display,s,&hover)); - assert(yasl_wait_event(&e,0)==1&&e.type==YASL_EVENT_DROP&&e.drop.action==YASL_DROP_LEAVE); - yasl_surface_set_refresh_callback(s,refresh,NULL); - assert(yasl_cpu_present(s)); + unsigned active = yasl_surface_get_state(s) & YASL_STATE_ACTIVATED; + struct yasl_private_event focus = { + .type = YASL_PRIVATE_EVENT_FOCUS, .surface = s, .focus = {.focused = !active}}; + assert(yasl_private_events_push(s->display, s, &focus)); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_WINDOW); + assert((e.window.state & YASL_STATE_ACTIVATED) == (active ? 0u : YASL_STATE_ACTIVATED) && + e.window.pixel_width == w); + assert(yasl_private_events_push(s->display, s, &focus)); + assert(yasl_wait_event(&e, 0) == 0 && e.type == YASL_EVENT_NONE); + struct yasl_private_event hover = {.type = YASL_PRIVATE_EVENT_DROP_HOVER, + .surface = s, + .drop = {YASL_PRIVATE_DROP_LEAVE, {0, 0}}}; + assert(yasl_private_events_push(s->display, s, &hover)); + assert(yasl_wait_event(&e, 0) == 1 && e.type == YASL_EVENT_DROP && + e.drop.action == YASL_DROP_LEAVE); + assert(yasl_surface_request_size(s, 112, 96) == 0); + uint64_t resize_deadline = yasl_time_ns() + 3000000000ull; + int logical_w = 0, logical_h = 0; + do { + assert(yasl_wait_event(&e, 20) >= 0); + yasl_surface_get_size(s, &logical_w, &logical_h); + } while ((logical_w != 112 || logical_h != 96) && yasl_time_ns() < resize_deadline); + assert(logical_w == 112 && logical_h == 96); + assert(yasl_cpu_acquire(s, &buffer) == 0); + assert(buffer.pixels[0] == 0xff102030u); + assert(buffer.pixels[(size_t)3 * buffer.width + 2] == 0xffaabbccu); + assert(buffer.pixels[(size_t)buffer.width * buffer.height - 1] == 0); + assert(yasl_cpu_present(s, &buffer) == 0); + yasl_surface_set_refresh_callback(s, refresh, NULL); + assert(yasl_cpu_acquire(s, &buffer) == 0); + assert(yasl_cpu_present(s, &buffer) == 0); #if YASL_HAS_COCOA yasl_test_frame_tick(s); #endif - uint64_t deadline=yasl_private_loop_now_ns()+3000000000ull; - while(!refreshes && yasl_private_loop_now_ns()=0); - assert(refreshes>0); - yasl_surface_set_refresh_callback(s,NULL,NULL); + uint64_t deadline = yasl_private_loop_now_ns() + 3000000000ull; + while (!refreshes && yasl_private_loop_now_ns() < deadline) + assert(yasl_wait_event(&e, 20) >= 0); + assert(refreshes > 0); + yasl_surface_set_refresh_callback(s, NULL, NULL); yasl_surface_destroy(s); - assert(!yasl_set_backend(backend)); - s=yasl_surface_create("shared backend remains",64,64,YASL_SURFACE_CPU);assert(s); - yasl_shutdown();assert(yasl_set_backend(backend)); - s=yasl_surface_create("reinitialized",64,64,YASL_SURFACE_CPU);assert(s);yasl_shutdown(); - puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed");return 0; + assert((yasl_init(&(struct yasl_options){.backend = backend}) < 0)); + s = yasl_surface_create(&(struct yasl_surface_options){.title = "shared backend remains", + .width = 64, + .height = 64, + .type = YASL_SURFACE_CPU, + .flags = 0}); + assert(s); + yasl_shutdown(); + assert((yasl_init(&(struct yasl_options){.backend = backend}) == 0)); + s = yasl_surface_create(&(struct yasl_surface_options){ + .title = "reinitialized", .width = 64, .height = 64, .type = YASL_SURFACE_CPU, .flags = 0}); + assert(s); + yasl_shutdown(); + puts("public surface lifecycle, pixels, ownership, input, wake and refresh passed"); + return 0; } -- cgit v1.2.3