[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