summaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2013-09-08 19:49:02 +0100
committerKristian Høgsberg <krh@bitplanet.net>2013-12-04 16:34:07 -0800
commit15a8d340fdadd4897dfcb102d6d7e3e097ad6d98 (patch)
treeb7ab7ab6fc4f143d707f155d4f9f64f35e51220f /clients
parent6bf23879e98c4bd8e30c28f3a5cd610ceb958da6 (diff)
nested: Add double-buffered state semantics to the nested example
The buffer and frame callback state on the surfaces in the nested compositor example are now double-buffered so that they only take effect when the commit request is received. This doesn't really make much difference for the current state that the example has but it will be useful when more state is added in later patches.
Diffstat (limited to 'clients')
-rw-r--r--clients/nested.c130
1 files changed, 103 insertions, 27 deletions
diff --git a/clients/nested.c b/clients/nested.c
index cf3a34e9..23be0e31 100644
--- a/clients/nested.c
+++ b/clients/nested.c
@@ -86,6 +86,16 @@ struct nested_surface {
GLuint texture;
struct wl_list link;
cairo_surface_t *cairo_surface;
+
+ struct {
+ /* wl_surface.attach */
+ int newly_attached;
+ struct nested_buffer *buffer;
+ struct wl_listener buffer_destroy_listener;
+
+ /* wl_surface.frame */
+ struct wl_list frame_callback_list;
+ } pending;
};
struct nested_frame_callback {
@@ -353,6 +363,11 @@ static void
destroy_surface(struct wl_resource *resource)
{
struct nested_surface *surface = wl_resource_get_user_data(resource);
+ struct nested_frame_callback *cb, *next;
+
+ wl_list_for_each_safe(cb, next,
+ &surface->pending.frame_callback_list, link)
+ wl_resource_destroy(cb->resource);
nested_buffer_reference(&surface->buffer_ref, NULL);
@@ -374,45 +389,75 @@ surface_attach(struct wl_client *client,
{
struct nested_surface *surface = wl_resource_get_user_data(resource);
struct nested *nested = surface->nested;
- EGLint format, width, height;
- cairo_device_t *device;
- struct nested_buffer *buffer =
- nested_buffer_from_resource(buffer_resource);
+ struct nested_buffer *buffer = NULL;
- nested_buffer_reference(&surface->buffer_ref, buffer);
+ if (buffer_resource) {
+ int format;
- if (!query_buffer(nested->egl_display, (void *) buffer_resource,
- EGL_TEXTURE_FORMAT, &format)) {
- fprintf(stderr, "attaching non-egl wl_buffer\n");
- return;
+ if (!query_buffer(nested->egl_display, (void *) buffer_resource,
+ EGL_TEXTURE_FORMAT, &format)) {
+ wl_resource_post_error(buffer_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "attaching non-egl wl_buffer");
+ return;
+ }
+
+ switch (format) {
+ case EGL_TEXTURE_RGB:
+ case EGL_TEXTURE_RGBA:
+ break;
+ default:
+ wl_resource_post_error(buffer_resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid format");
+ return;
+ }
+
+ buffer = nested_buffer_from_resource(buffer_resource);
+ if (buffer == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
}
+ if (surface->pending.buffer)
+ wl_list_remove(&surface->pending.buffer_destroy_listener.link);
+
+ surface->pending.buffer = buffer;
+ surface->pending.newly_attached = 1;
+ if (buffer) {
+ wl_signal_add(&buffer->destroy_signal,
+ &surface->pending.buffer_destroy_listener);
+ }
+}
+
+static void
+nested_surface_attach(struct nested_surface *surface,
+ struct nested_buffer *buffer)
+{
+ struct nested *nested = surface->nested;
+ EGLint width, height;
+ cairo_device_t *device;
+
+ nested_buffer_reference(&surface->buffer_ref, buffer);
+
if (surface->image != EGL_NO_IMAGE_KHR)
destroy_image(nested->egl_display, surface->image);
if (surface->cairo_surface)
cairo_surface_destroy(surface->cairo_surface);
- switch (format) {
- case EGL_TEXTURE_RGB:
- case EGL_TEXTURE_RGBA:
- break;
- default:
- fprintf(stderr, "unhandled format: %x\n", format);
- return;
- }
-
surface->image = create_image(nested->egl_display, NULL,
- EGL_WAYLAND_BUFFER_WL, buffer_resource,
+ EGL_WAYLAND_BUFFER_WL, buffer->resource,
NULL);
if (surface->image == EGL_NO_IMAGE_KHR) {
fprintf(stderr, "failed to create img\n");
return;
}
- query_buffer(nested->egl_display,
- (void *) buffer_resource, EGL_WIDTH, &width);
- query_buffer(nested->egl_display,
- (void *) buffer_resource, EGL_HEIGHT, &height);
+ query_buffer(nested->egl_display, (void *) buffer->resource,
+ EGL_WIDTH, &width);
+ query_buffer(nested->egl_display, (void *) buffer->resource,
+ EGL_HEIGHT, &height);
device = display_get_cairo_device(nested->display);
surface->cairo_surface =
@@ -420,8 +465,6 @@ surface_attach(struct wl_client *client,
CAIRO_CONTENT_COLOR_ALPHA,
surface->texture,
width, height);
-
- window_schedule_redraw(nested->window);
}
static void
@@ -446,7 +489,6 @@ surface_frame(struct wl_client *client,
{
struct nested_frame_callback *callback;
struct nested_surface *surface = wl_resource_get_user_data(resource);
- struct nested *nested = surface->nested;
callback = malloc(sizeof *callback);
if (callback == NULL) {
@@ -459,7 +501,8 @@ surface_frame(struct wl_client *client,
wl_resource_set_implementation(callback->resource, NULL, callback,
destroy_frame_callback);
- wl_list_insert(nested->frame_callback_list.prev, &callback->link);
+ wl_list_insert(surface->pending.frame_callback_list.prev,
+ &callback->link);
}
static void
@@ -481,6 +524,25 @@ surface_set_input_region(struct wl_client *client,
static void
surface_commit(struct wl_client *client, struct wl_resource *resource)
{
+ struct nested_surface *surface = wl_resource_get_user_data(resource);
+ struct nested *nested = surface->nested;
+
+ /* wl_surface.attach */
+ if (surface->pending.newly_attached)
+ nested_surface_attach(surface, surface->pending.buffer);
+
+ if (surface->pending.buffer) {
+ wl_list_remove(&surface->pending.buffer_destroy_listener.link);
+ surface->pending.buffer = NULL;
+ }
+ surface->pending.newly_attached = 0;
+
+ /* wl_surface.frame */
+ wl_list_insert_list(&nested->frame_callback_list,
+ &surface->pending.frame_callback_list);
+ wl_list_init(&surface->pending.frame_callback_list);
+
+ window_schedule_redraw(nested->window);
}
static void
@@ -502,6 +564,16 @@ static const struct wl_surface_interface surface_interface = {
};
static void
+surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct nested_surface *surface =
+ container_of(listener, struct nested_surface,
+ pending.buffer_destroy_listener);
+
+ surface->pending.buffer = NULL;
+}
+
+static void
compositor_create_surface(struct wl_client *client,
struct wl_resource *resource, uint32_t id)
{
@@ -516,6 +588,10 @@ compositor_create_surface(struct wl_client *client,
surface->nested = nested;
+ wl_list_init(&surface->pending.frame_callback_list);
+ surface->pending.buffer_destroy_listener.notify =
+ surface_handle_pending_buffer_destroy;
+
display_acquire_window_surface(nested->display,
nested->window, NULL);