[mutter] renderer-native: Resize legacy onscreen before panting



commit e891a8b6282eb8617422d4c351d731c47edf373f
Author: Jonas Ådahl <jadahl gmail com>
Date:   Wed Jul 6 13:17:34 2016 +0800

    renderer-native: Resize legacy onscreen before panting
    
    By creating a pending gbm/EGL surface pair, only setting it on
    swap-buffers, we would draw onto a buffer on the old surface, then swap
    the buffer from the new surface, causing the first frame after a
    hot-plug always having no content.
    
    This was in the past not very noticable since some non-deterministic but
    frequent side effect in gnome-shell caused hot-plugging to always render
    two new frames, but after "Introduce regional stage rendering", this
    side effect did not occur as often, thus making it more visible.
    
    This commit updates the current gbm/EGL surface pair before painting a
    frame, so that when the frame is painted, the surface with the correct
    size is used and the buffer from correct surface is swapped.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768976

 src/backends/native/meta-renderer-native.c |   86 +++++++++++++---------------
 src/backends/native/meta-stage-native.c    |   87 ++++++++++++++++++---------
 2 files changed, 98 insertions(+), 75 deletions(-)
---
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index e8d7451..67d0273 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -71,9 +71,6 @@ typedef struct _MetaOnscreenNative
   struct gbm_bo *next_bo;
   gboolean pending_swap_notify;
 
-  EGLSurface *pending_egl_surface;
-  struct gbm_surface *pending_surface;
-
   gboolean pending_set_crtc;
 
   MetaRendererView *view;
@@ -606,33 +603,10 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
   view = onscreen_native->view;
   clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
 
-  if (onscreen_native->pending_egl_surface)
-    {
-      CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
-
-      eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface);
-      egl_onscreen->egl_surface = onscreen_native->pending_egl_surface;
-      onscreen_native->pending_egl_surface = NULL;
-
-      _cogl_framebuffer_winsys_update_size (fb,
-                                            view_layout.width,
-                                            view_layout.height);
-      cogl_context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
-    }
-
   parent_vtable->onscreen_swap_buffers_with_damage (onscreen,
                                                     rectangles,
                                                     n_rectangles);
 
-  if (onscreen_native->pending_surface)
-    {
-      free_current_bo (onscreen);
-      if (onscreen_native->surface)
-        gbm_surface_destroy (onscreen_native->surface);
-      onscreen_native->surface = onscreen_native->pending_surface;
-      onscreen_native->pending_surface = NULL;
-    }
-
   /* Now we need to set the CRTC to whatever is the front buffer */
   onscreen_native->next_bo =
     gbm_surface_lock_front_buffer (onscreen_native->surface);
@@ -887,14 +861,27 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
 
   if (width != view_layout.width || height != view_layout.height)
     {
+      MetaBackend *backend = meta_get_backend ();
+      MetaMonitorManager *monitor_manager =
+        meta_backend_get_monitor_manager (backend);
+      MetaMonitorManagerKms *monitor_manager_kms =
+        META_MONITOR_MANAGER_KMS (monitor_manager);
       CoglFramebuffer *framebuffer =
         clutter_stage_view_get_framebuffer (stage_view);
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
       CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
       MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+      CoglDisplayEGL *egl_display = cogl_display->winsys;
       struct gbm_surface *new_surface;
       EGLSurface new_egl_surface;
 
+      /*
+       * Ensure we don't have any pending flips that will want
+       * to swap the current buffer.
+       */
+      while (onscreen_native->next_fb_id != 0)
+        meta_monitor_manager_kms_wait_for_flip (monitor_manager_kms);
+
       /* Need to drop the GBM surface and create a new one */
 
       if (!meta_renderer_native_create_surface (renderer_native,
@@ -904,29 +891,36 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
                                                 error))
         return FALSE;
 
-
-      if (onscreen_native->pending_egl_surface)
-        eglDestroySurface (egl_renderer->edpy,
-                           onscreen_native->pending_egl_surface);
-      if (onscreen_native->pending_surface)
-        gbm_surface_destroy (onscreen_native->pending_surface);
-
-      /* If there's already a surface, wait until the next swap to switch
-       * it out, otherwise, if we're just starting up we can use the new
-       * surface right away.
-       */
-      if (onscreen_native->surface != NULL)
+      if (egl_onscreen->egl_surface)
         {
-          onscreen_native->pending_surface = new_surface;
-          onscreen_native->pending_egl_surface = new_egl_surface;
+          _cogl_winsys_egl_make_current (cogl_display,
+                                         egl_display->dummy_surface,
+                                         egl_display->dummy_surface,
+                                         egl_display->egl_context);
+          eglDestroySurface (egl_renderer->edpy,
+                             egl_onscreen->egl_surface);
         }
-      else
-        {
-          onscreen_native->surface = new_surface;
-          egl_onscreen->egl_surface = new_egl_surface;
 
-          _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
-        }
+      /*
+       * Release the current buffer and destroy the associated surface. The
+       * kernel will deal with keeping the actual buffer alive until its no
+       * longer used.
+       */
+      free_current_bo (onscreen);
+      g_clear_pointer (&onscreen_native->surface, gbm_surface_destroy);
+
+      /*
+       * Update the active gbm and egl surfaces and make sure they they are
+       * used for drawing the coming frame.
+       */
+      onscreen_native->surface = new_surface;
+      egl_onscreen->egl_surface = new_egl_surface;
+      _cogl_winsys_egl_make_current (cogl_display,
+                                     egl_onscreen->egl_surface,
+                                     egl_onscreen->egl_surface,
+                                     egl_display->egl_context);
+
+      _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
     }
 
   meta_renderer_native_queue_modes_reset (renderer_native);
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index c0b6d24..2dadbb9 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -43,6 +43,10 @@ struct _MetaStageNative
 
   int64_t presented_frame_counter_sync;
   int64_t presented_frame_counter_complete;
