kathenas / rpms / mutter

Forked from rpms/mutter 5 years ago
Clone

Blame SOURCES/shadow-buffer-tile-damage.patch

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