[mutter] renderer/native: Create GBM surfaces with modifiers



commit cc4e0071489e739597a64ea2549ee9ab75060531
Author: Daniel Stone <daniels collabora com>
Date:   Thu Aug 3 15:42:50 2017 +0100

    renderer/native: Create GBM surfaces with modifiers
    
    Now that we have the list of supported modifiers from the monitor
    manager (via the CRTCs to the primary planes), we can use this to inform
    EGL it can use those modifiers to allocate the GBM surface with. Doing
    so allows us to use tiling and compression for our scanout surfaces.
    
    This requires the Mesa commit in:
    Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
    Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
    Otherwise Mesa closes the fd behind our back and re-importing will fail.
    See FDO bug #76188 for details.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=785779

 src/backends/native/meta-crtc-kms.c              |   14 ++
 src/backends/native/meta-crtc-kms.h              |    3 +
 src/backends/native/meta-renderer-native-gles3.c |  111 ++++++++++++--
 src/backends/native/meta-renderer-native.c       |  176 ++++++++++++++++++++-
 4 files changed, 280 insertions(+), 24 deletions(-)
---
diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c
index 8152991..344c80a 100644
--- a/src/backends/native/meta-crtc-kms.c
+++ b/src/backends/native/meta-crtc-kms.c
@@ -29,6 +29,8 @@
 #include "backends/meta-backend-private.h"
 #include "backends/native/meta-gpu-kms.h"
 
+#include <drm_fourcc.h>
+
 #define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
 #define ALL_TRANSFORMS_MASK ((1 << ALL_TRANSFORMS) - 1)
 
@@ -174,6 +176,18 @@ find_property_index (MetaGpu                    *gpu,
   return -1;
 }
 
+GArray *
+meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
+                             uint32_t  format)
+{
+  MetaCrtcKms *crtc_kms = crtc->driver_private;
+
+  if (format != DRM_FORMAT_XRGB8888)
+    return NULL;
+
+  return crtc_kms->modifiers_xrgb8888;
+}
+
 static inline uint32_t *
 formats_ptr (struct drm_format_modifier_blob *blob)
 {
diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h
index cb275f4..44899f6 100644
--- a/src/backends/native/meta-crtc-kms.h
+++ b/src/backends/native/meta-crtc-kms.h
@@ -37,6 +37,9 @@ void meta_crtc_kms_apply_transform (MetaCrtc *crtc);
 void meta_crtc_kms_set_underscan (MetaCrtc *crtc,
                                   gboolean  is_underscanning);
 
+GArray * meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
+                                      uint32_t  format);
+
 MetaCrtc * meta_create_kms_crtc (MetaGpuKms   *gpu_kms,
                                  drmModeCrtc  *drm_crtc,
                                  unsigned int  crtc_index);
diff --git a/src/backends/native/meta-renderer-native-gles3.c 
b/src/backends/native/meta-renderer-native-gles3.c
index 0914dfe..3bb09ce 100644
--- a/src/backends/native/meta-renderer-native-gles3.c
+++ b/src/backends/native/meta-renderer-native-gles3.c
@@ -26,11 +26,13 @@
 
 #include "backends/native/meta-renderer-native-gles3.h"
 
+#include <drm_fourcc.h>
 #include <errno.h>
 #include <gio/gio.h>
 #include <GLES3/gl3.h>
 #include <string.h>
 
+#include "backends/meta-egl-ext.h"
 #include "backends/meta-gles3.h"
 #include "backends/meta-gles3-table.h"
 
