180070
From e42c4e83283787062fb446a2aa698f227fe2db5f Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 29 Apr 2020 16:26:52 +0200
180070
Subject: [PATCH 01/20] cogl/dma-buf-handle: Pass more metadata to handle
180070
 constructor
180070
180070
Could be useful would one want to mmap the dmabuf and deal with its
180070
content manually in CPU space.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit e656d0caf01d8b012d2b458676e5658c540525dc)
180070
---
180070
 cogl/cogl/cogl-dma-buf-handle.c            | 45 +++++++++++++++++++++
180070
 cogl/cogl/cogl-dma-buf-handle.h            | 46 +++++++++++++++++++++-
180070
 src/backends/native/meta-renderer-native.c | 14 +++++--
180070
 3 files changed, 101 insertions(+), 4 deletions(-)
180070
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.c b/cogl/cogl/cogl-dma-buf-handle.c
180070
index 4a8f709f2c..d8b4e57c55 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.c
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.c
180070
@@ -40,6 +40,11 @@ struct _CoglDmaBufHandle
180070
 {
180070
   CoglFramebuffer *framebuffer;
180070
   int dmabuf_fd;
180070
+  int width;
180070
+  int height;
180070
+  int stride;
180070
+  int offset;
180070
+  int bpp;
180070
   gpointer user_data;
180070
   GDestroyNotify destroy_func;
180070
 };
180070
@@ -47,6 +52,11 @@ struct _CoglDmaBufHandle
180070
 CoglDmaBufHandle *
180070
 cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
180070
                          int              dmabuf_fd,
180070
+                         int              width,
180070
+                         int              height,
180070
+                         int              stride,
180070
+                         int              offset,
180070
+                         int              bpp,
180070
                          gpointer         user_data,
180070
                          GDestroyNotify   destroy_func)
180070
 {
180070
@@ -61,6 +71,12 @@ cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
180070
   dmabuf_handle->user_data = user_data;
180070
   dmabuf_handle->destroy_func = destroy_func;
180070
 
180070
+  dmabuf_handle->width = width;
180070
+  dmabuf_handle->height = height;
180070
+  dmabuf_handle->stride = stride;
180070
+  dmabuf_handle->offset = offset;
180070
+  dmabuf_handle->bpp = bpp;
180070
+
180070
   return dmabuf_handle;
180070
 }
180070
 
180070
@@ -92,3 +108,32 @@ cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle)
180070
   return dmabuf_handle->dmabuf_fd;
180070
 }
180070
 
180070
+int
180070
+cogl_dma_buf_handle_get_width (CoglDmaBufHandle *dmabuf_handle)
180070
+{
180070
+  return dmabuf_handle->width;
180070
+}
180070
+
180070
+int
180070
+cogl_dma_buf_handle_get_height (CoglDmaBufHandle *dmabuf_handle)
180070
+{
180070
+  return dmabuf_handle->height;
180070
+}
180070
+
180070
+int
180070
+cogl_dma_buf_handle_get_stride (CoglDmaBufHandle *dmabuf_handle)
180070
+{
180070
+  return dmabuf_handle->stride;
180070
+}
180070
+
180070
+int
180070
+cogl_dma_buf_handle_get_offset (CoglDmaBufHandle *dmabuf_handle)
180070
+{
180070
+  return dmabuf_handle->offset;
180070
+}
180070
+
180070
+int
180070
+cogl_dma_buf_handle_get_bpp (CoglDmaBufHandle *dmabuf_handle)
180070
+{
180070
+  return dmabuf_handle->bpp;
180070
+}
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.h b/cogl/cogl/cogl-dma-buf-handle.h
180070
index 25b9b0ccb5..f64a20678d 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.h
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.h
180070
@@ -46,7 +46,12 @@
180070
 CoglDmaBufHandle *
180070
 cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
180070
                          int              dmabuf_fd,
180070
-                         gpointer         data,
180070
+                         int              width,
180070
+                         int              height,
180070
+                         int              stride,
180070
+                         int              offset,
180070
+                         int              bpp,
180070
+                         gpointer         user_data,
180070
                          GDestroyNotify   destroy_func);
180070
 
180070
 /**
180070
@@ -79,5 +84,44 @@ cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle);
180070
 int
180070
 cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle);
180070
 
180070
+/**
180070
+ * cogl_dmabuf_handle_get_width: (skip)
180070
+ *
180070
+ * Returns: the buffer width
180070
+ */
180070
+int
180070
+cogl_dma_buf_handle_get_width (CoglDmaBufHandle *dmabuf_handle);
180070
+
180070
+/**
180070
+ * cogl_dmabuf_handle_get_height: (skip)
180070
+ *
180070
+ * Returns: the buffer height
180070
+ */
180070
+int
180070
+cogl_dma_buf_handle_get_height (CoglDmaBufHandle *dmabuf_handle);
180070
+
180070
+/**
180070
+ * cogl_dmabuf_handle_get_stride: (skip)
180070
+ *
180070
+ * Returns: the buffer stride
180070
+ */
180070
+int
180070
+cogl_dma_buf_handle_get_stride (CoglDmaBufHandle *dmabuf_handle);
180070
+
180070
+/**
180070
+ * cogl_dmabuf_handle_get_offset: (skip)
180070
+ *
180070
+ * Returns: the buffer offset
180070
+ */
180070
+int
180070
+cogl_dma_buf_handle_get_offset (CoglDmaBufHandle *dmabuf_handle);
180070
+
180070
+/**
180070
+ * cogl_dmabuf_handle_get_bpp: (skip)
180070
+ *
180070
+ * Returns: the number of bytes per pixel
180070
+ */
180070
+int
180070
+cogl_dma_buf_handle_get_bpp (CoglDmaBufHandle *dmabuf_handle);
180070
 
180070
 #endif /* __COGL_DMA_BUF_HANDLE_H__ */
180070
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
180070
index 25833b6cf6..c14cb5acda 100644
180070
--- a/src/backends/native/meta-renderer-native.c
180070
+++ b/src/backends/native/meta-renderer-native.c
180070
@@ -2641,6 +2641,9 @@ meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
180070
         CoglFramebuffer *dmabuf_fb;
180070
         CoglDmaBufHandle *dmabuf_handle;
180070
         struct gbm_bo *new_bo;
180070
+        int stride;
180070
+        int offset;
180070
+        int bpp;
180070
         int dmabuf_fd = -1;
180070
 
180070
         new_bo = gbm_bo_create (renderer_gpu_data->gbm.device,
180070
@@ -2664,11 +2667,14 @@ meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
180070
             return NULL;
180070
           }
180070
 
180070
+        stride = gbm_bo_get_stride (new_bo);
180070
+        offset = gbm_bo_get_offset (new_bo, 0);
180070
+        bpp = 4;
180070
         dmabuf_fb = create_dma_buf_framebuffer (renderer_native,
180070
                                                 dmabuf_fd,
180070
                                                 width, height,
180070
-                                                gbm_bo_get_stride (new_bo),
180070
-                                                gbm_bo_get_offset (new_bo, 0),
180070
+                                                stride,
180070
+                                                offset,
180070
                                                 DRM_FORMAT_MOD_LINEAR,
180070
                                                 DRM_FORMAT_XRGB8888,
180070
                                                 error);
180070
@@ -2677,7 +2683,9 @@ meta_renderer_native_create_dma_buf (CoglRenderer  *cogl_renderer,
180070
           return NULL;
180070
 
180070
         dmabuf_handle =
180070
-          cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
180070
+          cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
180070
+                                   width, height, stride, offset, bpp,
180070
+                                   new_bo,
180070
                                    (GDestroyNotify) gbm_bo_destroy);
180070
         cogl_object_unref (dmabuf_fb);
180070
         return dmabuf_handle;
180070
-- 
180070
2.28.0
180070
180070
180070
From 2270f6dcf7b1e70386f5b4242f92bf5735bb88ba Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Thu, 30 Apr 2020 10:42:30 +0200
180070
Subject: [PATCH 02/20] clutter/stage-view: Add name property
180070
180070
Will be used for logging to identify what view a log entry concerns. For
180070
the native and nested backend this is the name of the output the CRTC is
180070
assigned to drive; for X11 it's just "X11 screen", and for the legacy
180070
"X11 screen" emulation mode of the nested backend it's called "legacy
180070
nested".
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit c86367199febdee10ecd7ba24c69b6dda52cb896)
180070
---
180070
 clutter/clutter/clutter-stage-view.c           | 18 ++++++++++++++++++
180070
 src/backends/native/meta-renderer-native.c     |  3 +++
180070
 .../x11/nested/meta-renderer-x11-nested.c      |  4 ++++
180070
 3 files changed, 25 insertions(+)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 0fad6fc446..6b543b5d51 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -27,6 +27,7 @@ enum
