[mutter] wayland: Make MetaWaylandBuffer handle texture generation itself



commit 23455985cdc867772e9ad2dc78c2a29641b52473
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Oct 20 15:35:29 2016 +0800

    wayland: Make MetaWaylandBuffer handle texture generation itself
    
    Don't rely on the Cogl layer having Wayland specific paths by
    determining the buffer type and creating the EGLImage ourself, while
    using the newly exposed CoglTexture from EGLImage API. This changes the
    API used by MetaWaylandSurface to make the MetaWaylandBuffer API be
    aware when the buffer is being attached. For SHM and EGL buffers, only
    the first time it is attached will result in a new texture being
    allocated, but later for EGLStream's, more logic on every attach is
    needed.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=773629

 cogl/cogl/Makefile.am              |    2 +-
 src/wayland/meta-wayland-buffer.c  |  316 ++++++++++++++++++++++++++++++------
 src/wayland/meta-wayland-buffer.h  |    4 +-
 src/wayland/meta-wayland-surface.c |   26 ++-
 4 files changed, 291 insertions(+), 57 deletions(-)
---
diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am
index fef656a..88712a9 100644
--- a/cogl/cogl/Makefile.am
+++ b/cogl/cogl/Makefile.am
@@ -452,7 +452,7 @@ libmutter_cogl_la_LDFLAGS = \
        -avoid-version \
        -export-dynamic \
        -rpath $(mutterlibdir) \
-       -export-symbols-regex 
"^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_vtable|_cogl_winsys_egl_g
 
et_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current).*"
+       -export-symbols-regex 
"^(cogl|_cogl_debug_flags|_cogl_atlas_new|_cogl_atlas_add_reorganize_callback|_cogl_atlas_reserve_space|_cogl_callback|_cogl_util_get_eye_planes_for_screen_poly|_cogl_atlas_texture_remove_reorganize_callback|_cogl_atlas_texture_add_reorganize_callback|_cogl_texture_get_format|_cogl_texture_foreach_sub_texture_in_region|_cogl_texture_set_region|_cogl_profile_trace_message|_cogl_context_get_default|_cogl_framebuffer_get_stencil_bits|_cogl_clip_stack_push_rectangle|_cogl_framebuffer_get_modelview_stack|_cogl_object_default_unref|_cogl_pipeline_foreach_layer_internal|_cogl_clip_stack_push_primitive|_cogl_buffer_unmap_for_fill_or_fallback|_cogl_framebuffer_draw_primitive|_cogl_debug_instances|_cogl_framebuffer_get_projection_stack|_cogl_pipeline_layer_get_texture|_cogl_buffer_map_for_fill_or_fallback|_cogl_texture_can_hardware_repeat|_cogl_pipeline_prune_to_n_layers|_cogl_primitive_draw|test_|unit_test_|_cogl_winsys_glx_get_vtable|_cogl_winsys_egl_xlib_get_
 
vtable|_cogl_winsys_egl_get_vtable|_cogl_closure_disconnect|_cogl_onscreen_notify_complete|_cogl_onscreen_notify_frame_sync|_cogl_winsys_egl_renderer_connect_common|_cogl_winsys_error_quark|_cogl_set_error|_cogl_poll_renderer_add_fd|_cogl_poll_renderer_add_idle|_cogl_framebuffer_winsys_update_size|_cogl_winsys_egl_make_current|_cogl_pixel_format_get_bytes_per_pixel).*"
 
 libmutter_cogl_la_SOURCES = $(cogl_sources_c)
 nodist_libmutter_cogl_la_SOURCES = $(BUILT_SOURCES)
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index b23ca35..02c3923 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -27,9 +27,11 @@
 #include "meta-wayland-buffer.h"
 
 #include <clutter/clutter.h>
-#include <cogl/cogl-wayland-server.h>
+#include <cogl/cogl-egl.h>
 #include <meta/util.h>
 