+
+  gboolean pending_resize;
+  int pending_width;
+  int pending_height;
 };
 
 static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
@@ -164,35 +168,9 @@ meta_stage_native_legacy_set_size (MetaStageNative *stage_native,
                                    int              width,
                                    int              height)
 {
-  MetaBackend *backend = meta_get_backend ();
-  MetaRenderer *renderer = meta_backend_get_renderer (backend);
-  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
-  MetaRendererView *legacy_view;
-  GError *error = NULL;
-  cairo_rectangle_int_t view_layout;
-
-  legacy_view = get_legacy_view (renderer);
-  if (!legacy_view)
-    return;
-
-  if (!meta_renderer_native_set_legacy_view_size (renderer_native,
-                                                  legacy_view,
-                                                  width, height,
-                                                  &error))
-    {
-      meta_warning ("Applying display configuration failed: %s\n",
-                    error->message);
-      g_error_free (error);
-      return;
-    }
-
-  view_layout = (cairo_rectangle_int_t) {
-    .width = width,
-    .height = height
-  };
-  g_object_set (G_OBJECT (legacy_view),
-                "layout", &view_layout,
-                NULL);
+  stage_native->pending_resize = TRUE;
+  stage_native->pending_width = width;
+  stage_native->pending_height = height;
 }
 
 static void
@@ -283,6 +261,56 @@ meta_stage_native_get_frame_counter (ClutterStageWindow *stage_window)
 }
 
 static void
+maybe_resize_legacy_view (MetaStageNative *stage_native)
+{
+  MetaBackend *backend = meta_get_backend ();
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
+  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+  MetaRendererView *legacy_view;
+  int width = stage_native->pending_width;
+  int height = stage_native->pending_height;
+  GError *error = NULL;
+  cairo_rectangle_int_t view_layout;
+
+  if (!stage_native->pending_resize)
+    return;
+  stage_native->pending_resize = FALSE;
+
+  legacy_view = get_legacy_view (renderer);
+  if (!legacy_view)
+    return;
+
+  if (!meta_renderer_native_set_legacy_view_size (renderer_native,
+                                                  legacy_view,
+                                                  width, height,
+                                                  &error))
+    {
+      meta_warning ("Applying display configuration failed: %s\n",
+                    error->message);
+      g_error_free (error);
+      return;
+    }
+
+  view_layout = (cairo_rectangle_int_t) {
+    .width = width,
+    .height = height
+  };
+  g_object_set (G_OBJECT (legacy_view),
+                "layout", &view_layout,
+                NULL);
+}
+
+static void
+meta_stage_native_redraw (ClutterStageWindow *stage_window)
+{
+  MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window);
+
+  maybe_resize_legacy_view (stage_native);
+
+  clutter_stage_window_parent_iface->redraw (stage_window);
+}
+
+static void
 meta_stage_native_finish_frame (ClutterStageWindow *stage_window)
 {
   MetaBackend *backend = meta_get_backend ();
@@ -315,5 +343,6 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->get_geometry = meta_stage_native_get_geometry;
   iface->get_views = meta_stage_native_get_views;
   iface->get_frame_counter = meta_stage_native_get_frame_counter;
+  iface->redraw = meta_stage_native_redraw;
   iface->finish_frame = meta_stage_native_finish_frame;
 }


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