mirror of
https://github.com/jjsullivan5196/wvkbd.git
synced 2025-06-02 04:04:23 +02:00
Implement double buffering
Until this point we was using one single buffer. This cause tearing when they are scanned while we are drawing. This refactorize our buffer and damage tracking to use two buffers. One buffer, the back_buffer, is our dirty area. The other one, the display_buffer, is left untouched. Now we only flip buffers on adequate moments, indicated by the compositor sending the frame callback event. We can draw multiple time between those events, and we store all damaged areas. We only schedule frame callbacks when needed, after storing a new damaged area. Once flipped, we backport the damaged area from the new display_buffer to the new back_buffer. Which generally means, for wvkbd, one rectangle for each one of the surf and popup_surf. Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
This commit is contained in:
parent
646d47d072
commit
686b27a72d
140
drw.c
140
drw.c
@ -6,34 +6,102 @@
|
||||
#include "shm_open.h"
|
||||
#include "math.h"
|
||||
|
||||
void drwsurf_handle_frame_cb(void* data, struct wl_callback* callback,
|
||||
uint32_t time)
|
||||
{
|
||||
struct drwsurf *ds = data;
|
||||
wl_callback_destroy(ds->frame_cb);
|
||||
ds->frame_cb = NULL;
|
||||
|
||||
cairo_rectangle_int_t r = {0};
|
||||
for (int i = 0; i < cairo_region_num_rectangles(ds->back_buffer->damage); i++) {
|
||||
cairo_region_get_rectangle(ds->back_buffer->damage, i, &r);
|
||||
wl_surface_damage(ds->surf, r.x, r.y, r.width, r.height);
|
||||
};
|
||||
|
||||
drwsurf_flip(ds);
|
||||
}
|
||||
|
||||
const struct wl_callback_listener frame_listener = {
|
||||
.done = drwsurf_handle_frame_cb
|
||||
};
|
||||
|
||||
void drwsurf_register_frame_cb(struct drwsurf *ds)
|
||||
{
|
||||
if (ds->frame_cb)
|
||||
return;
|
||||
if (!ds->attached)
|
||||
return;
|
||||
ds->frame_cb = wl_surface_frame(ds->surf);
|
||||
wl_callback_add_listener(ds->frame_cb, &frame_listener, ds);
|
||||
wl_surface_commit(ds->surf);
|
||||
}
|
||||
|
||||
void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
{
|
||||
cairo_rectangle_int_t rect = { x, y, w, h };
|
||||
cairo_region_union_rectangle(ds->back_buffer->damage, &rect);
|
||||
drwsurf_register_frame_cb(ds);
|
||||
}
|
||||
|
||||
void
|
||||
drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s)
|
||||
{
|
||||
if (ds->buf) {
|
||||
munmap(ds->pool_data, ds->size);
|
||||
wl_buffer_destroy(ds->buf);
|
||||
ds->buf = NULL;
|
||||
}
|
||||
|
||||
ds->scale = s;
|
||||
ds->width = ceil(w * s);
|
||||
ds->height = ceil(h * s);
|
||||
|
||||
setup_buffer(ds);
|
||||
setup_buffer(ds, ds->back_buffer);
|
||||
setup_buffer(ds, ds->display_buffer);
|
||||
}
|
||||
|
||||
void
|
||||
drwsurf_backport(struct drwsurf *ds)
|
||||
{
|
||||
cairo_save(ds->back_buffer->cairo);
|
||||
|
||||
cairo_scale(ds->back_buffer->cairo, 1/ds->scale, 1/ds->scale);
|
||||
cairo_set_operator(ds->back_buffer->cairo, CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
cairo_rectangle_int_t r = {0};
|
||||
for (int i = 0; i < cairo_region_num_rectangles(ds->display_buffer->damage); i++) {
|
||||
cairo_region_get_rectangle(ds->display_buffer->damage, i, &r);
|
||||
|
||||
cairo_set_source_surface(ds->back_buffer->cairo, ds->display_buffer->cairo_surf, 0, 0);
|
||||
cairo_rectangle(
|
||||
ds->back_buffer->cairo,
|
||||
r.x * ds->scale,
|
||||
r.y * ds->scale,
|
||||
r.width * ds->scale,
|
||||
r.height * ds->scale
|
||||
);
|
||||
cairo_fill(ds->back_buffer->cairo);
|
||||
};
|
||||
|
||||
cairo_restore(ds->back_buffer->cairo);
|
||||
cairo_region_subtract(ds->display_buffer->damage, ds->display_buffer->damage);
|
||||
}
|
||||
|
||||
void
|
||||
drwsurf_flip(struct drwsurf *ds)
|
||||
{
|
||||
wl_surface_attach(ds->surf, ds->buf, 0, 0);
|
||||
wl_surface_attach(ds->surf, ds->back_buffer->buf, 0, 0);
|
||||
wl_surface_commit(ds->surf);
|
||||
ds->attached = true;
|
||||
|
||||
struct drwbuf *tmp = ds->back_buffer;
|
||||
ds->back_buffer = ds->display_buffer;
|
||||
ds->display_buffer = tmp;
|
||||
|
||||
drwsurf_backport(ds);
|
||||
}
|
||||
|
||||
void
|
||||
drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
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,
|
||||
PangoFontDescription *font_description)
|
||||
{
|
||||
struct drwbuf *d = ds->back_buffer;
|
||||
|
||||
cairo_save(d->cairo);
|
||||
|
||||
@ -58,8 +126,10 @@ drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
}
|
||||
|
||||
void
|
||||
drw_do_clear(struct drwsurf *d, 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)
|
||||
{
|
||||
struct drwbuf *d = ds->back_buffer;
|
||||
|
||||
cairo_save(d->cairo);
|
||||
|
||||
cairo_set_operator(d->cairo, CAIRO_OPERATOR_CLEAR);
|
||||
@ -70,9 +140,11 @@ drw_do_clear(struct drwsurf *d, uint32_t x, uint32_t y, uint32_t w, uint32_t h)
|
||||
}
|
||||
|
||||
void
|
||||
drw_do_rectangle(struct drwsurf *d, 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)
|
||||
{
|
||||
struct drwbuf *d = ds->back_buffer;
|
||||
|
||||
cairo_save(d->cairo);
|
||||
|
||||
if (over) {
|
||||
@ -128,41 +200,55 @@ drw_over_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
}
|
||||
|
||||
uint32_t
|
||||
setup_buffer(struct drwsurf *drwsurf)
|
||||
setup_buffer(struct drwsurf *drwsurf, struct drwbuf *drwbuf)
|
||||
{
|
||||
int prev_size = drwbuf->size;
|
||||
int stride = drwsurf->width * 4;
|
||||
drwsurf->size = stride * drwsurf->height;
|
||||
drwbuf->size = stride * drwsurf->height;
|
||||
|
||||
int fd = allocate_shm_file(drwsurf->size);
|
||||
int fd = allocate_shm_file(drwbuf->size);
|
||||
if (fd == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
drwsurf->pool_data =
|
||||
mmap(NULL, drwsurf->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (drwsurf->pool_data == MAP_FAILED) {
|
||||
if (drwbuf->pool_data)
|
||||
munmap(drwbuf->pool_data, prev_size);
|
||||
drwbuf->pool_data =
|
||||
mmap(NULL, drwbuf->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (drwbuf->pool_data == MAP_FAILED) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (drwbuf->buf)
|
||||
wl_buffer_destroy(drwbuf->buf);
|
||||
struct wl_shm_pool *pool =
|
||||
wl_shm_create_pool(drwsurf->ctx->shm, fd, drwsurf->size);
|
||||
drwsurf->buf =
|
||||
wl_shm_create_pool(drwsurf->ctx->shm, fd, drwbuf->size);
|
||||
drwbuf->buf =
|
||||
wl_shm_pool_create_buffer(pool, 0, drwsurf->width, drwsurf->height,
|
||||
stride, WL_SHM_FORMAT_ARGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(fd);
|
||||
|
||||
cairo_surface_t *s = cairo_image_surface_create_for_data(
|
||||
drwsurf->pool_data, CAIRO_FORMAT_ARGB32, drwsurf->width,
|
||||
|
||||
if (drwbuf->cairo_surf)
|
||||
cairo_surface_destroy(drwbuf->cairo_surf);
|
||||
drwbuf->cairo_surf = cairo_image_surface_create_for_data(
|
||||
drwbuf->pool_data, CAIRO_FORMAT_ARGB32, drwsurf->width,
|
||||
drwsurf->height, stride);
|
||||
|
||||
drwsurf->cairo = cairo_create(s);
|
||||
cairo_scale(drwsurf->cairo, drwsurf->scale, drwsurf->scale);
|
||||
cairo_set_antialias(drwsurf->cairo, CAIRO_ANTIALIAS_NONE);
|
||||
drwsurf->layout = pango_cairo_create_layout(drwsurf->cairo);
|
||||
pango_layout_set_auto_dir(drwsurf->layout, false);
|
||||
cairo_save(drwsurf->cairo);
|
||||
if (drwbuf->damage)
|
||||
cairo_region_destroy(drwbuf->damage);
|
||||
drwbuf->damage = cairo_region_create();
|
||||
|
||||
if (drwbuf->cairo)
|
||||
cairo_destroy(drwbuf->cairo);
|
||||
drwbuf->cairo = cairo_create(drwbuf->cairo_surf);
|
||||
cairo_scale(drwbuf->cairo, drwsurf->scale, drwsurf->scale);
|
||||
cairo_set_antialias(drwbuf->cairo, CAIRO_ANTIALIAS_NONE);
|
||||
drwbuf->layout = pango_cairo_create_layout(drwbuf->cairo);
|
||||
pango_layout_set_auto_dir(drwbuf->layout, false);
|
||||
cairo_save(drwbuf->cairo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
33
drw.h
33
drw.h
@ -7,21 +7,32 @@
|
||||
struct drw {
|
||||
struct wl_shm *shm;
|
||||
};
|
||||
struct drwbuf {
|
||||
uint32_t size;
|
||||
struct wl_buffer *buf;
|
||||
cairo_region_t *damage;
|
||||
cairo_surface_t *cairo_surf;
|
||||
cairo_t *cairo;
|
||||
PangoLayout *layout;
|
||||
unsigned char *pool_data;
|
||||
};
|
||||
struct drwsurf {
|
||||
uint32_t width, height, size;
|
||||
uint32_t width, height;
|
||||
double scale;
|
||||
|
||||
struct drw *ctx;
|
||||
struct wl_surface *surf;
|
||||
struct wl_buffer *buf;
|
||||
struct wl_shm *shm;
|
||||
unsigned char *pool_data;
|
||||
struct wl_callback *frame_cb;
|
||||
|
||||
cairo_t *cairo;
|
||||
PangoLayout *layout;
|
||||
bool attached;
|
||||
|
||||
struct drwbuf *back_buffer;
|
||||
struct drwbuf *display_buffer;
|
||||
};
|
||||
struct kbd;
|
||||
|
||||
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_flip(struct drwsurf *ds);
|
||||
|
||||
@ -30,19 +41,19 @@ typedef union {
|
||||
uint32_t color;
|
||||
} Color;
|
||||
|
||||
void drw_do_clear(struct drwsurf *d, uint32_t x, uint32_t y,
|
||||
void drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h);
|
||||
void drw_do_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
void drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h, bool fill, int rounding);
|
||||
void drw_fill_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
void drw_fill_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h, int rounding);
|
||||
void drw_over_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
void drw_over_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y,
|
||||
uint32_t w, uint32_t h, int rounding);
|
||||
|
||||
void drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y,
|
||||
void 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,
|
||||
PangoFontDescription *font_description);
|
||||
|
||||
uint32_t setup_buffer(struct drwsurf *drwsurf);
|
||||
uint32_t setup_buffer(struct drwsurf *ds, struct drwbuf *db);
|
||||
|
||||
#endif
|
||||
|
25
keyboard.c
25
keyboard.c
@ -337,10 +337,7 @@ kbd_release_key(struct kbd *kb, uint32_t time)
|
||||
kb->last_swipe = NULL;
|
||||
}
|
||||
|
||||
drwsurf_flip(kb->surf);
|
||||
|
||||
kbd_clear_last_popup(kb);
|
||||
drwsurf_flip(kb->popup_surf);
|
||||
}
|
||||
|
||||
void
|
||||
@ -366,10 +363,7 @@ kbd_motion_key(struct kbd *kb, uint32_t time, uint32_t x, uint32_t y)
|
||||
kbd_unpress_key(kb, time);
|
||||
}
|
||||
|
||||
drwsurf_flip(kb->surf);
|
||||
|
||||
kbd_clear_last_popup(kb);
|
||||
drwsurf_flip(kb->popup_surf);
|
||||
}
|
||||
|
||||
void
|
||||
@ -501,9 +495,6 @@ kbd_press_key(struct kbd *kb, struct key *k, uint32_t time)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
drwsurf_flip(kb->surf);
|
||||
drwsurf_flip(kb->popup_surf);
|
||||
}
|
||||
|
||||
void
|
||||
@ -553,8 +544,13 @@ kbd_clear_last_popup(struct kbd *kb)
|
||||
if (kb->last_popup_w && kb->last_popup_h) {
|
||||
drw_do_clear(kb->popup_surf, kb->last_popup_x, kb->last_popup_y,
|
||||
kb->last_popup_w, kb->last_popup_h);
|
||||
wl_surface_damage(kb->popup_surf->surf, kb->last_popup_x,
|
||||
kb->last_popup_y, kb->last_popup_w, kb->last_popup_h);
|
||||
drwsurf_damage(
|
||||
kb->popup_surf,
|
||||
kb->last_popup_x,
|
||||
kb->last_popup_y,
|
||||
kb->last_popup_w,
|
||||
kb->last_popup_h
|
||||
);
|
||||
|
||||
kb->last_popup_w = kb->last_popup_h = 0;
|
||||
}
|
||||
@ -588,7 +584,7 @@ kbd_draw_key(struct kbd *kb, struct key *k, enum key_draw_type type)
|
||||
|
||||
drw_draw_text(kb->surf, scheme->text, k->x, k->y, k->w, k->h,
|
||||
KBD_KEY_BORDER, label, scheme->font_description);
|
||||
wl_surface_damage(kb->surf->surf, k->x, k->y, k->w, k->h);
|
||||
drwsurf_damage(kb->surf, k->x, k->y, k->w, k->h);
|
||||
|
||||
if (type == Press || type == Unpress) {
|
||||
kbd_clear_last_popup(kb);
|
||||
@ -605,8 +601,7 @@ kbd_draw_key(struct kbd *kb, struct key *k, enum key_draw_type type)
|
||||
drw_draw_text(kb->popup_surf, scheme->text, k->x, kb->last_popup_y,
|
||||
k->w, k->h, KBD_KEY_BORDER, label,
|
||||
scheme->font_description);
|
||||
wl_surface_damage(kb->popup_surf->surf, k->x, kb->last_popup_y, k->w,
|
||||
k->h);
|
||||
drwsurf_damage(kb->popup_surf, k->x, kb->last_popup_y, k->w, k->h);
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,7 +628,7 @@ kbd_draw_layout(struct kbd *kb)
|
||||
}
|
||||
next_key++;
|
||||
}
|
||||
wl_surface_damage(d->surf, 0, 0, kb->w, kb->h);
|
||||
drwsurf_damage(d, 0, 0, kb->w, kb->h);
|
||||
}
|
||||
|
||||
void
|
||||
|
6
main.c
6
main.c
@ -62,6 +62,7 @@ static int wl_outputs_size;
|
||||
|
||||
/* drawing */
|
||||
static struct drw draw_ctx;
|
||||
static struct drwbuf draw_surf_back_buffer, draw_surf_display_buffer, popup_draw_surf_back_buffer, popup_draw_surf_display_buffer;
|
||||
static struct drwsurf draw_surf, popup_draw_surf;
|
||||
|
||||
/* layer surface parameters */
|
||||
@ -332,7 +333,6 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
||||
}
|
||||
|
||||
kbd_next_layer(&keyboard, NULL, (value >= 0));
|
||||
drwsurf_flip(keyboard.surf);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1018,7 +1018,11 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
draw_surf.ctx = &draw_ctx;
|
||||
draw_surf.back_buffer = &draw_surf_back_buffer;
|
||||
draw_surf.display_buffer = &draw_surf_display_buffer;
|
||||
popup_draw_surf.ctx = &draw_ctx;
|
||||
popup_draw_surf.back_buffer = &popup_draw_surf_back_buffer;
|
||||
popup_draw_surf.display_buffer = &popup_draw_surf_display_buffer;
|
||||
keyboard.surf = &draw_surf;
|
||||
keyboard.popup_surf = &popup_draw_surf;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user