[mutter] wayland: Add API to acquire a CoglScanout from a surface



commit ff7a42b8bc25c24d3e0fc0a277b1d628f5ea599a
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Sep 12 11:44:59 2019 +0200

    wayland: Add API to acquire a CoglScanout from a surface
    
    This will check whether the current backing buffer is compatible with
    the primary plane of the passed CoglOnscreen. Since this will extend the
    time before a buffer is released, the MetaWaylandBufferRef is swapped
    and orphaned if a new buffer is committed before the previous one was
    released. It'll eventually be released, usually by the next page flip
    callback.
    
    Currently implemented for EGLImage and DMA-BUF buffer types.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/798

 src/wayland/meta-wayland-buffer.c  |  92 +++++++++++++++++++++++++++++
 src/wayland/meta-wayland-buffer.h  |   2 +
 src/wayland/meta-wayland-dma-buf.c | 116 +++++++++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-dma-buf.h |   4 ++
 src/wayland/meta-wayland-surface.c |  48 +++++++++++++++
 src/wayland/meta-wayland-surface.h |   3 +
 6 files changed, 265 insertions(+)
---
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index 6236579e7..9c0195501 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -58,6 +58,11 @@
 #include "meta/util.h"
 #include "wayland/meta-wayland-dma-buf.h"
 
+#ifdef HAVE_NATIVE_BACKEND
+#include "backends/native/meta-drm-buffer-gbm.h"
+#include "backends/native/meta-renderer-native.h"
+#endif
+
 #ifndef DRM_FORMAT_MOD_INVALID
 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
 #endif
@@ -577,6 +582,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
     }
 }
 
+static CoglScanout *
+try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer,
+                               CoglOnscreen      *onscreen)
+{
+#ifdef HAVE_NATIVE_BACKEND
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+  MetaGpuKms *gpu_kms;
+  struct gbm_device *gbm_device;
+  struct gbm_bo *gbm_bo;
+  uint32_t drm_format;
+  uint64_t drm_modifier;
+  uint32_t stride;
+  MetaDrmBufferGbm *fb;
+  g_autoptr (GError) error = NULL;
+
+  gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
+  gbm_device = meta_gbm_device_from_gpu (gpu_kms);
+
+  gbm_bo = gbm_bo_import (gbm_device,
+                          GBM_BO_IMPORT_WL_BUFFER, buffer->resource,
+                          GBM_BO_USE_SCANOUT);
+  if (!gbm_bo)
+    return NULL;
+
+  drm_format = gbm_bo_get_format (gbm_bo);
+  drm_modifier = gbm_bo_get_modifier (gbm_bo);
+  stride = gbm_bo_get_stride (gbm_bo);
+  if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
+                                                          drm_format,
+                                                          drm_modifier,
+                                                          stride))
+    {
+      gbm_bo_destroy (gbm_bo);
+      return NULL;
+    }
+
+  fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
+                                     drm_modifier != DRM_FORMAT_MOD_INVALID,
+                                     &error);
+  if (!fb)
+    {
+      g_debug ("Failed to create scanout buffer: %s", error->message);
+      gbm_bo_destroy (gbm_bo);
+      return NULL;
+    }
+
+  return COGL_SCANOUT (fb);
+#else
+  return NULL;
+#endif
+}
+
+CoglScanout *
+meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
+                                         CoglOnscreen      *onscreen)
+{
+  switch (buffer->type)
+    {
+    case META_WAYLAND_BUFFER_TYPE_SHM:
+      return NULL;
+    case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
+      return try_acquire_egl_image_scanout (buffer, onscreen);
+#ifdef HAVE_WAYLAND_EGLSTREAM
+    case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
+      return NULL;
+#endif
+    case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
+      {
+        MetaWaylandDmaBufBuffer *dma_buf;
+
+        dma_buf = meta_wayland_dma_buf_from_buffer (buffer);
+        if (!dma_buf)
+          return NULL;
+
+        return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen);
+      }
+    case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
+      g_warn_if_reached ();
+      return NULL;
+    }
+
+  g_assert_not_reached ();
+  return NULL;
+}
+
 static void
 meta_wayland_buffer_finalize (GObject *object)
 {
diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h
index 4a503b183..77e68e724 100644
--- a/src/wayland/meta-wayland-buffer.h
+++ b/src/wayland/meta-wayland-buffer.h
@@ -88,5 +88,7 @@ gboolean                meta_wayland_buffer_is_y_inverted       (MetaWaylandBuff
 void                    meta_wayland_buffer_process_damage      (MetaWaylandBuffer     *buffer,
                                                                  CoglTexture           *texture,
                                                                  cairo_region_t        *region);
+CoglScanout *           meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer     *buffer,
+                                                                 CoglOnscreen          *onscreen);
 
 #endif /* META_WAYLAND_BUFFER_H */
diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c
index e50389aec..21560cd54 100644
--- a/src/wayland/meta-wayland-dma-buf.c
+++ b/src/wayland/meta-wayland-dma-buf.c
@@ -51,6 +51,11 @@
 #include "wayland/meta-wayland-private.h"
 #include "wayland/meta-wayland-versions.h"
 
+#ifdef HAVE_NATIVE_BACKEND
+#include "backends/native/meta-drm-buffer-gbm.h"
+#include "backends/native/meta-renderer-native.h"
+#endif
+
 #include "linux-dmabuf-unstable-v1-server-protocol.h"
 
 #ifndef DRM_FORMAT_MOD_INVALID
@@ -178,6 +183,117 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer  *buffer,
   return TRUE;
 }
 
