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



commit 82f03c51ac834dc63ad9a9249604727e64964835
Author: Ray Strode <rstrode redhat com>
Date:   Thu Sep 13 13:36:52 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: in order to get memcpy fastpath we get
    inverted colors and have to fix it up in the shader.
    
    FIXME: need to move some of the globals to be in
    a more structured place
    
    Closes https://gitlab.gnome.org/GNOME/mutter/issues/205

 src/backends/native/meta-renderer-native-gles3.c | 214 ++++++++++++++
 src/backends/native/meta-renderer-native-gles3.h |  11 +
 src/backends/native/meta-renderer-native.c       | 358 ++++++++++++++++++++++-
 3 files changed, 574 insertions(+), 9 deletions(-)
---
diff --git a/src/backends/native/meta-renderer-native-gles3.c 
b/src/backends/native/meta-renderer-native-gles3.c
index 7afea8648..4665add83 100644
--- a/src/backends/native/meta-renderer-native-gles3.c
+++ b/src/backends/native/meta-renderer-native-gles3.c
@@ -179,6 +179,97 @@ paint_egl_image (MetaGles3   *gles3,
                                     GL_NEAREST));
 }
 
+/* FIXME: all these declarations are just floating here
+ */
+struct __attribute__ ((__packed__)) position
+{
+  float x, y;
+};
+
+struct __attribute__ ((__packed__)) texture_coordinate
+{
+  float u, v;
+};
+
+struct __attribute__ ((__packed__)) vertex
+{
+  struct position position;
+  struct texture_coordinate texture_coordinate;
+};
+
+struct __attribute__ ((__packed__)) triangle
+{
+  unsigned int first_vertex;
+  unsigned int middle_vertex;
+  unsigned int last_vertex;
+};
+
+enum
+{
+  RIGHT_TOP_VERTEX = 0,
+  BOTTOM_RIGHT_VERTEX,
+  BOTTOM_LEFT_VERTEX,
+  TOP_LEFT_VERTEX
+};
+
+static const float view_left = -1.0f, view_right = 1.0f, view_top = 1.0f, view_bottom = -1.0f;
+static const float texture_left = 0.0f, texture_right = 1.0f, texture_top = 0.0f, texture_bottom = 1.0f;
+static GLuint vertex_array;
+static GLuint vertex_buffer;
+static GLuint triangle_buffer;
+
+struct vertex vertices[] = {
+  [RIGHT_TOP_VERTEX] = {{view_right, view_top},
+                        {texture_right, texture_top}},
+  [BOTTOM_RIGHT_VERTEX] = {{view_right, view_bottom},
+                           {texture_right, texture_bottom}},
+  [BOTTOM_LEFT_VERTEX] = {{view_left, view_bottom},
+                          {texture_left, texture_bottom}},
+  [TOP_LEFT_VERTEX] = {{view_left, view_top},
+                       {texture_left, texture_top}},
+};
+
+struct triangle triangles[] = {
+  {TOP_LEFT_VERTEX, BOTTOM_RIGHT_VERTEX, BOTTOM_LEFT_VERTEX},
+  {TOP_LEFT_VERTEX, RIGHT_TOP_VERTEX, BOTTOM_RIGHT_VERTEX},
+};
+
+gboolean
+meta_renderer_native_gles3_draw_pixels (MetaEgl        *egl,
+                                        MetaGles3      *gles3,
+                                        unsigned int    width,
+                                        unsigned int    height,
+                                        uint8_t        *pixels,
+                                        GError        **error)
+{
+  meta_gles3_clear_error (gles3);
+
+  GLBAS (gles3, glClearColor, (0.0,1.0,0.0,1.0));
+  GLBAS (gles3, glClear, (GL_COLOR_BUFFER_BIT));
+
+  GLBAS (gles3, glViewport, (0, 0, width, height));
+  GLBAS (gles3, glTexImage2D, (GL_TEXTURE_2D, 0, GL_RGBA,
+                               width, height, 0, GL_RGBA,
+                               GL_UNSIGNED_BYTE, pixels));
+
+  GLBAS (gles3, glBindBuffer, (GL_ARRAY_BUFFER, vertex_buffer));
+  GLBAS (gles3, glEnableVertexAttribArray, (0));
+  GLBAS (gles3, glVertexAttribPointer, (0,
+                                        sizeof (struct position) / sizeof (float), GL_FLOAT,
+                                        GL_FALSE,
+                                        sizeof (struct vertex), (void *) offsetof (struct vertex, 
position)));
+  GLBAS (gles3, glEnableVertexAttribArray, (1));
+  GLBAS (gles3, glVertexAttribPointer, (1,
+                                        sizeof (struct texture_coordinate) / sizeof (float), GL_FLOAT,
+                                        GL_FALSE,
+                                        sizeof (struct vertex), (void *) offsetof (struct vertex, 
texture_coordinate)));
+  GLBAS (gles3, glDrawElements, (GL_TRIANGLES,
+                                 G_N_ELEMENTS (triangles) * (sizeof (struct triangle) / sizeof (unsigned 
int)), GL_UNSIGNED_INT,
+                                 0));
+
+  return TRUE;
+}
+
 gboolean
 meta_renderer_native_gles3_blit_shared_bo (MetaEgl        *egl,
                                            MetaGles3      *gles3,
@@ -238,3 +329,126 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl        *egl,
 
   return TRUE;
 }