180070
 {
180070
   PROP_0,
180070
 
180070
+  PROP_NAME,
180070
   PROP_LAYOUT,
180070
   PROP_FRAMEBUFFER,
180070
   PROP_OFFSCREEN,
180070
@@ -40,6 +41,8 @@ static GParamSpec *obj_props[PROP_LAST];
180070
 
180070
 typedef struct _ClutterStageViewPrivate
180070
 {
180070
+  char *name;
180070
+
180070
   cairo_rectangle_int_t layout;
180070
   float scale;
180070
   CoglFramebuffer *framebuffer;
180070
@@ -339,6 +342,9 @@ clutter_stage_view_get_property (GObject    *object,
180070
 
180070
   switch (prop_id)
180070
     {
180070
+    case PROP_NAME:
180070
+      g_value_set_string (value, priv->name);
180070
+      break;
180070
     case PROP_LAYOUT:
180070
       g_value_set_boxed (value, &priv->layout);
180070
       break;
180070
@@ -372,6 +378,9 @@ clutter_stage_view_set_property (GObject      *object,
180070
 
180070
   switch (prop_id)
180070
     {
180070
+    case PROP_NAME:
180070
+      priv->name = g_value_dup_string (value);
180070
+      break;
180070
     case PROP_LAYOUT:
180070
       layout = g_value_get_boxed (value);
180070
       priv->layout = *layout;
180070
@@ -414,6 +423,7 @@ clutter_stage_view_dispose (GObject *object)
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
 
180070
+  g_clear_pointer (&priv->name, g_free);
180070
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
180070
   g_clear_pointer (&priv->shadowfb, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
180070
@@ -446,6 +456,14 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
180070
   object_class->set_property = clutter_stage_view_set_property;
180070
   object_class->dispose = clutter_stage_view_dispose;
180070
 
180070
+  obj_props[PROP_NAME] =
180070
+    g_param_spec_string ("name",
180070
+                         "Name",
180070
+                         "Name of view",
180070
+                         NULL,
180070
+                         G_PARAM_READWRITE |
180070
+                         G_PARAM_CONSTRUCT_ONLY |
180070
+                         G_PARAM_STATIC_STRINGS);
180070
   obj_props[PROP_LAYOUT] =
180070
     g_param_spec_boxed ("layout",
180070
                         "View layout",
180070
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
180070
index c14cb5acda..d3fb5b3c55 100644
180070
--- a/src/backends/native/meta-renderer-native.c
180070
+++ b/src/backends/native/meta-renderer-native.c
180070
@@ -3679,6 +3679,7 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
180070
   CoglContext *cogl_context =
180070
     cogl_context_from_renderer_native (renderer_native);
180070
   CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
180070
+  MetaMonitor *monitor;
180070
   CoglDisplayEGL *cogl_display_egl;
180070
   CoglOnscreenEGL *onscreen_egl;
180070
   MetaMonitorTransform view_transform;
180070
@@ -3742,7 +3743,9 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
180070
         g_error ("Failed to allocate shadow buffer texture: %s", error->message);
180070
     }
180070
 
180070
+  monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
180070
   view = g_object_new (META_TYPE_RENDERER_VIEW,
180070
+                       "name", meta_monitor_get_connector (monitor),
180070
                        "layout", &logical_monitor->rect,
180070
                        "scale", scale,
180070
                        "framebuffer", onscreen,
180070
diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c b/src/backends/x11/nested/meta-renderer-x11-nested.c
180070
index 5000bf3579..f3a5547dbb 100644
180070
--- a/src/backends/x11/nested/meta-renderer-x11-nested.c
180070
+++ b/src/backends/x11/nested/meta-renderer-x11-nested.c
180070
@@ -163,6 +163,7 @@ meta_renderer_x11_nested_ensure_legacy_view (MetaRendererX11Nested *renderer_x11
180070
     .height = height
180070
   };
180070
   legacy_view = g_object_new (META_TYPE_RENDERER_VIEW,
180070
+                              "name", "legacy nested",
180070
                               "layout", &view_layout,
180070
                               "framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
180070
                               NULL);
180070
@@ -179,6 +180,7 @@ meta_renderer_x11_nested_create_view (MetaRenderer       *renderer,
180070
     meta_backend_get_monitor_manager (backend);
180070
   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
180070
   CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
180070
+  MetaMonitor *monitor;
180070
   MetaMonitorTransform view_transform;
180070
   float view_scale;
180070
   int width, height;
180070
@@ -212,7 +214,9 @@ meta_renderer_x11_nested_create_view (MetaRenderer       *renderer,
180070
   else
180070
     offscreen = NULL;
180070
 
180070
+  monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
180070
   return g_object_new (META_TYPE_RENDERER_VIEW,
180070
+                       "name", meta_monitor_get_connector (monitor),
180070
                        "layout", &logical_monitor->rect,
180070
                        "framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
180070
                        "offscreen", COGL_FRAMEBUFFER (offscreen),
180070
-- 
180070
2.28.0
180070
180070
180070
From 6716fde14c5b1a00a02a80b46db67d3f236a87c1 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Thu, 30 Apr 2020 17:53:30 +0200
180070
Subject: [PATCH 03/20] renderer-native: Move shadow fb construction to the
180070
 stage view
180070
180070
The stage view will need a more involved approach to shadow buffers, in
180070
order to implement things such double buffered shadow buffers and damage
180070
detection.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 3ab89be574f0e02dc67e1b1f538bb24f94612bcf)
180070
---
180070
 clutter/clutter/clutter-stage-view.c       | 115 ++++++++++++++++++---
180070
 src/backends/native/meta-renderer-native.c |  25 +----
180070
 2 files changed, 106 insertions(+), 34 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 6b543b5d51..db0067297c 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -31,7 +31,7 @@ enum
180070
   PROP_LAYOUT,
180070
   PROP_FRAMEBUFFER,
180070
   PROP_OFFSCREEN,
180070
-  PROP_SHADOWFB,
180070
+  PROP_USE_SHADOWFB,
180070
   PROP_SCALE,
180070
 
180070
   PROP_LAST
180070
@@ -50,6 +50,7 @@ typedef struct _ClutterStageViewPrivate
180070
   CoglOffscreen *offscreen;
180070
   CoglPipeline *offscreen_pipeline;
180070
 
180070
+  gboolean use_shadowfb;
180070
   CoglOffscreen *shadowfb;
180070
   CoglPipeline *shadowfb_pipeline;
180070
 
180070
@@ -206,6 +207,80 @@ clutter_stage_view_copy_to_framebuffer (ClutterStageView            *view,
180070
   cogl_framebuffer_pop_matrix (dst_framebuffer);
180070
 }
180070
 
180070
+static CoglOffscreen *
180070
+create_offscreen_framebuffer (CoglContext  *context,
180070
+                              int           width,
180070
+                              int           height,
180070
+                              GError      **error)
180070
+{
180070
+  CoglOffscreen *framebuffer;
180070
+  CoglTexture2D *texture;
180070
+
180070
+  texture = cogl_texture_2d_new_with_size (context, width, height);
180070
+  cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture),
180070
+                                          FALSE);
180070
+
180070
+  if (!cogl_texture_allocate (COGL_TEXTURE (texture), error))
180070
+    {
180070
+      cogl_object_unref (texture);
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  framebuffer = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
180070
+  cogl_object_unref (texture);
180070
+  if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (framebuffer), error))
180070
+    {
180070
+      cogl_object_unref (framebuffer);
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  return framebuffer;
180070
+}
180070
+
180070
+static gboolean
180070
+init_offscreen_shadowfb (ClutterStageView  *view,
180070
+                         CoglContext       *cogl_context,
180070
+                         int                width,
180070
+                         int                height,
180070
+                         GError           **error)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  CoglOffscreen *offscreen;
180070
+
180070
+  offscreen = create_offscreen_framebuffer (cogl_context, width, height, error);
180070
+  if (!offscreen)
180070
+    return FALSE;
180070
+
180070
+  priv->shadowfb = offscreen;
180070
+  return TRUE;
180070
+}
180070
+
180070
+static void
180070
+init_shadowfb (ClutterStageView *view)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  g_autoptr (GError) error = NULL;
180070
+  int width;
180070
+  int height;
180070
+  CoglContext *cogl_context;
180070
+
180070
+  width = cogl_framebuffer_get_width (priv->framebuffer);
180070
+  height = cogl_framebuffer_get_height (priv->framebuffer);
180070
+  cogl_context = cogl_framebuffer_get_context (priv->framebuffer);
180070
+
180070
+  if (!init_offscreen_shadowfb (view, cogl_context, width, height, &error))
180070
+    {
180070
+      g_warning ("Failed to initialize single buffered shadow fb for %s: %s",
180070
+                 priv->name, error->message);
180070
+    }
180070
+  else
180070
+    {
180070
+      g_message ("Initialized single buffered shadow fb for %s", priv->name);
180070
+    }
180070
+}
180070
+
180070
 void
180070
 clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
                                    const cairo_rectangle_int_t *rect)
180070
@@ -354,8 +429,8 @@ clutter_stage_view_get_property (GObject    *object,
180070
     case PROP_OFFSCREEN:
180070
       g_value_set_boxed (value, priv->offscreen);
180070
       break;
180070
-    case PROP_SHADOWFB:
180070
-      g_value_set_boxed (value, priv->shadowfb);
180070
+    case PROP_USE_SHADOWFB:
180070
+      g_value_set_boolean (value, priv->use_shadowfb);
180070
       break;
180070
     case PROP_SCALE:
180070
       g_value_set_float (value, priv->scale);
180070
@@ -405,8 +480,8 @@ clutter_stage_view_set_property (GObject      *object,
180070
     case PROP_OFFSCREEN:
180070
       priv->offscreen = g_value_dup_boxed (value);
180070
       break;
180070
-    case PROP_SHADOWFB:
180070
-      priv->shadowfb = g_value_dup_boxed (value);
180070
+    case PROP_USE_SHADOWFB:
180070
+      priv->use_shadowfb = g_value_get_boolean (value);
180070
       break;
180070
     case PROP_SCALE:
180070
       priv->scale = g_value_get_float (value);
180070
@@ -416,6 +491,19 @@ clutter_stage_view_set_property (GObject      *object,
180070
     }
180070
 }
180070
 
180070
+static void
180070
+clutter_stage_view_constructed (GObject *object)
180070
+{
180070
+  ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+
180070
+  if (priv->use_shadowfb)
180070
+    init_shadowfb (view);
180070
+
180070
+  G_OBJECT_CLASS (clutter_stage_view_parent_class)->constructed (object);
180070
+}
180070
+
180070
 static void
180070
 clutter_stage_view_dispose (GObject *object)
180070
 {
180070
@@ -454,6 +542,7 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
180070
 
180070
   object_class->get_property = clutter_stage_view_get_property;
180070
   object_class->set_property = clutter_stage_view_set_property;
180070
+  object_class->constructed = clutter_stage_view_constructed;
180070
   object_class->dispose = clutter_stage_view_dispose;
180070
 
180070
   obj_props[PROP_NAME] =
180070
@@ -491,14 +580,14 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
180070
                         G_PARAM_CONSTRUCT_ONLY |
180070
                         G_PARAM_STATIC_STRINGS);
180070
 
180070
-  obj_props[PROP_SHADOWFB] =
180070
-    g_param_spec_boxed ("shadowfb",
180070
-                        "Shadow framebuffer",
180070
-                        "Framebuffer used as intermediate shadow buffer",
180070
-                        COGL_TYPE_HANDLE,
180070
-                        G_PARAM_READWRITE |
180070
-                        G_PARAM_CONSTRUCT_ONLY |
180070
-                        G_PARAM_STATIC_STRINGS);
180070
+  obj_props[PROP_USE_SHADOWFB] =
180070
+    g_param_spec_boolean ("use-shadowfb",
180070
+                          "Use shadowfb",
180070
+                          "Whether to use one or more shadow framebuffers",
180070
+                          FALSE,
180070
+                          G_PARAM_READWRITE |
180070
+                          G_PARAM_CONSTRUCT_ONLY |
180070
+                          G_PARAM_STATIC_STRINGS);
180070
 
180070
   obj_props[PROP_SCALE] =
180070
     g_param_spec_float ("scale",
180070
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
180070
index d3fb5b3c55..463dddd3a7 100644
180070
--- a/src/backends/native/meta-renderer-native.c
180070
+++ b/src/backends/native/meta-renderer-native.c
180070
@@ -3685,7 +3685,7 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
180070
   MetaMonitorTransform view_transform;
180070
   CoglOnscreen *onscreen = NULL;
180070
   CoglOffscreen *offscreen = NULL;
180070
-  CoglOffscreen *shadowfb = NULL;
180070
+  gboolean use_shadowfb;
180070
   float scale;
180070
   int width, height;
180070
   MetaRendererView *view;
180070
@@ -3724,24 +3724,8 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
180070
 
180070
     }
180070
 
180070
-  if (should_force_shadow_fb (renderer_native,
180070
-                              renderer_native->primary_gpu_kms))
180070
-    {
180070
-      int shadow_width;
180070
-      int shadow_height;
180070
-
180070
-      /* The shadowfb must be the same size as the on-screen framebuffer */
180070
-      shadow_width = cogl_framebuffer_get_width (COGL_FRAMEBUFFER (onscreen));
180070
-      shadow_height = cogl_framebuffer_get_height (COGL_FRAMEBUFFER (onscreen));
180070
-
180070
-      shadowfb = meta_renderer_native_create_offscreen (renderer_native,
180070
-                                                        cogl_context,
180070
-                                                        shadow_width,
180070
-                                                        shadow_height,
180070
-                                                        &error);
180070
-      if (!shadowfb)
180070
-        g_error ("Failed to allocate shadow buffer texture: %s", error->message);
180070
-    }
180070
+  use_shadowfb = should_force_shadow_fb (renderer_native,
180070
+                                         renderer_native->primary_gpu_kms);
180070
 
180070
   monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
180070
   view = g_object_new (META_TYPE_RENDERER_VIEW,
180070
@@ -3750,12 +3734,11 @@ meta_renderer_native_create_view (MetaRenderer       *renderer,
180070
                        "scale", scale,
180070
                        "framebuffer", onscreen,
180070
                        "offscreen", offscreen,
180070
-                       "shadowfb", shadowfb,
180070
+                       "use-shadowfb", use_shadowfb,
180070
                        "logical-monitor", logical_monitor,
180070
                        "transform", view_transform,
180070
                        NULL);
180070
   g_clear_pointer (&offscreen, cogl_object_unref);
180070
-  g_clear_pointer (&shadowfb, cogl_object_unref);
180070
 
180070
   meta_onscreen_native_set_view (onscreen, view);
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From f79b37583e575d34edb4b7965cb0e48eb2736749 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Thu, 30 Apr 2020 18:19:30 +0200
180070
Subject: [PATCH 04/20] clutter/stage-view: Move shadowfb struct fields into
180070
 anonymous struct
180070
180070
With the aim to collect shadow buffer related things in one place, place
180070
them in an anonymous struct.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 310ca695d90b48074a06327e87bd7e924f49cb7f)
180070
---
180070
 clutter/clutter/clutter-stage-view.c | 32 +++++++++++++++-------------
180070
 1 file changed, 17 insertions(+), 15 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index db0067297c..9bbe158f36 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -51,8 +51,10 @@ typedef struct _ClutterStageViewPrivate
180070
   CoglPipeline *offscreen_pipeline;
180070
 
180070
   gboolean use_shadowfb;
180070
-  CoglOffscreen *shadowfb;
180070
-  CoglPipeline *shadowfb_pipeline;
180070
+  struct {
180070
+    CoglOffscreen *framebuffer;
180070
+    CoglPipeline *pipeline;
180070
+  } shadow;
180070
 
180070
   guint dirty_viewport   : 1;
180070
   guint dirty_projection : 1;
180070
@@ -86,8 +88,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
180070
 
180070
   if (priv->offscreen)
180070
     return priv->offscreen;
180070
-  else if (priv->shadowfb)
180070
-    return priv->shadowfb;
180070
+  else if (priv->shadow.framebuffer)
180070
+    return priv->shadow.framebuffer;
180070
   else
180070
     return priv->framebuffer;
180070
 }
180070
@@ -153,11 +155,11 @@ clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
 
180070
-  if (priv->shadowfb_pipeline)
180070
+  if (priv->shadow.pipeline)
180070
     return;
180070
 
180070
-  priv->shadowfb_pipeline =
180070
-    clutter_stage_view_create_framebuffer_pipeline (priv->shadowfb);
180070
+  priv->shadow.pipeline =
180070
+    clutter_stage_view_create_framebuffer_pipeline (priv->shadow.framebuffer);
180070
 }
180070
 
180070
 void
180070
@@ -252,7 +254,7 @@ init_offscreen_shadowfb (ClutterStageView  *view,
180070
   if (!offscreen)
180070
     return FALSE;
180070
 
180070
-  priv->shadowfb = offscreen;
180070
+  priv->shadow.framebuffer = offscreen;
180070
   return TRUE;
180070
 }
180070
 
180070
@@ -297,13 +299,13 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
       clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
180070
       can_blit = cogl_matrix_is_identity (&matrix);
180070
 
180070
-      if (priv->shadowfb)
180070
+      if (priv->shadow.framebuffer)
180070
         {
180070
           clutter_stage_view_copy_to_framebuffer (view,
180070
                                                   rect,
180070
                                                   priv->offscreen_pipeline,
180070
                                                   priv->offscreen,
180070
-                                                  priv->shadowfb,
180070
+                                                  priv->shadow.framebuffer,
180070
                                                   can_blit);
180070
         }
180070
       else
180070
@@ -317,13 +319,13 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
         }
180070
     }
180070
 
180070
-  if (priv->shadowfb)
180070
+  if (priv->shadow.framebuffer)
180070
     {
180070
       clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
180070
       clutter_stage_view_copy_to_framebuffer (view,
180070
                                               rect,
180070
-                                              priv->shadowfb_pipeline,
180070
-                                              priv->shadowfb,
180070
+                                              priv->shadow.pipeline,
180070
+                                              priv->shadow.framebuffer,
180070
                                               priv->framebuffer,
180070
                                               TRUE);
180070
     }
180070
@@ -513,10 +515,10 @@ clutter_stage_view_dispose (GObject *object)
180070
 
180070
   g_clear_pointer (&priv->name, g_free);
180070
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
180070
-  g_clear_pointer (&priv->shadowfb, cogl_object_unref);
180070
+  g_clear_pointer (&priv->shadow.framebuffer, cogl_object_unref);
180070
+  g_clear_pointer (&priv->shadow.pipeline, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
180070
-  g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
180070
 
180070
   G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
180070
 }
180070
-- 
180070
2.28.0
180070
180070
180070
From 7bf71e7b5f39fcf34c4a636640636f9452b4b06c Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Thu, 30 Apr 2020 21:51:10 +0200
180070
Subject: [PATCH 05/20] clutter/stage-view: Move fb viewport and projection
180070
 setting to here
180070
180070
The stage would fetch the front framebuffer and set the viewport and
180070
projection matrix, but if we are going to more than one front buffer,
180070
that won't work, so let the stage just pass the viewport and projection
180070
matrix to the view and have the view deal with the framebuffer(s).
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit c79bcf0d7e35cf9e85864cf72ea53659a6b8d8a7)
180070
---
180070
 clutter/clutter/clutter-stage-view-private.h |  8 ++++++
180070
 clutter/clutter/clutter-stage-view.c         | 29 ++++++++++++++++++++
180070
 clutter/clutter/clutter-stage.c              | 16 ++++-------
180070
 3 files changed, 42 insertions(+), 11 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
180070
index 89c42599fc..78aa37c9f4 100644
180070
--- a/clutter/clutter/clutter-stage-view-private.h
180070
+++ b/clutter/clutter/clutter-stage-view-private.h
180070
@@ -28,10 +28,18 @@ gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
180070
 void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
180070
                                             gboolean          dirty);
180070
 
180070
+void clutter_stage_view_set_viewport (ClutterStageView *view,
180070
+                                      float             x,
180070
+                                      float             y,
180070
+                                      float             width,
180070
+                                      float             height);
180070
+
180070
 gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
180070
 
180070
 void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
180070
                                               gboolean          dirty);
180070
 
180070
+void clutter_stage_view_set_projection (ClutterStageView *view,
180070
+                                        const CoglMatrix *matrix);
180070
 
180070
 #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 9bbe158f36..4d8bbddc9d 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -359,6 +359,22 @@ clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
180070
   priv->dirty_viewport = dirty;
180070
 }
180070
 
180070
+void
180070
+clutter_stage_view_set_viewport (ClutterStageView *view,
180070
+                                 float             x,
180070
+                                 float             y,
180070
+                                 float             width,
180070
+                                 float             height)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  CoglFramebuffer *framebuffer;
180070
+
180070
+  priv->dirty_viewport = FALSE;
180070
+  framebuffer = clutter_stage_view_get_framebuffer (view);
180070
+  cogl_framebuffer_set_viewport (framebuffer, x, y, width, height);
180070
+}
180070
+
180070
 gboolean
180070
 clutter_stage_view_is_dirty_projection (ClutterStageView *view)
180070
 {
180070
@@ -378,6 +394,19 @@ clutter_stage_view_set_dirty_projection (ClutterStageView *view,
180070
   priv->dirty_projection = dirty;
180070
 }
180070
 
180070
+void
180070
+clutter_stage_view_set_projection (ClutterStageView *view,
180070
+                                   const CoglMatrix *matrix)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  CoglFramebuffer *framebuffer;
180070
+
180070
+  priv->dirty_projection = FALSE;
180070
+  framebuffer = clutter_stage_view_get_framebuffer (view);
180070
+  cogl_framebuffer_set_projection_matrix (framebuffer, matrix);
180070
+}
180070
+
180070
 void
180070
 clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view,
180070
                                                         CoglMatrix       *matrix)
180070
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
180070
index 34c4e0119a..4bde234dbf 100644
180070
--- a/clutter/clutter/clutter-stage.c
180070
+++ b/clutter/clutter/clutter-stage.c
180070
@@ -3687,7 +3687,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage     *stage,
180070
                                      ClutterStageView *view)