+#include "backends/meta-backend-private.h"
+
 enum
 {
   RESOURCE_DESTROYED,
@@ -79,79 +81,301 @@ meta_wayland_buffer_from_resource (struct wl_resource *resource)
   return buffer;
 }
 
-CoglTexture *
-meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
+typedef enum _MetaWaylandBufferType
 {
-  CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
-  CoglError *catch_error = NULL;
-  CoglTexture *texture;
-  struct wl_shm_buffer *shm_buffer;
+  META_WAYLAND_BUFFER_TYPE_UNKNOWN,
+  META_WAYLAND_BUFFER_TYPE_SHM,
+  META_WAYLAND_BUFFER_TYPE_EGL_IMAGE,
+} MetaWaylandBufferType;
+
+static MetaWaylandBufferType
+determine_buffer_type (MetaWaylandBuffer *buffer)
+{
+  EGLint format;
+  MetaBackend *backend = meta_get_backend ();
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+  EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
+
+  if (wl_shm_buffer_get (buffer->resource) != NULL)
+    return META_WAYLAND_BUFFER_TYPE_SHM;
+
+
+  if (meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
+                                     EGL_TEXTURE_FORMAT, &format,
+                                     NULL))
+    return META_WAYLAND_BUFFER_TYPE_EGL_IMAGE;
+
+  return META_WAYLAND_BUFFER_TYPE_UNKNOWN;
+}
+
+static void
+shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer  *shm_buffer,
+                                  CoglPixelFormat       *format_out,
+                                  CoglTextureComponents *components_out)
+{
+  CoglPixelFormat format;
+  CoglTextureComponents components = COGL_TEXTURE_COMPONENTS_RGBA;
+
+  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;
+      components = COGL_TEXTURE_COMPONENTS_RGB;
+      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;
+      components = COGL_TEXTURE_COMPONENTS_RGB;
+      break;
+#endif
+    default:
+      g_warn_if_reached ();
+      format = COGL_PIXEL_FORMAT_ARGB_8888;
+    }
+
+  if (format_out)
+    *format_out = format;
+  if (components_out)
+    *components_out = components;
+}
 
-  g_return_val_if_fail (buffer->resource, NULL);
+static gboolean
+shm_buffer_attach (MetaWaylandBuffer *buffer,
+                   GError           **error)
+{
+  MetaBackend *backend = meta_get_backend ();
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+  struct wl_shm_buffer *shm_buffer;
+  int stride, width, height;
+  CoglPixelFormat format;
+  CoglTextureComponents components;
+  CoglBitmap *bitmap;
+  CoglTexture *texture;
 
   if (buffer->texture)
-    goto out;
+    return TRUE;
 
   shm_buffer = wl_shm_buffer_get (buffer->resource);
+  stride = wl_shm_buffer_get_stride (shm_buffer);
+  width = wl_shm_buffer_get_width (shm_buffer);
+  height = wl_shm_buffer_get_height (shm_buffer);
+
+  wl_shm_buffer_begin_access (shm_buffer);
+
+  shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components);
+
+  bitmap = cogl_bitmap_new_for_data (cogl_context,
+                                     width, height,
+                                     format,
+                                     stride,
+                                     wl_shm_buffer_get_data (shm_buffer));
+
+  texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap));
+  cogl_texture_set_components (COGL_TEXTURE (texture), components);
+
+  cogl_object_unref (bitmap);
+
+  if (!cogl_texture_allocate (COGL_TEXTURE (texture), error))
+    g_clear_pointer (&texture, cogl_object_unref);
+
+  wl_shm_buffer_end_access (shm_buffer);
+
+  buffer->texture = texture;
+
+  if (!buffer->texture)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+egl_image_buffer_attach (MetaWaylandBuffer *buffer,
+                         GError           **error)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
+  CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+  EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context);
+  EGLContext egl_context = cogl_egl_context_get_egl_context (cogl_context);
+  int format, width, height;
+  CoglPixelFormat cogl_format;
+  EGLImageKHR egl_image;
+  CoglTexture2D *texture;
+
+  if (buffer->texture)
+    return TRUE;
 
