From b7944e4bbfa64a6bb1a1d9e1f172827dde53aed2 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 17:12:10 +0300 Subject: 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 --- src/platform/wayland/buffer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/platform/wayland/buffer.c') diff --git a/src/platform/wayland/buffer.c b/src/platform/wayland/buffer.c index f5a2c0f..b906f4f 100644 --- a/src/platform/wayland/buffer.c +++ b/src/platform/wayland/buffer.c @@ -472,9 +472,20 @@ bool wayland_surface_present(struct wayland_surface *w, const struct yasl_frameb return false; commit_buffer(w, w->cur); w->frame_presented = true; + w->shown = w->cur; + w->has_shown = true; return true; } +bool wayland_surface_read_pixels(struct wayland_surface *w, uint32_t *out, size_t cap, + struct yasl_vector2i *size) +{ + if (!w || w->closed || w->frame_active || !w->has_shown) return false; + const struct buffer *b = &w->buffers[w->shown]; + if (!b->pixels) return false; + return yasl_copy_frame(b->pixels, (struct yasl_vector2i){b->width, b->height}, out, cap, size); +} + void surface_draw_frame(struct wayland_surface *w) { if (w->closed || !w->configured) @@ -491,6 +502,9 @@ void surface_draw_frame(struct wayland_surface *w) w->frames_skipped++; return; } + /* Drawing reuses the presented buffer only after the compositor released it. */ + if (w->has_shown && idx == w->shown) + w->has_shown = false; if (buffer_prepare(w, &w->buffers[idx], w->width, w->height, &buffer_listener) < 0) { w->frames_skipped++; return; -- cgit v1.2.3