[gtk/wip/chergert/macos-iosurface] add some comments on how this works
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/macos-iosurface] add some comments on how this works
- Date: Wed, 9 Feb 2022 22:57:19 +0000 (UTC)
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]