@@ -48,24 +50,91 @@ create_egl_image (MetaEgl       *egl,
                   EGLContext     egl_context,
                   unsigned int   width,
                   unsigned int   height,
-                  uint32_t       stride,
+                  uint32_t       n_planes,
+                  uint32_t      *strides,
+                  uint32_t      *offsets,
+                  uint64_t      *modifiers,
                   uint32_t       format,
                   int            fd,
                   GError       **error)
 {
-  EGLint attributes[] = {
-    EGL_WIDTH, width,
-    EGL_HEIGHT, height,
-    EGL_LINUX_DRM_FOURCC_EXT, format,
-    EGL_DMA_BUF_PLANE0_FD_EXT, fd,
-    EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
-    EGL_DMA_BUF_PLANE0_PITCH_EXT, stride,
-    EGL_NONE
-  };
+  EGLint attribs[37];
+  int atti = 0;
+  gboolean has_modifier;
+
+  /* This requires the Mesa commit in
+   * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
+   * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
+   * Otherwise Mesa closes the fd behind our back and re-importing
+   * will fail.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=76188
+   */
+
+  attribs[atti++] = EGL_WIDTH;
+  attribs[atti++] = width;
+  attribs[atti++] = EGL_HEIGHT;
+  attribs[atti++] = height;
+  attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+  attribs[atti++] = format;
+
+  has_modifier = (modifiers[0] != DRM_FORMAT_MOD_INVALID);
+
+  if (n_planes > 0)
+    {
+      attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+      attribs[atti++] = fd;
+      attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+      attribs[atti++] = offsets[0];
+      attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+      attribs[atti++] = strides[0];
+      if (has_modifier)
+        {
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+          attribs[atti++] = modifiers[0] & 0xFFFFFFFF;
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+          attribs[atti++] = modifiers[0] >> 32;
+        }
+    }
+
+  if (n_planes > 1)
+    {
+      attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+      attribs[atti++] = fd;
+      attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+      attribs[atti++] = offsets[1];
+      attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+      attribs[atti++] = strides[1];
+      if (has_modifier)
+        {
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+          attribs[atti++] = modifiers[1] & 0xFFFFFFFF;
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+          attribs[atti++] = modifiers[1] >> 32;
+        }
+    }
+
+  if (n_planes > 2)
+    {
+      attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+      attribs[atti++] = fd;
+      attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+      attribs[atti++] = offsets[2];
+      attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+      attribs[atti++] = strides[2];
+      if (has_modifier)
+        {
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
+          attribs[atti++] = modifiers[2] & 0xFFFFFFFF;
+          attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
+          attribs[atti++] = modifiers[2] >> 32;
+        }
+    }
+
+  attribs[atti++] = EGL_NONE;
 
   return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
                                 EGL_LINUX_DMA_BUF_EXT, NULL,
-                                attributes,
+                                attribs,
                                 error);
 }
 
@@ -120,7 +189,10 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl        *egl,
   int shared_bo_fd;
   unsigned int width;
   unsigned int height;
-  uint32_t stride;
+  uint32_t i, n_planes;
+  uint32_t strides[4] = { 0, };
+  uint32_t offsets[4] = { 0, };
+  uint64_t modifiers[4] = { 0, };
   uint32_t format;
   EGLImageKHR egl_image;
 
@@ -134,14 +206,23 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl        *egl,
 
   width = gbm_bo_get_width (shared_bo);
   height = gbm_bo_get_height (shared_bo);
-  stride = gbm_bo_get_stride (shared_bo);
   format = gbm_bo_get_format (shared_bo);
 
+  n_planes = gbm_bo_get_plane_count (shared_bo);
+  for (i = 0; i < n_planes; i++)
+    {
+      strides[i] = gbm_bo_get_stride_for_plane (shared_bo, i);
+      offsets[i] = gbm_bo_get_offset (shared_bo, i);
+      modifiers[i] = gbm_bo_get_modifier (shared_bo);
+    }
+
   egl_image = create_egl_image (egl,
                                 egl_display,
                                 egl_context,
-                                width, height, stride,
-                                format,
+                                width, height,
+                                n_planes,
+                                strides, offsets,
+                                modifiers, format,
                                 shared_bo_fd,
                                 error);
   close (shared_bo_fd);
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 2e59161..5b3a9a9 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -56,6 +56,7 @@
 #include "backends/meta-logical-monitor.h"
 #include "backends/meta-output.h"
 #include "backends/meta-renderer-view.h"
+#include "backends/native/meta-crtc-kms.h"
 #include "backends/native/meta-gpu-kms.h"
 #include "backends/native/meta-monitor-manager-kms.h"
 #include "backends/native/meta-renderer-native.h"
@@ -1638,6 +1639,146 @@ meta_renderer_native_init_egl_context (CoglContext *cogl_context,
   return TRUE;
 }
 
