From 1ad0e81b7bc9b0e9bb4f28192f09744546d25af7 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 27 Jun 2013 14:22:41 +0100 Subject: [PATCH] wayland-server: Update because wl_shm_buffer is no longer a wl_buffer The Wayland server API has changed so that wl_shm_buffer is no longer a type of wl_buffer and it instead must be retrieved directly from the resource. cogl_wayland_texture_2d_new_from_buffer now takes a resource pointer instead of directly taking a wl_buffer and it will do different things depending on whether it can get a wl_shm_buffer out of the resource instead of trying to query the buffer type. Cogland has also been updated so that it tracks a resource for buffers of surfaces instead of directly tracking a wl_buffer. This are pointed to by a new CoglandBuffer struct which can be referenced by a CoglandBufferReference. The WL_BUFFER_RELEASE event will be posted when the last reference to the buffer is removed instead of directly whenever a new buffer is attached. This is similar to how Weston works. https://bugzilla.gnome.org/show_bug.cgi?id=702999 Reviewed-by: Robert Bragg (cherry picked from commit 9b35e1651ad0e46ed489893b60563e2c25457701) Conflicts: examples/cogland.c --- cogl/cogl-texture-2d.c | 107 ++++++++------- cogl/cogl-wayland-server.h | 8 +- examples/cogland.c | 265 +++++++++++++++++++++++-------------- 3 files changed, 232 insertions(+), 148 deletions(-) diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index e0998e131..d8c293901 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -259,18 +259,22 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx, #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, - struct wl_buffer *buffer, + struct wl_resource *buffer_resource, CoglError **error) { - int format; + struct wl_shm_buffer *shm_buffer; - if (wl_buffer_is_shm (buffer)) + shm_buffer = wl_shm_buffer_get (buffer_resource); + + if (shm_buffer) { - int stride = wl_shm_buffer_get_stride (buffer); + int stride = wl_shm_buffer_get_stride (shm_buffer); CoglPixelFormat format; CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; + int width = wl_shm_buffer_get_width (shm_buffer); + int height = wl_shm_buffer_get_height (shm_buffer); - switch (wl_shm_buffer_get_format (buffer)) + switch (wl_shm_buffer_get_format (shm_buffer)) { #if G_BYTE_ORDER == G_BIG_ENDIAN case WL_SHM_FORMAT_ARGB8888: @@ -295,55 +299,68 @@ cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, } return cogl_texture_2d_new_from_data (ctx, - buffer->width, - buffer->height, + width, height, format, internal_format, stride, - wl_shm_buffer_get_data (buffer), + wl_shm_buffer_get_data (shm_buffer), error); } - else if (_cogl_egl_query_wayland_buffer (ctx, buffer, - EGL_TEXTURE_FORMAT, - &format)) + else { - EGLImageKHR image; - CoglTexture2D *tex = NULL; - CoglPixelFormat internal_format; + struct wl_buffer *buffer = (struct wl_buffer *) buffer_resource; + int format, width, height; - _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & - COGL_RENDERER_CONSTRAINT_USES_EGL, - NULL); - - switch (format) + if (_cogl_egl_query_wayland_buffer (ctx, + buffer, + EGL_TEXTURE_FORMAT, + &format) && + _cogl_egl_query_wayland_buffer (ctx, + buffer, + EGL_WIDTH, + &width) && + _cogl_egl_query_wayland_buffer (ctx, + buffer, + EGL_HEIGHT, + &height)) { - case EGL_TEXTURE_RGB: - internal_format = COGL_PIXEL_FORMAT_RGB_888; - break; - case EGL_TEXTURE_RGBA: - internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; - break; - default: - _cogl_set_error (error, - COGL_SYSTEM_ERROR, - COGL_SYSTEM_ERROR_UNSUPPORTED, - "Can't create texture from unknown " - "wayland buffer format %d\n", format); - return NULL; - } + EGLImageKHR image; + CoglTexture2D *tex = NULL; + CoglPixelFormat internal_format; - image = _cogl_egl_create_image (ctx, - EGL_WAYLAND_BUFFER_WL, - buffer, - NULL); - tex = _cogl_egl_texture_2d_new_from_image (ctx, - buffer->width, - buffer->height, - internal_format, - image, - error); - _cogl_egl_destroy_image (ctx, image); - return tex; + _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints & + COGL_RENDERER_CONSTRAINT_USES_EGL, + NULL); + + switch (format) + { + case EGL_TEXTURE_RGB: + internal_format = COGL_PIXEL_FORMAT_RGB_888; + break; + case EGL_TEXTURE_RGBA: + internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; + break; + default: + _cogl_set_error (error, + COGL_SYSTEM_ERROR, + COGL_SYSTEM_ERROR_UNSUPPORTED, + "Can't create texture from unknown " + "wayland buffer format %d\n", format); + return NULL; + } + + image = _cogl_egl_create_image (ctx, + EGL_WAYLAND_BUFFER_WL, + buffer, + NULL); + tex = _cogl_egl_texture_2d_new_from_image (ctx, + width, height, + internal_format, + image, + error); + _cogl_egl_destroy_image (ctx, image); + return tex; + } } _cogl_set_error (error, diff --git a/cogl/cogl-wayland-server.h b/cogl/cogl-wayland-server.h index 567a9f97f..e56f5bd96 100644 --- a/cogl/cogl-wayland-server.h +++ b/cogl/cogl-wayland-server.h @@ -51,10 +51,12 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display, /** * cogl_wayland_texture_2d_new_from_buffer: * @ctx: A #CoglContext - * @buffer: A Wayland buffer + * @buffer: A Wayland resource for a buffer * @error: A #CoglError for exceptions * - * Uploads the given Wayland @buffer to a #CoglTexture2D. + * Uploads the @buffer referenced by the given Wayland resource to a + * #CoglTexture2D. The buffer resource may refer to a wl_buffer or a + * wl_shm_buffer. * * The results are undefined for passing an invalid @buffer * pointer @@ -74,7 +76,7 @@ cogl_wayland_display_set_compositor_display (CoglDisplay *display, */ CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, - struct wl_buffer *buffer, + struct wl_resource *buffer, CoglError **error); COGL_END_DECLS diff --git a/examples/cogland.c b/examples/cogland.c index 77aa6f7e7..b0471ec93 100644 --- a/examples/cogland.c +++ b/examples/cogland.c @@ -21,6 +21,28 @@ typedef struct CoglandRegion region; } CoglandSharedRegion; +typedef struct +{ + struct wl_resource *resource; + struct wl_signal destroy_signal; + struct wl_listener destroy_listener; + + union + { + struct wl_shm_buffer *shm_buffer; + struct wl_buffer *legacy_buffer; + }; + + int32_t width, height; + uint32_t busy_count; +} CoglandBuffer; + +typedef struct +{ + CoglandBuffer *buffer; + struct wl_listener destroy_listener; +} CoglandBufferReference; + typedef struct { CoglandCompositor *compositor; @@ -28,8 +50,7 @@ typedef struct struct wl_resource resource; int x; int y; - struct wl_buffer *buffer; - struct wl_listener buffer_destroy_listener; + CoglandBufferReference buffer_ref; CoglTexture2D *texture; CoglBool has_shell_surface; @@ -39,7 +60,7 @@ typedef struct { /* wl_surface.attach */ CoglBool newly_attached; - struct wl_buffer *buffer; + CoglandBuffer *buffer; struct wl_listener buffer_destroy_listener; int32_t sx; int32_t sy; @@ -268,6 +289,81 @@ wayland_event_source_new (struct wl_display *display) return &source->source; } +static void +cogland_buffer_destroy_handler (struct wl_listener *listener, + void *data) +{ + CoglandBuffer *buffer = wl_container_of (listener, buffer, destroy_listener); + + wl_signal_emit (&buffer->destroy_signal, buffer); + g_slice_free (CoglandBuffer, buffer); +} + +static CoglandBuffer * +cogland_buffer_from_resource (struct wl_resource *resource) +{ + CoglandBuffer *buffer; + struct wl_listener *listener; + + listener = wl_resource_get_destroy_listener (resource, + cogland_buffer_destroy_handler); + + if (listener) + { + buffer = wl_container_of (listener, buffer, destroy_listener); + } + else + { + buffer = g_slice_new0 (CoglandBuffer); + + buffer->resource = resource; + wl_signal_init (&buffer->destroy_signal); + buffer->destroy_listener.notify = cogland_buffer_destroy_handler; + wl_resource_add_destroy_listener (resource, &buffer->destroy_listener); + } + + return buffer; +} + +static void +cogland_buffer_reference_handle_destroy (struct wl_listener *listener, + void *data) +{ + CoglandBufferReference *ref = + wl_container_of (listener, ref, destroy_listener); + + g_assert (data == ref->buffer); + + ref->buffer = NULL; +} + +static void +cogland_buffer_reference (CoglandBufferReference *ref, + CoglandBuffer *buffer) +{ + if (ref->buffer && buffer != ref->buffer) + { + ref->buffer->busy_count--; + + if (ref->buffer->busy_count == 0) + { + g_assert (wl_resource_get_client (ref->buffer->resource)); + wl_resource_queue_event (ref->buffer->resource, WL_BUFFER_RELEASE); + } + + wl_list_remove (&ref->destroy_listener.link); + } + + if (buffer && buffer != ref->buffer) + { + buffer->busy_count++; + wl_signal_add (&buffer->destroy_signal, &ref->destroy_listener); + } + + ref->buffer = buffer; + ref->destroy_listener.notify = cogland_buffer_reference_handle_destroy; +} + typedef struct _CoglandFrameCallback { struct wl_list link; @@ -342,45 +438,49 @@ surface_damaged (CoglandSurface *surface, int32_t width, int32_t height) { - struct wl_buffer *wayland_buffer = surface->buffer; - - if (surface->texture && - wl_buffer_is_shm (surface->buffer)) + if (surface->buffer_ref.buffer && + surface->texture) { - CoglPixelFormat format; - int stride = wl_shm_buffer_get_stride (wayland_buffer); - const uint8_t *data = wl_shm_buffer_get_data (wayland_buffer); + struct wl_shm_buffer *shm_buffer = + wl_shm_buffer_get (surface->buffer_ref.buffer->resource); - switch (wl_shm_buffer_get_format (wayland_buffer)) + if (shm_buffer) { -#if G_BYTE_ORDER == G_BIG_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888; - break; -#elif G_BYTE_ORDER == G_LITTLE_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888; - break; -#endif - default: - g_warn_if_reached (); - format = COGL_PIXEL_FORMAT_ARGB_8888; - } + CoglPixelFormat format; + int stride = wl_shm_buffer_get_stride (shm_buffer); + const uint8_t *data = wl_shm_buffer_get_data (shm_buffer); - cogl_texture_set_region (COGL_TEXTURE (surface->texture), - x, y, /* src_x/y */ - x, y, /* dst_x/y */ - width, height, /* dst_width/height */ - width, height, /* width/height */ - format, - stride, - data); + switch (wl_shm_buffer_get_format (shm_buffer)) + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; + break; + case WL_SHM_FORMAT_XRGB8888: + format = COGL_PIXEL_FORMAT_ARGB_8888; + break; +#elif G_BYTE_ORDER == G_LITTLE_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; + break; + case WL_SHM_FORMAT_XRGB8888: + format = COGL_PIXEL_FORMAT_BGRA_8888; + break; +#endif + default: + g_warn_if_reached (); + format = COGL_PIXEL_FORMAT_ARGB_8888; + } + + cogl_texture_set_region (COGL_TEXTURE (surface->texture), + x, y, /* src_x/y */ + x, y, /* dst_x/y */ + width, height, /* dst_width/height */ + width, height, /* width/height */ + format, + stride, + data); + } } cogland_queue_redraw (surface->compositor); @@ -393,52 +493,6 @@ cogland_surface_destroy (struct wl_client *wayland_client, wl_resource_destroy (wayland_resource); } -static void -cogland_surface_detach_buffer (CoglandSurface *surface) -{ - struct wl_buffer *buffer = surface->buffer; - - if (buffer) - { - wl_list_remove (&surface->buffer_destroy_listener.link); - - surface->buffer = NULL; - - if (surface->texture) - { - cogl_object_unref (surface->texture); - surface->texture = NULL; - } - - cogland_queue_redraw (surface->compositor); - } -} - -static void -surface_handle_buffer_destroy (struct wl_listener *listener, - void *data) -{ - CoglandSurface *surface = - wl_container_of (listener, surface, buffer_destroy_listener); - - cogland_surface_detach_buffer (surface); -} - -static void -cogland_surface_detach_buffer_and_notify (CoglandSurface *surface) -{ - struct wl_buffer *buffer = surface->buffer; - - if (buffer) - { - g_assert (buffer->resource.client != NULL); - - wl_resource_queue_event (&buffer->resource, WL_BUFFER_RELEASE); - - cogland_surface_detach_buffer (surface); - } -} - static void cogland_surface_attach (struct wl_client *wayland_client, struct wl_resource *wayland_surface_resource, @@ -446,8 +500,12 @@ cogland_surface_attach (struct wl_client *wayland_client, int32_t sx, int32_t sy) { CoglandSurface *surface = wayland_surface_resource->data; - struct wl_buffer *buffer = - wayland_buffer_resource ? wayland_buffer_resource->data : NULL; + CoglandBuffer *buffer; + + if (wayland_buffer_resource) + buffer = cogland_buffer_from_resource (wayland_buffer_resource); + else + buffer = NULL; /* Attach without commit in between does not went wl_buffer.release */ if (surface->pending.buffer) @@ -459,7 +517,7 @@ cogland_surface_attach (struct wl_client *wayland_client, surface->pending.newly_attached = TRUE; if (buffer) - wl_signal_add (&buffer->resource.destroy_signal, + wl_signal_add (&buffer->destroy_signal, &surface->pending.buffer_destroy_listener); } @@ -527,17 +585,26 @@ cogland_surface_commit (struct wl_client *client, /* wl_surface.attach */ if (surface->pending.newly_attached && - surface->buffer != surface->pending.buffer) + surface->buffer_ref.buffer != surface->pending.buffer) { CoglError *error = NULL; - cogland_surface_detach_buffer_and_notify (surface); + if (surface->texture) + { + cogl_object_unref (surface->texture); + surface->texture = NULL; + } + + cogland_buffer_reference (&surface->buffer_ref, surface->pending.buffer); if (surface->pending.buffer) { + struct wl_resource *buffer_resource = + surface->pending.buffer->resource; + surface->texture = cogl_wayland_texture_2d_new_from_buffer (compositor->cogl_context, - surface->pending.buffer, + buffer_resource, &error); if (!surface->texture) @@ -546,11 +613,6 @@ cogland_surface_commit (struct wl_client *client, error->message); cogl_error_free (error); } - - surface->buffer = surface->pending.buffer; - - wl_signal_add (&surface->buffer->resource.destroy_signal, - &surface->buffer_destroy_listener); } } if (surface->pending.buffer) @@ -563,7 +625,7 @@ cogland_surface_commit (struct wl_client *client, surface->pending.newly_attached = FALSE; /* wl_surface.damage */ - if (surface->buffer && + if (surface->buffer_ref.buffer && surface->texture && !region_is_empty (&surface->pending.damage)) { @@ -618,7 +680,10 @@ cogland_surface_free (CoglandSurface *surface) CoglandFrameCallback *cb, *next; compositor->surfaces = g_list_remove (compositor->surfaces, surface); - cogland_surface_detach_buffer_and_notify (surface); + + cogland_buffer_reference (&surface->buffer_ref, NULL); + if (surface->texture) + cogl_object_unref (surface->texture); if (surface->pending.buffer) wl_list_remove (&surface->pending.buffer_destroy_listener.link); @@ -628,7 +693,10 @@ cogland_surface_free (CoglandSurface *surface) wl_resource_destroy (&cb->resource); g_slice_free (CoglandSurface, surface); + + cogland_queue_redraw (compositor); } + static void cogland_surface_resource_destroy_cb (struct wl_resource *resource) { @@ -664,9 +732,6 @@ cogland_compositor_create_surface (struct wl_client *wayland_client, (void (**)(void)) &cogland_surface_interface; surface->resource.data = surface; - surface->buffer_destroy_listener.notify = - surface_handle_buffer_destroy; - surface->pending.buffer_destroy_listener.notify = surface_handle_pending_buffer_destroy; wl_list_init (&surface->pending.frame_callback_list);