[metacity] compositor-xrender: move window painting to MetaSurfaceXRender



commit 097357c62c94c04ccb1da439eb4d3a542e693aef
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Fri Oct 18 15:41:58 2019 +0300

    compositor-xrender: move window painting to MetaSurfaceXRender

 src/compositor/meta-compositor-xrender.c | 118 +++--------------
 src/compositor/meta-surface-xrender.c    | 218 +++++++++++++++++++++++++++++--
 src/compositor/meta-surface-xrender.h    |   9 +-
 3 files changed, 233 insertions(+), 112 deletions(-)
---
diff --git a/src/compositor/meta-compositor-xrender.c b/src/compositor/meta-compositor-xrender.c
index ea081de2..72b73d80 100644
--- a/src/compositor/meta-compositor-xrender.c
+++ b/src/compositor/meta-compositor-xrender.c
@@ -109,8 +109,6 @@ typedef struct _MetaCompWindow
   int shadow_width;
   int shadow_height;
 
-  XserverRegion border_clip;
-
   /* This is a copy of the original unshaded window so that we can still see
    * what the window looked like when it is needed for the _get_window_surface
    * function.
@@ -1175,19 +1173,23 @@ paint_dock_shadows (MetaCompositorXRender *xrender,
 
   for (l = surfaces; l != NULL; l = l->next)
     {
-      MetaSurface *surface;
+      MetaSurfaceXRender *surface;
       MetaCompWindow *cw;
       XserverRegion shadow_clip;
 
-      surface = META_SURFACE (l->data);
+      surface = META_SURFACE_XRENDER (l->data);
       cw = g_object_get_data (G_OBJECT (surface), "cw");
 
       if (cw->window->type == META_WINDOW_DOCK &&
           cw->needs_shadow && cw->shadow)
         {
+          XserverRegion border_clip;
+
           shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0);
+          border_clip = meta_surface_xrender_get_border_clip (surface);
+
           XFixesIntersectRegion (xdisplay, shadow_clip,
-                                 cw->border_clip, region);
+                                 border_clip, region);
 
           XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0, shadow_clip);
 
@@ -1241,13 +1243,12 @@ paint_windows (MetaCompositorXRender *xrender,
   last = NULL;
   for (index = surfaces; index; index = index->next)
     {
-      MetaSurface *surface;
-      Picture picture;
+      MetaSurfaceXRender *surface;
 
       /* Store the last window we dealt with */
       last = index;
 
-      surface = META_SURFACE (index->data);
+      surface = META_SURFACE_XRENDER (index->data);
       cw = g_object_get_data (G_OBJECT (surface), "cw");
 
       if (!cw->damaged)
@@ -1256,11 +1257,9 @@ paint_windows (MetaCompositorXRender *xrender,
           continue;
         }
 
-      if (!meta_surface_is_visible (surface))
+      if (!meta_surface_is_visible (META_SURFACE (surface)))
         continue;
 
-      picture = meta_surface_xrender_get_picture (META_SURFACE_XRENDER (surface));
-
       if (cw->window_region == None)
         cw->window_region = get_window_region (display, cw);
 
@@ -1273,50 +1272,15 @@ paint_windows (MetaCompositorXRender *xrender,
       if (cw->extents == None)
         cw->extents = win_extents (xrender, cw);
 
+      meta_surface_xrender_paint (surface, paint_region, root_buffer, TRUE);
+
       if (cw->mode == WINDOW_SOLID)
         {
-          int x, y, wid, hei;
-          MetaFrame *frame;
-          MetaFrameBorders borders;
-
-          x = cw->rect.x;
-          y = cw->rect.y;
-          wid = cw->rect.width;
-          hei = cw->rect.height;
-
-          frame = meta_window_get_frame (cw->window);
-          meta_frame_calc_borders (frame, &borders);
-
-          XFixesSetPictureClipRegion (xdisplay, root_buffer,
-                                      0, 0, paint_region);
-          XRenderComposite (xdisplay, PictOpSrc, picture, None, root_buffer,
-                            borders.total.left, borders.total.top, 0, 0,
-                            x + borders.total.left, y + borders.total.top,
-                            wid - borders.total.left - borders.total.right,
-                            hei - borders.total.top - borders.total.bottom);
-
           if (cw->window->type == META_WINDOW_DESKTOP)
             {
               desktop_region = XFixesCreateRegion (xdisplay, 0, 0);
               XFixesCopyRegion (xdisplay, desktop_region, paint_region);
             }
-
-          if (frame == NULL)
-            {
-              XFixesSubtractRegion (xdisplay, paint_region,
-                                    paint_region, cw->window_region);
-            }
-          else
-            {
-              XFixesSubtractRegion (xdisplay, paint_region,
-                                    paint_region, cw->client_region);
-            }
-        }
-
-      if (!cw->border_clip)
-        {
-          cw->border_clip = XFixesCreateRegion (xdisplay, 0, 0);
-          XFixesCopyRegion (xdisplay, cw->border_clip, paint_region);
         }
     }
 