180070
 {
180070
   ClutterStagePrivate *priv = stage->priv;
180070
-  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
180070
 
180070
   if (clutter_stage_view_is_dirty_viewport (view))
180070
     {
180070
@@ -3716,9 +3715,10 @@ _clutter_stage_maybe_setup_viewport (ClutterStage     *stage,
180070
       viewport_y = roundf (priv->viewport[1] * fb_scale - viewport_offset_y);
180070
       viewport_width = roundf (priv->viewport[2] * fb_scale);
180070
       viewport_height = roundf (priv->viewport[3] * fb_scale);
180070
-      cogl_framebuffer_set_viewport (fb,
180070
-                                     viewport_x, viewport_y,
180070
-                                     viewport_width, viewport_height);
180070
+
180070
+      clutter_stage_view_set_viewport (view,
180070
+                                       viewport_x, viewport_y,
180070
+                                       viewport_width, viewport_height);
180070
 
180070
       perspective = priv->perspective;
180070
 
180070
@@ -3751,16 +3751,10 @@ _clutter_stage_maybe_setup_viewport (ClutterStage     *stage,
180070
                                           z_2d,
180070
                                           priv->viewport[2],
180070
                                           priv->viewport[3]);
180070
-
180070
-      clutter_stage_view_set_dirty_viewport (view, FALSE);
180070
     }
180070
 
180070
   if (clutter_stage_view_is_dirty_projection (view))
180070
-    {
180070
-      cogl_framebuffer_set_projection_matrix (fb, &priv->projection);
180070
-
180070
-      clutter_stage_view_set_dirty_projection (view, FALSE);
180070
-    }
180070
+    clutter_stage_view_set_projection (view, &priv->projection);
180070
 }
180070
 
180070
 #undef _DEG_TO_RAD
180070
-- 
180070
2.28.0
180070
180070
180070
From 0b345dc3a108f12ebc00e831692b43291c84cd07 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Thu, 30 Apr 2020 21:59:49 +0200
180070
Subject: [PATCH 06/20] clutter/stage-view: Change set_dirty..() API to
180070
 invalidate..()
180070
180070
The manual "cleaning" of the viewport and projection state is removed,
180070
and we only ever try to invalidate the state so that it'll be updated
180070
next time. Change the API used to reflect this.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 3080ee672a366a3a52d9f43523c40e3afd08e874)
180070
---
180070
 clutter/clutter/clutter-stage-view-private.h |  6 ++----
180070
 clutter/clutter/clutter-stage-view.c         | 10 ++++------
180070
 clutter/clutter/clutter-stage.c              |  4 ++--
180070
 3 files changed, 8 insertions(+), 12 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
180070
index 78aa37c9f4..e27f140b8a 100644
180070
--- a/clutter/clutter/clutter-stage-view-private.h
180070
+++ b/clutter/clutter/clutter-stage-view-private.h
180070
@@ -25,8 +25,7 @@ void clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
 
180070
 gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
180070
 
180070
-void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
180070
-                                            gboolean          dirty);
180070
+void clutter_stage_view_invalidate_viewport (ClutterStageView *view);
180070
 
180070
 void clutter_stage_view_set_viewport (ClutterStageView *view,
180070
                                       float             x,
180070
@@ -36,8 +35,7 @@ void clutter_stage_view_set_viewport (ClutterStageView *view,
180070
 
180070
 gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
180070
 
180070
-void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
180070
-                                              gboolean          dirty);
180070
+void clutter_stage_view_invalidate_projection (ClutterStageView *view);
180070
 
180070
 void clutter_stage_view_set_projection (ClutterStageView *view,
180070
                                         const CoglMatrix *matrix);
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 4d8bbddc9d..40edfad6e1 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -350,13 +350,12 @@ clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
180070
 }
180070
 
180070
 void
180070
-clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
180070
-                                       gboolean          dirty)
180070
+clutter_stage_view_invalidate_viewport (ClutterStageView *view)
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
 
180070
-  priv->dirty_viewport = dirty;
180070
+  priv->dirty_viewport = TRUE;
180070
 }
180070
 
180070
 void
180070
@@ -385,13 +384,12 @@ clutter_stage_view_is_dirty_projection (ClutterStageView *view)
180070
 }
180070
 
180070
 void
180070
-clutter_stage_view_set_dirty_projection (ClutterStageView *view,
180070
-                                         gboolean          dirty)
180070
+clutter_stage_view_invalidate_projection (ClutterStageView *view)
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
 
180070
-  priv->dirty_projection = dirty;
180070
+  priv->dirty_projection = TRUE;
180070
 }
180070
 
180070
 void
180070
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
180070
index 4bde234dbf..aaa77d9ede 100644
180070
--- a/clutter/clutter/clutter-stage.c
180070
+++ b/clutter/clutter/clutter-stage.c
180070
@@ -2636,7 +2636,7 @@ _clutter_stage_dirty_projection (ClutterStage *stage)
180070
     {
180070
       ClutterStageView *view = l->data;
180070
 
180070
-      clutter_stage_view_set_dirty_projection (view, TRUE);
180070
+      clutter_stage_view_invalidate_projection (view);
180070
     }
180070
 }
180070
 
180070
@@ -2725,7 +2725,7 @@ _clutter_stage_dirty_viewport (ClutterStage *stage)
180070
     {
180070
       ClutterStageView *view = l->data;
180070
 
180070
-      clutter_stage_view_set_dirty_viewport (view, TRUE);
180070
+      clutter_stage_view_invalidate_viewport (view);
180070
     }
180070
 }
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From 32da7b5c31277c56089e4b3b8ccf43bc552e8974 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 17:05:36 +0200
180070
Subject: [PATCH 07/20] cogl: Make private BLIT_FRAMEBUFFER feature public
180070
180070
Will be a requirement for enabling shadow buffers.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit b3153760bf81af07f5328ba07b0ff3009bd8305b)
180070
---
180070
 cogl/cogl/cogl-blit.c                       | 2 +-
180070
 cogl/cogl/cogl-context.h                    | 3 +++
180070
 cogl/cogl/cogl-framebuffer.c                | 2 +-
180070
 cogl/cogl/cogl-framebuffer.h                | 2 +-
180070
 cogl/cogl/cogl-private.h                    | 1 -
180070
 cogl/cogl/driver/gl/cogl-framebuffer-gl.c   | 4 ++--
180070
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c     | 4 ++--
180070
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 4 ++--
180070
 8 files changed, 12 insertions(+), 10 deletions(-)
180070
180070
diff --git a/cogl/cogl/cogl-blit.c b/cogl/cogl/cogl-blit.c
180070
index ae5a8a345d..dd5fffff37 100644
180070
--- a/cogl/cogl/cogl-blit.c
180070
+++ b/cogl/cogl/cogl-blit.c
180070
@@ -158,7 +158,7 @@ _cogl_blit_framebuffer_begin (CoglBlitData *data)
180070
      supported. */
180070
   if ((_cogl_texture_get_format (data->src_tex) & COGL_PREMULT_BIT) !=
180070
       (_cogl_texture_get_format (data->dst_tex) & COGL_PREMULT_BIT) ||
180070
-      !_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER))
180070
+      !cogl_has_feature (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
180070
     return FALSE;
180070
 
180070
   dst_offscreen = _cogl_offscreen_new_with_texture_full
180070
diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h
180070
index d4104625e6..ec90491e94 100644
180070
--- a/cogl/cogl/cogl-context.h
180070
+++ b/cogl/cogl/cogl-context.h
180070
@@ -227,6 +227,8 @@ cogl_is_context (void *object);
180070
  *     the depth buffer to a texture.
180070
  * @COGL_FEATURE_ID_PRESENTATION_TIME: Whether frame presentation
180070
  *    time stamps will be recorded in #CoglFrameInfo objects.
180070
+ * @COGL_FEATURE_ID_BLIT_FRAMEBUFFER: Whether blitting using
180070
+ *    cogl_blit_framebuffer() is supported.
180070
  *
180070
  * All the capabilities that can vary between different GPUs supported
180070
  * by Cogl. Applications that depend on any of these features should explicitly
180070
@@ -261,6 +263,7 @@ typedef enum _CoglFeatureID
180070
   COGL_FEATURE_ID_TEXTURE_RG,
180070
   COGL_FEATURE_ID_BUFFER_AGE,
180070
   COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
180070
+  COGL_FEATURE_ID_BLIT_FRAMEBUFFER,
180070
 
180070
   /*< private >*/
180070
   _COGL_N_FEATURE_IDS   /*< skip >*/
180070
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
180070
index d64fc89fb6..fffac3f685 100644
180070
--- a/cogl/cogl/cogl-framebuffer.c
180070
+++ b/cogl/cogl/cogl-framebuffer.c
180070
@@ -1464,7 +1464,7 @@ cogl_blit_framebuffer (CoglFramebuffer *src,
180070
   int src_x1, src_y1, src_x2, src_y2;
180070
   int dst_x1, dst_y1, dst_x2, dst_y2;
180070
 
180070
-  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER))
180070
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
180070
     {
180070
       g_set_error_literal (error, COGL_SYSTEM_ERROR,
180070
                            COGL_SYSTEM_ERROR_UNSUPPORTED,
180070
diff --git a/cogl/cogl/cogl-framebuffer.h b/cogl/cogl/cogl-framebuffer.h
180070
index 38ada9feb7..c347076919 100644
180070
--- a/cogl/cogl/cogl-framebuffer.h
180070
+++ b/cogl/cogl/cogl-framebuffer.h
180070
@@ -1863,7 +1863,7 @@ cogl_is_framebuffer (void *object);
180070
  *
180070
  * This blits a region of the color buffer of the source buffer
180070
  * to the destination buffer. This function should only be
180070
- * called if the COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER feature is
180070
+ * called if the COGL_FEATURE_ID_BLIT_FRAMEBUFFER feature is
180070
  * advertised.
180070
  *
180070
  * The source and destination rectangles are defined in offscreen
180070
diff --git a/cogl/cogl/cogl-private.h b/cogl/cogl/cogl-private.h
180070
index d9fbe68c76..07ac7eb2d8 100644
180070
--- a/cogl/cogl/cogl-private.h
180070
+++ b/cogl/cogl/cogl-private.h
180070
@@ -42,7 +42,6 @@ typedef enum
180070
 {
180070
   COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE,
180070
   COGL_PRIVATE_FEATURE_MESA_PACK_INVERT,
180070
-  COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER,
180070
   COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES,
180070
   COGL_PRIVATE_FEATURE_PBOS,
180070
   COGL_PRIVATE_FEATURE_VBOS,
180070
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
180070
index 6466fd6bcf..2c0613462f 100644
180070
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
180070
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
180070
@@ -401,8 +401,8 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
180070
         {
180070
           /* NB: Currently we only take advantage of binding separate
180070
            * read/write buffers for framebuffer blit purposes. */
180070
-          _COGL_RETURN_IF_FAIL (_cogl_has_private_feature
180070
-                                (ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER));
180070
+          _COGL_RETURN_IF_FAIL (cogl_has_feature
180070
+                                (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER));
180070
 
180070
           _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
180070
           _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);
180070
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
180070
index 716617b54b..f905267c53 100644
180070
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
180070
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
180070
@@ -466,8 +466,8 @@ _cogl_driver_update_features (CoglContext *ctx,
180070
     }
180070
 
180070
   if (ctx->glBlitFramebuffer)
180070
-    COGL_FLAGS_SET (private_features,
180070
-                    COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER, TRUE);
180070
+    COGL_FLAGS_SET (ctx->features,
180070
+                    COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE);
180070
 
180070
   if (ctx->glRenderbufferStorageMultisampleIMG)
180070
     {
180070
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
180070
index 902bd0bd3a..e55bb302c4 100644
180070
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
180070
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
180070
@@ -325,8 +325,8 @@ _cogl_driver_update_features (CoglContext *context,
180070
     }
180070
 
180070
   if (context->glBlitFramebuffer)
180070
-    COGL_FLAGS_SET (private_features,
180070
-                    COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER, TRUE);
180070
+    COGL_FLAGS_SET (context->features,
180070
+                    COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE);
180070
 
180070
   if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions))
180070
     {
180070
-- 
180070
2.28.0
180070
180070
180070
From 32aa92e50a12a5fd9652866937750a3c86c4845f Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 17:06:35 +0200
180070
Subject: [PATCH 08/20] renderer/native: Only enable shadowfbs if we can blit
180070
180070
There is no point in enabling shadow buffers if we can't as that'd be
180070
even slower than not having them at all.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit f191c3b74f572547707fcb6522db76a88689eae2)
180070
---
180070
 src/backends/native/meta-renderer-native.c | 3 +++
180070
 1 file changed, 3 insertions(+)
180070
180070
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
180070
index 463dddd3a7..62ca4bcbd4 100644
180070
--- a/src/backends/native/meta-renderer-native.c
180070
+++ b/src/backends/native/meta-renderer-native.c
180070
@@ -3649,6 +3649,9 @@ should_force_shadow_fb (MetaRendererNative *renderer_native,
180070
       break;
180070
     }
180070
 
180070
+  if (!cogl_has_feature (cogl_context, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
180070
+    return FALSE;
180070
+
180070
   kms_fd = meta_gpu_kms_get_fd (primary_gpu);
180070
   if (drmGetCap (kms_fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) == 0)
180070
     {
180070
-- 
180070
2.28.0
180070
180070
180070
From 5f247503e261f5bbb6baedc40c737c96b8144218 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 18:55:03 +0200
180070
Subject: [PATCH 09/20] clutter/stage-view: Always use cogl_blit_framebuffer()
180070
 from shadowfb
180070
180070
It should only be used when direct blitting is supported, so there is no
180070
reason we should have to deal with pipelines etc when blitting from the
180070
shadow buffer to the onscreen.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 130f696f303a01d6d666ac967c53b4b5dc372f08)
180070
---
180070
 clutter/clutter/clutter-stage-view.c | 37 +++++++++++-----------------
180070
 1 file changed, 15 insertions(+), 22 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 40edfad6e1..e7e33963a6 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -53,7 +53,6 @@ typedef struct _ClutterStageViewPrivate
180070
   gboolean use_shadowfb;
180070
   struct {
180070
     CoglOffscreen *framebuffer;
180070
-    CoglPipeline *pipeline;
180070
   } shadow;
180070
 
180070
   guint dirty_viewport   : 1;
180070
@@ -149,19 +148,6 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
180070
     view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
180070
 }
180070
 
180070
-static void
180070
-clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
180070
-{
180070
-  ClutterStageViewPrivate *priv =
180070
-    clutter_stage_view_get_instance_private (view);
180070
-
180070
-  if (priv->shadow.pipeline)
180070
-    return;
180070
-
180070
-  priv->shadow.pipeline =
180070
-    clutter_stage_view_create_framebuffer_pipeline (priv->shadow.framebuffer);
180070
-}
180070
-
180070
 void
180070
 clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
180070
 {
180070
@@ -321,13 +307,21 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
 
180070
   if (priv->shadow.framebuffer)
180070
     {
180070
-      clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
180070
-      clutter_stage_view_copy_to_framebuffer (view,
180070
-                                              rect,
180070
-                                              priv->shadow.pipeline,
180070
-                                              priv->shadow.framebuffer,
180070
-                                              priv->framebuffer,
180070
-                                              TRUE);
180070
+      int width, height;
180070
+      g_autoptr (GError) error = NULL;
180070
+
180070
+      width = cogl_framebuffer_get_width (priv->framebuffer);
180070
+      height = cogl_framebuffer_get_height (priv->framebuffer);
180070
+      if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
180070
+                                  priv->framebuffer,
180070
+                                  0, 0,
180070
+                                  0, 0,
180070
+                                  width, height,
180070
+                                  &error))
180070
+        {
180070
+          g_warning ("Failed to blit shadow buffer: %s", error->message);
180070
+          return;
180070
+        }
180070
     }
180070
 }
180070
 
180070
@@ -543,7 +537,6 @@ clutter_stage_view_dispose (GObject *object)
180070
   g_clear_pointer (&priv->name, g_free);
180070
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
180070
   g_clear_pointer (&priv->shadow.framebuffer, cogl_object_unref);
180070
-  g_clear_pointer (&priv->shadow.pipeline, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From d20008aa8630c87d8607e64ff77188fc67b3d22a Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 18:59:32 +0200
180070
Subject: [PATCH 10/20] clutter/stage-view: Simplify painting of offscreen
180070
 slightly
180070
180070
We will only ever have an "offscreen" if we're painting transformed in
180070
some way, so the 'can_blit' checking is unnecessary. Remove it.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 32d5e7d3d77c7ba29b8a7da45731aa31bd486056)
180070
---
180070
 clutter/clutter/clutter-stage-view.c | 49 +++++++---------------------
180070
 1 file changed, 12 insertions(+), 37 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index e7e33963a6..64fb20cb00 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -158,29 +158,13 @@ clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
180070
 }
