diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 13:19:58 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 13:19:58 +0300 |
| commit | 3d012d707d0242780cd386868ab511846dc9b0af (patch) | |
| tree | 131e1621f400f78cba1541f2fbf9591ffcb4ce08 | |
| parent | 8d9ee60888e01e5d88c306afe0c77bad02a29e5b (diff) | |
Add damage presentation and reduce CPU surface latency
Add yasl_cpu_present_damage to submit partial damage rectangles.
Skip commit timers for CPU surfaces to prevent display delay.
Remove frame callback gating in surface_draw_frame when free buffers exist.
Flush the display immediately on CPU present.
Forward tearing option to window specifications.
| -rw-r--r-- | include/yasl/yasl.h | 6 | ||||
| -rw-r--r-- | src/common/backend.h | 1 | ||||
| -rw-r--r-- | src/common/surface.c | 22 | ||||
| -rw-r--r-- | src/platform/wayland/buffer.c | 4 |
4 files changed, 28 insertions, 5 deletions
diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 6d2b4f0..15bbe16 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -62,7 +62,7 @@ struct yasl_surface_options { const char *title; int width, height; /**< Required. */ enum yasl_surface_type type; - bool undecorated, fixed_size; + bool undecorated, fixed_size, tearing; void *userdata; /** Called when the window needs drawing while the system blocks the event * loop, as during a macOS live resize; draw and present before returning. @@ -281,8 +281,12 @@ YASL_API uint64_t yasl_time_ns(void); * 0xAARRGGBB pixels, rows tightly packed. They persist, and a resize keeps the * overlap and zeroes the rest. Valid until the next wait. Present to show them; * the system may also show them when it redraws the window. */ +struct yasl_damage { + int x, y, width, height; +}; YASL_API uint32_t *yasl_cpu_pixels(yasl_surface *surface, int *pixel_width, int *pixel_height); YASL_API int yasl_cpu_present(yasl_surface *surface); +YASL_API int yasl_cpu_present_damage(yasl_surface *surface, const struct yasl_damage *damage, int count); typedef void (*yasl_gl_proc)(void); /** These four may run on a rendering thread; synchronize them with destruction. diff --git a/src/common/backend.h b/src/common/backend.h index e26f9d2..b111d3e 100644 --- a/src/common/backend.h +++ b/src/common/backend.h @@ -38,6 +38,7 @@ struct yasl_surface { /* CPU canvas returned by yasl_cpu_pixels and copied into each drawn frame. */ uint32_t *canvas; int canvas_width, canvas_height; + struct yasl_private_damage_list cpu_damage; /* Window values last reported through public WINDOW events. */ struct yasl_private_vector2i reported_size; uint32_t reported_scale_120, reported_state; diff --git a/src/common/surface.c b/src/common/surface.c index fa8ee3d..aeca3d8 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -195,8 +195,9 @@ static void draw_canvas(yasl_surface *s, struct yasl_private_frame *frame, void if (!canvas_fit(s, w, h)) return; memcpy(frame->target.pixels, s->canvas, (size_t)w * (size_t)h * sizeof(uint32_t)); - struct yasl_private_damage_list damage = {.n = -1}; + struct yasl_private_damage_list damage = s->cpu_damage.n != 0 ? s->cpu_damage : (struct yasl_private_damage_list){.n = -1}; yasl_private_surface_present(s, &frame->target, &damage); + s->cpu_damage = (struct yasl_private_damage_list){0}; } static void register_surface(yasl_surface *s, unsigned flags, yasl_surface *parent, void *userdata) { @@ -279,6 +280,7 @@ yasl_surface *yasl_surface_create(const struct yasl_surface_options *o) .size = {o->width, o->height}, .flags = flags, .external_gpu = o->type != YASL_SURFACE_CPU, + .tearing = o->tearing, }; yasl_surface *s = o->type == YASL_SURFACE_GL ? create_gl(&spec, attrs, share) : yasl_private_surface_create_toplevel(display, &spec); @@ -936,7 +938,7 @@ uint32_t *yasl_cpu_pixels(yasl_surface *s, int *pw, int *ph) *ph = s->canvas_height; return s->canvas; } -int yasl_cpu_present(yasl_surface *s) +int yasl_cpu_present_damage(yasl_surface *s, const struct yasl_damage *damage, int count) { if (!yasl_public_connected(s)) return -errno; @@ -944,9 +946,25 @@ int yasl_cpu_present(yasl_surface *s) return yasl_public_error(ENOTSUP); if (!canvas_fit(s, s->size.x, s->size.y)) return -errno; + if (damage && count > 0) { + s->cpu_damage.n = count <= 16 ? count : 16; + for (int i = 0; i < s->cpu_damage.n; i++) { + s->cpu_damage.rects[i] = (struct yasl_private_rect2i){ + .x = damage[i].x, .y = damage[i].y, + .width = damage[i].width, .height = damage[i].height, + }; + } + } else { + s->cpu_damage.n = -1; + } yasl_private_surface_request_frame(s); + yasl_private_display_flush(s->display); return 0; } +int yasl_cpu_present(yasl_surface *s) +{ + return yasl_cpu_present_damage(s, NULL, 0); +} /* OpenGL; these may run on a rendering thread, so they read only immutable or atomic state. */ static bool gl_surface(yasl_surface *s) diff --git a/src/platform/wayland/buffer.c b/src/platform/wayland/buffer.c index b68621d..7ff4bd0 100644 --- a/src/platform/wayland/buffer.c +++ b/src/platform/wayland/buffer.c @@ -497,7 +497,7 @@ static void commit_buffer(struct wayland_surface *w, int idx) wp_fifo_v1_wait_barrier(w->fifo); wp_fifo_v1_set_barrier(w->fifo); } - if (w->commit_timer && w->conn->pres_clock_known) { + if (w->commit_timer && w->conn->pres_clock_known && w->base.presenter != YASL_PRIVATE_PRESENTER_CPU) { uint64_t now = yasl_private_loop_now_ns(); uint64_t next = yasl_private_clock_next_present_ns(&w->clock); bool soon = next > now && next - now < (uint64_t)(w->clock.refresh_ns * 1.5); @@ -558,7 +558,7 @@ void surface_draw_frame(struct wayland_surface *w) surface_fail(w); return; } - if (w->closed || !w->cbs->draw || w->frame_cb || !w->want_draw) + if (w->closed || !w->cbs->draw || !w->want_draw) return; int idx = buffer_pick_free_index(w->buffers, w->cur); |