+
+static void
+meta_renderer_native_gles3_load_basic_shaders (MetaEgl   *egl,
+                                               MetaGles3 *gles3)
+{
+  GLuint vertex_shader = 0, fragment_shader = 0, shader_program;
+  gboolean status = FALSE;
+  const char *vertex_shader_source =
+"#version 330 core\n"
+"layout (location = 0) in vec2 position;\n"
+"layout (location = 1) in vec2 input_texture_coords;\n"
+"out vec2 texture_coords;\n"
+"void main()\n"
+"{\n"
+"  gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);\n"
+"  texture_coords = input_texture_coords;\n"
+"}\n";
+
+  const char *fragment_shader_source =
+"#version 330 core\n"
+"uniform sampler2D input_texture;\n"
+"in vec2 texture_coords;\n"
+"out vec4 output_color;\n"
+"void main()\n"
+"{\n"
+/* FIXME: cogl uses a framebuffer format of COGL_PIXEL_FORMAT_RGBA_8888_PRE
+ * by default which maps to DRM_FORMAT_ABGR8888 on little endian.  The
+ * destination format is DRM_FORMAT_XRGB8888, so the color channels are
+ * swapped.  The .bgra swizzle here swaps it back, but we should see if
+ * we can find a better fix (this probably breaks on big endian) */
+"  output_color = texture(input_texture, texture_coords).bgra;\n"
+"}\n";
+
+  vertex_shader = glCreateShader (GL_VERTEX_SHADER);
+  glShaderSource (vertex_shader, 1, &vertex_shader_source, NULL);
+  glCompileShader (vertex_shader);
+  glGetShaderiv (vertex_shader, GL_COMPILE_STATUS, &status);
+
+  if (!status)
+    {
+      char compile_log[1024] = "";
+      glGetShaderInfoLog (vertex_shader, sizeof (compile_log), NULL, compile_log);
+      g_warning ("vertex shader compilation failed:\n %s\n", compile_log);
+      goto out;
+    }
+
+  fragment_shader = glCreateShader (GL_FRAGMENT_SHADER);
+  glShaderSource (fragment_shader, 1, &fragment_shader_source, NULL);
+  glCompileShader (fragment_shader);
+  glGetShaderiv (fragment_shader, GL_COMPILE_STATUS, &status);
+
+  if (!status)
+    {
+      char compile_log[1024] = "";
+      glGetShaderInfoLog (fragment_shader, sizeof (compile_log), NULL, compile_log);
+      g_warning ("fragment shader compilation failed:\n %s\n", compile_log);
+      goto out;
+    }
+
+  shader_program = glCreateProgram ();
+  glAttachShader (shader_program, vertex_shader);
+  glAttachShader (shader_program, fragment_shader);
+  glLinkProgram (shader_program);
+
+  glGetProgramiv (shader_program, GL_LINK_STATUS, &status);
+
+  if (!status)
+    {
+      char link_log[1024] = "";
+
+      glGetProgramInfoLog (shader_program, sizeof (link_log), NULL, link_log);
+      g_warning ("shader link failed:\n %s\n", link_log);
+      goto out;
+    }
+
+  glUseProgram (shader_program);
+
+out:
+  if (vertex_shader)
+    glDeleteShader (vertex_shader);
+  if (fragment_shader)
+    glDeleteShader (fragment_shader);
+}
+
+gboolean
+meta_renderer_native_gles3_prepare_for_drawing (MetaEgl    *egl,
+                                                MetaGles3  *gles3,
+                                                GError    **error)
+{
+  GLuint texture;
+
+  meta_renderer_native_gles3_load_basic_shaders (egl, gles3);
+
+  meta_gles3_clear_error (gles3);
+
+  GLBAS (gles3, glGenVertexArrays, (1, &vertex_array));
+  GLBAS (gles3, glBindVertexArray, (vertex_array));
+
+  GLBAS (gles3, glGenBuffers, (1, &vertex_buffer));
+  GLBAS (gles3, glBindBuffer, (GL_ARRAY_BUFFER, vertex_buffer));
+  GLBAS (gles3, glBufferData, (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STREAM_DRAW));
+
+  GLBAS (gles3, glGenBuffers, (1, &triangle_buffer));
+  GLBAS (gles3, glBindBuffer, (GL_ELEMENT_ARRAY_BUFFER, triangle_buffer));
+  GLBAS (gles3, glBufferData, (GL_ELEMENT_ARRAY_BUFFER, sizeof (triangles), triangles, GL_STREAM_DRAW));
+
+  GLBAS (gles3, glActiveTexture, (GL_TEXTURE0));
+  GLBAS (gles3, glGenTextures, (1, &texture));
+  GLBAS (gles3, glBindTexture, (GL_TEXTURE_2D, texture));
+
+  GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                                  GL_NEAREST));
+  GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                                  GL_NEAREST));
+  GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+                                  GL_CLAMP_TO_EDGE));
+  GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+                                  GL_CLAMP_TO_EDGE));
+  GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_R_OES,
+                                  GL_CLAMP_TO_EDGE));
+
+  return TRUE;
+}
diff --git a/src/backends/native/meta-renderer-native-gles3.h 
b/src/backends/native/meta-renderer-native-gles3.h
index 4e7324c8d..1de13f9be 100644
--- a/src/backends/native/meta-renderer-native-gles3.h
+++ b/src/backends/native/meta-renderer-native-gles3.h
@@ -37,4 +37,15 @@ gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl       *egl,
                                                     struct gbm_bo *shared_bo,
                                                     GError       **error);
 
