Blame SOURCES/0011-clutter-stage-view-Separate-offscreen-and-shadowfb.patch

657d8e
From cf8f1fb8478e4b76c91e825d1537396b014689a0 Mon Sep 17 00:00:00 2001
657d8e
From: Olivier Fourdan <ofourdan@redhat.com>
657d8e
Date: Tue, 22 Oct 2019 17:03:03 +0200
657d8e
Subject: [PATCH 11/12] clutter/stage-view: Separate offscreen and shadowfb
657d8e
657d8e
Previously, we would use a single offscreen framebuffer for both
657d8e
transformations and when a shadow framebuffer should be used, but that
657d8e
can be dreadfully slow when using software rendering with a discrete GPU
657d8e
due to bandwidth limitations.
657d8e
657d8e
Keep the offscreen framebuffer for transformations only and add another
657d8e
intermediate shadow framebuffer used as a copy of the onscreen
657d8e
framebuffer.
657d8e
657d8e
https://gitlab.gnome.org/GNOME/mutter/merge_requests/917
657d8e
657d8e
(cherry picked from commit 2b8b450fe16c21f0f37a1779560c0e5da61a9b89)
657d8e
---
657d8e
 clutter/clutter/clutter-stage-view.c      | 162 +++++++++++++++++-----
657d8e
 clutter/clutter/cogl/clutter-stage-cogl.c |   6 +-
657d8e
 2 files changed, 128 insertions(+), 40 deletions(-)
657d8e
657d8e
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
657d8e
index 503c31e78..c536ac720 100644
657d8e
--- a/clutter/clutter/clutter-stage-view.c
657d8e
+++ b/clutter/clutter/clutter-stage-view.c
657d8e
@@ -29,6 +29,7 @@ enum
657d8e
   PROP_LAYOUT,
657d8e
   PROP_FRAMEBUFFER,
657d8e
   PROP_OFFSCREEN,
657d8e
+  PROP_SHADOWFB,
657d8e
   PROP_SCALE,
657d8e
 
657d8e
   PROP_LAST
657d8e
@@ -43,7 +44,10 @@ typedef struct _ClutterStageViewPrivate
657d8e
   CoglFramebuffer *framebuffer;
657d8e
 
657d8e
   CoglOffscreen *offscreen;
657d8e
-  CoglPipeline *pipeline;
657d8e
+  CoglPipeline *offscreen_pipeline;
657d8e
+
657d8e
+  CoglOffscreen *shadowfb;
657d8e
+  CoglPipeline *shadowfb_pipeline;
657d8e
 
657d8e
   guint dirty_viewport   : 1;
657d8e
   guint dirty_projection : 1;
657d8e
@@ -69,6 +73,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
657d8e
 
657d8e
   if (priv->offscreen)
657d8e
     return priv->offscreen;
657d8e
+  else if (priv->shadowfb)
657d8e
+    return priv->shadowfb;
657d8e
   else
657d8e
     return priv->framebuffer;
657d8e
 }
657d8e
@@ -82,6 +88,24 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
657d8e
   return priv->framebuffer;
657d8e
 }
657d8e
 
657d8e
+static CoglPipeline *
657d8e
+clutter_stage_view_create_framebuffer_pipeline (CoglFramebuffer *framebuffer)
657d8e
+{
657d8e
+  CoglPipeline *pipeline;
657d8e
+
657d8e
+  pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
657d8e
+
657d8e
+  cogl_pipeline_set_layer_filters (pipeline, 0,
657d8e
+                                   COGL_PIPELINE_FILTER_NEAREST,
657d8e
+                                   COGL_PIPELINE_FILTER_NEAREST);
657d8e
+  cogl_pipeline_set_layer_texture (pipeline, 0,
657d8e
+                                   cogl_offscreen_get_texture (framebuffer));
657d8e
+  cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
657d8e
+                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
657d8e
+
657d8e
+  return pipeline;
657d8e
+}
657d8e
+
657d8e
 static void
657d8e
 clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
657d8e
 {
657d8e
@@ -92,71 +116,122 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
657d8e
 
657d8e
   g_assert (priv->offscreen != NULL);
657d8e
 
657d8e
-  if (priv->pipeline)
657d8e
+  if (priv->offscreen_pipeline)
657d8e
     return;
657d8e
 
657d8e
-  priv->pipeline =
657d8e
-    cogl_pipeline_new (cogl_framebuffer_get_context (priv->offscreen));
657d8e
-  cogl_pipeline_set_layer_filters (priv->pipeline, 0,
657d8e
-                                   COGL_PIPELINE_FILTER_NEAREST,
657d8e
-                                   COGL_PIPELINE_FILTER_NEAREST);
657d8e
-  cogl_pipeline_set_layer_texture (priv->pipeline, 0,
657d8e
-                                   cogl_offscreen_get_texture (priv->offscreen));
657d8e
-  cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0,
657d8e
-                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
657d8e
+  priv->offscreen_pipeline =
657d8e
+    clutter_stage_view_create_framebuffer_pipeline (priv->offscreen);
657d8e
 
657d8e
   if (view_class->setup_offscreen_blit_pipeline)
657d8e
-    view_class->setup_offscreen_blit_pipeline (view, priv->pipeline);
657d8e
+    view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
657d8e
 }