-  if (shm_buffer)
-    wl_shm_buffer_begin_access (shm_buffer);
+  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
+                                      EGL_TEXTURE_FORMAT, &format,
+                                      error))
+    return FALSE;
 
-  texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (ctx,
-                                                                   buffer->resource,
-                                                                   &catch_error));
+  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
+                                      EGL_WIDTH, &width,
+                                      error))
+    return FALSE;
 
-  if (shm_buffer)
-    wl_shm_buffer_end_access (shm_buffer);
+  if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource,
+                                      EGL_HEIGHT, &height,
+                                      error))
+    return FALSE;
+
+  switch (format)
+    {
+    case EGL_TEXTURE_RGB:
+      cogl_format = COGL_PIXEL_FORMAT_RGB_888;
+      break;
+    case EGL_TEXTURE_RGBA:
+      cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
+      break;
+    default:
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Unsupported buffer format %d", format);
+      return FALSE;
+    }
+
+  egl_image = meta_egl_create_image (egl, egl_display, egl_context,
+                                     EGL_WAYLAND_BUFFER_WL, buffer->resource,
+                                     NULL,
+                                     error);
+  if (egl_image == EGL_NO_IMAGE_KHR)
+    return FALSE;
+
+  texture = cogl_egl_texture_2d_new_from_image (cogl_context,
+                                                width, height,
+                                                cogl_format,
+                                                egl_image,
+                                                error);
+
+  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
 
   if (!texture)
+    return FALSE;
+
+  buffer->texture = COGL_TEXTURE (texture);
+
+  return TRUE;
+}
+
+gboolean
+meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
+                            GError           **error)
+{
+  MetaWaylandBufferType buffer_type;
+
+  g_return_val_if_fail (buffer->resource, FALSE);
+
+  buffer_type = determine_buffer_type (buffer);
+
+  switch (buffer_type)
     {
-      meta_warning ("Could not import pending buffer, ignoring commit: %s\n",
-                    catch_error->message);
-      cogl_error_free (catch_error);
-      goto out;
+    case META_WAYLAND_BUFFER_TYPE_SHM:
+      return shm_buffer_attach (buffer, error);
+    case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+      return egl_image_buffer_attach (buffer, error);
+    case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Unknown buffer type");
+      return FALSE;
     }
 
-  buffer->texture = texture;
+  g_assert_not_reached ();
+}
 
- out:
+CoglTexture *
+meta_wayland_buffer_get_texture (MetaWaylandBuffer *buffer)
+{
   return buffer->texture;
 }
 
-void
-meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
-                                    cairo_region_t    *region)
+static gboolean
+process_shm_buffer_damage (MetaWaylandBuffer *buffer,
+                           cairo_region_t    *region,
+                           GError           **error)
 {
   struct wl_shm_buffer *shm_buffer;
+  int i, n_rectangles;
+  gboolean set_texture_failed = FALSE;
+
+  n_rectangles = cairo_region_num_rectangles (region);
 
   shm_buffer = wl_shm_buffer_get (buffer->resource);
+  wl_shm_buffer_begin_access (shm_buffer);
 
-  if (shm_buffer)
+  for (i = 0; i < n_rectangles; i++)
     {
-      int i, n_rectangles;
+      const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
+      int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
+      CoglPixelFormat format;
+      int bpp;
+      cairo_rectangle_int_t rect;
+
+      shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL);
+      bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+      cairo_region_get_rectangle (region, i, &rect);
+
+      if (!_cogl_texture_set_region (buffer->texture,
+                                     rect.width, rect.height,
+                                     format,
+                                     stride,
+                                     data + rect.x * bpp + rect.y * stride,
+                                     rect.x, rect.y,
+                                     0,
+                                     error))
+        {
+          set_texture_failed = TRUE;
+          break;
+        }
+    }
 