180070
 
180070
 static void
180070
-clutter_stage_view_copy_to_framebuffer (ClutterStageView            *view,
180070
-                                        const cairo_rectangle_int_t *rect,
180070
-                                        CoglPipeline                *pipeline,
180070
-                                        CoglFramebuffer             *src_framebuffer,
180070
-                                        CoglFramebuffer             *dst_framebuffer,
180070
-                                        gboolean                     can_blit)
180070
+paint_transformed_framebuffer (ClutterStageView *view,
180070
+                               CoglPipeline     *pipeline,
180070
+                               CoglFramebuffer  *src_framebuffer,
180070
+                               CoglFramebuffer  *dst_framebuffer)
180070
 {
180070
   CoglMatrix matrix;
180070
 
180070
-  /* First, try with blit */
180070
-  if (can_blit)
180070
-    {
180070
-      if (cogl_blit_framebuffer (src_framebuffer,
180070
-                                 dst_framebuffer,
180070
-                                 0, 0,
180070
-                                 0, 0,
180070
-                                 cogl_framebuffer_get_width (dst_framebuffer),
180070
-                                 cogl_framebuffer_get_height (dst_framebuffer),
180070
-                                 NULL))
180070
-        return;
180070
-    }
180070
-
180070
-  /* If blit fails, fallback to the slower painting method */
180070
   cogl_framebuffer_push_matrix (dst_framebuffer);
180070
 
180070
   cogl_matrix_init_identity (&matrix);
180070
@@ -278,30 +262,21 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
 
180070
   if (priv->offscreen)
180070
     {
180070
-      gboolean can_blit;
180070
-      CoglMatrix matrix;
180070
-
180070
       clutter_stage_view_ensure_offscreen_blit_pipeline (view);
180070
-      clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
180070
-      can_blit = cogl_matrix_is_identity (&matrix);
180070
 
180070
       if (priv->shadow.framebuffer)
180070
         {
180070
-          clutter_stage_view_copy_to_framebuffer (view,
180070
-                                                  rect,
180070
-                                                  priv->offscreen_pipeline,
180070
-                                                  priv->offscreen,
180070
-                                                  priv->shadow.framebuffer,
180070
-                                                  can_blit);
180070
+          paint_transformed_framebuffer (view,
180070
+                                         priv->offscreen_pipeline,
180070
+                                         priv->offscreen,
180070
+                                         priv->shadow.framebuffer);
180070
         }
180070
       else
180070
         {
180070
-          clutter_stage_view_copy_to_framebuffer (view,
180070
-                                                  rect,
180070
-                                                  priv->offscreen_pipeline,
180070
-                                                  priv->offscreen,
180070
-                                                  priv->framebuffer,
180070
-                                                  can_blit);
180070
+          paint_transformed_framebuffer (view,
180070
+                                         priv->offscreen_pipeline,
180070
+                                         priv->offscreen,
180070
+                                         priv->framebuffer);
180070
         }
180070
     }
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From 8fca65cc3ff989529bf08a47f20b80691f91f95f Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 19:08:03 +0200
180070
Subject: [PATCH 11/20] region-utils: Make transform util const correct
180070
180070
The input should be const, as it will not be altered.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 761bc64cdd4746389625173454b8861cf211cd79)
180070
---
180070
 src/compositor/region-utils.c | 2 +-
180070
 src/compositor/region-utils.h | 2 +-
180070
 2 files changed, 2 insertions(+), 2 deletions(-)
180070
180070
diff --git a/src/compositor/region-utils.c b/src/compositor/region-utils.c
180070
index 752af85c5c..8edb89322c 100644
180070
--- a/src/compositor/region-utils.c
180070
+++ b/src/compositor/region-utils.c
180070
@@ -376,7 +376,7 @@ meta_make_border_region (cairo_region_t *region,
180070
 }
180070
 
180070
 cairo_region_t *
180070
-meta_region_transform (cairo_region_t       *region,
180070
+meta_region_transform (const cairo_region_t *region,
180070
                        MetaMonitorTransform  transform,
180070
                        int                   width,
180070
                        int                   height)
180070
diff --git a/src/compositor/region-utils.h b/src/compositor/region-utils.h
180070
index 84e4d83bc2..ca1b8b7b45 100644
180070
--- a/src/compositor/region-utils.h
180070
+++ b/src/compositor/region-utils.h
180070
@@ -106,7 +106,7 @@ cairo_region_t * meta_make_border_region (cairo_region_t *region,
180070
                                           int             y_amount,
180070
                                           gboolean        flip);
180070
 
180070
-cairo_region_t * meta_region_transform (cairo_region_t       *region,
180070
+cairo_region_t * meta_region_transform (const cairo_region_t *region,
180070
                                         MetaMonitorTransform  transform,
180070
                                         int                   width,
180070
                                         int                   height);
180070
-- 
180070
2.28.0
180070
180070
180070
From 58331ff2f10aad87f537e3ebdaa5707c13c9e41b Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 19:05:36 +0200
180070
Subject: [PATCH 12/20] clutter/stage-cogl: Use buffer age when view monitor is
180070
 rotated
180070
180070
We failed to use the buffer age when monitors were rotated, as when they
180070
are, we first composite to an offscreen framebuffer, then later again to
180070
the onscreen. The buffer age checking happened on the offscreen, and an
180070
offscreen being single buffered, they can't possible support buffer
180070
ages.
180070
180070
Instead, move the buffer age check to check the actual onscreen
180070
framebuffer. The offscreen to onscreen painting is still always full
180070
frame, but that will be fixed in a later commit.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 41c2c2c7d72a0bc8ac1970d35183345424642cf1)
180070
---
180070
 clutter/clutter/clutter-stage-view-private.h |  6 +++
180070
 clutter/clutter/clutter-stage-view.c         | 29 ++++++-----
180070
 clutter/clutter/clutter-stage-view.h         | 11 ++--
180070
 clutter/clutter/cogl/clutter-stage-cogl.c    | 54 +++++++-------------
180070
 src/backends/meta-renderer-view.c            | 22 ++++++++
180070
 5 files changed, 68 insertions(+), 54 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
180070
index e27f140b8a..10f9847b70 100644
180070
--- a/clutter/clutter/clutter-stage-view-private.h
180070
+++ b/clutter/clutter/clutter-stage-view-private.h
180070
@@ -40,4 +40,10 @@ void clutter_stage_view_invalidate_projection (ClutterStageView *view);
180070
 void clutter_stage_view_set_projection (ClutterStageView *view,
180070
                                         const CoglMatrix *matrix);
180070
 
180070
+void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView            *view,
180070
+                                                    const cairo_rectangle_int_t *src_rect,
180070
+                                                    int                          dst_width,
180070
+                                                    int                          dst_height,
180070
+                                                    cairo_rectangle_int_t       *dst_rect);
180070
+
180070
 #endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 64fb20cb00..080bfd6669 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -157,6 +157,22 @@ clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
180070
   g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
180070
 }
180070
 
180070
+void
180070
+clutter_stage_view_transform_rect_to_onscreen (ClutterStageView            *view,
180070
+                                               const cairo_rectangle_int_t *src_rect,
180070
+                                               int                          dst_width,
180070
+                                               int                          dst_height,
180070
+                                               cairo_rectangle_int_t       *dst_rect)
180070
+{
180070
+  ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view);
180070
+
180070
+  return view_class->transform_rect_to_onscreen (view,
180070
+                                                 src_rect,
180070
+                                                 dst_width,
180070
+                                                 dst_height,
180070
+                                                 dst_rect);
180070
+}
180070
+
180070
 static void
180070
 paint_transformed_framebuffer (ClutterStageView *view,
180070
                                CoglPipeline     *pipeline,
180070
@@ -383,19 +399,6 @@ clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view,
180070
   view_class->get_offscreen_transformation_matrix (view, matrix);
180070
 }
180070
 
180070
-void
180070
-clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
180070
-                                          gfloat           *x,
180070
-                                          gfloat           *y)
180070
-{
180070
-  gfloat z = 0, w = 1;
180070
-  CoglMatrix matrix;
180070
-
180070
-  clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
180070
-  cogl_matrix_get_inverse (&matrix, &matrix);
180070
-  cogl_matrix_transform_point (&matrix, x, y, &z, &w);
180070
-}
180070
-
180070
 static void
180070
 clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *view,
180070
                                                            CoglMatrix       *matrix)
180070
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
180070
index 26bf10e798..eb0184e9ab 100644
180070
--- a/clutter/clutter/clutter-stage-view.h
180070
+++ b/clutter/clutter/clutter-stage-view.h
180070
@@ -43,6 +43,12 @@ struct _ClutterStageViewClass
180070
 
180070
   void (* get_offscreen_transformation_matrix) (ClutterStageView *view,
180070
                                                 CoglMatrix       *matrix);
180070
+
180070
+  void (* transform_rect_to_onscreen) (ClutterStageView            *view,
180070
+                                       const cairo_rectangle_int_t *src_rect,
180070
+                                       int                          dst_width,
180070
+                                       int                          dst_height,
180070
+                                       cairo_rectangle_int_t       *dst_rect);
180070
 };
180070
 
180070
 CLUTTER_EXPORT
180070
@@ -56,11 +62,6 @@ CoglFramebuffer *clutter_stage_view_get_onscreen (ClutterStageView *view);
180070
 CLUTTER_EXPORT
180070
 void             clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view);
180070
 
180070
-CLUTTER_EXPORT
180070
-void             clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
180070
-                                                           gfloat           *x,
180070
-                                                           gfloat           *y);
180070
-
180070
 CLUTTER_EXPORT
180070
 float clutter_stage_view_get_scale (ClutterStageView *view);
180070
 
180070
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
index 005c6f6922..821f78ee7c 100644
180070
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
180070
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
@@ -509,36 +509,17 @@ static void
180070
 transform_swap_region_to_onscreen (ClutterStageView      *view,
180070
                                    cairo_rectangle_int_t *swap_region)
180070
 {
180070
-  CoglFramebuffer *framebuffer;
180070
-  cairo_rectangle_int_t layout;
180070
-  gfloat x1, y1, x2, y2;
180070
-  gint width, height;
180070
-
180070
-  framebuffer = clutter_stage_view_get_onscreen (view);
180070
-  clutter_stage_view_get_layout (view, &layout);
180070
-
180070
-  x1 = (float) swap_region->x / layout.width;
180070
-  y1 = (float) swap_region->y / layout.height;
180070
-  x2 = (float) (swap_region->x + swap_region->width) / layout.width;
180070
-  y2 = (float) (swap_region->y + swap_region->height) / layout.height;
180070
-
180070
-  clutter_stage_view_transform_to_onscreen (view, &x1, &y1;;
180070
-  clutter_stage_view_transform_to_onscreen (view, &x2, &y2;;
180070
-
180070
-  width = cogl_framebuffer_get_width (framebuffer);
180070
-  height = cogl_framebuffer_get_height (framebuffer);
180070
-
180070
-  x1 = floor (x1 * width);
180070
-  y1 = floor (height - (y1 * height));
180070
-  x2 = ceil (x2 * width);
180070
-  y2 = ceil (height - (y2 * height));
180070
-
180070
-  *swap_region = (cairo_rectangle_int_t) {
180070
-    .x = x1,
180070
-    .y = y1,
180070
-    .width = x2 - x1,
180070
-    .height = y2 - y1
180070
-  };
180070
+  CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
180070
+  int width, height;
180070
+
180070
+  width = cogl_framebuffer_get_width (onscreen);
180070
+  height = cogl_framebuffer_get_height (onscreen);
180070
+
180070
+  clutter_stage_view_transform_rect_to_onscreen (view,
180070
+                                                 swap_region,
180070
+                                                 width,
180070
+                                                 height,
180070
+                                                 swap_region);
180070
 }
180070
 
180070
 static void
180070
@@ -593,6 +574,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
   ClutterStageViewCoglPrivate *view_priv =
180070
     clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
   CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
180070
+  CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
180070
   cairo_rectangle_int_t view_rect;
180070
   gboolean have_clip;
180070
   gboolean may_use_clipped_redraw;
180070
@@ -618,10 +600,10 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
   fb_height = cogl_framebuffer_get_height (fb);
180070
 
180070
   can_blit_sub_buffer =
180070
-    cogl_is_onscreen (fb) &&
180070
+    cogl_is_onscreen (onscreen) &&
180070
     cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
180070
 
180070
-  has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
180070
+  has_buffer_age = cogl_is_onscreen (onscreen) && is_buffer_age_enabled ();
180070
 
180070
   /* NB: a zero width redraw clip == full stage redraw */
180070
   if (stage_cogl->bounding_redraw_clip.width == 0)
180070
@@ -645,7 +627,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
       have_clip &&
180070
       /* some drivers struggle to get going and produce some junk
180070
        * frames when starting up... */
180070
-      cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3)
180070
+      cogl_onscreen_get_frame_counter (COGL_ONSCREEN (onscreen)) > 3)
180070
     {
180070
       ClutterRect rect;
180070
 
180070
@@ -686,7 +668,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
           cairo_rectangle_int_t *current_fb_damage =
180070
             &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)];
180070
 
180070
-          age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
180070
+          age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (onscreen));
180070
 
180070
           if (valid_buffer_age (view_cogl, age))
180070
             {
180070
@@ -961,9 +943,9 @@ clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
180070
                                     int                *x,
180070
                                     int                *y)
