[mutter] renderer/native: Use primary GPU to copy



commit 3794df608cd8cf63007822306692dce742b6f7d4
Author: Pekka Paalanen <pekka paalanen collabora com>
Date:   Thu Nov 29 13:34:40 2018 +0200

    renderer/native: Use primary GPU to copy
    
    When the preferred path META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU cannot
    be used, as is the case for e.g. DisplayLink devices which do not actually have
    a GPU, try to use the primary GPU for the copying before falling back to
    read-pixels which is a CPU copy.
    
    When the primary GPU copy works, it should be a significant performance win
    over the CPU copy by avoiding stalling libmutter for the duration.
    
    This also renames META_SHARED_FRAMEBUFFER_COPY_MODE_* because the new names are
    more accurate. While the secondary GPU copy is always a GPU copy, the primary
    copy might be either a CPU or a GPU copy.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/615

 src/backends/native/meta-renderer-native.c | 172 ++++++++++++++++++++++++++---
 1 file changed, 154 insertions(+), 18 deletions(-)
---
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 42c6a9ef2..5aa3af472 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -3,7 +3,7 @@
 /*
  * Copyright (C) 2011 Intel Corporation.
  * Copyright (C) 2016 Red Hat
- * Copyright (c) 2018 DisplayLink (UK) Ltd.
+ * Copyright (c) 2018,2019 DisplayLink (UK) Ltd.
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -69,6 +69,7 @@
 #include "backends/native/meta-renderer-native-gles3.h"
 #include "backends/native/meta-renderer-native.h"
 #include "cogl/cogl.h"
+#include "cogl/cogl-framebuffer.h"
 #include "core/boxes-private.h"
 
 #ifndef EGL_DRM_MASTER_FD_EXT
@@ -93,8 +94,14 @@ static GParamSpec *obj_props[PROP_LAST];
 
 typedef enum _MetaSharedFramebufferCopyMode
 {
-  META_SHARED_FRAMEBUFFER_COPY_MODE_GPU,
-  META_SHARED_FRAMEBUFFER_COPY_MODE_CPU
+  /* the secondary GPU will make the copy */
+  META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU,
+  /*
+   * The copy is made in the primary GPU rendering context, either
+   * as a CPU copy through Cogl read-pixels or as primary GPU copy
+   * using glBlitFramebuffer.
+   */
+  META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY
 } MetaSharedFramebufferCopyMode;
 
 typedef struct _MetaRendererNativeGpuData
