[mutter] clutter/stage-view: Separate offscreen and shadowfb



commit db90c0d509f38dfd4c88b32d0cbb1ea53f399a63
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Tue Oct 22 17:03:03 2019 +0200

    clutter/stage-view: Separate offscreen and shadowfb
    
    Previously, we would use a single offscreen framebuffer for both
    transformations and when a shadow framebuffer should be used, but that
    can be dreadfully slow when using software rendering with a discrete GPU
    due to bandwidth limitations.
    
    Keep the offscreen framebuffer for transformations only and add another
    intermediate shadow framebuffer used as a copy of the onscreen
    framebuffer.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/877

 clutter/clutter/clutter-stage-view-private.h |   4 +-
 clutter/clutter/clutter-stage-view.c         | 162 +++++++++++++++++++++------
 clutter/clutter/cogl/clutter-stage-cogl.c    |   6 +-
 3 files changed, 130 insertions(+), 42 deletions(-)
---
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
index 89c42599f..9fcbadba5 100644
--- a/clutter/clutter/clutter-stage-view-private.h
+++ b/clutter/clutter/clutter-stage-view-private.h
@@ -20,8 +20,8 @@
 
 #include "clutter/clutter-stage-view.h"
 
-void clutter_stage_view_blit_offscreen (ClutterStageView            *view,
-                                        const cairo_rectangle_int_t *clip);
+void clutter_stage_view_after_paint (ClutterStageView            *view,
+                                     const cairo_rectangle_int_t *clip);
 
 gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
 
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index b76bf677b..aa1cb212f 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -30,6 +30,7 @@ enum
   PROP_LAYOUT,
   PROP_FRAMEBUFFER,
   PROP_OFFSCREEN,
+  PROP_SHADOWFB,
   PROP_SCALE,
 
   PROP_LAST
@@ -44,7 +45,10 @@ typedef struct _ClutterStageViewPrivate
   CoglFramebuffer *framebuffer;
 
   CoglOffscreen *offscreen;
-  CoglPipeline *pipeline;
+  CoglPipeline *offscreen_pipeline;
+
+  CoglOffscreen *shadowfb;
+  CoglPipeline *shadowfb_pipeline;
 
   guint dirty_viewport   : 1;
   guint dirty_projection : 1;
@@ -78,6 +82,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
 
   if (priv->offscreen)
     return priv->offscreen;
+  else if (priv->shadowfb)
+    return priv->shadowfb;
   else
     return priv->framebuffer;
 }
@@ -99,6 +105,24 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
   return priv->framebuffer;
 }
 
+static CoglPipeline *
+clutter_stage_view_create_framebuffer_pipeline (CoglFramebuffer *framebuffer)
+{
+  CoglPipeline *pipeline;
+
+  pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
+
+  cogl_pipeline_set_layer_filters (pipeline, 0,
+                                   COGL_PIPELINE_FILTER_NEAREST,
+                                   COGL_PIPELINE_FILTER_NEAREST);
+  cogl_pipeline_set_layer_texture (pipeline, 0,
+                                   cogl_offscreen_get_texture (framebuffer));
+  cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
+                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+  return pipeline;
+}
+
 static void
 clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
 {
@@ -109,71 +133,122 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
 
   g_assert (priv->offscreen != NULL);
 
-  if (priv->pipeline)
+  if (priv->offscreen_pipeline)
     return;
 
-  priv->pipeline =
-    cogl_pipeline_new (cogl_framebuffer_get_context (priv->offscreen));
-  cogl_pipeline_set_layer_filters (priv->pipeline, 0,
-                                   COGL_PIPELINE_FILTER_NEAREST,
-                                   COGL_PIPELINE_FILTER_NEAREST);
-  cogl_pipeline_set_layer_texture (priv->pipeline, 0,
-                                   cogl_offscreen_get_texture (priv->offscreen));
-  cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0,
-                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+  priv->offscreen_pipeline =
+    clutter_stage_view_create_framebuffer_pipeline (priv->offscreen);
 
   if (view_class->setup_offscreen_blit_pipeline)
-    view_class->setup_offscreen_blit_pipeline (view, priv->pipeline);
+    view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
 }
 
-void
-clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
+static void
+clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
 {
   ClutterStageViewPrivate *priv =
     clutter_stage_view_get_instance_private (view);
 
-  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+  if (priv->shadowfb_pipeline)
+    return;
+
+  priv->shadowfb_pipeline =
+    clutter_stage_view_create_framebuffer_pipeline (priv->shadowfb);
 }
 
 void
