Optimize the backporting condition

At the moment we flip the two buffers, and we backport the damaged
area on every frame callback. We completely ignore the compositor
sent event buffer->release. This event means that the compositor
finished reading the buffer pixels, and will never read them again. So
we can keep using the same buffer instead of fliping, if we receive the
event before asking for a new frame callback.

The change is not complicated, but we have to distinguish
drwsurf_attach, and drwsurf_flip. We try to flip before trying to
draw anything. And if the buffer has already been released, we don't
flip.

We also have to track the backport_damage separately than the buffer
current damage.

Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
This commit is contained in:
Willow Barraco 2025-04-17 17:58:38 +02:00 committed by Maarten van Gompel
parent 686b27a72d
commit 55b88bc14f
3 changed files with 39 additions and 11 deletions

42
drw.c
View File

@ -6,6 +6,15 @@
#include "shm_open.h" #include "shm_open.h"
#include "math.h" #include "math.h"
void drwbuf_handle_release(void *data, struct wl_buffer *wl_buffer) {
struct drwbuf *db = data;
db->released = true;
};
const struct wl_buffer_listener buffer_listener = {
.release = drwbuf_handle_release
};
void drwsurf_handle_frame_cb(void* data, struct wl_callback* callback, void drwsurf_handle_frame_cb(void* data, struct wl_callback* callback,
uint32_t time) uint32_t time)
{ {
@ -18,8 +27,9 @@ void drwsurf_handle_frame_cb(void* data, struct wl_callback* callback,
cairo_region_get_rectangle(ds->back_buffer->damage, i, &r); cairo_region_get_rectangle(ds->back_buffer->damage, i, &r);
wl_surface_damage(ds->surf, r.x, r.y, r.width, r.height); wl_surface_damage(ds->surf, r.x, r.y, r.width, r.height);
}; };
cairo_region_subtract(ds->display_buffer->damage, ds->display_buffer->damage);
drwsurf_flip(ds); drwsurf_attach(ds);
} }
const struct wl_callback_listener frame_listener = { const struct wl_callback_listener frame_listener = {
@ -41,6 +51,7 @@ void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint
{ {
cairo_rectangle_int_t rect = { x, y, w, h }; cairo_rectangle_int_t rect = { x, y, w, h };
cairo_region_union_rectangle(ds->back_buffer->damage, &rect); cairo_region_union_rectangle(ds->back_buffer->damage, &rect);
cairo_region_union_rectangle(ds->back_buffer->backport_damage, &rect);
drwsurf_register_frame_cb(ds); drwsurf_register_frame_cb(ds);
} }
@ -64,8 +75,8 @@ drwsurf_backport(struct drwsurf *ds)
cairo_set_operator(ds->back_buffer->cairo, CAIRO_OPERATOR_SOURCE); cairo_set_operator(ds->back_buffer->cairo, CAIRO_OPERATOR_SOURCE);
cairo_rectangle_int_t r = {0}; cairo_rectangle_int_t r = {0};
for (int i = 0; i < cairo_region_num_rectangles(ds->display_buffer->damage); i++) { for (int i = 0; i < cairo_region_num_rectangles(ds->display_buffer->backport_damage); i++) {
cairo_region_get_rectangle(ds->display_buffer->damage, i, &r); cairo_region_get_rectangle(ds->display_buffer->backport_damage, i, &r);
cairo_set_source_surface(ds->back_buffer->cairo, ds->display_buffer->cairo_surf, 0, 0); cairo_set_source_surface(ds->back_buffer->cairo, ds->display_buffer->cairo_surf, 0, 0);
cairo_rectangle( cairo_rectangle(
@ -79,16 +90,23 @@ drwsurf_backport(struct drwsurf *ds)
}; };
cairo_restore(ds->back_buffer->cairo); cairo_restore(ds->back_buffer->cairo);
cairo_region_subtract(ds->display_buffer->damage, ds->display_buffer->damage); cairo_region_subtract(ds->display_buffer->backport_damage, ds->display_buffer->backport_damage);
}
void
drwsurf_attach(struct drwsurf *ds)
{
wl_surface_attach(ds->surf, ds->back_buffer->buf, 0, 0);
wl_surface_commit(ds->surf);
ds->back_buffer->released = false;
ds->attached = true;
} }
void void
drwsurf_flip(struct drwsurf *ds) drwsurf_flip(struct drwsurf *ds)
{ {
wl_surface_attach(ds->surf, ds->back_buffer->buf, 0, 0); if (ds->back_buffer->released)
wl_surface_commit(ds->surf); return;
ds->attached = true;
struct drwbuf *tmp = ds->back_buffer; struct drwbuf *tmp = ds->back_buffer;
ds->back_buffer = ds->display_buffer; ds->back_buffer = ds->display_buffer;
ds->display_buffer = tmp; ds->display_buffer = tmp;
@ -101,6 +119,7 @@ drw_draw_text(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
uint32_t w, uint32_t h, uint32_t b, const char *label, uint32_t w, uint32_t h, uint32_t b, const char *label,
PangoFontDescription *font_description) PangoFontDescription *font_description)
{ {
drwsurf_flip(ds);
struct drwbuf *d = ds->back_buffer; struct drwbuf *d = ds->back_buffer;
cairo_save(d->cairo); cairo_save(d->cairo);
@ -128,6 +147,7 @@ drw_draw_text(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
void void
drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h) drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{ {
drwsurf_flip(ds);
struct drwbuf *d = ds->back_buffer; struct drwbuf *d = ds->back_buffer;
cairo_save(d->cairo); cairo_save(d->cairo);
@ -143,6 +163,7 @@ void
drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
uint32_t w, uint32_t h, bool over, int rounding) uint32_t w, uint32_t h, bool over, int rounding)
{ {
drwsurf_flip(ds);
struct drwbuf *d = ds->back_buffer; struct drwbuf *d = ds->back_buffer;
cairo_save(d->cairo); cairo_save(d->cairo);
@ -229,6 +250,8 @@ setup_buffer(struct drwsurf *drwsurf, struct drwbuf *drwbuf)
stride, WL_SHM_FORMAT_ARGB8888); stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
close(fd); close(fd);
wl_buffer_add_listener(drwbuf->buf, &buffer_listener, drwbuf);
drwbuf->released = true;
if (drwbuf->cairo_surf) if (drwbuf->cairo_surf)
@ -240,6 +263,9 @@ setup_buffer(struct drwsurf *drwsurf, struct drwbuf *drwbuf)
if (drwbuf->damage) if (drwbuf->damage)
cairo_region_destroy(drwbuf->damage); cairo_region_destroy(drwbuf->damage);
drwbuf->damage = cairo_region_create(); drwbuf->damage = cairo_region_create();
if (drwbuf->backport_damage)
cairo_region_destroy(drwbuf->backport_damage);
drwbuf->backport_damage = cairo_region_create();
if (drwbuf->cairo) if (drwbuf->cairo)
cairo_destroy(drwbuf->cairo); cairo_destroy(drwbuf->cairo);

4
drw.h
View File

@ -10,11 +10,12 @@ struct drw {
struct drwbuf { struct drwbuf {
uint32_t size; uint32_t size;
struct wl_buffer *buf; struct wl_buffer *buf;
cairo_region_t *damage; cairo_region_t *damage, *backport_damage;
cairo_surface_t *cairo_surf; cairo_surface_t *cairo_surf;
cairo_t *cairo; cairo_t *cairo;
PangoLayout *layout; PangoLayout *layout;
unsigned char *pool_data; unsigned char *pool_data;
bool released;
}; };
struct drwsurf { struct drwsurf {
uint32_t width, height; uint32_t width, height;
@ -34,6 +35,7 @@ struct kbd;
void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h); void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s); void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s);
void drwsurf_attach(struct drwsurf *ds);
void drwsurf_flip(struct drwsurf *ds); void drwsurf_flip(struct drwsurf *ds);
typedef union { typedef union {

4
main.c
View File

@ -517,7 +517,7 @@ xdg_popup_surface_configure(void *data, struct xdg_surface *xdg_surface,
{ {
xdg_surface_ack_configure(xdg_surface, serial); xdg_surface_ack_configure(xdg_surface, serial);
popup_xdg_surface_configured = true; popup_xdg_surface_configured = true;
drwsurf_flip(&popup_draw_surf); drwsurf_attach(&popup_draw_surf);
} }
static const struct xdg_surface_listener xdg_popup_surface_listener = { static const struct xdg_surface_listener xdg_popup_surface_listener = {
@ -664,7 +664,7 @@ layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
kbd_resize(&keyboard, layouts, NumLayouts); kbd_resize(&keyboard, layouts, NumLayouts);
drwsurf_flip(&draw_surf); drwsurf_attach(&draw_surf);
} else { } else {
zwlr_layer_surface_v1_ack_configure(surface, serial); zwlr_layer_surface_v1_ack_configure(surface, serial);
} }