@@ -1334,31 +1298,27 @@ paint_windows (MetaCompositorXRender *xrender,
    */
   for (index = last; index; index = index->prev)
     {
-      MetaSurface *surface;
-      Picture picture;
-      Picture mask;
+      MetaSurfaceXRender *surface;
 
-      surface = META_SURFACE (index->data);
+      surface = META_SURFACE_XRENDER (index->data);
       cw = g_object_get_data (G_OBJECT (surface), "cw");
 
-      picture = meta_surface_xrender_get_picture (META_SURFACE_XRENDER (surface));
-      mask = meta_surface_xrender_get_mask_picture (META_SURFACE_XRENDER (surface));
-
-      if (picture)
+      if (meta_surface_xrender_get_picture (surface) != None)
         {
-          int x, y, wid, hei;
+          int x, y;
 
           x = cw->rect.x;
           y = cw->rect.y;
-          wid = cw->rect.width;
-          hei = cw->rect.height;
 
           if (cw->shadow && cw->window->type != META_WINDOW_DOCK)
             {
               XserverRegion shadow_clip;
+              XserverRegion border_clip;
 
               shadow_clip = XFixesCreateRegion (xdisplay, NULL, 0);
-              XFixesSubtractRegion (xdisplay, shadow_clip, cw->border_clip,
+              border_clip = meta_surface_xrender_get_border_clip (surface);
+
+              XFixesSubtractRegion (xdisplay, shadow_clip, border_clip,
                                     cw->visible_region);
               XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0,
                                           shadow_clip);
@@ -1372,29 +1332,7 @@ paint_windows (MetaCompositorXRender *xrender,
                 XFixesDestroyRegion (xdisplay, shadow_clip);
             }
 
-          XFixesIntersectRegion (xdisplay, cw->border_clip, cw->border_clip,
-                                 cw->window_region);
-          XFixesSetPictureClipRegion (xdisplay, root_buffer, 0, 0,
-                                      cw->border_clip);
-
-          if (cw->mode == WINDOW_SOLID && mask != None)
-            {
-              XRenderComposite (xdisplay, PictOpOver, picture,
-                                mask, root_buffer, 0, 0, 0, 0,
-                                x, y, wid, hei);
-            }
-          else if (cw->mode == WINDOW_ARGB)
-            {
-              XRenderComposite (xdisplay, PictOpOver, picture,
-                                mask, root_buffer, 0, 0, 0, 0,
-                                x, y, wid, hei);
-            }
-        }
-
-      if (cw->border_clip)
-        {
-          XFixesDestroyRegion (xdisplay, cw->border_clip);
-          cw->border_clip = None;
+          meta_surface_xrender_paint (surface, paint_region, root_buffer, FALSE);
         }
     }
 
@@ -1504,12 +1442,6 @@ free_win (MetaCompWindow *cw,
       cw->client_region = None;
     }
 
-  if (cw->border_clip)
-    {
-      XFixesDestroyRegion (xdisplay, cw->border_clip);
-      cw->border_clip = None;
-    }
-
   if (cw->extents)
     {
       XFixesDestroyRegion (xdisplay, cw->extents);
@@ -1650,12 +1582,6 @@ notify_decorated_cb (MetaWindow            *window,
       cw->shadow = None;
     }
 
-  if (cw->border_clip != None)
-    {
-      XFixesDestroyRegion (xrender->xdisplay, cw->border_clip);
-      cw->border_clip = None;
-    }
-
   determine_mode (xrender, cw);
   cw->needs_shadow = window_has_shadow (xrender, cw);
 
@@ -2022,8 +1948,6 @@ meta_compositor_xrender_add_window (MetaCompositor *compositor,
   else
     cw->shadow_type = META_SHADOW_MEDIUM;
 
-  cw->border_clip = None;
-
   cw->shaded_surface = NULL;
 
   determine_mode (xrender, cw);
diff --git a/src/compositor/meta-surface-xrender.c b/src/compositor/meta-surface-xrender.c
index 35c9239a..d119281a 100644
--- a/src/compositor/meta-surface-xrender.c
+++ b/src/compositor/meta-surface-xrender.c
@@ -31,19 +31,182 @@
 
 struct _MetaSurfaceXRender
 {
-  MetaSurface  parent;
+  MetaSurface    parent;
 
-  MetaDisplay *display;
-  Display     *xdisplay;
+  MetaDisplay   *display;
+  Display       *xdisplay;
 
-  Picture      picture;
+  Picture        picture;
 
-  Pixmap       mask_pixmap;
-  Picture      mask_picture;
+  Pixmap         mask_pixmap;
+  Picture        mask_picture;
+
+  XserverRegion  border_clip;
 };
 
 G_DEFINE_TYPE (MetaSurfaceXRender, meta_surface_xrender, META_TYPE_SURFACE)
 
+static gboolean
+is_argb (MetaSurfaceXRender *self)
+{
+  MetaWindow *window;
+  Visual *xvisual;
+  XRenderPictFormat *format;
+
+  window = meta_surface_get_window (META_SURFACE (self));
+  xvisual = meta_window_get_toplevel_xvisual (window);
+
+  format = XRenderFindVisualFormat (self->xdisplay, xvisual);
+
+  if (format && format->type == PictTypeDirect && format->direct.alphaMask)
+    return TRUE;
+
+  if (window->opacity != OPAQUE)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+is_region_empty (Display       *xdisplay,
+                 XserverRegion  region)
+{
+  int n_rects;
+  XRectangle bounds;
+  XRectangle *rects;
+
+  rects = XFixesFetchRegionAndBounds (xdisplay, region, &n_rects, &bounds);
+
+  if (rects != NULL)
+    XFree (rects);
+
+  if (n_rects == 0 || bounds.width == 0 || bounds.height == 0)
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+paint_opaque_parts (MetaSurfaceXRender *self,
+                    XserverRegion       paint_region,
+                    Picture             paint_buffer)
+{
+  MetaSurface *surface;
+  MetaWindow *window;
+  XserverRegion shape_region;
+  XserverRegion opaque_region;
+  int x;
+  int y;
+  int width;
+  int height;
+  XserverRegion clip_region;
+
+  surface = META_SURFACE (self);
+
+  window = meta_surface_get_window (surface);
+  shape_region = meta_surface_get_shape_region (surface);
+  opaque_region = meta_surface_get_opaque_region (surface);
+
+  if ((is_argb (self) && opaque_region == None) ||
+      window->opacity != OPAQUE)
+    return;
+
+  x = meta_surface_get_x (surface);
+  y = meta_surface_get_y (surface);
+  width = meta_surface_get_width (surface);
+  height = meta_surface_get_height (surface);
+
+  clip_region = XFixesCreateRegion (self->xdisplay, NULL, 0);
+  XFixesCopyRegion (self->xdisplay, clip_region, shape_region);
+
+  if (window->frame != NULL)
+    {
+      MetaFrameBorders borders;
+      XRectangle client_rect;
+      XserverRegion client_region;
+
+      meta_frame_calc_borders (window->frame, &borders);
+
+      client_rect = (XRectangle) {
+        .x = borders.total.left,
+        .y = borders.total.top,
+        .width = width - borders.total.left - borders.total.right,
+        .height = height - borders.total.top - borders.total.bottom
+      };
+
+      client_region = XFixesCreateRegion (self->xdisplay, &client_rect, 1);
+
+      XFixesIntersectRegion (self->xdisplay, clip_region, clip_region, client_region);
+      XFixesDestroyRegion (self->xdisplay, client_region);
+    }
+
+  if (opaque_region != None)
+    XFixesIntersectRegion (self->xdisplay, clip_region, clip_region, opaque_region);
+
+  XFixesTranslateRegion (self->xdisplay, clip_region, x, y);
+  XFixesIntersectRegion (self->xdisplay, clip_region, clip_region, paint_region);
+
+  if (is_region_empty (self->xdisplay, clip_region))
+    {
+      XFixesDestroyRegion (self->xdisplay, clip_region);
+      return;
+    }
+
+  XFixesSetPictureClipRegion (self->xdisplay, paint_buffer, 0, 0, clip_region);
+
+  XRenderComposite (self->xdisplay, PictOpSrc,
+                    self->picture, None, paint_buffer,
+                    0, 0, 0, 0,
+                    x, y, width, height);
+
+  XFixesSubtractRegion (self->xdisplay, paint_region, paint_region, clip_region);
+  XFixesDestroyRegion (self->xdisplay, clip_region);
+}
+
+static void
+paint_argb_parts (MetaSurfaceXRender *self,
+                  Picture             paint_buffer)
+{
+  MetaSurface *surface;
+  int x;
+  int y;
+  int width;
+  int height;
+  XserverRegion border_clip;
+  XserverRegion shape_region;
+  XserverRegion clip_region;
+
+  if (is_region_empty (self->xdisplay, self->border_clip))
+    return;
+
+  surface = META_SURFACE (self);
+
+  x = meta_surface_get_x (surface);
+  y = meta_surface_get_y (surface);
+  width = meta_surface_get_width (surface);
+  height = meta_surface_get_height (surface);
+
+  border_clip = self->border_clip;
+  shape_region = meta_surface_get_shape_region (surface);
+
+  clip_region = XFixesCreateRegion (self->xdisplay, NULL, 0);
+  XFixesCopyRegion (self->xdisplay, clip_region, shape_region);
+
+  XFixesTranslateRegion (self->xdisplay, clip_region, x, y);
+  XFixesIntersectRegion (self->xdisplay, border_clip, border_clip, clip_region);
+  XFixesDestroyRegion (self->xdisplay, clip_region);
+
+  if (is_region_empty (self->xdisplay, border_clip))
+    return;
+
+  XFixesSetPictureClipRegion (self->xdisplay, paint_buffer, 0, 0, border_clip);
+
+  XRenderComposite (self->xdisplay, PictOpOver,
+                    self->picture, self->mask_picture, paint_buffer,
+                    0, 0, 0, 0,
+                    x, y, width, height);
+}
+
 static void
 clip_to_shape_region (MetaSurfaceXRender *self,
                       cairo_t            *cr)
@@ -317,6 +480,12 @@ meta_surface_xrender_finalize (GObject *object)
   free_mask_pixmap (self);
   free_mask_picture (self);
 
+  if (self->border_clip != None)
+    {
+      XFixesDestroyRegion (self->xdisplay, self->border_clip);
+      self->border_clip = None;
+    }
+
   G_OBJECT_CLASS (meta_surface_xrender_parent_class)->finalize (object);
 }
 
@@ -523,14 +692,39 @@ meta_surface_xrender_get_picture (MetaSurfaceXRender *self)
   return self->picture;
 }
 
-Pixmap
-meta_surface_xrender_get_mask_pixmap (MetaSurfaceXRender *self)
+XserverRegion
+meta_surface_xrender_get_border_clip (MetaSurfaceXRender *self)
 {
-  return self->mask_pixmap;
+  return self->border_clip;
 }
 
-Picture
-meta_surface_xrender_get_mask_picture (MetaSurfaceXRender *self)
+void
+meta_surface_xrender_paint (MetaSurfaceXRender *self,
+                            XserverRegion       paint_region,
+                            Picture             paint_buffer,
+                            gboolean            opaque)
 {
-  return self->mask_picture;
+  if (!meta_surface_is_visible (META_SURFACE (self)) ||
+      self->picture == None)
+    return;
+
+  if (opaque)
+    {
+      paint_opaque_parts (self, paint_region, paint_buffer);
+
+      g_assert (self->border_clip == None);
+
+      self->border_clip = XFixesCreateRegion (self->xdisplay, NULL, 0);
+      XFixesCopyRegion (self->xdisplay, self->border_clip, paint_region);
+    }
+  else
+    {
+      paint_argb_parts (self, paint_buffer);
+
+      if (self->border_clip != None)
+        {
+          XFixesDestroyRegion (self->xdisplay, self->border_clip);
+          self->border_clip = None;
+        }
+    }
 }
diff --git a/src/compositor/meta-surface-xrender.h b/src/compositor/meta-surface-xrender.h
index a402749e..9729be1c 100644
--- a/src/compositor/meta-surface-xrender.h
+++ b/src/compositor/meta-surface-xrender.h
@@ -27,11 +27,14 @@ G_BEGIN_DECLS
 G_DECLARE_FINAL_TYPE (MetaSurfaceXRender, meta_surface_xrender,
                       META, SURFACE_XRENDER, MetaSurface)
 
-Picture meta_surface_xrender_get_picture      (MetaSurfaceXRender *self);
+Picture       meta_surface_xrender_get_picture     (MetaSurfaceXRender *self);
 
-Pixmap  meta_surface_xrender_get_mask_pixmap  (MetaSurfaceXRender *self);
+XserverRegion meta_surface_xrender_get_border_clip (MetaSurfaceXRender *self);
 
-Picture meta_surface_xrender_get_mask_picture (MetaSurfaceXRender *self);
+void          meta_surface_xrender_paint           (MetaSurfaceXRender *self,
+                                                    XserverRegion       paint_region,
+                                                    Picture             paint_buffer,
+                                                    gboolean            opaque);
 
 G_END_DECLS
 


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