+#ifdef HAVE_NATIVE_BACKEND
+static struct gbm_bo *
+create_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf,
+               MetaGpuKms              *gpu_kms,
+               int                      n_planes,
+               gboolean                *use_modifier)
+{
+  struct gbm_device *gbm_device;
+
+  gbm_device = meta_gbm_device_from_gpu (gpu_kms);
+
+  if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID ||
+      n_planes > 1 ||
+      dma_buf->offsets[0] > 0)
+    {
+      struct gbm_import_fd_modifier_data import_with_modifier;
+
+      import_with_modifier = (struct gbm_import_fd_modifier_data) {
+        .width = dma_buf->width,
+        .height = dma_buf->height,
+        .format = dma_buf->drm_format,
+        .num_fds = n_planes,
+        .modifier = dma_buf->drm_modifier,
+      };
+      memcpy (import_with_modifier.fds,
+              dma_buf->fds,
+              sizeof (dma_buf->fds));
+      memcpy (import_with_modifier.strides,
+              dma_buf->strides,
+              sizeof (import_with_modifier.strides));
+      memcpy (import_with_modifier.offsets,
+              dma_buf->offsets,
+              sizeof (import_with_modifier.offsets));
+
+      *use_modifier = TRUE;
+      return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER,
+                            &import_with_modifier,
+                            GBM_BO_USE_SCANOUT);
+    }
+  else
+    {
+      struct gbm_import_fd_data import_legacy;
+
+      import_legacy = (struct gbm_import_fd_data) {
+        .width = dma_buf->width,
+        .height = dma_buf->height,
+        .format = dma_buf->drm_format,
+        .stride = dma_buf->strides[0],
+        .fd = dma_buf->fds[0],
+      };
+
+      *use_modifier = FALSE;
+      return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD,
+                            &import_legacy,
+                            GBM_BO_USE_SCANOUT);
+    }
+}
+#endif
+
+CoglScanout *
+meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
+                                          CoglOnscreen            *onscreen)
+{
+#ifdef HAVE_NATIVE_BACKEND
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+  MetaGpuKms *gpu_kms;
+  int n_planes;
+  uint32_t drm_format;
+  uint64_t drm_modifier;
+  uint32_t stride;
+  struct gbm_bo *gbm_bo;
+  gboolean use_modifier;
+  g_autoptr (GError) error = NULL;
+  MetaDrmBufferGbm *fb;
+
+  for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
+    {
+      if (dma_buf->fds[n_planes] < 0)
+        break;
+    }
+
+  drm_format = dma_buf->drm_format;
+  drm_modifier = dma_buf->drm_modifier;
+  stride = dma_buf->strides[0];
+  if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
+                                                          drm_format,
+                                                          drm_modifier,
+                                                          stride))
+    return NULL;
+
+  gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
+  gbm_bo = create_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier);
+
+  fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
+                                     use_modifier,
+                                     &error);
+  if (!fb)
+    {
+      g_debug ("Failed to create scanout buffer: %s", error->message);
+      gbm_bo_destroy (gbm_bo);
+      return NULL;
+    }
+
+  return COGL_SCANOUT (fb);
+#else
+  return NULL;
+#endif
+}
+
 static void
 buffer_params_add (struct wl_client   *client,
                    struct wl_resource *resource,
diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h
index b7f712d8d..cdc65aeb5 100644
--- a/src/wayland/meta-wayland-dma-buf.h
+++ b/src/wayland/meta-wayland-dma-buf.h
@@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer  *buffer,
 MetaWaylandDmaBufBuffer *
 meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
 
+CoglScanout *
+meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
+                                          CoglOnscreen            *onscreen);
+
 #endif /* META_WAYLAND_DMA_BUF_H */
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 99f3fc58b..fa84944bd 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -131,6 +131,13 @@ meta_wayland_buffer_ref_new (void)
   return buffer_ref;
 }
 
