summaryrefslogtreecommitdiff
path: root/tests/common
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 17:12:10 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 17:12:10 +0300
commitb7944e4bbfa64a6bb1a1d9e1f172827dde53aed2 (patch)
treed73ff8e368039f67f824ad2dc9130643ef4947ae /tests/common
parentac6f9f5e7711521455b83ceb843a25e091646d43 (diff)
Read back the last presented CPU frame
wsap_term writes PNG screenshots for its debug server and keeps its own copy of the frame because YASL had no readback. yasl_surface_read_pixels() copies the frame from the last successful present, or reports its extent when the buffer is too small. X11 and Cocoa keep it in their single CPU target until the next draw starts; X11 now also forgets it when a resize replaces the target, and Cocoa records the presented extent because a resize can change the size before the next draw. Wayland remembers which buffer it committed and forgets it when a draw reuses that buffer. The backend test checks the copy on Wayland and X11, and that draws that never present do not show through. The Cocoa path is not built or run here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/common')
-rw-r--r--tests/common/test_backends.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/tests/common/test_backends.c b/tests/common/test_backends.c
index 74860c8..30f9b67 100644
--- a/tests/common/test_backends.c
+++ b/tests/common/test_backends.c
@@ -112,6 +112,15 @@ static void configure(struct yasl_surface *s, struct yasl_geometry geometry, voi
if (w->destroy_on_configure) { yasl_surface_destroy(s); w->surface = NULL; }
}
+static void draw_without_present(struct yasl_surface *s, struct yasl_frame *frame, void *ud)
+{
+ (void)s;
+ struct window *w = ud;
+ size_t count = (size_t)frame->target.size.x * (size_t)frame->target.size.y;
+ for (size_t i = 0; i < count; i++) frame->target.pixels[i] = 0xff000000;
+ w->draws++;
+}
+
static void close_window(struct yasl_surface *s, void *ud)
{
struct window *w = ud;
@@ -146,6 +155,48 @@ static struct window create(struct yasl_display *d)
return (struct window){.surface = s, .display = d};
}
+/* The last presented frame reads back until a later draw replaces it. */
+static void test_read_pixels(struct yasl_loop *loop, struct yasl_display *d, struct window *w)
+{
+ struct yasl_vector2i size = {-1, -1};
+ assert(!yasl_surface_read_pixels(w->surface, NULL, 0, NULL));
+ assert(!yasl_surface_read_pixels(NULL, NULL, 0, &size) && !size.x && !size.y);
+ assert(!yasl_surface_read_pixels(w->surface, NULL, 0, &size));
+ struct yasl_vector2i extent = yasl_surface_geometry(w->surface).size;
+ assert(size.x == extent.x && size.y == extent.y);
+ size_t count = (size_t)size.x * (size_t)size.y;
+ uint32_t *pixels = calloc(count, sizeof(*pixels));
+ assert(pixels);
+ assert(!yasl_surface_read_pixels(w->surface, pixels, count - 1, &size));
+ assert(!pixels[0]);
+ assert(yasl_surface_read_pixels(w->surface, pixels, count, &size));
+ for (size_t i = 0; i < count; i++) assert(pixels[i] == 0xff4080c0);
+
+ /* Draws that never present must not show through. X11 reuses its one
+ * target; Wayland keeps the presented buffer while the compositor holds it. */
+ struct yasl_window_cbs skip = callbacks;
+ skip.draw = draw_without_present;
+ yasl_surface_set_callbacks(w->surface, &skip, w);
+ for (int i = 0; i < 4; i++) {
+ yasl_surface_schedule_redraw(w->surface);
+ pump(loop, d, NULL);
+ if (yasl_surface_read_pixels(w->surface, pixels, count, &size)) {
+ assert(yasl_display_backend(d) != YASL_BACKEND_X11);
+ for (size_t j = 0; j < count; j++) assert(pixels[j] == 0xff4080c0);
+ } else {
+ assert(!size.x && !size.y);
+ }
+ }
+
+ attach(w);
+ yasl_surface_schedule_redraw(w->surface);
+ pump(loop, d, NULL);
+ memset(pixels, 0, count * sizeof(*pixels));
+ assert(yasl_surface_read_pixels(w->surface, pixels, count, &size));
+ assert(pixels[0] == 0xff4080c0 && pixels[count - 1] == 0xff4080c0);
+ free(pixels);
+}
+
static void test_window_spec(struct yasl_loop *loop, struct yasl_display *d)
{
struct window w = {.display = d, .destroy_on_draw = true};
@@ -427,6 +478,7 @@ int main(int argc, char **argv)
yasl_surface_schedule_redraw(w.surface);
pump(loop, d, NULL);
assert(w.draws > 0);
+ test_read_pixels(loop, d, &w);
if (yasl_display_backend(d) == YASL_BACKEND_X11)
x11_behavior(loop, d, &w);
if (w.surface) yasl_surface_destroy(w.surface);