-      n_rectangles = cairo_region_num_rectangles (region);
+  wl_shm_buffer_end_access (shm_buffer);
 
-      wl_shm_buffer_begin_access (shm_buffer);
+  return !set_texture_failed;
+}
 
-      for (i = 0; i < n_rectangles; i++)
-        {
-          CoglError *error = NULL;
-          cairo_rectangle_int_t rect;
-          cairo_region_get_rectangle (region, i, &rect);
-          cogl_wayland_texture_set_region_from_shm_buffer (buffer->texture,
-                                                           rect.x, rect.y, rect.width, rect.height,
-                                                           shm_buffer,
-                                                           rect.x, rect.y, 0, &error);
-
-          if (error)
-            {
-              meta_warning ("Failed to set texture region: %s\n", error->message);
-              cogl_error_free (error);
-            }
-        }
+void
+meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
+                                    cairo_region_t    *region)
+{
+  MetaWaylandBufferType buffer_type;
+  gboolean res = FALSE;
+  GError *error = NULL;
+
+  g_return_if_fail (buffer->resource);
+
+  buffer_type = determine_buffer_type (buffer);
 
-      wl_shm_buffer_end_access (shm_buffer);
+  switch (buffer_type)
+    {
+    case META_WAYLAND_BUFFER_TYPE_SHM:
+      res = process_shm_buffer_damage (buffer, region, &error);
+    case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+      res = TRUE;
+      break;
+    case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
+      g_set_error (&error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Unknown buffer type");
+      res = FALSE;
+    }
+
+  if (!res)
+    {
+      g_warning ("Failed to process Wayland buffer damage: %s", error->message);
+      g_error_free (error);
     }
 }
 
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index 977892b..286c19a 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -46,7 +46,9 @@ G_DECLARE_FINAL_TYPE (MetaWaylandBuffer, meta_wayland_buffer,
                       META, WAYLAND_BUFFER, GObject);
 
 MetaWaylandBuffer *     meta_wayland_buffer_from_resource       (struct wl_resource    *resource);
-CoglTexture *           meta_wayland_buffer_ensure_texture      (MetaWaylandBuffer     *buffer);
+gboolean                meta_wayland_buffer_attach              (MetaWaylandBuffer     *buffer,
+                                                                 GError               **error);
+CoglTexture *           meta_wayland_buffer_get_texture         (MetaWaylandBuffer     *buffer);
 void                    meta_wayland_buffer_process_damage      (MetaWaylandBuffer     *buffer,
                                                                  cairo_region_t        *region);
 
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 99e3dfd..e089ab7 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -738,21 +738,29 @@ apply_pending_state (MetaWaylandSurface      *surface,
       if (pending->buffer)
         meta_wayland_surface_ref_buffer_use_count (surface);
 
-      if (switched_buffer && pending->buffer)
+      if (pending->buffer)
         {
-          CoglTexture *texture;
+          GError *error = NULL;
 
-          texture = meta_wayland_buffer_ensure_texture (pending->buffer);
-          if (!texture)
+          if (!meta_wayland_buffer_attach (pending->buffer, &error))
             {
+              g_warning ("Could not import pending buffer: %s", error->message);
               wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY,
-                              "Failed to create a texture for surface %i",
-                              wl_resource_get_id (surface->resource));
-
+                                      "Failed to create a texture for surface %i: %s",
+                                      wl_resource_get_id (surface->resource),
+                                      error->message);
+              g_error_free (error);
               goto cleanup;
             }
-          meta_surface_actor_wayland_set_texture (surface_actor_wayland,
-                                                  texture);
+
+          if (switched_buffer)
+            {
+              CoglTexture *texture;
+
+              texture = meta_wayland_buffer_get_texture (pending->buffer);
+              meta_surface_actor_wayland_set_texture (surface_actor_wayland,
+                                                      texture);
+            }
         }
 
       /* If the newly attached buffer is going to be accessed directly without


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]