180070
 {
180070
-  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
180070
+  CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
180070
   gboolean has_buffer_age =
180070
-    cogl_is_onscreen (framebuffer) &&
180070
+    cogl_is_onscreen (onscreen) &&
180070
     is_buffer_age_enabled ();
180070
   float fb_scale;
180070
   gboolean scale_is_fractional;
180070
diff --git a/src/backends/meta-renderer-view.c b/src/backends/meta-renderer-view.c
180070
index cab1f5f483..4e45f2ef02 100644
180070
--- a/src/backends/meta-renderer-view.c
180070
+++ b/src/backends/meta-renderer-view.c
180070
@@ -34,6 +34,7 @@
180070
 
180070
 #include "backends/meta-renderer.h"
180070
 #include "clutter/clutter-mutter.h"
180070
+#include "compositor/region-utils.h"
180070
 
180070
 enum
180070
 {
180070
@@ -125,6 +126,25 @@ meta_renderer_view_setup_offscreen_blit_pipeline (ClutterStageView *view,
180070
   cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
180070
 }
180070
 
180070
+static void
180070
+meta_renderer_view_transform_rect_to_onscreen (ClutterStageView            *view,
180070
+                                               const cairo_rectangle_int_t *src_rect,
180070
+                                               int                          dst_width,
180070
+                                               int                          dst_height,
180070
+                                               cairo_rectangle_int_t       *dst_rect)
180070
+{
180070
+  MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
180070
+  MetaMonitorTransform inverted_transform;
180070
+
180070
+  inverted_transform =
180070
+    meta_monitor_transform_invert (renderer_view->transform);
180070
+  return meta_rectangle_transform (src_rect,
180070
+                                   inverted_transform,
180070
+                                   dst_width,
180070
+                                   dst_height,
180070
+                                   dst_rect);
180070
+}
180070
+
180070
 static void
180070
 meta_renderer_view_set_transform (MetaRendererView     *view,
180070
                                   MetaMonitorTransform  transform)
180070
@@ -195,6 +215,8 @@ meta_renderer_view_class_init (MetaRendererViewClass *klass)
180070
     meta_renderer_view_setup_offscreen_blit_pipeline;
180070
   view_class->get_offscreen_transformation_matrix =
180070
     meta_renderer_view_get_offscreen_transformation_matrix;
180070
+  view_class->transform_rect_to_onscreen =
180070
+    meta_renderer_view_transform_rect_to_onscreen;
180070
 
180070
   object_class->get_property = meta_renderer_view_get_property;
180070
   object_class->set_property = meta_renderer_view_set_property;
180070
-- 
180070
2.28.0
180070
180070
180070
From 6fc1da9dd3ac2753771bb68adb780d1d55494cba Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 19:22:10 +0200
180070
Subject: [PATCH 13/20] clutter/stage-view: Only paint redraw clip from
180070
 offscreen
180070
180070
The rest didn't change, so only actually paint the part of the offscreen
180070
that was composited as part of the stage painting. In practice, this
180070
means that, unless a shadow buffer is used, we now only paint the
180070
damaged part of the stage, and copy the damage part of the offscreen to
180070
the onscreen.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit acf6b79e3a5b9d8d285886c471961e8c0bec48ce)
180070
---
180070
 clutter/clutter/clutter-stage-view.c | 85 ++++++++++++++++++++++++----
180070
 1 file changed, 73 insertions(+), 12 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 080bfd6669..b686272db0 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -19,6 +19,7 @@
180070
 
180070
 #include "clutter/clutter-stage-view.h"
180070
 #include "clutter/clutter-stage-view-private.h"
180070
+#include "clutter/clutter-private.h"
180070
 
180070
 #include <cairo-gobject.h>
180070
 #include <math.h>
180070
@@ -174,23 +175,81 @@ clutter_stage_view_transform_rect_to_onscreen (ClutterStageView            *view
180070
 }
180070
 
180070
 static void
180070
-paint_transformed_framebuffer (ClutterStageView *view,
180070
-                               CoglPipeline     *pipeline,
180070
-                               CoglFramebuffer  *src_framebuffer,
180070
-                               CoglFramebuffer  *dst_framebuffer)
180070
+paint_transformed_framebuffer (ClutterStageView            *view,
180070
+                               CoglPipeline                *pipeline,
180070
+                               CoglFramebuffer             *src_framebuffer,
180070
+                               CoglFramebuffer             *dst_framebuffer,
180070
+                               const cairo_rectangle_int_t *redraw_clip)
180070
 {
180070
   CoglMatrix matrix;
180070
+  int dst_width, dst_height;
180070
+  cairo_rectangle_int_t view_layout;
180070
+  cairo_rectangle_int_t onscreen_layout;
180070
+  float view_scale;
180070
+  float *coordinates;
180070
+  cairo_rectangle_int_t src_rect;
180070
+  cairo_rectangle_int_t dst_rect;
180070
+
180070
+  dst_width = cogl_framebuffer_get_width (dst_framebuffer);
180070
+  dst_height = cogl_framebuffer_get_height (dst_framebuffer);
180070
+  clutter_stage_view_get_layout (view, &view_layout);
180070
+  clutter_stage_view_transform_rect_to_onscreen (view,
180070
+                                                 &(cairo_rectangle_int_t) {
180070
+                                                   .width = view_layout.width,
180070
+                                                   .height = view_layout.height,
180070
+                                                 },
180070
+                                                 view_layout.width,
180070
+                                                 view_layout.height,
180070
+                                                 &onscreen_layout);
180070
+  view_scale = clutter_stage_view_get_scale (view);
180070
 
180070
   cogl_framebuffer_push_matrix (dst_framebuffer);
180070
 
180070
   cogl_matrix_init_identity (&matrix);
180070
-  cogl_matrix_translate (&matrix, -1, 1, 0);
180070
-  cogl_matrix_scale (&matrix, 2, -2, 0);
180070
+  cogl_matrix_scale (&matrix,
180070
+                     1.0 / (dst_width / 2.0),
180070
+                     -1.0 / (dst_height / 2.0), 0);
180070
+  cogl_matrix_translate (&matrix,
180070
+                         -(dst_width / 2.0),
180070
+                         -(dst_height / 2.0), 0);
180070
   cogl_framebuffer_set_projection_matrix (dst_framebuffer, &matrix);
180070
-
180070
-  cogl_framebuffer_draw_rectangle (dst_framebuffer,
180070
-                                   pipeline,
180070
-                                   0, 0, 1, 1);
180070
+  cogl_framebuffer_set_viewport (dst_framebuffer,
180070
+                                 0, 0, dst_width, dst_height);
180070
+
180070
+  coordinates = g_newa (float, 2 * 4);
180070
+
180070
+  src_rect = *redraw_clip;
180070
+  _clutter_util_rectangle_offset (&src_rect,
180070
+                                  -view_layout.x,
180070
+                                  -view_layout.y,
180070
+                                  &src_rect);
180070
+
180070
+  clutter_stage_view_transform_rect_to_onscreen (view,
180070
+                                                 &src_rect,
180070
+                                                 onscreen_layout.width,
180070
+                                                 onscreen_layout.height,
180070
+                                                 &dst_rect);
180070
+
180070
+  coordinates[0] = (float) dst_rect.x * view_scale;
180070
+  coordinates[1] = (float) dst_rect.y * view_scale;
180070
+  coordinates[2] = ((float) (dst_rect.x + dst_rect.width) *
180070
+                    view_scale);
180070
+  coordinates[3] = ((float) (dst_rect.y + dst_rect.height) *
180070
+                    view_scale);
180070
+
180070
+  coordinates[4] = (((float) dst_rect.x / (float) dst_width) *
180070
+                    view_scale);
180070
+  coordinates[5] = (((float) dst_rect.y / (float) dst_height) *
180070
+                    view_scale);
180070
+  coordinates[6] = ((float) (dst_rect.x + dst_rect.width) /
180070
+                    (float) dst_width) * view_scale;
180070
+  coordinates[7] = ((float) (dst_rect.y + dst_rect.height) /
180070
+                    (float) dst_height) * view_scale;
180070
+
180070
+  cogl_framebuffer_draw_textured_rectangles (dst_framebuffer,
180070
+                                             pipeline,
180070
+                                             coordinates,
180070
+                                             1);
180070
 
180070
   cogl_framebuffer_pop_matrix (dst_framebuffer);
180070
 }
180070
@@ -285,14 +344,16 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
           paint_transformed_framebuffer (view,
180070
                                          priv->offscreen_pipeline,
180070
                                          priv->offscreen,
180070
-                                         priv->shadow.framebuffer);
180070
+                                         priv->shadow.framebuffer,
180070
+                                         rect);
180070
         }
180070
       else
180070
         {
180070
           paint_transformed_framebuffer (view,
180070
                                          priv->offscreen_pipeline,
180070
                                          priv->offscreen,
180070
-                                         priv->framebuffer);
180070
+                                         priv->framebuffer,
180070
+                                         rect);
180070
         }
180070
     }
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From ff3164440e6bbb3e845a1d4a23843a5792afc16f Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 13 May 2020 17:18:50 +0200
180070
Subject: [PATCH 14/20] clutter/stage-cogl: Only construct damage array if
180070
 it'll be used
180070
180070
It's only used when we actually swap buffers, which we only do if the
180070
target framebuffer is an onscreen.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 95a80c442b6300ce5b41b4b3975a372f1eabd166)
180070
---
180070
 clutter/clutter/cogl/clutter-stage-cogl.c | 22 +++++++++++-----------
180070
 1 file changed, 11 insertions(+), 11 deletions(-)
180070
180070
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
index 821f78ee7c..fc6d0d031d 100644
180070
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
180070
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
@@ -413,17 +413,6 @@ swap_framebuffer (ClutterStageWindow    *stage_window,
180070
                   gboolean               swap_with_damage)
180070
 {
180070
   CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
180070
-  int damage[4], ndamage;
180070
-
180070
-  damage[0] = swap_region->x;
180070
-  damage[1] = swap_region->y;
180070
-  damage[2] = swap_region->width;
180070
-  damage[3] = swap_region->height;
180070
-
180070
-  if (swap_region->width != 0)
180070
-    ndamage = 1;
180070
-  else
180070
-    ndamage = 0;
180070
 
180070
   if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
180070
     paint_damage_region (stage_window, view, swap_region);
180070
@@ -431,6 +420,17 @@ swap_framebuffer (ClutterStageWindow    *stage_window,
180070
   if (cogl_is_onscreen (framebuffer))
180070
     {
180070
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
180070
+      int damage[4], ndamage;
180070
+
180070
+      damage[0] = swap_region->x;
180070
+      damage[1] = swap_region->y;
180070
+      damage[2] = swap_region->width;
180070
+      damage[3] = swap_region->height;
180070
+
180070
+      if (swap_region->width != 0)
180070
+        ndamage = 1;
180070
+      else
180070
+        ndamage = 0;
180070
 
180070
       /* push on the screen */
180070
       if (ndamage == 1 && !swap_with_damage)
180070
-- 
180070
2.28.0
180070
180070
180070
From f946746f5938e7d6c48b688827fb991f22dc1364 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Tue, 5 May 2020 19:25:23 +0200
180070
Subject: [PATCH 15/20] clutter/stage-view: Only blit the damage part of the
180070
 shadow buffer
180070
180070
This fixes the last "copy everything" paths when clutter doesn't
180070
directly paint onto the onscreen framebuffer. It adds a new hook into
180070
the stage view called before the swap buffer, as at this point, we have
180070
the swap buffer damag regions ready, which corresponds to the regions we
180070
must blit according to the damage reported to clutter.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 851e7727ec6f3719139ab562ac2524cdc1bd64ae)
180070
---
180070
 clutter/clutter/clutter-stage-view-private.h |  3 +++
180070
 clutter/clutter/clutter-stage-view.c         | 25 ++++++++++++++++++--
180070
 clutter/clutter/cogl/clutter-stage-cogl.c    |  2 ++
180070
 3 files changed, 28 insertions(+), 2 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h
180070
index 10f9847b70..bddc38ded6 100644
180070
--- a/clutter/clutter/clutter-stage-view-private.h
180070
+++ b/clutter/clutter/clutter-stage-view-private.h
180070
@@ -23,6 +23,9 @@
180070
 void clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
                                         const cairo_rectangle_int_t *clip);
180070
 
180070
+void clutter_stage_view_before_swap_buffer (ClutterStageView            *view,
180070
+                                            const cairo_rectangle_int_t *swap_region);
180070
+
180070
 gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
180070
 
180070
 void clutter_stage_view_invalidate_viewport (ClutterStageView *view);
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index b686272db0..21ab02c97b 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -356,11 +356,22 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
                                          rect);
180070
         }
180070
     }
180070
+}
180070
+
180070
+void
180070
+clutter_stage_view_before_swap_buffer (ClutterStageView            *view,
180070
+                                       const cairo_rectangle_int_t *swap_region)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  g_autoptr (GError) error = NULL;
180070
 
180070
-  if (priv->shadow.framebuffer)
180070
+  if (!priv->shadow.framebuffer)
180070
+    return;
180070
+
180070
+  if (swap_region->width == 0 || swap_region->height == 0)
180070
     {
180070
       int width, height;
180070
-      g_autoptr (GError) error = NULL;
180070
 
180070
       width = cogl_framebuffer_get_width (priv->framebuffer);
180070
       height = cogl_framebuffer_get_height (priv->framebuffer);
180070
@@ -370,6 +381,16 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
                                   0, 0,
180070
                                   width, height,
180070
                                   &error))
180070
+        g_warning ("Failed to blit shadow buffer: %s", error->message);
180070
+    }
180070
+  else
180070
+    {
180070
+      if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
180070
+                                  priv->framebuffer,
180070
+                                  swap_region->x, swap_region->y,
180070
+                                  swap_region->x, swap_region->y,
180070
+                                  swap_region->width, swap_region->height,
180070
+                                  &error))
180070
         {
180070
           g_warning ("Failed to blit shadow buffer: %s", error->message);
180070
           return;
180070
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
index fc6d0d031d..884819ebd3 100644
180070
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
180070
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
@@ -417,6 +417,8 @@ swap_framebuffer (ClutterStageWindow    *stage_window,
180070
   if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
180070
     paint_damage_region (stage_window, view, swap_region);
180070
 
180070
+  clutter_stage_view_before_swap_buffer (view, swap_region);
180070
+
180070
   if (cogl_is_onscreen (framebuffer))
180070
     {
180070
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
180070
-- 
180070
2.28.0
180070
180070
180070
From 757dd09dc9b76a7654f087679db1c7f005b7653c Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 6 May 2020 09:11:34 +0200
180070
Subject: [PATCH 16/20] clutter/stage-cogl: Extract damage history logic
180070
180070
Move the damage history tracking to a new ClutterDamageHistory helper
180070
type. The aim is to be able to track damage history elsewhere without
180070
reimplementing the data structure and tracking logic.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 09271bcfef8889022f15a3b2949843e55f3df9da)
180070
---
180070
 clutter/clutter/clutter-damage-history.c  |  89 +++++++++++++++++
180070
 clutter/clutter/clutter-damage-history.h  |  42 ++++++++
180070
 clutter/clutter/cogl/clutter-stage-cogl.c | 116 ++++++++++++----------
180070
 clutter/clutter/meson.build               |   2 +
180070
 4 files changed, 195 insertions(+), 54 deletions(-)
180070
 create mode 100644 clutter/clutter/clutter-damage-history.c
180070
 create mode 100644 clutter/clutter/clutter-damage-history.h
180070
180070
diff --git a/clutter/clutter/clutter-damage-history.c b/clutter/clutter/clutter-damage-history.c
180070
new file mode 100644
180070
index 0000000000..78ab0f7b5e
180070
--- /dev/null
180070
+++ b/clutter/clutter/clutter-damage-history.c
180070
@@ -0,0 +1,89 @@
180070
+/*
180070
+ * Copyright (C) 2007,2008,2009,2010,2011  Intel Corporation.
180070
+ * Copyright (C) 2020 Red Hat Inc
180070
+ *
180070
+ * This library is free software; you can redistribute it and/or
180070
+ * modify it under the terms of the GNU Lesser General Public
180070
+ * License as published by the Free Software Foundation; either
180070
+ * version 2 of the License, or (at your option) any later version.
180070
+ *
180070
+ * This library is distributed in the hope that it will be useful,
180070
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
180070
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
180070
+ * Lesser General Public License for more details.
180070
+ *
180070
+ * You should have received a copy of the GNU Lesser General Public
180070
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
180070
+ */
180070
+
180070
+#include "clutter-build-config.h"
180070
+
180070
+#include "clutter-damage-history.h"
180070
+
180070
+#define DAMAGE_HISTORY_LENGTH 0x10
180070
+
180070
+struct _ClutterDamageHistory
180070
+{
180070
+  cairo_rectangle_int_t damages[DAMAGE_HISTORY_LENGTH];
180070
+  int index;
180070
+};
180070
+
180070
+ClutterDamageHistory *
180070
+clutter_damage_history_new (void)
180070
+{
180070
+  ClutterDamageHistory *history;
180070
+
180070
+  history = g_new0 (ClutterDamageHistory, 1);
180070
+
180070
+  return history;
180070
+}
180070
+
180070
+void
180070
+clutter_damage_history_free (ClutterDamageHistory *history)
180070
+{
180070
+  g_free (history);
180070
+}
180070
+
180070
+gboolean
180070
+clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
180070
+                                     int                   age)
180070
+{
180070
+  const cairo_rectangle_int_t *damage;
180070
+
180070
+  if (age >= DAMAGE_HISTORY_LENGTH ||
180070
+      age < 1)
180070
+    return FALSE;
180070
+
180070
+  damage = clutter_damage_history_lookup (history, age);
180070
+  if (damage->width == 0 || damage->height == 0)
180070
+    return FALSE;
180070
+
180070
+  return TRUE;
180070
+}
180070
+
180070
+void
180070
+clutter_damage_history_record (ClutterDamageHistory        *history,
180070
+                               const cairo_rectangle_int_t *damage)
180070
+{
180070
+  history->damages[history->index] = *damage;
180070
+}
180070
+
180070
+static inline int
180070
+step_damage_index (int current,
180070
+                   int diff)
180070
+{
180070
+  return (current + diff) & (DAMAGE_HISTORY_LENGTH - 1);
180070
+}
180070
+
180070
+void
180070
+clutter_damage_history_step (ClutterDamageHistory *history)
180070
+{
180070
+  history->index = step_damage_index (history->index, 1);
180070
+}
180070
+
180070
+const cairo_rectangle_int_t *
180070
+clutter_damage_history_lookup (ClutterDamageHistory *history,
180070
+                               int                   age)
180070
+{
180070
+  return &history->damages[step_damage_index (history->index, -age)];
180070
+}
180070
diff --git a/clutter/clutter/clutter-damage-history.h b/clutter/clutter/clutter-damage-history.h
180070
new file mode 100644
180070
index 0000000000..6c483acab7
180070
--- /dev/null
180070
+++ b/clutter/clutter/clutter-damage-history.h
180070
@@ -0,0 +1,42 @@
180070
+/*
180070
+ * Copyright (C) 2007,2008,2009,2010,2011  Intel Corporation.
180070
+ * Copyright (C) 2020 Red Hat Inc
180070
+ *
180070
+ * This library is free software; you can redistribute it and/or
180070
+ * modify it under the terms of the GNU Lesser General Public
180070
+ * License as published by the Free Software Foundation; either
180070
+ * version 2 of the License, or (at your option) any later version.
180070
+ *
180070
+ * This library is distributed in the hope that it will be useful,
180070
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
180070
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
180070
+ * Lesser General Public License for more details.
180070
+ *
180070
+ * You should have received a copy of the GNU Lesser General Public
180070
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
180070
+ */
180070
+
180070
+#ifndef CLUTTER_DAMAGE_HISTORY_H
180070
+#define CLUTTER_DAMAGE_HISTORY_H
180070
+
180070
+#include <cairo.h>
180070
+#include <glib.h>
180070
+
180070
+typedef struct _ClutterDamageHistory ClutterDamageHistory;
180070
+
180070
+ClutterDamageHistory * clutter_damage_history_new (void);
180070
+
180070
+void clutter_damage_history_free (ClutterDamageHistory *history);
180070
+
180070
+gboolean clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
180070
+                                              int                   age);
180070
+
180070
+void clutter_damage_history_record (ClutterDamageHistory        *history,
180070
+                                    const cairo_rectangle_int_t *damage);
180070
+
180070
+void clutter_damage_history_step (ClutterDamageHistory *history);
180070
+
180070
+const cairo_rectangle_int_t * clutter_damage_history_lookup (ClutterDamageHistory *history,
180070
+                                                             int                   age);
180070
+
180070
+#endif /* CLUTTER_DAMAGE_HISTORY_H */
180070
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
index 884819ebd3..11273ec894 100644
180070
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
180070
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
@@ -38,6 +38,7 @@
180070
 