+gboolean meta_renderer_native_gles3_prepare_for_drawing (MetaEgl    *egl,
+                                                         MetaGles3  *gles3,
+                                                         GError    **error);
+
+gboolean meta_renderer_native_gles3_draw_pixels (MetaEgl        *egl,
+                                                 MetaGles3      *gles3,
+                                                 unsigned int    width,
+                                                 unsigned int    height,
+                                                 uint8_t        *pixels,
+                                                 GError        **error);
+
 #endif /* META_RENDERER_NATIVE_GLES3_H */
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index d57a76d4e..59f3147d7 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       *copied_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,
+                     DRM_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.copied_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.copied_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.copied_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,48 @@ 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);
+  CoglContext *cogl_context = framebuffer->context;
+  int width, height;
+  uint8_t *target_data;
+  uint32_t target_drm_format = DRM_FORMAT_XRGB8888;
+  CoglBitmap *dumb_bitmap;
+  CoglPixelFormat cogl_format;
+  gboolean ret;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+  target_data = secondary_gpu_state->egl.copied_pixels;
+
+  ret = cogl_pixel_format_from_drm_format (target_drm_format,
+                                           &cogl_format,
+                                           NULL);
+  g_assert (ret);
+
+  dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
+                                          width,
+                                          height,
+                                          cogl_format,
+                                          width * 4,
+                                          target_data);
+
+  if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
+                                                 0 /* x */,
+                                                 0 /* y */,
+                                                 COGL_READ_PIXELS_COLOR_BUFFER,
+                                                 dumb_bitmap))
+    g_warning ("Failed to read pixels from primary renderer");
+
+  cogl_object_unref (dumb_bitmap);
+}
+#endif
+
 static void
 update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
 {
@@ -1989,6 +2258,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 +2302,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;
@@ -2815,7 +3099,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;
@@ -3267,11 +3551,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_prepare_for_drawing (egl, renderer_native->gles3, NULL);
+
+  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)
 {
@@ -3283,8 +3611,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]