[mutter/wip/3-monitors-on-nvidia: 219/221] wip! renderer/native: start to add stream copy mode



commit 952677cb5789c0da06c140145ae5ca6b28969022
Author: Ray Strode <rstrode redhat com>
Date:   Thu Sep 13 07:08:55 2018 -0400

    wip! renderer/native: start to add stream copy mode
    
    At the moment, mutter only supports using GBM for
    doing GPU blits to secondary video cards.
    
    This commit starts to sketch out using eglstreams
    for doing the copy.
    
    fixme: stepping through gdb shows mesa isn't
    getting the memcpy fastpath because of the GBM
    format/gl type we're using, need to figure out
    what combination makes memcpy kick in.
    
    Closes https://gitlab.gnome.org/GNOME/mutter/issues/205

 src/backends/native/meta-renderer-native.c | 341 ++++++++++++++++++++++++++++-
 1 file changed, 332 insertions(+), 9 deletions(-)
---
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 346bb9d5a..25a67aa12 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -84,7 +84,10 @@ static GParamSpec *obj_props[PROP_LAST];
 typedef enum _MetaSharedFramebufferCopyMode
 {
   META_SHARED_FRAMEBUFFER_COPY_MODE_GPU,
-  META_SHARED_FRAMEBUFFER_COPY_MODE_CPU
+  META_SHARED_FRAMEBUFFER_COPY_MODE_CPU,
+#ifdef HAVE_EGL_DEVICE
+  META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM
+#endif
 } MetaSharedFramebufferCopyMode;
 
 typedef struct _MetaRendererNativeGpuData
@@ -111,6 +114,7 @@ typedef struct _MetaRendererNativeGpuData
    * Fields used for blitting iGPU framebuffer content onto dGPU framebuffers.
    */
   struct {
+    MetaRendererNativeMode mode;
     MetaSharedFramebufferCopyMode copy_mode;
 
 #ifdef HAVE_EGL_DEVICE
@@ -150,6 +154,14 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState
     struct gbm_bo *next_bo;
   } gbm;
 
+#ifdef HAVE_EGL_DEVICE
+  struct {
+    uint8_t       *read_pixels;
+    MetaDumbBuffer dumb_fb;
+    EGLStreamKHR   stream;
+  } egl;
+#endif
+
   struct {
     MetaDumbBuffer *dumb_fb;
     MetaDumbBuffer dumb_fbs[2];
@@ -235,6 +247,19 @@ init_dumb_fb (MetaDumbBuffer *dumb_fb,
               uint32_t        format,
               GError        **error);
 
+#ifdef HAVE_EGL_DEVICE
+static gboolean
+meta_renderer_native_create_surface_egl_device (CoglOnscreen       *onscreen,
+                                                MetaMonitor        *monitor,
+                                                EGLDisplay          egl_display,
+                                                EGLConfig           egl_config,
+                                                int                 width,
+                                                int                 height,
+                                                EGLStreamKHR       *out_egl_stream,
+                                                EGLSurface         *out_egl_surface,
+                                                GError            **error);
+#endif
+
 static MetaEgl *
 meta_renderer_native_get_egl (MetaRendererNative *renderer_native);
 
@@ -640,6 +665,63 @@ init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative         *renderer_nat
   return TRUE;
 }
 