180070
 #include "clutter-actor-private.h"
180070
 #include "clutter-backend-private.h"
180070
+#include "clutter-damage-history.h"
180070
 #include "clutter-debug.h"
180070
 #include "clutter-event.h"
180070
 #include "clutter-enum-types.h"
180070
@@ -49,13 +50,9 @@
180070
 
180070
 typedef struct _ClutterStageViewCoglPrivate
180070
 {
180070
-  /*
180070
-   * List of previous damaged areas in stage view framebuffer coordinate space.
180070
+  /* Damage history, in stage view render target framebuffer coordinate space.
180070
    */
180070
-#define DAMAGE_HISTORY_MAX 16
180070
-#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
180070
-  cairo_rectangle_int_t damage_history[DAMAGE_HISTORY_MAX];
180070
-  unsigned int damage_index;
180070
+  ClutterDamageHistory *damage_history;
180070
 } ClutterStageViewCoglPrivate;
180070
 
180070
 G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
180070
@@ -348,10 +345,7 @@ valid_buffer_age (ClutterStageViewCogl *view_cogl,
180070
   ClutterStageViewCoglPrivate *view_priv =
180070
     clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
 
180070
-  if (age <= 0)
180070
-    return FALSE;
180070
-
180070
-  return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
180070
+  return clutter_damage_history_is_age_valid (view_priv->damage_history, age);
180070
 }
180070
 
180070
 static void
180070
@@ -483,30 +477,6 @@ paint_stage (ClutterStageCogl            *stage_cogl,
180070
   clutter_stage_view_blit_offscreen (view, clip);
180070
 }
180070
 
180070
-static void
180070
-fill_current_damage_history_and_step (ClutterStageView *view)
180070
-{
180070
-  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
180070
-  ClutterStageViewCoglPrivate *view_priv =
180070
-    clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
-  cairo_rectangle_int_t view_rect;
180070
-  float fb_scale;
180070
-  cairo_rectangle_int_t *current_fb_damage;
180070
-
180070
-  current_fb_damage =
180070
-    &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
180070
-  clutter_stage_view_get_layout (view, &view_rect);
180070
-  fb_scale = clutter_stage_view_get_scale (view);
180070
-
180070
-  *current_fb_damage = (cairo_rectangle_int_t) {
180070
-    .x = 0,
180070
-    .y = 0,
180070
-    .width = view_rect.width * fb_scale,
180070
-    .height = view_rect.height * fb_scale
180070
-  };
180070
-  view_priv->damage_index++;
180070
-}
180070
-
180070
 static void
180070
 transform_swap_region_to_onscreen (ClutterStageView      *view,
180070
                                    cairo_rectangle_int_t *swap_region)
180070
@@ -567,6 +537,24 @@ scale_and_clamp_rect (const ClutterRect     *rect,
180070
   _clutter_util_rectangle_int_extents (&tmp, dest);
180070
 }
180070
 
180070
+static void
180070
+record_full_damage (ClutterStageView *view)
180070
+{
180070
+  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
180070
+  ClutterStageViewCoglPrivate *view_priv =
180070
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
+  CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
180070
+  int fb_width, fb_height;
180070
+
180070
+  fb_width = cogl_framebuffer_get_width (fb);
180070
+  fb_height = cogl_framebuffer_get_height (fb);
180070
+  clutter_damage_history_record (view_priv->damage_history,
180070
+                                 &(cairo_rectangle_int_t) {
180070
+                                   .width = fb_width,
180070
+                                   .height = fb_height
180070
+                                 });
180070
+}
180070
+
180070
 static gboolean
180070
 clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
                                 ClutterStageView   *view)
180070
@@ -666,9 +654,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
     {
180070
       if (use_clipped_redraw && !clip_region_empty)
180070
         {
180070
-          int age, i;
180070
-          cairo_rectangle_int_t *current_fb_damage =
180070
-            &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index++)];
180070
+          int age;
180070
 
180070
           age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (onscreen));
180070
 
180070
@@ -676,16 +662,20 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
             {
180070
               ClutterRect rect;
180070
               cairo_rectangle_int_t damage_region;
180070
+              int i;
180070
 
180070
-              *current_fb_damage = fb_clip_region;
180070
+              clutter_damage_history_record (view_priv->damage_history,
180070
+                                             &fb_clip_region);
180070
 
180070
               for (i = 1; i <= age; i++)
180070
                 {
180070
-                  cairo_rectangle_int_t *fb_damage =
180070
-                    &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - i - 1)];
180070
+                  const cairo_rectangle_int_t *old_damage;
180070
+
180070
+                  old_damage =
180070
+                    clutter_damage_history_lookup (view_priv->damage_history, i);
180070
 
180070
                   _clutter_util_rectangle_union (&fb_clip_region,
180070
-                                                 fb_damage,
180070
+                                                 old_damage,
180070
                                                  &fb_clip_region);
180070
                 }
180070
 
180070
@@ -713,18 +703,15 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
180070
             {
180070
               CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", age);
180070
               use_clipped_redraw = FALSE;
180070
-              *current_fb_damage = (cairo_rectangle_int_t) {
180070
-                .x = 0,
180070
-                .y = 0,
180070
-                .width = view_rect.width * fb_scale,
180070
-                .height = view_rect.height * fb_scale
180070
-              };
180070
+              record_full_damage (view);
180070
             }
180070
         }
180070
       else if (!use_clipped_redraw)
180070
         {
180070
-          fill_current_damage_history_and_step (view);
180070
+          record_full_damage (view);
180070
         }
180070
+
180070
+      clutter_damage_history_step (view_priv->damage_history);
180070
     }
180070
 
180070
   cogl_push_framebuffer (fb);
180070
@@ -946,6 +933,9 @@ clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
180070
                                     int                *y)
180070
 {
180070
   CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
180070
+  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
180070
+  ClutterStageViewCoglPrivate *view_priv =
180070
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
   gboolean has_buffer_age =
180070
     cogl_is_onscreen (onscreen) &&
180070
     is_buffer_age_enabled ();
180070
@@ -967,22 +957,21 @@ clutter_stage_cogl_get_dirty_pixel (ClutterStageWindow *stage_window,
180070
    * For now, always use the (0, 0) pixel for picking when using fractional
180070
    * framebuffer scaling.
180070
    */
180070
-  if (!has_buffer_age || scale_is_fractional)
180070
+  if (!has_buffer_age ||
180070
+      scale_is_fractional ||
180070
+      !clutter_damage_history_is_age_valid (view_priv->damage_history, 0))
180070
     {
180070
       *x = 0;
180070
       *y = 0;
180070
     }
180070
   else
180070
     {
180070
-      ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
180070
-      ClutterStageViewCoglPrivate *view_priv =
180070
-        clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
       cairo_rectangle_int_t view_layout;
180070
-      cairo_rectangle_int_t *fb_damage;
180070
+      const cairo_rectangle_int_t *fb_damage;
180070
 
180070
       clutter_stage_view_get_layout (view, &view_layout);
180070
 
180070
-      fb_damage = &view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index - 1)];
180070
+      fb_damage = clutter_damage_history_lookup (view_priv->damage_history, 0);
180070
       *x = fb_damage->x / fb_scale;
180070
       *y = fb_damage->y / fb_scale;
180070
     }
180070
@@ -1052,12 +1041,31 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
180070
   stage->update_time = -1;
180070
 }
180070
 
180070
+static void
180070
+clutter_stage_view_cogl_finalize (GObject *object)
180070
+{
180070
+  ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (object);
180070
+  ClutterStageViewCoglPrivate *view_priv =
180070
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
+
180070
+  clutter_damage_history_free (view_priv->damage_history);
180070
+
180070
+  G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
180070
+}
180070
+
180070
 static void
180070
 clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
180070
 {
180070
+  ClutterStageViewCoglPrivate *view_priv =
180070
+    clutter_stage_view_cogl_get_instance_private (view_cogl);
180070
+
180070
+  view_priv->damage_history = clutter_damage_history_new ();
180070
 }
180070
 
180070
 static void
180070
 clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
180070
 {
180070
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
180070
+
180070
+  object_class->finalize = clutter_stage_view_cogl_finalize;
180070
 }
180070
diff --git a/clutter/clutter/meson.build b/clutter/clutter/meson.build
180070
index 8e0484453d..c9eab96d29 100644
180070
--- a/clutter/clutter/meson.build
180070
+++ b/clutter/clutter/meson.build
180070
@@ -116,6 +116,7 @@ clutter_sources = [
180070
   'clutter-constraint.c',
180070
   'clutter-container.c',
180070
   'clutter-content.c',
180070
+  'clutter-damage-history.c',
180070
   'clutter-deform-effect.c',
180070
   'clutter-desaturate-effect.c',
180070
   'clutter-device-manager.c',
180070
@@ -186,6 +187,7 @@ clutter_private_headers = [
180070
   'clutter-bezier.h',
180070
   'clutter-constraint-private.h',
180070
   'clutter-content-private.h',
180070
+  'clutter-damage-history.h',
180070
   'clutter-debug.h',
180070
   'clutter-device-manager-private.h',
180070
   'clutter-easing.h',
180070
-- 
180070
2.28.0
180070
180070
180070
From 5da1c8083784a351a7763a0c9a9ce4c8359522a4 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 6 May 2020 21:40:40 +0200
180070
Subject: [PATCH 17/20] cogl/dma-buf: Add API to synchronize reading
180070
180070
Used before and after accessing DMA buffer content using mmap().
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 2d972fc761b9e39f78e66dd84eab57309cdc8658)
180070
---
180070
 cogl/cogl/cogl-dma-buf-handle.c | 51 +++++++++++++++++++++++++++++++++
180070
 cogl/cogl/cogl-dma-buf-handle.h |  8 ++++++
180070
 cogl/meson.build                |  1 +
180070
 3 files changed, 60 insertions(+)
180070
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.c b/cogl/cogl/cogl-dma-buf-handle.c
180070
index d8b4e57c55..7e86e2267b 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.c
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.c
180070
@@ -34,6 +34,10 @@
180070
 #include "cogl-dma-buf-handle.h"
180070
 #include "cogl-object.h"
180070
 
180070
+#include <errno.h>
180070
+#include <gio/gio.h>
180070
+#include <linux/dma-buf.h>
180070
+#include <sys/ioctl.h>
180070
 #include <unistd.h>
180070
 
180070
 struct _CoglDmaBufHandle
180070
@@ -96,6 +100,53 @@ cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle)
180070
   g_free (dmabuf_handle);
180070
 }
180070
 
180070
+static gboolean
180070
+sync_read (CoglDmaBufHandle  *dmabuf_handle,
180070
+           uint64_t           start_or_end,
180070
+           GError           **error)
180070
+{
180070
+  struct dma_buf_sync sync = { 0 };
180070
+
180070
+  sync.flags = start_or_end | DMA_BUF_SYNC_READ;
180070
+
180070
+  while (TRUE)
180070
+    {
180070
+      int ret;
180070
+
180070
+      ret = ioctl (dmabuf_handle->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync);
180070
+      if (ret == -1 && errno == EINTR)
180070
+        {
180070
+          continue;
180070
+        }
180070
+      else if (ret == -1)
180070
+        {
180070
+          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
180070
+                       "ioctl: %s", g_strerror (errno));
180070
+          return FALSE;
180070
+        }
180070
+      else
180070
+        {
180070
+          break;
180070
+        }
180070
+    }
180070
+
180070
+  return TRUE;
180070
+}
180070
+
180070
+gboolean
180070
+cogl_dma_buf_handle_sync_read_start (CoglDmaBufHandle  *dmabuf_handle,
180070
+                                     GError           **error)
180070
+{
180070
+  return sync_read (dmabuf_handle, DMA_BUF_SYNC_START, error);
180070
+}
180070
+
180070
+gboolean
180070
+cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle  *dmabuf_handle,
180070
+                                   GError           **error)
180070
+{
180070
+  return sync_read (dmabuf_handle, DMA_BUF_SYNC_END, error);
180070
+}
180070
+
180070
 CoglFramebuffer *
180070
 cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle)
180070
 {
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.h b/cogl/cogl/cogl-dma-buf-handle.h
180070
index f64a20678d..63c5bab7b7 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.h
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.h
180070
@@ -63,6 +63,14 @@ cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
180070
 void
180070
 cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle);
180070
 