-clutter_stage_view_blit_offscreen (ClutterStageView            *view,
-                                   const cairo_rectangle_int_t *rect)
+clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
 {
   ClutterStageViewPrivate *priv =
     clutter_stage_view_get_instance_private (view);
+
+  g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
+}
+
+static void
+clutter_stage_view_copy_to_framebuffer (ClutterStageView            *view,
+                                        const cairo_rectangle_int_t *rect,
+                                        CoglPipeline                *pipeline,
+                                        CoglFramebuffer             *src_framebuffer,
+                                        CoglFramebuffer             *dst_framebuffer,
+                                        gboolean                     can_blit)
+{
   CoglMatrix matrix;
 
-  clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
-  if (cogl_matrix_is_identity (&matrix))
+  /* First, try with blit */
+  if (can_blit)
     {
-      int fb_width = cogl_framebuffer_get_width (priv->framebuffer);
-      int fb_height = cogl_framebuffer_get_height (priv->framebuffer);
-
-      if (cogl_blit_framebuffer (priv->offscreen,
-                                 priv->framebuffer,
+      if (cogl_blit_framebuffer (src_framebuffer,
+                                 dst_framebuffer,
                                  0, 0,
                                  0, 0,
-                                 fb_width, fb_height,
+                                 cogl_framebuffer_get_width (dst_framebuffer),
+                                 cogl_framebuffer_get_height (dst_framebuffer),
                                  NULL))
         return;
     }
 
-  clutter_stage_view_ensure_offscreen_blit_pipeline (view);
-  cogl_framebuffer_push_matrix (priv->framebuffer);
+  /* If blit fails, fallback to the slower painting method */
+  cogl_framebuffer_push_matrix (dst_framebuffer);
 
-  /* Set transform so 0,0 is on the top left corner and 1,1 on
-   * the bottom right corner.
-   */
   cogl_matrix_init_identity (&matrix);
   cogl_matrix_translate (&matrix, -1, 1, 0);
   cogl_matrix_scale (&matrix, 2, -2, 0);
-  cogl_framebuffer_set_projection_matrix (priv->framebuffer, &matrix);
+  cogl_framebuffer_set_projection_matrix (dst_framebuffer, &matrix);
 
-  cogl_framebuffer_draw_rectangle (priv->framebuffer,
-                                   priv->pipeline,
+  cogl_framebuffer_draw_rectangle (dst_framebuffer,
+                                   pipeline,
                                    0, 0, 1, 1);
 
-  cogl_framebuffer_pop_matrix (priv->framebuffer);
+  cogl_framebuffer_pop_matrix (dst_framebuffer);
+}
+
+void
+clutter_stage_view_after_paint (ClutterStageView            *view,
+                                const cairo_rectangle_int_t *rect)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  if (priv->offscreen)
+    {
+      gboolean can_blit;
+      CoglMatrix matrix;
+
+      clutter_stage_view_ensure_offscreen_blit_pipeline (view);
+      clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
+      can_blit = cogl_matrix_is_identity (&matrix);
+
+      if (priv->shadowfb)
+        {
+          clutter_stage_view_copy_to_framebuffer (view,
+                                                  rect,
+                                                  priv->offscreen_pipeline,
+                                                  priv->offscreen,
+                                                  priv->shadowfb,
+                                                  can_blit);
+        }
+      else
+        {
+          clutter_stage_view_copy_to_framebuffer (view,
+                                                  rect,
+                                                  priv->offscreen_pipeline,
+                                                  priv->offscreen,
+                                                  priv->framebuffer,
+                                                  can_blit);
+        }
+    }
+
+  if (priv->shadowfb)
+    {
+      clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
+      clutter_stage_view_copy_to_framebuffer (view,
+                                              rect,
+                                              priv->shadowfb_pipeline,
+                                              priv->shadowfb,
+                                              priv->framebuffer,
+                                              TRUE);
+    }
 }
 
 float
@@ -273,6 +348,9 @@ clutter_stage_view_get_property (GObject    *object,
     case PROP_OFFSCREEN:
       g_value_set_boxed (value, priv->offscreen);
       break;
+    case PROP_SHADOWFB:
+      g_value_set_boxed (value, priv->shadowfb);
+      break;
     case PROP_SCALE:
       g_value_set_float (value, priv->scale);
       break;
@@ -318,6 +396,9 @@ clutter_stage_view_set_property (GObject      *object,
     case PROP_OFFSCREEN:
       priv->offscreen = g_value_dup_boxed (value);
       break;
+    case PROP_SHADOWFB:
+      priv->shadowfb = g_value_dup_boxed (value);
+      break;
     case PROP_SCALE:
       priv->scale = g_value_get_float (value);
       break;
@@ -334,8 +415,10 @@ clutter_stage_view_dispose (GObject *object)
     clutter_stage_view_get_instance_private (view);
 
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
+  g_clear_pointer (&priv->shadowfb, cogl_object_unref);
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
-  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+  g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
+  g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
 
   G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
 }
@@ -390,6 +473,15 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
                         G_PARAM_CONSTRUCT_ONLY |
                         G_PARAM_STATIC_STRINGS);
 
+  obj_props[PROP_SHADOWFB] =
+    g_param_spec_boxed ("shadowfb",
+                        "Shadow framebuffer",
+                        "Framebuffer used as intermediate shadow buffer",
+                        COGL_TYPE_HANDLE,
+                        G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS);
+
   obj_props[PROP_SCALE] =
     g_param_spec_float ("scale",
                         "View scale",
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index fdc22476a..6dfde0b6b 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -563,11 +563,7 @@ paint_stage (ClutterStageCogl            *stage_cogl,
   _clutter_stage_maybe_setup_viewport (stage, view);
   _clutter_stage_paint_view (stage, view, &paint_rect);
 
-  if (clutter_stage_view_get_onscreen (view) !=
-      clutter_stage_view_get_framebuffer (view))
-    {
-      clutter_stage_view_blit_offscreen (view, &paint_rect);
-    }
+  clutter_stage_view_after_paint (view, &paint_rect);
 }
 
 static void


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