657d8e
 
657d8e
-void
657d8e
-clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
657d8e
+static void
657d8e
+clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
657d8e
 {
657d8e
   ClutterStageViewPrivate *priv =
657d8e
     clutter_stage_view_get_instance_private (view);
657d8e
 
657d8e
-  g_clear_pointer (&priv->pipeline, cogl_object_unref);
657d8e
+  if (priv->shadowfb_pipeline)
657d8e
+    return;
657d8e
+
657d8e
+  priv->shadowfb_pipeline =
657d8e
+    clutter_stage_view_create_framebuffer_pipeline (priv->shadowfb);
657d8e
 }
657d8e
 
657d8e
 void
657d8e
-clutter_stage_view_blit_offscreen (ClutterStageView            *view,
657d8e
-                                   const cairo_rectangle_int_t *rect)
657d8e
+clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
657d8e
 {
657d8e
   ClutterStageViewPrivate *priv =
657d8e
     clutter_stage_view_get_instance_private (view);
657d8e
+
657d8e
+  g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
657d8e
+}
657d8e
+
657d8e
+static void
657d8e
+clutter_stage_view_copy_to_framebuffer (ClutterStageView            *view,
657d8e
+                                        const cairo_rectangle_int_t *rect,
657d8e
+                                        CoglPipeline                *pipeline,
657d8e
+                                        CoglFramebuffer             *src_framebuffer,
657d8e
+                                        CoglFramebuffer             *dst_framebuffer,
657d8e
+                                        gboolean                     can_blit)
657d8e
+{
657d8e
   CoglMatrix matrix;
657d8e
 
657d8e
-  clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
657d8e
-  if (cogl_matrix_is_identity (&matrix))
657d8e
+  /* First, try with blit */
657d8e
+  if (can_blit)
657d8e
     {
657d8e
-      int fb_width = cogl_framebuffer_get_width (priv->framebuffer);
657d8e
-      int fb_height = cogl_framebuffer_get_height (priv->framebuffer);
657d8e
-
657d8e
-      if (cogl_blit_framebuffer (priv->offscreen,
657d8e
-                                 priv->framebuffer,
657d8e
+      if (cogl_blit_framebuffer (src_framebuffer,
657d8e
+                                 dst_framebuffer,
657d8e
                                  0, 0,
657d8e
                                  0, 0,
657d8e
-                                 fb_width, fb_height,
657d8e
+                                 cogl_framebuffer_get_width (dst_framebuffer),
657d8e
+                                 cogl_framebuffer_get_height (dst_framebuffer),
657d8e
                                  NULL))
657d8e
         return;
657d8e
     }
657d8e
 
657d8e
-  clutter_stage_view_ensure_offscreen_blit_pipeline (view);
657d8e
-  cogl_framebuffer_push_matrix (priv->framebuffer);
657d8e
+  /* If blit fails, fallback to the slower painting method */
657d8e
+  cogl_framebuffer_push_matrix (dst_framebuffer);
657d8e
 
657d8e
-  /* Set transform so 0,0 is on the top left corner and 1,1 on
657d8e
-   * the bottom right corner.
657d8e
-   */
657d8e
   cogl_matrix_init_identity (&matrix);
657d8e
   cogl_matrix_translate (&matrix, -1, 1, 0);
657d8e
   cogl_matrix_scale (&matrix, 2, -2, 0);
657d8e
-  cogl_framebuffer_set_projection_matrix (priv->framebuffer, &matrix);
657d8e
+  cogl_framebuffer_set_projection_matrix (dst_framebuffer, &matrix);
657d8e
 
657d8e
-  cogl_framebuffer_draw_rectangle (priv->framebuffer,
657d8e
-                                   priv->pipeline,
657d8e
+  cogl_framebuffer_draw_rectangle (dst_framebuffer,
657d8e
+                                   pipeline,
657d8e
                                    0, 0, 1, 1);
657d8e
 
657d8e
-  cogl_framebuffer_pop_matrix (priv->framebuffer);
657d8e
+  cogl_framebuffer_pop_matrix (dst_framebuffer);
657d8e
+}
657d8e
+
657d8e
+void
657d8e
+clutter_stage_view_blit_offscreen (ClutterStageView            *view,
657d8e
+                                   const cairo_rectangle_int_t *rect)
657d8e
+{
657d8e
+  ClutterStageViewPrivate *priv =
657d8e
+    clutter_stage_view_get_instance_private (view);
657d8e
+
657d8e
+  if (priv->offscreen)
657d8e
+    {
657d8e
+      gboolean can_blit;
657d8e
+      CoglMatrix matrix;
657d8e
+
657d8e
+      clutter_stage_view_ensure_offscreen_blit_pipeline (view);
657d8e
+      clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
657d8e
+      can_blit = cogl_matrix_is_identity (&matrix);
657d8e
+
657d8e
+      if (priv->shadowfb)
657d8e
+        {
657d8e
+          clutter_stage_view_copy_to_framebuffer (view,
657d8e
+                                                  rect,
657d8e
+                                                  priv->offscreen_pipeline,
657d8e
+                                                  priv->offscreen,
657d8e
+                                                  priv->shadowfb,
657d8e
+                                                  can_blit);
657d8e
+        }
657d8e
+      else
657d8e
+        {
657d8e
+          clutter_stage_view_copy_to_framebuffer (view,
657d8e
+                                                  rect,
657d8e
+                                                  priv->offscreen_pipeline,
657d8e
+                                                  priv->offscreen,
657d8e
+                                                  priv->framebuffer,
657d8e
+                                                  can_blit);
657d8e
+        }
657d8e
+    }
657d8e
+
657d8e
+  if (priv->shadowfb)
657d8e
+    {
657d8e
+      clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
657d8e
+      clutter_stage_view_copy_to_framebuffer (view,
657d8e
+                                              rect,
657d8e
+                                              priv->shadowfb_pipeline,
657d8e
+                                              priv->shadowfb,
657d8e
+                                              priv->framebuffer,
657d8e
+                                              TRUE);
657d8e
+    }
657d8e
 }
657d8e
 
657d8e
 float
657d8e
@@ -256,6 +331,9 @@ clutter_stage_view_get_property (GObject    *object,
657d8e
     case PROP_OFFSCREEN:
657d8e
       g_value_set_boxed (value, priv->offscreen);
657d8e
       break;
657d8e
+    case PROP_SHADOWFB:
657d8e
+      g_value_set_boxed (value, priv->shadowfb);
657d8e
+      break;
657d8e
     case PROP_SCALE:
657d8e
       g_value_set_float (value, priv->scale);
657d8e
       break;
657d8e
@@ -301,6 +379,9 @@ clutter_stage_view_set_property (GObject      *object,
657d8e
     case PROP_OFFSCREEN:
657d8e
       priv->offscreen = g_value_dup_boxed (value);
657d8e
       break;
657d8e
+    case PROP_SHADOWFB:
657d8e
+      priv->shadowfb = g_value_dup_boxed (value);
657d8e
+      break;
657d8e
     case PROP_SCALE:
657d8e
       priv->scale = g_value_get_float (value);
657d8e
       break;
657d8e
@@ -317,8 +398,10 @@ clutter_stage_view_dispose (GObject *object)
657d8e
     clutter_stage_view_get_instance_private (view);
657d8e
 
657d8e
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
657d8e
+  g_clear_pointer (&priv->shadowfb, cogl_object_unref);
657d8e
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
657d8e
-  g_clear_pointer (&priv->pipeline, cogl_object_unref);
657d8e
+  g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
657d8e
+  g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
657d8e
 
657d8e
   G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
657d8e
 }
657d8e
@@ -373,6 +456,15 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
657d8e
                         G_PARAM_CONSTRUCT_ONLY |
657d8e
                         G_PARAM_STATIC_STRINGS);
657d8e
 
657d8e
+  obj_props[PROP_SHADOWFB] =
657d8e
+    g_param_spec_boxed ("shadowfb",
657d8e
+                        "Shadow framebuffer",
657d8e
+                        "Framebuffer used as intermediate shadow buffer",
657d8e
+                        COGL_TYPE_HANDLE,
657d8e
+                        G_PARAM_READWRITE |
657d8e
+                        G_PARAM_CONSTRUCT_ONLY |
657d8e
+                        G_PARAM_STATIC_STRINGS);
657d8e
+
657d8e
   obj_props[PROP_SCALE] =
657d8e
     g_param_spec_float ("scale",
657d8e
                         "View scale",
657d8e
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
657d8e
index e0c39185b..eab76e52f 100644
657d8e
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
657d8e
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
657d8e
@@ -477,11 +477,7 @@ paint_stage (ClutterStageCogl            *stage_cogl,
657d8e
   _clutter_stage_maybe_setup_viewport (stage, view);
657d8e
   _clutter_stage_paint_view (stage, view, clip);
657d8e
 
657d8e
-  if (clutter_stage_view_get_onscreen (view) !=
657d8e
-      clutter_stage_view_get_framebuffer (view))
657d8e
-    {
657d8e
-      clutter_stage_view_blit_offscreen (view, clip);
657d8e
-    }
657d8e
+  clutter_stage_view_blit_offscreen (view, clip);
657d8e
 }
657d8e
 
657d8e
 static void
657d8e
-- 
657d8e
2.21.0
657d8e