180070
+gboolean
180070
+cogl_dma_buf_handle_sync_read_start (CoglDmaBufHandle  *dmabuf_handle,
180070
+                                     GError           **error);
180070
+
180070
+gboolean
180070
+cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle  *dmabuf_handle,
180070
+                                   GError           **error);
180070
+
180070
 /**
180070
  * cogl_dma_buf_handle_get_framebuffer: (skip)
180070
  *
180070
diff --git a/cogl/meson.build b/cogl/meson.build
180070
index 356d596f56..47e6a3e0da 100644
180070
--- a/cogl/meson.build
180070
+++ b/cogl/meson.build
180070
@@ -23,6 +23,7 @@ cogl_mutter_config_h = configure_file(
180070
 
180070
 cogl_pkg_deps = [
180070
   glib_dep,
180070
+  gio_dep,
180070
   gobject_dep,
180070
 ]
180070
 
180070
-- 
180070
2.28.0
180070
180070
180070
From 360a397c19046c6a914ee27e3e5104da3ad0c1c6 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 6 May 2020 22:12:46 +0200
180070
Subject: [PATCH 18/20] cogl/dma-buf: Add mmap/munmap helpers
180070
180070
Avoids dealing directly with mmap() and munmap().
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit e05a1a6c0b2526146c85ec9c381bb2b49d19b4b2)
180070
---
180070
 cogl/cogl/cogl-dma-buf-handle.c | 41 +++++++++++++++++++++++++++++++++
180070
 cogl/cogl/cogl-dma-buf-handle.h |  9 ++++++++
180070
 2 files changed, 50 insertions(+)
180070
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.c b/cogl/cogl/cogl-dma-buf-handle.c
180070
index 7e86e2267b..9724ac9c95 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.c
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.c
180070
@@ -38,6 +38,7 @@
180070
 #include <gio/gio.h>
180070
 #include <linux/dma-buf.h>
180070
 #include <sys/ioctl.h>
180070
+#include <sys/mman.h>
180070
 #include <unistd.h>
180070
 
180070
 struct _CoglDmaBufHandle
180070
@@ -147,6 +148,46 @@ cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle  *dmabuf_handle,
180070
   return sync_read (dmabuf_handle, DMA_BUF_SYNC_END, error);
180070
 }
180070
 
180070
+gpointer
180070
+cogl_dma_buf_handle_mmap (CoglDmaBufHandle  *dmabuf_handle,
180070
+                          GError           **error)
180070
+{
180070
+  size_t size;
180070
+  gpointer data;
180070
+
180070
+  size = dmabuf_handle->height * dmabuf_handle->stride;
180070
+
180070
+  data = mmap (NULL, size, PROT_READ, MAP_PRIVATE,
180070
+               dmabuf_handle->dmabuf_fd,
180070
+               dmabuf_handle->offset);
180070
+  if (data == MAP_FAILED)
180070
+    {
180070
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
180070
+                   "mmap failed: %s", g_strerror (errno));
180070
+      return NULL;
180070
+    }
180070
+
180070
+  return data;
180070
+}
180070
+
180070
+gboolean
180070
+cogl_dma_buf_handle_munmap (CoglDmaBufHandle  *dmabuf_handle,
180070
+                            gpointer           data,
180070
+                            GError           **error)
180070
+{
180070
+  size_t size;
180070
+
180070
+  size = dmabuf_handle->height * dmabuf_handle->stride;
180070
+  if (munmap (data, size) != 0)
180070
+    {
180070
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
180070
+                   "munmap failed: %s", g_strerror (errno));
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  return TRUE;
180070
+}
180070
+
180070
 CoglFramebuffer *
180070
 cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle)
180070
 {
180070
diff --git a/cogl/cogl/cogl-dma-buf-handle.h b/cogl/cogl/cogl-dma-buf-handle.h
180070
index 63c5bab7b7..08f307c1db 100644
180070
--- a/cogl/cogl/cogl-dma-buf-handle.h
180070
+++ b/cogl/cogl/cogl-dma-buf-handle.h
180070
@@ -71,6 +71,15 @@ gboolean
180070
 cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle  *dmabuf_handle,
180070
                                    GError           **error);
180070
 
180070
+gpointer
180070
+cogl_dma_buf_handle_mmap (CoglDmaBufHandle  *dmabuf_handle,
180070
+                          GError           **error);
180070
+
180070
+gboolean
180070
+cogl_dma_buf_handle_munmap (CoglDmaBufHandle  *dmabuf_handle,
180070
+                            gpointer           data,
180070
+                            GError           **error);
180070
+
180070
 /**
180070
  * cogl_dma_buf_handle_get_framebuffer: (skip)
180070
  *
180070
-- 
180070
2.28.0
180070
180070
180070
From ff8a80137047a91ed27d90467b004d691428bac4 Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
180070
Date: Wed, 6 May 2020 22:14:17 +0200
180070
Subject: [PATCH 19/20] clutter/stage-view: Add tile based shadow damage
180070
 detection
180070
180070
Compare, tile by tile, whether actual damage actually changed any
180070
pixels. While this requires mmap():ing DMA buffers and comparing their
180070
content, we should only ever use shadow buffers when we're using the
180070
software renderer, meaning mmap() is cheap as it doesn't involve any
180070
downloading.
180070
180070
This works by making the shadow framebuffer double buffered, while
180070
keeping track of damage history. When we're about to swap the onscreen
180070
buffer, we compare what part of the posted damage actually changed,
180070
records that into a damage history, then given the onscreen buffer age,
180070
collect all actual damage for that age. The intersection of these tiles,
180070
and the actual damage, is then used when blitting the shadow buffer to
180070
the onscreen framebuffer.
180070
180070
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1157
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 068385df3a0cf545e5110378b59db56cbd1bdef3)
180070
---
180070
 clutter/clutter/clutter-private.h    |   3 +
180070
 clutter/clutter/clutter-stage-view.c | 472 +++++++++++++++++++++++++--
180070
 clutter/clutter/clutter-util.c       |  22 ++
180070
 3 files changed, 465 insertions(+), 32 deletions(-)
180070
180070
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
180070
index a5cd1fa197..5a0fed85c9 100644
180070
--- a/clutter/clutter/clutter-private.h
180070
+++ b/clutter/clutter/clutter-private.h
180070
@@ -265,6 +265,9 @@ gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1
180070
                                                const cairo_rectangle_int_t *src2,
180070
                                                cairo_rectangle_int_t       *dest);
180070
 
180070
+gboolean _clutter_util_rectangle_contains (const cairo_rectangle_int_t *src1,
180070
+                                           const cairo_rectangle_int_t *src2);
180070
+
180070
 
180070
 struct _ClutterVertex4
180070
 {
180070
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
180070
index 21ab02c97b..5e5966d06e 100644
180070
--- a/clutter/clutter/clutter-stage-view.c
180070
+++ b/clutter/clutter/clutter-stage-view.c
180070
@@ -17,6 +17,7 @@
180070
 
180070
 #include "clutter-build-config.h"
180070
 
180070
+#include "clutter/clutter-damage-history.h"
180070
 #include "clutter/clutter-stage-view.h"
180070
 #include "clutter/clutter-stage-view-private.h"
180070
 #include "clutter/clutter-private.h"
180070
@@ -53,6 +54,12 @@ typedef struct _ClutterStageViewPrivate
180070
 
180070
   gboolean use_shadowfb;
180070
   struct {
180070
+    struct {
180070
+      CoglDmaBufHandle *handles[2];
180070
+      int current_idx;
180070
+      ClutterDamageHistory *damage_history;
180070
+    } dma_buf;
180070
+
180070
     CoglOffscreen *framebuffer;
180070
   } shadow;
180070
 
180070
@@ -254,6 +261,66 @@ paint_transformed_framebuffer (ClutterStageView            *view,
180070
   cogl_framebuffer_pop_matrix (dst_framebuffer);
180070
 }
180070
 
180070
+static gboolean
180070
+is_shadowfb_double_buffered (ClutterStageView *view)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+
180070
+  return priv->shadow.dma_buf.handles[0] && priv->shadow.dma_buf.handles[1];
180070
+}
180070
+
180070
+static gboolean
180070
+init_dma_buf_shadowfbs (ClutterStageView  *view,
180070
+                        CoglContext       *cogl_context,
180070
+                        int                width,
180070
+                        int                height,
180070
+                        GError           **error)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context);
180070
+  CoglFramebuffer *initial_shadowfb;
180070
+
180070
+  if (!cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE))
180070
+    {
180070
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
180070
+                   "Buffer age not supported");
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  if (!cogl_is_onscreen (priv->framebuffer))
180070
+    {
180070
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
180070
+                   "Tried to use shadow buffer without onscreen");
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  priv->shadow.dma_buf.handles[0] = cogl_renderer_create_dma_buf (cogl_renderer,
180070
+                                                                  width, height,
180070
+                                                                  error);
180070
+  if (!priv->shadow.dma_buf.handles[0])
180070
+    return FALSE;
180070
+
180070
+  priv->shadow.dma_buf.handles[1] = cogl_renderer_create_dma_buf (cogl_renderer,
180070
+                                                                  width, height,
180070
+                                                                  error);
180070
+  if (!priv->shadow.dma_buf.handles[1])
180070
+    {
180070
+      g_clear_pointer (&priv->shadow.dma_buf.handles[0],
180070
+                       cogl_dma_buf_handle_free);
180070
+      return FALSE;
180070
+    }
180070
+
180070
+  priv->shadow.dma_buf.damage_history = clutter_damage_history_new ();
180070
+
180070
+  initial_shadowfb =
180070
+    cogl_dma_buf_handle_get_framebuffer (priv->shadow.dma_buf.handles[0]);
180070
+  priv->shadow.framebuffer = cogl_object_ref (initial_shadowfb);
180070
+
180070
+  return TRUE;
180070
+}
180070
+
180070
 static CoglOffscreen *
180070
 create_offscreen_framebuffer (CoglContext  *context,
180070
                               int           width,
180070
@@ -285,11 +352,11 @@ create_offscreen_framebuffer (CoglContext  *context,
180070
 }
180070
 
180070
 static gboolean
180070
-init_offscreen_shadowfb (ClutterStageView  *view,
180070
-                         CoglContext       *cogl_context,
180070
-                         int                width,
180070
-                         int                height,
180070
-                         GError           **error)
180070
+init_fallback_shadowfb (ClutterStageView  *view,
180070
+                        CoglContext       *cogl_context,
180070
+                        int                width,
180070
+                        int                height,
180070
+                        GError           **error)
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
@@ -317,7 +384,17 @@ init_shadowfb (ClutterStageView *view)
180070
   height = cogl_framebuffer_get_height (priv->framebuffer);
180070
   cogl_context = cogl_framebuffer_get_context (priv->framebuffer);
180070
 
180070
-  if (!init_offscreen_shadowfb (view, cogl_context, width, height, &error))
180070
+  if (init_dma_buf_shadowfbs (view, cogl_context, width, height, &error))
180070
+    {
180070
+      g_message ("Initialized double buffered shadow fb for %s", priv->name);
180070
+      return;
180070
+    }
180070
+
180070
+  g_warning ("Failed to initialize double buffered shadow fb for %s: %s",
180070
+             priv->name, error->message);
180070
+  g_clear_error (&error);
180070
+
180070
+  if (!init_fallback_shadowfb (view, cogl_context, width, height, &error))
180070
     {
180070
       g_warning ("Failed to initialize single buffered shadow fb for %s: %s",
180070
                  priv->name, error->message);
180070
@@ -358,44 +435,298 @@ clutter_stage_view_blit_offscreen (ClutterStageView            *view,
180070
     }
180070
 }
180070
 
180070
-void
180070
-clutter_stage_view_before_swap_buffer (ClutterStageView            *view,
180070
-                                       const cairo_rectangle_int_t *swap_region)
180070
+static gboolean
180070
+is_tile_dirty (cairo_rectangle_int_t *tile,
180070
+               uint8_t               *current_data,
180070
+               uint8_t               *prev_data,
180070
+               int                    bpp,
180070
+               int                    stride)
180070
+{
180070
+  int y;
180070
+
180070
+  for (y = tile->y; y < tile->y + tile->height; y++)
180070
+    {
180070
+      if (memcmp (prev_data + y * stride + tile->x * bpp,
180070
+                  current_data + y * stride + tile->x * bpp,
180070
+                  tile->width * bpp) != 0)
180070
+        return TRUE;
180070
+    }
180070
+
180070
+  return FALSE;
180070
+}
180070
+
180070
+static int
180070
+flip_dma_buf_idx (int idx)
180070
+{
180070
+  return (idx + 1) % 2;
180070
+}
180070
+
180070
+static cairo_region_t *
180070
+find_damaged_tiles (ClutterStageView      *view,
180070
+                    const cairo_region_t  *damage_region,
180070
+                    GError               **error)
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
-  g_autoptr (GError) error = NULL;
180070
+  cairo_region_t *tile_damage_region;
180070
+  cairo_rectangle_int_t damage_extents;
180070
+  cairo_rectangle_int_t fb_rect;
180070
+  int prev_dma_buf_idx;
180070
+  CoglDmaBufHandle *prev_dma_buf_handle;
180070
+  uint8_t *prev_data;
180070
+  int current_dma_buf_idx;
180070
+  CoglDmaBufHandle *current_dma_buf_handle;
180070
+  uint8_t *current_data;
180070
+  int width, height, stride, bpp;
180070
+  int tile_x_min, tile_x_max;
180070
+  int tile_y_min, tile_y_max;
180070
+  int tile_x, tile_y;
180070
+  const int tile_size = 16;
180070
+
180070
+  prev_dma_buf_idx = flip_dma_buf_idx (priv->shadow.dma_buf.current_idx);
180070
+  prev_dma_buf_handle = priv->shadow.dma_buf.handles[prev_dma_buf_idx];
180070
+
180070
+  current_dma_buf_idx = priv->shadow.dma_buf.current_idx;
180070
+  current_dma_buf_handle = priv->shadow.dma_buf.handles[current_dma_buf_idx];
180070
+
180070
+  width = cogl_dma_buf_handle_get_width (current_dma_buf_handle);
180070
+  height = cogl_dma_buf_handle_get_height (current_dma_buf_handle);
180070
+  stride = cogl_dma_buf_handle_get_stride (current_dma_buf_handle);
180070
+  bpp = cogl_dma_buf_handle_get_bpp (current_dma_buf_handle);
180070
+
180070
+  cogl_framebuffer_finish (priv->shadow.framebuffer);
180070
+
180070
+  if (!cogl_dma_buf_handle_sync_read_start (prev_dma_buf_handle, error))
180070
+    return NULL;
180070
+
180070
+  if (!cogl_dma_buf_handle_sync_read_start (current_dma_buf_handle, error))
180070
+    goto err_sync_read_current;
180070
+
180070
+  prev_data = cogl_dma_buf_handle_mmap (prev_dma_buf_handle, error);
180070
+  if (!prev_data)
180070
+    goto err_mmap_prev;
180070
+  current_data = cogl_dma_buf_handle_mmap (current_dma_buf_handle, error);
180070
+  if (!current_data)
180070
+    goto err_mmap_current;
180070
+
180070
+  fb_rect = (cairo_rectangle_int_t) {
180070
+    .width = width,
180070
+    .height = height,
180070
+  };
180070
+
180070
+  cairo_region_get_extents (damage_region, &damage_extents);
180070
+
180070
+  tile_x_min = damage_extents.x / tile_size;
180070
+  tile_x_max = ((damage_extents.x + damage_extents.width + tile_size - 1) /
180070
+                tile_size);
180070
+  tile_y_min = damage_extents.y / tile_size;
180070
+  tile_y_max = ((damage_extents.y + damage_extents.height + tile_size - 1) /
180070
+                tile_size);
180070
+
180070
+  tile_damage_region = cairo_region_create ();
180070
+
180070
+  for (tile_y = tile_y_min; tile_y <= tile_y_max; tile_y++)
180070
+    {
180070
+      for (tile_x = tile_x_min; tile_x <= tile_x_max; tile_x++)
180070
+        {
180070
+          cairo_rectangle_int_t tile = {
180070
+            .x = tile_x * tile_size,
180070
+            .y = tile_y * tile_size,
180070
+            .width = tile_size,
180070
+            .height = tile_size,
180070
+          };
180070
 
180070
-  if (!priv->shadow.framebuffer)
180070
-    return;
180070
+          if (cairo_region_contains_rectangle (damage_region, &tile) ==
180070
+              CAIRO_REGION_OVERLAP_OUT)
180070
+            continue;
180070
 
180070
-  if (swap_region->width == 0 || swap_region->height == 0)
180070
+          _clutter_util_rectangle_intersection (&tile, &fb_rect, &tile;;
180070
+
180070
+          if (is_tile_dirty (&tile, current_data, prev_data, bpp, stride))
180070
+            cairo_region_union_rectangle (tile_damage_region, &tile;;
180070
+        }
180070
+    }
180070
+
180070
+  if (!cogl_dma_buf_handle_sync_read_end (prev_dma_buf_handle, error))
180070
     {
180070
-      int width, height;
180070
+      g_warning ("Failed to end DMA buffer read synchronization: %s",
180070
+                 (*error)->message);
180070
+      g_clear_error (error);
180070
+    }
180070
 
180070
-      width = cogl_framebuffer_get_width (priv->framebuffer);
180070
-      height = cogl_framebuffer_get_height (priv->framebuffer);
180070
-      if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
180070
-                                  priv->framebuffer,
180070
-                                  0, 0,
180070
-                                  0, 0,
180070
-                                  width, height,
180070
-                                  &error))
180070
-        g_warning ("Failed to blit shadow buffer: %s", error->message);
180070
+  if (!cogl_dma_buf_handle_sync_read_end (current_dma_buf_handle, error))
180070
+    {
180070
+      g_warning ("Failed to end DMA buffer read synchronization: %s",
180070
+                 (*error)->message);
180070
+      g_clear_error (error);
180070
+    }
180070
+
180070
+  cogl_dma_buf_handle_munmap (prev_dma_buf_handle, prev_data, NULL);
180070
+  cogl_dma_buf_handle_munmap (current_dma_buf_handle, current_data, NULL);
180070
+
180070
+  cairo_region_intersect (tile_damage_region, damage_region);
180070
+
180070
+  return tile_damage_region;
180070
+
180070
+err_mmap_current:
180070
+  cogl_dma_buf_handle_munmap (prev_dma_buf_handle, prev_data, NULL);
180070
+
180070
+err_mmap_prev:
180070
+  cogl_dma_buf_handle_sync_read_end (current_dma_buf_handle, NULL);
180070
+
180070
+err_sync_read_current:
180070
+  cogl_dma_buf_handle_sync_read_end (prev_dma_buf_handle, NULL);
180070
+
180070
+  return NULL;
180070
+}
180070
+
180070
+static void
180070
+swap_dma_buf_framebuffer (ClutterStageView *view)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  int next_idx;
180070
+  CoglDmaBufHandle *next_dma_buf_handle;
180070
+  CoglOffscreen *next_framebuffer;
180070
+
180070
+  next_idx = ((priv->shadow.dma_buf.current_idx + 1) %
180070
+              G_N_ELEMENTS (priv->shadow.dma_buf.handles));
180070
+  priv->shadow.dma_buf.current_idx = next_idx;
180070
+
180070
+  next_dma_buf_handle = priv->shadow.dma_buf.handles[next_idx];
180070
+  next_framebuffer =
180070
+    cogl_dma_buf_handle_get_framebuffer (next_dma_buf_handle);
180070
+  cogl_clear_object (&priv->shadow.framebuffer);
180070
+  priv->shadow.framebuffer = cogl_object_ref (next_framebuffer);
180070
+}
180070
+
180070
+static void
180070
+copy_shadowfb_to_onscreen (ClutterStageView            *view,
180070
+                           const cairo_rectangle_int_t *swap_region)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+  ClutterDamageHistory *damage_history = priv->shadow.dma_buf.damage_history;
180070
+  cairo_region_t *damage_region;
180070
+  int age;
180070
+  int i;
180070
+
180070
+  if (swap_region->width == 0 || swap_region->height == 0)
180070
+    {
180070
+      cairo_rectangle_int_t full_damage = {
180070
+        .width = cogl_framebuffer_get_width (priv->framebuffer),
180070
+        .height = cogl_framebuffer_get_height (priv->framebuffer),
180070
+      };
180070
+      damage_region = cairo_region_create_rectangle (&full_damage);
180070
     }
180070
   else
180070
     {
180070
+      damage_region = cairo_region_create_rectangle (swap_region);
180070
+    }
180070
+
180070
+  if (is_shadowfb_double_buffered (view))
180070
+    {
180070
+      CoglOnscreen *onscreen = COGL_ONSCREEN (priv->framebuffer);
180070
+      cairo_region_t *changed_region;
180070
+
180070
+      if (cogl_onscreen_get_frame_counter (onscreen) >= 1)
180070
+        {
180070
+          g_autoptr (GError) error = NULL;
180070
+
180070
+          changed_region = find_damaged_tiles (view, damage_region, &error);
180070
+          if (!changed_region)
180070
+            {
180070
+              int other_dma_buf_idx;
180070
+
180070
+              g_warning ("Disabling actual damage detection: %s",
180070
+                         error->message);
180070
+
180070
+              other_dma_buf_idx =
180070
+                flip_dma_buf_idx (priv->shadow.dma_buf.current_idx);
180070
+              g_clear_pointer (&priv->shadow.dma_buf.handles[other_dma_buf_idx],
180070
+                               cogl_dma_buf_handle_free);
180070
+            }
180070
+        }
180070
+      else
180070
+        {
180070
+          changed_region = cairo_region_copy (damage_region);
180070
+        }
180070
+
180070
+      if (changed_region)
180070
+        {
180070
+          cairo_rectangle_int_t changed_extents;
180070
+          int buffer_age;
180070
+
180070
+          cairo_region_get_extents (changed_region, &changed_extents);
180070
+          clutter_damage_history_record (damage_history, &changed_extents);
180070
+
180070
+          buffer_age = cogl_onscreen_get_buffer_age (onscreen);
180070
+          if (clutter_damage_history_is_age_valid (damage_history, buffer_age))
180070
+            {
180070
+              for (age = 1; age <= buffer_age; age++)
180070
+                {
180070
+                  const cairo_rectangle_int_t *old_damage;
180070
+
180070
+                  old_damage = clutter_damage_history_lookup (damage_history, age);
180070
+                  cairo_region_union_rectangle (changed_region, old_damage);
180070
+                }
180070
+
180070
+              cairo_region_destroy (damage_region);
180070
+              damage_region = g_steal_pointer (&changed_region);
180070
+            }
180070
+          else
180070
+            {
180070
+              cairo_region_destroy (changed_region);
180070
+            }
180070
+
180070
+          clutter_damage_history_step (damage_history);
180070
+        }
180070
+    }
180070
+
180070
+  if (0)
180070
+    {
180070
+      CoglColor clear_color;
180070
+
180070
+      cogl_color_init_from_4ub (&clear_color,
180070
+                                0, 0, 0, 0);
180070
+      cogl_framebuffer_clear (priv->framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color);
180070
+    }
180070
+
180070
+  for (i = 0; i < cairo_region_num_rectangles (damage_region); i++)
180070
+    {
180070
+      g_autoptr (GError) error = NULL;
180070
+      cairo_rectangle_int_t rect;
180070
+
180070
+      cairo_region_get_rectangle (damage_region, i, &rect);
180070
+
180070
       if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
180070
                                   priv->framebuffer,
180070
-                                  swap_region->x, swap_region->y,
180070
-                                  swap_region->x, swap_region->y,
180070
-                                  swap_region->width, swap_region->height,
180070
+                                  rect.x, rect.y,
180070
+                                  rect.x, rect.y,
180070
+                                  rect.width, rect.height,
180070
                                   &error))
180070
         {
180070
           g_warning ("Failed to blit shadow buffer: %s", error->message);
180070
+          cairo_region_destroy (damage_region);
180070
           return;
180070
         }
180070
     }
180070
+
180070
+  cairo_region_destroy (damage_region);
180070
+
180070
+  if (is_shadowfb_double_buffered (view))
180070
+    swap_dma_buf_framebuffer (view);
180070
+}
180070
+
180070
+void
180070
+clutter_stage_view_before_swap_buffer (ClutterStageView            *view,
180070
+                                       const cairo_rectangle_int_t *swap_region)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+
180070
+  if (priv->shadow.framebuffer)
180070
+    copy_shadowfb_to_onscreen (view, swap_region);
180070
 }
180070
 
180070
 float
180070
@@ -407,6 +738,47 @@ clutter_stage_view_get_scale (ClutterStageView *view)
180070
   return priv->scale;
180070
 }
180070
 
180070
+typedef void (*FrontBufferCallback) (CoglFramebuffer *framebuffer,
180070
+                                     gconstpointer    user_data);
180070
+
180070
+static void
180070
+clutter_stage_view_foreach_front_buffer (ClutterStageView    *view,
180070
+                                         FrontBufferCallback  callback,
180070
+                                         gconstpointer        user_data)
180070
+{
180070
+  ClutterStageViewPrivate *priv =
180070
+    clutter_stage_view_get_instance_private (view);
180070
+
180070
+  if (priv->offscreen)
180070
+    {
180070
+      callback (priv->offscreen, user_data);
180070
+    }
180070
+  else if (priv->shadow.framebuffer)
180070
+    {
180070
+      if (is_shadowfb_double_buffered (view))
180070
+        {
180070
+          int i;
180070
+
180070
+          for (i = 0; i < G_N_ELEMENTS (priv->shadow.dma_buf.handles); i++)
180070
+            {
180070
+              CoglDmaBufHandle *handle = priv->shadow.dma_buf.handles[i];
180070
+              CoglFramebuffer *framebuffer =
180070
+                cogl_dma_buf_handle_get_framebuffer (handle);
180070
+
180070
+              callback (framebuffer, user_data);
180070
+            }
180070
+        }
180070
+      else
180070
+        {
180070
+          callback (priv->shadow.framebuffer, user_data);
180070
+        }
180070
+    }
180070
+  else
180070
+    {
180070
+      callback (priv->framebuffer, user_data);
180070
+    }
180070
+}
180070
+
180070
 gboolean
180070
 clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
180070
 {
180070
@@ -425,6 +797,19 @@ clutter_stage_view_invalidate_viewport (ClutterStageView *view)
180070
   priv->dirty_viewport = TRUE;
180070
 }
180070
 
180070
+static void
180070
+set_framebuffer_viewport (CoglFramebuffer *framebuffer,
180070
+                          gconstpointer    user_data)
180070
+{
180070
+  const ClutterRect *rect = user_data;
180070
+
180070
+  cogl_framebuffer_set_viewport (framebuffer,
180070
+                                 rect->origin.x,
180070
+                                 rect->origin.y,
180070
+                                 rect->size.width,
180070
+                                 rect->size.height);
180070
+}
180070
+
180070
 void
180070
 clutter_stage_view_set_viewport (ClutterStageView *view,
180070
                                  float             x,
180070
@@ -434,11 +819,17 @@ clutter_stage_view_set_viewport (ClutterStageView *view,
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
-  CoglFramebuffer *framebuffer;
180070
+  ClutterRect rect;
180070
 
180070
   priv->dirty_viewport = FALSE;
180070
-  framebuffer = clutter_stage_view_get_framebuffer (view);
180070
-  cogl_framebuffer_set_viewport (framebuffer, x, y, width, height);
180070
+
180070
+  rect = (ClutterRect) {
180070
+    .origin = { .x = x, .y = y },
180070
+    .size = { .width = width, .height = height },
180070
+  };
180070
+  clutter_stage_view_foreach_front_buffer (view,
180070
+                                           set_framebuffer_viewport,
180070
+                                           &rect);
180070
 }
180070
 
180070
 gboolean
180070
@@ -450,6 +841,13 @@ clutter_stage_view_is_dirty_projection (ClutterStageView *view)
180070
   return priv->dirty_projection;
180070
 }
180070
 
180070
+static void
180070
+set_framebuffer_projection_matrix (CoglFramebuffer *framebuffer,
180070
+                                   gconstpointer    user_data)
180070
+{
180070
+  cogl_framebuffer_set_projection_matrix (framebuffer, user_data);
180070
+}
180070
+
180070
 void
180070
 clutter_stage_view_invalidate_projection (ClutterStageView *view)
180070
 {
180070
@@ -465,11 +863,11 @@ clutter_stage_view_set_projection (ClutterStageView *view,
180070
 {
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
-  CoglFramebuffer *framebuffer;
180070
 
180070
   priv->dirty_projection = FALSE;
180070
-  framebuffer = clutter_stage_view_get_framebuffer (view);
180070
-  cogl_framebuffer_set_projection_matrix (framebuffer, matrix);
180070
+  clutter_stage_view_foreach_front_buffer (view,
180070
+                                           set_framebuffer_projection_matrix,
180070
+                                           matrix);
180070
 }
180070
 
180070
 void
180070
@@ -593,10 +991,20 @@ clutter_stage_view_dispose (GObject *object)
180070
   ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
180070
   ClutterStageViewPrivate *priv =
180070
     clutter_stage_view_get_instance_private (view);
180070
+  int i;
180070
 
180070
   g_clear_pointer (&priv->name, g_free);
180070
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
180070
+
180070
   g_clear_pointer (&priv->shadow.framebuffer, cogl_object_unref);
180070
+  for (i = 0; i < G_N_ELEMENTS (priv->shadow.dma_buf.handles); i++)
180070
+    {
180070
+      g_clear_pointer (&priv->shadow.dma_buf.handles[i],
180070
+                       cogl_dma_buf_handle_free);
180070
+    }
180070
+  g_clear_pointer (&priv->shadow.dma_buf.damage_history,
180070
+                   clutter_damage_history_free);
180070
+
180070
   g_clear_pointer (&priv->offscreen, cogl_object_unref);
180070
   g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
180070
 
180070
diff --git a/clutter/clutter/clutter-util.c b/clutter/clutter/clutter-util.c
180070
index ed52b69774..834adae39a 100644
180070
--- a/clutter/clutter/clutter-util.c
180070
+++ b/clutter/clutter/clutter-util.c
180070
@@ -210,6 +210,28 @@ _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1,
180070
     }
180070
 }
180070
 
180070
+gboolean
180070
+_clutter_util_rectangle_contains (const cairo_rectangle_int_t *src1,
180070
+                                  const cairo_rectangle_int_t *src2)
180070
+{
180070
+  int x1, y1, x2, y2;
180070
+
180070
+  x1 = MAX (src1->x, src2->x);
180070
+  y1 = MAX (src1->y, src2->y);
180070
+
180070
+  x2 = MIN (src1->x + (int) src1->width,  src2->x + (int) src2->width);
180070
+  y2 = MIN (src1->y + (int) src1->height, src2->y + (int) src2->height);
180070
+
180070
+  if (x1 >= x2 || y1 >= y2)
180070
+    {
180070
+      return FALSE;
180070
+    }
180070
+  else
180070
+    {
180070
+      return TRUE;
180070
+    }
180070
+}
180070
+
180070
 float
180070
 _clutter_util_matrix_determinant (const ClutterMatrix *matrix)
180070
 {
180070
-- 
180070
2.28.0
180070
180070
180070
From 9968d4aeefc2c47a63e12f977dad031672a63abe Mon Sep 17 00:00:00 2001
180070
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
180070
Date: Sat, 7 Mar 2020 20:29:09 +0100
180070
Subject: [PATCH 20/20] clutter/stage-cogl: Use view fb instead of onscreen fb
180070
 for debug-drawing
180070
180070
We need to use the framebuffer of the view instead of the onscreen
180070
framebuffer when painting the damage region, otherwise the redraw clips
180070
on rotated monitors won't be shown correctly.
180070
180070
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
180070
(cherry picked from commit 8e1bd64e05c3098fcce4f916f9e4468decb8f30c)
180070
---
180070
 clutter/clutter/cogl/clutter-stage-cogl.c | 2 +-
180070
 1 file changed, 1 insertion(+), 1 deletion(-)
180070
180070
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
index 11273ec894..3f1f609c4e 100644
180070
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
180070
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
180070
@@ -353,7 +353,7 @@ paint_damage_region (ClutterStageWindow    *stage_window,
180070
                      ClutterStageView      *view,
180070
                      cairo_rectangle_int_t *swap_region)
180070
 {
180070
-  CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
180070
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
180070
   CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
180070
   static CoglPipeline *overlay_blue = NULL;
180070
   ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
180070
-- 
180070
2.28.0
180070