+#ifdef HAVE_EGL_DEVICE
+static gboolean
+init_secondary_gpu_state_stream_copy_mode (MetaRendererNative         *renderer_native,
+                                           CoglOnscreen               *onscreen,
+                                           MetaMonitor                *monitor,
+                                           MetaRendererNativeGpuData  *renderer_gpu_data,
+                                           MetaGpuKms                 *gpu_kms,
+                                           GError                    **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  EGLStreamKHR egl_stream;
+  int width, height;
+  EGLSurface egl_surface;
+  MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+
+  secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
+
+  if (!init_dumb_fb (&secondary_gpu_state->egl.dumb_fb,
+                     gpu_kms,
+                     width, height,
+                     GBM_FORMAT_XRGB8888,
+                     error))
+      goto failed;
+
+  if (!meta_renderer_native_create_surface_egl_device (onscreen,
+                                                       monitor,
+                                                       renderer_gpu_data->secondary.egl_display,
+                                                       renderer_gpu_data->secondary.egl_config,
+                                                       width, height,
+                                                       &egl_stream,
+                                                       &egl_surface,
+                                                       error))
+      goto failed;
+
+  secondary_gpu_state->gpu_kms = gpu_kms;
+  secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
+  secondary_gpu_state->egl.stream = egl_stream;
+  secondary_gpu_state->egl.read_pixels = g_malloc (width * height * 4);
+  secondary_gpu_state->egl_surface = egl_surface;
+
+  g_hash_table_insert (onscreen_native->secondary_gpu_states,
+                       gpu_kms, secondary_gpu_state);
+
+  return TRUE;
+
+failed:
+  if (secondary_gpu_state->egl.dumb_fb.fb_id)
+    release_dumb_fb (&secondary_gpu_state->egl.dumb_fb, gpu_kms);
+  return FALSE;
+}
+#endif
+
 static void
 secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
 {
@@ -648,6 +730,25 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta
   MetaGpuKms *gpu_kms = secondary_gpu_state->gpu_kms;
   unsigned int i;
 
+#ifdef HAVE_EGL_DEVICE
+  if (secondary_gpu_state->egl.dumb_fb.fb_id)
+    release_dumb_fb (&secondary_gpu_state->egl.dumb_fb, gpu_kms);
+
+  if (secondary_gpu_state->egl.stream != EGL_NO_STREAM_KHR)
+    {
+      MetaRendererNativeGpuData *renderer_gpu_data;
+
+      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
+      meta_egl_destroy_stream (egl,
+                               renderer_gpu_data->secondary.egl_display,
+                               secondary_gpu_state->egl.stream,
+                               NULL);
+      secondary_gpu_state->egl.stream = EGL_NO_STREAM_KHR;
+      g_clear_pointer (&secondary_gpu_state->egl.read_pixels,
+                       g_free);
+    }
+#endif
+
   if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
     {
       MetaRendererNativeGpuData *renderer_gpu_data;
@@ -720,6 +821,7 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative         *renderer_nat
 static gboolean
 init_secondary_gpu_state (MetaRendererNative  *renderer_native,
                           CoglOnscreen        *onscreen,
+                          MetaMonitor         *monitor,
                           MetaGpuKms          *gpu_kms,
                           GError             **error)
 {
@@ -738,6 +840,17 @@ init_secondary_gpu_state (MetaRendererNative  *renderer_native,
                                                    error))
         return FALSE;
       break;
+#ifdef HAVE_EGL_DEVICE
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
+      if (!init_secondary_gpu_state_stream_copy_mode (renderer_native,
+                                                      onscreen,
+                                                      monitor,
+                                                      renderer_gpu_data,
+                                                      gpu_kms,
+                                                      error))
+        return FALSE;
+      break;
+#endif
     case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
       if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
                                                    onscreen,
@@ -838,6 +951,10 @@ free_current_secondary_bo (MetaGpuKms                          *gpu_kms,
           secondary_gpu_state->gbm.current_bo = NULL;
         }
       break;
+#ifdef HAVE_EGL_DEVICE
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
+      break;
+#endif
     case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
       break;
     }
@@ -1272,6 +1389,10 @@ free_next_secondary_bo (MetaGpuKms                          *gpu_kms,
           secondary_gpu_state->gbm.next_bo = NULL;
         }
       break;
+#ifdef HAVE_EGL_DEVICE
+    case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
+      break;
+#endif
     case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
       break;
     }
@@ -1395,6 +1516,29 @@ flip_primary_egl_stream (MetaOnscreenNative *onscreen_native,
 
   return ret;
 }
