[Cogl] [PATCH 5/6] wayland-server: Update because wl_shm_buffer is no longer a wl_buffer
Neil Roberts
neil at linux.intel.com
Fri Jun 28 10:03:10 PDT 2013
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
---
cogl/cogl-texture-2d.c | 109 +++++++++++--------
cogl/cogl-wayland-server.h | 8 +-
examples/cogland.c | 259 ++++++++++++++++++++++++++++-----------------
3 files changed, 230 insertions(+), 146 deletions(-)
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index a9ca01e..d253bad 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;
-
- _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
- COGL_RENDERER_CONSTRAINT_USES_EGL,
- NULL);
-
- switch (format)
+ struct wl_buffer *buffer = (struct wl_buffer *) buffer_resource;
+ int format, width, height;
+
+ 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;
+
+ _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;
}
-
- 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_set_error (error,
diff --git a/cogl/cogl-wayland-server.h b/cogl/cogl-wayland-server.h
index 567a9f9..e56f5bd 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.
*
* <note>The results are undefined for passing an invalid @buffer
* pointer</note>
@@ -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 98865f0..c5ad8d9 100644
--- a/examples/cogland.c
+++ b/examples/cogland.c
@@ -23,13 +23,34 @@ typedef struct
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;
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)
{
+ CoglPixelFormat format;
+ int stride = wl_shm_buffer_get_stride (shm_buffer);
+ const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
+
+ 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;
+ 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;
+ 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;
- }
+ default:
+ g_warn_if_reached ();
+ format = COGL_PIXEL_FORMAT_ARGB_8888;
+ }
- cogl_texture_set_region (COGL_TEXTURE (surface->texture),
- width, height,
- format,
- stride,
- data + x * 4 + y * stride,
- x, y, /* dst_x/y */
- 0, /* level */
- NULL /* error */);
+ cogl_texture_set_region (COGL_TEXTURE (surface->texture),
+ width, height,
+ format,
+ stride,
+ data + x * 4 + y * stride,
+ x, y, /* dst_x/y */
+ 0, /* level */
+ NULL /* error */);
+ }
}
cogland_queue_redraw (surface->compositor);
@@ -394,60 +494,18 @@ cogland_surface_destroy (struct wl_client *wayland_client,
}
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,
struct wl_resource *wayland_buffer_resource,
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);
--
1.7.11.3.g3c3efa5
More information about the Cogl
mailing list