@@ -121,6 +128,7 @@ typedef struct _MetaRendererNativeGpuData
   struct {
     MetaSharedFramebufferCopyMode copy_mode;
     gboolean is_hardware_rendering;
+    gboolean has_EGL_EXT_image_dma_buf_import_modifiers;
 
     /* For GPU blit mode */
     EGLContext egl_context;
@@ -875,7 +883,7 @@ init_secondary_gpu_state (MetaRendererNative  *renderer_native,
 
   switch (renderer_gpu_data->secondary.copy_mode)
     {
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
       if (!init_secondary_gpu_state_gpu_copy_mode (renderer_native,
                                                    onscreen,
                                                    renderer_gpu_data,
@@ -883,7 +891,7 @@ init_secondary_gpu_state (MetaRendererNative  *renderer_native,
                                                    error))
         return FALSE;
       break;
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
       if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
                                                    onscreen,
                                                    renderer_gpu_data,
@@ -967,10 +975,10 @@ free_current_secondary_bo (MetaGpuKms                          *gpu_kms,
   renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
   switch (renderer_gpu_data->secondary.copy_mode)
     {
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
       g_clear_object (&secondary_gpu_state->gbm.current_fb);
       break;
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
       break;
     }
 }
@@ -1458,10 +1466,10 @@ free_next_secondary_bo (MetaGpuKms                          *gpu_kms,
   renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
   switch (renderer_gpu_data->secondary.copy_mode)
     {
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
       g_clear_object (&secondary_gpu_state->gbm.next_fb);
       break;
-    case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
       break;
     }
 }
@@ -1831,6 +1839,125 @@ secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *seconda
     return &secondary_gpu_state->cpu.dumb_fbs[0];
 }
 
+static gboolean
+copy_shared_framebuffer_primary_gpu (CoglOnscreen                        *onscreen,
+                                     MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = framebuffer->context;
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglRenderer *cogl_renderer = cogl_display->renderer;
+  CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+  EGLDisplay egl_display = cogl_renderer_egl->edpy;
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  MetaRendererNativeGpuData *primary_gpu_data;
+  MetaDrmBufferDumb *buffer_dumb;
+  MetaDumbBuffer *dumb_fb;
+  int dmabuf_fd;
+  EGLImageKHR egl_image;
+  g_autoptr (GError) error = NULL;
+  uint32_t strides[1];
+  uint32_t offsets[1];
+  uint64_t modifiers[1];
+  CoglPixelFormat cogl_format;
+  CoglTexture2D *cogl_tex;
+  CoglOffscreen *cogl_fbo;
+  int ret;
+
+  primary_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
+                                                        renderer_native->primary_gpu_kms);
+  if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers)
+    return FALSE;
+
+  dumb_fb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
+
+  g_assert (cogl_framebuffer_get_width (framebuffer) == dumb_fb->width);
+  g_assert (cogl_framebuffer_get_height (framebuffer) == dumb_fb->height);
+
+  ret = cogl_pixel_format_from_drm_format (dumb_fb->drm_format,
+                                           &cogl_format,
+                                           NULL);
+  g_assert (ret);
+
+  dmabuf_fd = meta_dumb_buffer_ensure_dmabuf_fd (dumb_fb,
+                                                 secondary_gpu_state->gpu_kms);
+  if (dmabuf_fd == -1)
+    return FALSE;
+
+  strides[0] = dumb_fb->stride_bytes;
+  offsets[0] = 0;
+  modifiers[0] = DRM_FORMAT_MOD_LINEAR;
+  egl_image = meta_egl_create_dmabuf_image (egl,
+                                            egl_display,
+                                            dumb_fb->width,
+                                            dumb_fb->height,
+                                            dumb_fb->drm_format,
+                                            1 /* n_planes */,
+                                            &dmabuf_fd,
+                                            strides,
+                                            offsets,
+                                            modifiers,
+                                            &error);
+  if (egl_image == EGL_NO_IMAGE_KHR)
+    {
+      g_debug ("%s: Failed to import dumb buffer to EGL: %s",
+               __func__, error->message);
+
+      return FALSE;
+    }
+
+  cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context,
+                                                 dumb_fb->width,
+                                                 dumb_fb->height,
+                                                 cogl_format,
+                                                 egl_image,
+                                                 &error);
+
+  meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
+
+  if (!cogl_tex)
+    {
+      g_debug ("%s: Failed to make Cogl texture: %s",
+               __func__, error->message);
+
+      return FALSE;
+    }
+
+  cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
+  cogl_object_unref (cogl_tex);
+
+  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), &error))
+    {
+      g_debug ("%s: Failed Cogl FBO alloc: %s",
+               __func__, error->message);
+      cogl_object_unref (cogl_fbo);
+
+      return FALSE;
+    }
+
+  if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (cogl_fbo),
+                              0, 0, 0, 0,
+                              dumb_fb->width, dumb_fb->height, &error))
+    {
+      g_debug ("%s: Failed Cogl blit: %s", __func__, error->message);
+      cogl_object_unref (cogl_fbo);
+
+      return FALSE;
+    }
+
+  cogl_object_unref (cogl_fbo);
+
+  g_clear_object (&secondary_gpu_state->gbm.next_fb);
+  buffer_dumb = meta_drm_buffer_dumb_new (dumb_fb->fb_id);
+  secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_dumb);
+  secondary_gpu_state->cpu.dumb_fb = dumb_fb;
+
+  return TRUE;
+}
+
 typedef struct _PixelFormatMap {
   uint32_t drm_format;
   CoglPixelFormat cogl_format;
@@ -1953,13 +2080,17 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
       renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
       switch (renderer_gpu_data->secondary.copy_mode)
         {
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
           /* Done after eglSwapBuffers. */
           break;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
-          copy_shared_framebuffer_cpu (onscreen,
-                                       secondary_gpu_state,
-                                       renderer_gpu_data);
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
+          if (!copy_shared_framebuffer_primary_gpu (onscreen,
+                                                    secondary_gpu_state))
+            {
+              copy_shared_framebuffer_cpu (onscreen,
+                                           secondary_gpu_state,
+                                           renderer_gpu_data);
+            }
           break;
         }
     }
@@ -1987,13 +2118,13 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
                                            secondary_gpu_state->gpu_kms);
       switch (renderer_gpu_data->secondary.copy_mode)
         {
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
           copy_shared_framebuffer_gpu (onscreen,
                                        secondary_gpu_state,
                                        renderer_gpu_data,
                                        egl_context_changed);
           break;
-        case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
           /* Done before eglSwapBuffers. */
           break;
         }
@@ -3396,7 +3527,12 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
   renderer_gpu_data->secondary.is_hardware_rendering = TRUE;
   renderer_gpu_data->secondary.egl_context = egl_context;
   renderer_gpu_data->secondary.egl_config = egl_config;
-  renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
+  renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU;
+
+  renderer_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers =
+    meta_egl_has_extensions (egl, egl_display, NULL,
+                             "EGL_EXT_image_dma_buf_import_modifiers",
+                             NULL);
 
   return TRUE;
 
@@ -3416,7 +3552,7 @@ static void
 init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
 {
   renderer_gpu_data->secondary.is_hardware_rendering = FALSE;
-  renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_CPU;
+  renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
 }
 
 static void


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