[cairo-commit] 4 commits - src/win32

Bryce Harrington bryce at kemper.freedesktop.org
Fri Jun 1 01:31:51 UTC 2018


 src/win32/cairo-win32-device.c           |   39 +++++++++++++++++++------------
 src/win32/cairo-win32-display-surface.c  |    4 +--
 src/win32/cairo-win32-gdi-compositor.c   |   22 +++++++++++++++--
 src/win32/cairo-win32-printing-surface.c |    2 -
 src/win32/cairo-win32-private.h          |    5 +++
 5 files changed, 52 insertions(+), 20 deletions(-)

New commits:
commit c6e12d33bff84f26cff22a1c0cf1fc0b929eedb0
Author: Bryce Harrington <bryce at bryceharrington.org>
Date:   Thu May 31 18:31:12 2018 -0700

    win32: Copyedit recent comments

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index e0b4a2c5e..6fce722ec 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -166,9 +166,10 @@ _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 	if (!is_display && GetDeviceCaps(dc, SHADEBLENDCAPS) != SB_NONE)
 	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
 
-	/* ARGB32 available operations is a strict subset of RGB24 available
-	 * operations. It's because the same gdi functions can be used but most
-	 * of them always reset alpha channel to 0 which is bad for ARGB32.
+	/* ARGB32 available operations are a strict subset of RGB24
+	 * available operations. This is because the same GDI functions
+	 * can be used but most of them always reset alpha channel to 0
+	 * which is bad for ARGB32.
 	 */
 	if (format == CAIRO_FORMAT_RGB24)
 	{
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 4a09a70a9..1d1d7f873 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -239,7 +239,8 @@ copy_boxes (cairo_win32_display_surface_t *dst,
     if (src->format != dst->win32.format &&
 	!(src->format == CAIRO_FORMAT_ARGB32 && dst->win32.format == CAIRO_FORMAT_RGB24))
     {
-	/* forbid copy different surfaces unless it is from argb32 to rgb (alpha-drop) */
+	/* forbid copy different surfaces unless it is from argb32 to
+	 * rgb (dropping alpha) */
         return CAIRO_INT_STATUS_UNSUPPORTED;
     }
     cb.dst = dst->win32.dc;
commit d4355ecee26f6ca7db26874ce4dbfec599f6040e
Author: Vasily Galkin <galkin-vv at yandex.ru>
Date:   Sat Apr 28 22:27:01 2018 +0300

    win32: Allow GDI operations for argb32 surfaces (allowed by surface flags)
    
    This finishes a patch series to speed up CAIRO_OPERATOR_SOURCE when used
    to copy data to a argb32 cairo surface corresponding to a win32 dc from
    a "backbuffer" - DibSection-based cairo surface created with
    cairo_surface_create_similar().
    
    This final patch allows the GDI compositor to be used on argb32
    surfaces.  For display surfaces, only copying is allowed with gdi (by
    BitBlt), since other operations are filtered by flags in
    implementations.
    
    But since copying pixels is the only operation used in the most common
    scenario (prepare an offscreen image and send it to the screen) - this
    is important for presenting argb32 windows with Cairo directly or with
    gtk+gdk (which nowadays always creates argb32 windows).
    
    Before this patch pixel copy worked by:
    1. mapping image to memory (by copying data from window dc to system
       memory which is very slow on windows maybe due to gpu or interprocess
       access)
    2. copying new data over that image.
    3. copying updated image from system memory back to window dc.
    
    After this patch there is only one step:
    
    2+3. Copying new data over window dc.
    
    Completely eliminating step 1 gives a very huge speedup and allows
    argb32 cairo drawing be as fast as typical dibsection-buffered gdi
    drawing.
    
    There is quick & dirty cairo-vs-gdi perf test made for this patch set:
    https://gitlab.gnome.org/galkinvv/cairo/snippets/109
    See the Cairo mailing list for April 2018 for data and discussion of
    performance improvements.
    
    End-user visible speedup does present too - it relates to the following bug
    
    https://gitlab.gnome.org/GNOME/meld/issues/133
    
    This Cairo speedup allows more simultaneous meld windows
    without eating 100% of cpu core time on spinner rendering.

diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 0873391eb..4a09a70a9 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -488,7 +488,8 @@ static cairo_bool_t check_blit (cairo_composite_rectangles_t *composite)
     if (dst->fallback)
 	return FALSE;
 
-    if (dst->win32.format != CAIRO_FORMAT_RGB24)
+    if (dst->win32.format != CAIRO_FORMAT_RGB24
+	&& dst->win32.format != CAIRO_FORMAT_ARGB32)
 	return FALSE;
 
     if (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)
commit 0cb7aad2a375f957803c5f34fb6088e330f17f85
Author: Vasily Galkin <galkin-vv at yandex.ru>
Date:   Sat Apr 28 22:27:00 2018 +0300

    win32: CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH and other argb32 flags set+check
    
    This belongs to a patch series that speeds up CAIRO_OPERATOR_SOURCE when
    used to copy data to an argb32 cairo surface corresponding to a win32 dc
    from a "backbuffer" - DibSection-based cairo surface created with
    cairo_surface_create_similar().
    
    This patch introduces checks to ensure that no solid brush GDI operations
    are attempted when using argb32 surfaces.  Doing this allows enabling
    usage of the GDI compositor when these surfaces are in use.
    
    To make these checks work, _cairo_win32_flags_for_dc disables
    STRETCHBLT, STRETCHDIB and RGB_BRUSH in the argb32 flag.
    
    _cairo_win32_flags_for_dc() is also refactored to make the distinction
    between rgb24 and argb32 more readable.  All logic & flags for rgb24
    surfaces are retained, except for the addition of
    CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH.
    
    The logic of forbidding AlphaBlend on display surfaces is also
    kept as is without investigation.

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index d2c1ac585..e0b4a2c5e 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -156,17 +156,31 @@ unsigned
 _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 {
     uint32_t flags = 0;
-    int cap;
+    cairo_bool_t is_display = GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY;
+
+    if (format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_ARGB32)
+    {
+	int cap = GetDeviceCaps(dc, RASTERCAPS);
+	if (cap & RC_BITBLT)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
+	if (!is_display && GetDeviceCaps(dc, SHADEBLENDCAPS) != SB_NONE)
+	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
 
-    cap = GetDeviceCaps(dc, RASTERCAPS);
-    if (cap & RC_BITBLT)
-	flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
-    if (cap & RC_STRETCHBLT)
-	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
-    if (cap & RC_STRETCHDIB)
-	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
+	/* ARGB32 available operations is a strict subset of RGB24 available
+	 * operations. It's because the same gdi functions can be used but most
+	 * of them always reset alpha channel to 0 which is bad for ARGB32.
+	 */
+	if (format == CAIRO_FORMAT_RGB24)
+	{
+	    flags |= CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH;
+	    if (cap & RC_STRETCHBLT)
+		flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
+	    if (cap & RC_STRETCHDIB)
+		flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
+	}
+    }
 
-    if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
+    if (is_display) {
 	flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
 
 	/* These will always be possible, but the actual GetDeviceCaps
@@ -181,10 +195,6 @@ _cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
 	flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
 #endif
-    } else {
-	cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
-	if (cap != SB_NONE)
-	    flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
     }
 
     return flags;
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 2858affcb..0873391eb 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -179,6 +179,9 @@ fill_boxes (cairo_win32_display_surface_t	*dst,
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
+    if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     fb.dc = dst->win32.dc;
     fb.brush = CreateSolidBrush (color_to_rgb(color));
     if (!fb.brush)
@@ -213,6 +216,7 @@ copy_boxes (cairo_win32_display_surface_t *dst,
     struct copy_box cb;
     cairo_surface_t *surface;
     cairo_status_t status;
+    cairo_win32_surface_t *src;
 
     TRACE ((stderr, "%s\n", __FUNCTION__));
 
@@ -230,8 +234,16 @@ copy_boxes (cairo_win32_display_surface_t *dst,
 						&cb.tx, &cb.ty))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    src = to_win32_surface(surface);
+
+    if (src->format != dst->win32.format &&
+	!(src->format == CAIRO_FORMAT_ARGB32 && dst->win32.format == CAIRO_FORMAT_RGB24))
+    {
+	/* forbid copy different surfaces unless it is from argb32 to rgb (alpha-drop) */
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
     cb.dst = dst->win32.dc;
-    cb.src = to_win32_surface(surface)->dc;
+    cb.src = src->dc;
 
     /* First check that the data is entirely within the image */
     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
@@ -614,6 +626,10 @@ _cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t	*compositor,
 	cairo_win32_display_surface_t *dst = to_win32_display_surface (composite->surface);
 
 	TRACE ((stderr, "%s\n", __FUNCTION__));
+
+	if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+
 	status = _cairo_win32_display_surface_set_clip(dst, composite->clip);
 	if (status)
 	    return status;
commit 884275c3ab6e76ec2723cc889060b2791868190d
Author: Vasily Galkin <galkin-vv at yandex.ru>
Date:   Sat Apr 28 22:26:59 2018 +0300

    win32: Introduce new flag to mark surfaces that support solid brush drawing
    
    This is part of a patch series to speed up CAIRO_OPERATOR_SOURCE when
    used to copy data to an argb32 cairo surface corresponding to a win32 dc
    from a "backbuffer" - DibSection-based cairo surface created with
    cairo_surface_create_similar().
    
    This initial patch presents only private header changes without changing
    any implementation logic.
    
    The big problem with argb32 surfaces and GDI is that GDI is unable to
    correctly set the alpha channel when using operations other than BitBlt
    and AlphaBlend.
    
    To solve this, a CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH flag is introduced in
    this commit to be mark surfaces that correctly handle such brushes
    - essentially all surface types except argb32.
    The _cairo_win32_flags_for_dc() call receives a new argument that is
    used to calculate the flag.

diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index f0df15e1d..d2c1ac585 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -153,7 +153,7 @@ _cairo_win32_device_get (void)
 }
 
 unsigned
-_cairo_win32_flags_for_dc (HDC dc)
+_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format)
 {
     uint32_t flags = 0;
     int cap;
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 2b40e1acf..304d34aea 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -258,7 +258,7 @@ _create_dc_and_bitmap (cairo_win32_display_surface_t *surface,
 	}
     }
 
-    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
+    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format);
 
     return CAIRO_STATUS_SUCCESS;
 
@@ -1007,7 +1007,7 @@ cairo_win32_surface_create_with_format (HDC hdc, cairo_format_t format)
     surface->is_dib = FALSE;
     surface->saved_dc_bitmap = NULL;
 
-    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
+    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format);
 
     device = _cairo_win32_device_get ();
 
diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index 7f88cd1e5..da7357caa 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -2159,7 +2159,7 @@ cairo_win32_printing_surface_create (HDC hdc)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
 
-    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc);
+    surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, CAIRO_FORMAT_RGB24);
     surface->win32.flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
 
     _cairo_win32_printing_surface_init_ps_mode (surface);
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index e3e13d5b1..85f88a9e8 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -81,6 +81,9 @@ enum {
 
     /* Whether we can use the CHECKPNGFORMAT escape function */
     CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8),
+
+    /* Whether we can use gdi drawing with solid rgb brush with this surface */
+    CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH = (1<<9),
 };
 
 typedef struct _cairo_win32_surface {
@@ -204,7 +207,7 @@ _cairo_win32_surface_get_extents (void			  *abstract_surface,
 				  cairo_rectangle_int_t   *rectangle);
 
 uint32_t
-_cairo_win32_flags_for_dc (HDC dc);
+_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format);
 
 cairo_int_status_t
 _cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst,


More information about the cairo-commit mailing list