[gtk/wip/chergert/macos-iosurface] add some comments on how this works



commit 2cb44edb7ad57e1302e10965002fc227547974f7
Author: Christian Hergert <christian hergert me>
Date:   Wed Feb 9 14:52:20 2022 -0800

    add some comments on how this works

 gdk/macos/gdkmacoscairocontext.c | 43 ++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 15 deletions(-)
---
diff --git a/gdk/macos/gdkmacoscairocontext.c b/gdk/macos/gdkmacoscairocontext.c
index aed6614155..1f6c611bea 100644
--- a/gdk/macos/gdkmacoscairocontext.c
+++ b/gdk/macos/gdkmacoscairocontext.c
@@ -88,11 +88,25 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
   stride = _gdk_macos_buffer_get_stride (back);
   base_address = IOSurfaceGetBaseAddress (io_surface);
 
+  /* Instead of forcing cairo to do everything through a CGContext,
+   * we just use an image surface backed by an IOSurfaceRef mapped
+   * into user-space. We can then use pixman which is quite fast as
+   * far as software rendering goes.
+   *
+   * Additionally, cairo_quartz_surface_t can't handle a number of
+   * tricks that the GSK cairo renderer does with border nodes and
+   * shadows, so an image surface is necessary for that.
+   *
+   * Since our IOSurfaceRef is width*scale-by-height*scale, we undo
+   * the scaling using cairo_surface_set_device_scale() so the renderer
+   * just thinks it's on a 2x scale surface for HiDPI.
+   */
   image_surface = cairo_image_surface_create_for_data (base_address,
                                                        CAIRO_FORMAT_ARGB32,
                                                        width, height, stride);
   cairo_surface_set_device_scale (image_surface, scale, scale);
 
+  /* Lock the buffer so we can modify it safely */
   _gdk_macos_buffer_lock (back);
   cairo_surface_set_user_data (image_surface,
                                &buffer_key,
@@ -102,40 +116,39 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
   if (!(cr = cairo_create (image_surface)))
     goto failure;
 
+  /* Clip to the current damage region */
   if (damage != NULL)
     {
       gdk_cairo_region (cr, damage);
       cairo_clip (cr);
     }
 
+  /* If we have some exposed transparent area in the damage region,
+   * we need to clear the existing content first to leave an transparent
+   * area for cairo. We use (surface_bounds or damage)-(opaque) to get
+   * the smallest set of rectangles we need to clear as it's expensive.
+   */
   if (!opaque)
     {
       cairo_region_t *transparent;
-      cairo_rectangle_int_t r;
+      cairo_rectangle_int_t r = { 0, 0, width/scale, height/scale };
 
       cairo_save (cr);
 
       if (damage != NULL)
-        {
-          cairo_region_get_extents (damage, &r);
-        }
-      else
-        {
-          r.x = r.y = 0;
-          r.width = width / scale;
-          r.height = height / scale;
-        }
-
+        cairo_region_get_extents (damage, &r);
       transparent = cairo_region_create_rectangle (&r);
       if (surface->opaque_region)
         cairo_region_subtract (transparent, surface->opaque_region);
 
-      gdk_cairo_region (cr, transparent);
-      cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
-      cairo_fill (cr);
+      if (!cairo_region_is_empty (transparent))
+        {
+          gdk_cairo_region (cr, transparent);
+          cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+          cairo_fill (cr);
+        }
 
       cairo_region_destroy (transparent);
-
       cairo_restore (cr);
     }
 


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