+static MetaWaylandBufferRef *
+meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref)
+{
+  g_ref_count_inc (&buffer_ref->ref_count);
+  return buffer_ref;
+}
+
 static void
 meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref)
 {
@@ -667,6 +674,12 @@ meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
       if (surface->buffer_held)
         meta_wayland_surface_unref_buffer_use_count (surface);
 
+      if (surface->buffer_ref->use_count > 0)
+        {
+          meta_wayland_buffer_ref_unref (surface->buffer_ref);
+          surface->buffer_ref = meta_wayland_buffer_ref_new ();
+        }
+
       g_set_object (&surface->buffer_ref->buffer, state->buffer);
 
       if (state->buffer)
@@ -1959,3 +1972,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface)
       return height / surface->scale;
     }
 }
+
+static void
+scanout_destroyed (gpointer  data,
+                   GObject  *where_the_object_was)
+{
+  MetaWaylandBufferRef *buffer_ref = data;
+
+  meta_wayland_buffer_ref_dec_use_count (buffer_ref);
+  meta_wayland_buffer_ref_unref (buffer_ref);
+}
+
+CoglScanout *
+meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
+                                          CoglOnscreen       *onscreen)
+{
+  CoglScanout *scanout;
+  MetaWaylandBufferRef *buffer_ref;
+
+  if (!surface->buffer_ref->buffer)
+    return NULL;
+
+  if (surface->buffer_ref->use_count == 0)
+    return NULL;
+
+  scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer,
+                                                     onscreen);
+  if (!scanout)
+    return NULL;
+
+  buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref);
+  meta_wayland_buffer_ref_inc_use_count (buffer_ref);
+  g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref);
+
+  return scanout;
+}
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 9cedba506..50736758a 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -346,6 +346,9 @@ void                meta_wayland_surface_update_outputs_recursively (MetaWayland
 int                 meta_wayland_surface_get_width (MetaWaylandSurface *surface);
 int                 meta_wayland_surface_get_height (MetaWaylandSurface *surface);
 
+CoglScanout *       meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
+                                                              CoglOnscreen       *onscreen);
+
 static inline GNode *
 meta_get_next_subsurface_sibling (GNode *n)
 {


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