+
+static gboolean
+flip_secondary_gpu_egl_stream (MetaOnscreenNative *onscreen_native,
+                               MetaGpuKms         *gpu_kms,
+                               MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
+                               GClosure           *flip_closure)
+{
+  MetaRendererNativeGpuData *renderer_gpu_data;
+  gboolean ret;
+
+  renderer_gpu_data =
+    meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
+                                       gpu_kms);
+
+  ret = flip_egl_stream (onscreen_native,
+                         gpu_kms,
+                         renderer_gpu_data->secondary.egl_display,
+                         secondary_gpu_state->egl.stream,
+                         flip_closure);
+  g_closure_ref (flip_closure);
+
+  return ret;
+}
 #endif /* HAVE_EGL_DEVICE */
 
 static void
@@ -1423,7 +1567,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
     }
 
   renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
-                                                         render_gpu);
+                                                         gpu_kms);
 
   if (gpu_kms == render_gpu)
     {
@@ -1460,9 +1604,25 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
       break;
 #ifdef HAVE_EGL_DEVICE
     case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
-      if (flip_primary_egl_stream (onscreen_native,
-                                   flip_closure))
-        onscreen_native->total_pending_flips++;
+      if (gpu_kms == render_gpu)
+        {
+          if (!flip_primary_egl_stream (onscreen_native,
+                                       flip_closure))
+            return;
+        }
+      else
+        {
+          if (!flip_secondary_gpu_egl_stream (onscreen_native,
+                                              gpu_kms,
+                                              secondary_gpu_state,
+                                              flip_closure))
+            return;
+        }
+
+      onscreen_native->total_pending_flips++;
+      if (secondary_gpu_state)
+        secondary_gpu_state->pending_flips++;
+
       *fb_in_use = TRUE;
       break;
 #endif
@@ -1496,12 +1656,25 @@ set_crtc_fb (MetaLogicalMonitor *logical_monitor,
   else
     {
       MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
+      MetaRendererNativeGpuData *renderer_gpu_data;
 
       secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
       if (!secondary_gpu_state)
         return;
 
-      fb_id = secondary_gpu_state->gbm.next_fb_id;
+      renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
+
+      switch (renderer_gpu_data->secondary.mode)
+        {
+        case META_RENDERER_NATIVE_MODE_GBM:
+          fb_id = secondary_gpu_state->gbm.next_fb_id;
+          break;
+#ifdef HAVE_EGL_DEVICE
+        case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+          fb_id = secondary_gpu_state->egl.dumb_fb.fb_id;
+        break;
+#endif
+        }
     }
 
   x = crtc->rect.x - logical_monitor->rect.x;
@@ -1849,6 +2022,60 @@ copy_shared_framebuffer_gpu (CoglOnscreen                        *onscreen,
                       &secondary_gpu_state->gbm.next_fb_id);
 }
 
+#ifdef HAVE_EGL_DEVICE
+static void
+draw_shared_framebuffer_stream (CoglOnscreen                        *onscreen,
+                                MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
+                                MetaRendererNativeGpuData           *renderer_gpu_data,
+                                gboolean                            *egl_context_changed)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  GError *error = NULL;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  uint32_t width, height;
+  void *target_data;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+
+  target_data = secondary_gpu_state->egl.read_pixels;
+
+  if (!meta_egl_make_current (egl,
+                              renderer_gpu_data->secondary.egl_display,
+                              secondary_gpu_state->egl_surface,
+                              secondary_gpu_state->egl_surface,
+                              renderer_gpu_data->secondary.egl_context,
+                              &error))
+    {
+      g_warning ("Failed to make current: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  *egl_context_changed = TRUE;
+
+  meta_renderer_native_gles3_draw_pixels (egl,
+                                          renderer_native->gles3,
+                                          width,
+                                          height,
+                                          target_data,
+                                          &error);
+
+  if (!meta_egl_swap_buffers (egl,
+                              renderer_gpu_data->secondary.egl_display,
+                              secondary_gpu_state->egl_surface,
+                              &error))
+    {
+      g_warning ("Failed to swap buffers: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+}
+#endif
+
 typedef struct _PixelFormatMap {
   uint32_t drm_format;
   CoglPixelFormat cogl_format;
@@ -1968,6 +2195,31 @@ copy_shared_framebuffer_cpu (CoglOnscreen                        *onscreen,
   secondary_gpu_state->gbm.next_fb_id = target_fb_id;
 }
 
+#ifdef HAVE_EGL_DEVICE
+static void
+copy_shared_framebuffer_stream (CoglOnscreen                        *onscreen,
+                                MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
+                                MetaRendererNativeGpuData           *renderer_gpu_data)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
+  MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
+  MetaRendererNative *renderer_native = onscreen_native->renderer_native;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  int width, height;
+  uint8_t *target_data;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+  target_data = secondary_gpu_state->egl.read_pixels;
+
+  meta_renderer_native_gles3_read_pixels (egl,
+                                          renderer_native->gles3,
+                                          width, height,
+                                          target_data);
+}
+#endif
+
 static void
 update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
 {
@@ -1989,6 +2241,13 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
         case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
           /* Done after eglSwapBuffers. */
           break;
+#ifdef HAVE_EGL_DEVICE
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
+          copy_shared_framebuffer_stream (onscreen,
+                                          secondary_gpu_state,
+                                          renderer_gpu_data);
+          break;
+#endif
         case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
           copy_shared_framebuffer_cpu (onscreen,
                                        secondary_gpu_state,
@@ -2026,6 +2285,14 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
                                        renderer_gpu_data,
                                        egl_context_changed);
           break;
+#ifdef HAVE_EGL_DEVICE
+        case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
+          draw_shared_framebuffer_stream (onscreen,
+                                          secondary_gpu_state,
+                                          renderer_gpu_data,
+                                          egl_context_changed);
+          break;
+#endif
         case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
           /* Done before eglSwapBuffers. */
           break;
@@ -2813,7 +3080,7 @@ meta_renderer_native_create_onscreen (MetaRendererNative   *renderer_native,
       if (get_secondary_gpu_state (onscreen, gpu_kms))
         continue;
 
-      if (!init_secondary_gpu_state (renderer_native, onscreen, gpu_kms, error))
+      if (!init_secondary_gpu_state (renderer_native, onscreen, monitor, gpu_kms, error))
         {
           cogl_object_unref (onscreen);
           return NULL;
@@ -3265,11 +3532,55 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data,
 
   renderer_gpu_data->secondary.egl_context = egl_context;
   renderer_gpu_data->secondary.egl_config = egl_config;
+  renderer_gpu_data->secondary.mode = META_RENDERER_NATIVE_MODE_GBM;
   renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
 
   return TRUE;
 }
 
+#ifdef HAVE_EGL_DEVICE
+static gboolean
+init_secondary_gpu_data_stream (MetaRendererNativeGpuData  *renderer_gpu_data,
+                                GError                    **error)
+{
+  MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
+  MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
+  EGLDisplay egl_display = renderer_gpu_data->secondary.egl_display;
+  EGLConfig egl_config;
+  EGLContext egl_context;
+
+  if (!create_secondary_egl_config (egl,
+                                    renderer_gpu_data->secondary.mode, egl_display,
+                                    &egl_config, error))
+    return FALSE;
+
+  egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error);
+  if (egl_context == EGL_NO_CONTEXT)
+    return FALSE;
+
+  meta_renderer_native_ensure_gles3 (renderer_native);
+
+  if (!meta_egl_make_current (egl,
+                              egl_display,
+                              EGL_NO_SURFACE,
+                              EGL_NO_SURFACE,
+                              egl_context,
+                              error))
+    {
+      meta_egl_destroy_context (egl, egl_display, egl_context, NULL);
+      return FALSE;
+    }
+
+  meta_renderer_native_gles3_load_basic_shaders (egl, renderer_native->gles3);
+
+  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_STREAM;
+
+  return TRUE;
+}
+#endif
+
 static void
 init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
 {
@@ -3281,8 +3592,20 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
 {
   GError *error = NULL;
 
-  if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error))
-    return;
+  switch (renderer_gpu_data->secondary.mode)
+    {
+      case META_RENDERER_NATIVE_MODE_GBM:
+        if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error))
+          return;
+      break;
+
+#ifdef HAVE_EGL_DEVICE
+      case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
+        if (init_secondary_gpu_data_stream (renderer_gpu_data, &error))
+          return;
+      break;
+#endif
+    }
 
   g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s",
              error->message);


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