simple-shm: honour wl_buffer.release

Change simple-shm to properly process the wl_buffer.release event, and
not reuse a buffer until it is released by the server, as specified in
the protocol.

In case the server has not released the buffer, but signals that it has
been shown (frame callback), allocate a second buffer. Simple-shm will
now automatically do double-buffering if needed.

Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
Pekka Paalanen 12 years ago committed by Kristian Høgsberg
parent edce9c295c
commit 99b705bb17
  1. 113
      clients/simple-shm.c

@ -42,22 +42,39 @@ struct display {
uint32_t formats; uint32_t formats;
}; };
struct buffer {
struct wl_buffer *buffer;
void *shm_data;
int busy;
};
struct window { struct window {
struct display *display; struct display *display;
int width, height; int width, height;
struct wl_surface *surface; struct wl_surface *surface;
struct wl_shell_surface *shell_surface; struct wl_shell_surface *shell_surface;
struct wl_buffer *buffer; struct buffer buffers[2];
void *shm_data; struct buffer *prev_buffer;
struct wl_callback *callback; struct wl_callback *callback;
}; };
static struct wl_buffer * static void
create_shm_buffer(struct display *display, buffer_release(void *data, struct wl_buffer *buffer)
int width, int height, uint32_t format, void **data_out) {
struct buffer *mybuf = data;
mybuf->busy = 0;
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release
};
static int
create_shm_buffer(struct display *display, struct buffer *buffer,
int width, int height, uint32_t format)
{ {
struct wl_shm_pool *pool; struct wl_shm_pool *pool;
struct wl_buffer *buffer;
int fd, size, stride; int fd, size, stride;
void *data; void *data;
@ -68,25 +85,27 @@ create_shm_buffer(struct display *display,
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "creating a buffer file for %d B failed: %m\n", fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size); size);
return NULL; return -1;
} }
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) { if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n"); fprintf(stderr, "mmap failed: %m\n");
close(fd); close(fd);
return NULL; return -1;
} }
pool = wl_shm_create_pool(display->shm, fd, size); pool = wl_shm_create_pool(display->shm, fd, size);
buffer = wl_shm_pool_create_buffer(pool, 0, buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
width, height, stride, format); width, height,
stride, format);
wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool); wl_shm_pool_destroy(pool);
close(fd); close(fd);
*data_out = data; buffer->shm_data = data;
return buffer; return 0;
} }
static void static void
@ -117,18 +136,10 @@ static struct window *
create_window(struct display *display, int width, int height) create_window(struct display *display, int width, int height)
{ {
struct window *window; struct window *window;
window = malloc(sizeof *window);
window->buffer = create_shm_buffer(display,
width, height,
WL_SHM_FORMAT_XRGB8888,
&window->shm_data);
if (!window->buffer) { window = calloc(1, sizeof *window);
free(window); if (!window)
return NULL; return NULL;
}
window->callback = NULL; window->callback = NULL;
window->display = display; window->display = display;
@ -155,12 +166,45 @@ destroy_window(struct window *window)
if (window->callback) if (window->callback)
wl_callback_destroy(window->callback); wl_callback_destroy(window->callback);
wl_buffer_destroy(window->buffer); if (window->buffers[0].buffer)
wl_buffer_destroy(window->buffers[0].buffer);
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);
wl_shell_surface_destroy(window->shell_surface); wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface); wl_surface_destroy(window->surface);
free(window); free(window);
} }
static struct buffer *
window_next_buffer(struct window *window)
{
struct buffer *buffer;
int ret = 0;
if (!window->buffers[0].busy)
buffer = &window->buffers[0];
else if (!window->buffers[1].busy)
buffer = &window->buffers[1];
else
return NULL;
if (!buffer->buffer) {
ret = create_shm_buffer(window->display, buffer,
window->width, window->height,
WL_SHM_FORMAT_XRGB8888);
if (ret < 0)
return NULL;
/* paint the padding */
memset(buffer->shm_data, 0xff,
window->width * window->height * 4);
}
return buffer;
}
static void static void
paint_pixels(void *image, int padding, int width, int height, uint32_t time) paint_pixels(void *image, int padding, int width, int height, uint32_t time)
{ {
@ -213,8 +257,23 @@ static void
redraw(void *data, struct wl_callback *callback, uint32_t time) redraw(void *data, struct wl_callback *callback, uint32_t time)
{ {
struct window *window = data; struct window *window = data;
struct buffer *buffer;
buffer = window_next_buffer(window);
if (!buffer) {
fprintf(stderr,
!callback ? "Failed to create the first buffer.\n" :
"Both buffers busy at redraw(). Server bug?\n");
abort();
}
paint_pixels(buffer->shm_data, 20, window->width, window->height, time);
if (window->prev_buffer != buffer) {
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
window->prev_buffer = buffer;
}
paint_pixels(window->shm_data, 20, window->width, window->height, time);
wl_surface_damage(window->surface, wl_surface_damage(window->surface,
20, 20, window->width - 40, window->height - 40); 20, 20, window->width - 40, window->height - 40);
@ -224,6 +283,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
window->callback = wl_surface_frame(window->surface); window->callback = wl_surface_frame(window->surface);
wl_callback_add_listener(window->callback, &frame_listener, window); wl_callback_add_listener(window->callback, &frame_listener, window);
wl_surface_commit(window->surface); wl_surface_commit(window->surface);
buffer->busy = 1;
} }
static const struct wl_callback_listener frame_listener = { static const struct wl_callback_listener frame_listener = {
@ -340,8 +400,9 @@ main(int argc, char **argv)
sigint.sa_flags = SA_RESETHAND; sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL); sigaction(SIGINT, &sigint, NULL);
memset(window->shm_data, 0xff, window->width * window->height * 4); /* Initialise damage to full surface, so the padding gets painted */
wl_surface_attach(window->surface, window->buffer, 0, 0); wl_surface_damage(window->surface, 0, 0,
window->width, window->height);
redraw(window, NULL, 0); redraw(window, NULL, 0);

Loading…
Cancel
Save