+static GArray *
+get_supported_modifiers (CoglOnscreen *onscreen,
+                         uint32_t      format)
+{
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaLogicalMonitor *logical_monitor = onscreen_native->logical_monitor;
+  MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
+  CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglRenderer *cogl_renderer = cogl_context->display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  GArray *modifiers;
+  GArray *base_mods;
+  GList *l_crtc, *l_monitor;
+  MetaCrtc *base_crtc = NULL;
+  GList *other_crtcs = NULL;
+  unsigned int i;
+
+  if (!logical_monitor)
+    return NULL;
+
+  /* Find our base CRTC to intersect against. */
+  for (l_monitor = meta_logical_monitor_get_monitors (logical_monitor);
+       l_monitor;
+       l_monitor = l_monitor->next)
+    {
+      MetaMonitor *monitor = l_monitor->data;
+      MetaGpu *gpu = meta_monitor_get_gpu (monitor);
+      MetaRendererNativeGpuData *renderer_gpu_data;
+
+      /* All secondary GPUs need to be able to import DMA BUF with modifiers */
+      renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                             META_GPU_KMS (gpu));
+      if (cogl_renderer_egl->platform != renderer_gpu_data &&
+          !meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL,
+                                    "EGL_EXT_image_dma_buf_import_modifiers",
+                                    NULL))
+        goto out;
+
+      for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next)
+        {
+          MetaCrtc *crtc = l_crtc->data;
+
+          if (crtc->logical_monitor != logical_monitor)
+            continue;
+
+          if (!base_crtc)
+            base_crtc = crtc;
+          else if (crtc == base_crtc)
+            continue;
+          else if (g_list_index (other_crtcs, crtc) == -1)
+            other_crtcs = g_list_append (other_crtcs, crtc);
+        }
+    }
+
+  if (!base_crtc)
+    goto out;
+
+  base_mods = meta_crtc_kms_get_modifiers (base_crtc, format);
+  if (!base_mods)
+    goto out;
+
+  /*
+   * If this is the only CRTC we have, we don't need to intersect the sets of
+   * modifiers.
+   */
+  if (other_crtcs == NULL)
+    {
+      modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
+                                     base_mods->len);
+      g_array_append_vals (modifiers, base_mods->data, base_mods->len);
+      return modifiers;
+    }
+
+  modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
+
+  /*
+   * For each modifier from base_crtc, check if it's available on all other
+   * CRTCs.
+   */
+  for (i = 0; i < base_mods->len; i++)
+    {
+      uint64_t modifier = g_array_index (base_mods, uint64_t, i);
+      gboolean found_everywhere = TRUE;
+      GList *k;
+
+      /* Check if we have the same modifier available for all CRTCs. */
+      for (k = other_crtcs; k; k = k->next)
+        {
+          MetaCrtc *crtc = k->data;
+          GArray *crtc_mods;
+          unsigned int m;
+          gboolean found_here = FALSE;
+
+          if (crtc->logical_monitor != logical_monitor)
+            continue;
+
+          crtc_mods = meta_crtc_kms_get_modifiers (crtc, format);
+          if (!crtc_mods)
+            {
+              g_array_free (modifiers, TRUE);
+              goto out;
+            }
+
+          for (m = 0; m < crtc_mods->len; m++)
+            {
+              uint64_t local_mod = g_array_index (crtc_mods, uint64_t, m);
+
+              if (local_mod == modifier)
+                {
+                  found_here = TRUE;
+                  break;
+                }
+            }
+
+          if (!found_here)
+            {
+              found_everywhere = FALSE;
+              break;
+            }
+        }
+
+      if (found_everywhere)
+        g_array_append_val (modifiers, modifier);
+    }
+
+  if (modifiers->len == 0)
+    {
+      g_array_free (modifiers, TRUE);
+      goto out;
+    }
+
+  return modifiers;
+
+out:
+  g_list_free (other_crtcs);
+  return NULL;
+}
+
 static gboolean
 should_surface_be_sharable (CoglOnscreen *onscreen)
 {
@@ -1690,19 +1831,36 @@ meta_renderer_native_create_surface_gbm (CoglOnscreen        *onscreen,
   struct gbm_surface *new_gbm_surface;
   EGLNativeWindowType egl_native_window;
   EGLSurface new_egl_surface;
-  uint32_t flags;
-
-  flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
-  if (should_surface_be_sharable (onscreen))
-    flags |= GBM_BO_USE_LINEAR;
+  uint32_t format = GBM_FORMAT_XRGB8888;
+  GArray *modifiers;
 
   renderer_gpu_data =
     meta_renderer_native_get_gpu_data (renderer_native,
                                        onscreen_native->render_gpu);
-  new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
-                                        width, height,
-                                        GBM_FORMAT_XRGB8888,
-                                        flags);
+
+  modifiers = get_supported_modifiers (onscreen, format);
+
+  if (modifiers)
+    {
+      new_gbm_surface =
+        gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device,
+                                           width, height, format,
+                                           (uint64_t *) modifiers->data,
+                                           modifiers->len);
+      g_array_free (modifiers, TRUE);
+    }
+  else
+    {
+      uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
+
+      if (should_surface_be_sharable (onscreen))
+        flags |= GBM_BO_USE_LINEAR;
+
+      new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
+                                            width, height,
+                                            format,
+                                            flags);
+    }
 
   if (!new_gbm_surface)
     {


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