diff --git a/mingw-w64-cairo/0001-win32-introduce-new-flag-to-mark-surfaces-supporting.patch b/mingw-w64-cairo/0001-win32-introduce-new-flag-to-mark-surfaces-supporting.patch new file mode 100644 index 0000000000..44f42293df --- /dev/null +++ b/mingw-w64-cairo/0001-win32-introduce-new-flag-to-mark-surfaces-supporting.patch @@ -0,0 +1,104 @@ +From ba41e2203ea32e459cd26dfb20d748cead547d82 Mon Sep 17 00:00:00 2001 +From: Vasily Galkin +Date: Sat, 28 Apr 2018 21:10:54 +0300 +Subject: [PATCH 1/3] win32: introduce new flag to mark surfaces supporting + solid brush drawing + +This is beginning of a patch series that speedups the 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 initial patch presents only private header changes +without changing any implementation logic. + +The big problem with argb32 surfaces and gdi is the gdi's inability to +correctly set alpha channel on all operations except BitBlt and AlphaBlend + +So CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH flag introduced in this commit +will be used as a mark that surfaces that correctly such handle brushes - +essentially all surface types except argb32. +_cairo_win32_flags_for_dc receives new argument +that would be used in flag calculation. +--- + src/win32/cairo-win32-device.c | 2 +- + src/win32/cairo-win32-display-surface.c | 4 ++-- + src/win32/cairo-win32-printing-surface.c | 2 +- + src/win32/cairo-win32-private.h | 5 ++++- + 4 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c +index c60c4948d..309f16c56 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 92d1f6ce4..0d737f542 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; + +@@ -973,7 +973,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 7f374a076..84960772a 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 6fdf96f87..79e1e0f77 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 CHECKJPEGFORMAT 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 { +@@ -186,7 +189,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, +-- +2.17.0 + diff --git a/mingw-w64-cairo/0002-win32-CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH-and-other-ar.patch b/mingw-w64-cairo/0002-win32-CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH-and-other-ar.patch new file mode 100644 index 0000000000..34633d9ebf --- /dev/null +++ b/mingw-w64-cairo/0002-win32-CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH-and-other-ar.patch @@ -0,0 +1,140 @@ +From 4534b8cbbd032451da6f56f012cdf7b034b86159 Mon Sep 17 00:00:00 2001 +From: Vasily Galkin +Date: Sat, 28 Apr 2018 21:36:21 +0300 +Subject: [PATCH 2/3] win32: CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH and other argb32 + flags set+check + +This belongs to a patch series that speedups the 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 patch introduces checks that ensure that no solid brush gdi operations +are done with argb32 surfaces. +This is needed for enabling gdi compositor usage for win32 argb32 surfaces. + +To make this checks working the calculatinig function correctly fills +argb32 flags disabling STRETCHBLT, STRETCHDIB and RGB_BRUSH. + +_cairo_win32_flags_for_dc refactored to make rgb24 vs argb32 distinction +more readable. All logic&flags for rgb24 surfaces are kept, +except addition of CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH. + +The logic of forbidding AlphaBlend on display surfaces +kept as is without investigation. +--- + src/win32/cairo-win32-device.c | 36 ++++++++++++++++---------- + src/win32/cairo-win32-gdi-compositor.c | 18 ++++++++++++- + 2 files changed, 40 insertions(+), 14 deletions(-) + +diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c +index 309f16c56..a2c95087c 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; +-- +2.17.0 + diff --git a/mingw-w64-cairo/0003-win32-Allow-gdi-operations-for-argb32-surfaces-allow.patch b/mingw-w64-cairo/0003-win32-Allow-gdi-operations-for-argb32-surfaces-allow.patch new file mode 100644 index 0000000000..8e4468e17a --- /dev/null +++ b/mingw-w64-cairo/0003-win32-Allow-gdi-operations-for-argb32-surfaces-allow.patch @@ -0,0 +1,88 @@ +From dfc2a62106416cf57fadf8a94108f1e454ddebd3 Mon Sep 17 00:00:00 2001 +From: Vasily Galkin +Date: Sat, 28 Apr 2018 22:06:48 +0300 +Subject: [PATCH 3/3] win32: Allow gdi operations for argb32 surfaces (allowed + by surface flags) + +This ends the patch series that speedups the 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 gdi compositor to be used on argb32 surfaces. +Actually 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 used operation in common scenario +"prepare offscreen image and put it to screen" - this is important for +presenting argb32 windows with cairo directly +or with gtk+gdk (which nowdays always create 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 fats 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 +The results show multiple times improvement: + +Before speedup + +Painting 5000 32bits-per-pixel single-color frames of size 1056x1056 for profiling +GDI entire pipeline : 4.123983 GB/s, 5408.053900 ms, 924.546998 FPS +GDI entire drawing : 4.156272 GB/s, 5366.039400 ms +cairo entire pipeline : 0.835951 GB/s, 26679.463300 ms, 187.410067 FPS +cairo entire drawing : 0.838992 GB/s, 26582.750800 ms +cairo fill inmem : 16.130683 GB/s, 1382.627100 ms +cairo to window : 1.102623 GB/s, 20226.963700 ms + +After speedup (running several times shows that there is 5-10% inaccuracy, so this results sgouldn't be used as a source for comparing raw gdi vs cairo) + +Painting 5000 32bits-per-pixel single-color frames of size 1056x1056 for profiling +GDI entire pipeline : 4.139421 GB/s, 5387.883400 ms, 928.008204 FPS +GDI entire drawing : 4.165124 GB/s, 5354.635400 ms +cairo entire pipeline : 4.029344 GB/s, 5535.075100 ms, 903.330110 FPS +cairo entire drawing : 4.063073 GB/s, 5489.126000 ms +cairo fill inmem : 22.665569 GB/s, 983.991200 ms +cairo to window : 5.049950 GB/s, 4416.423700 ms + +End-user visible speedup does present too - it relates to the following bug + +https://gitlab.gnome.org/GNOME/meld/issues/133 + +Cairo speedup allow more simultaneous meld windows +without eating 100% of cpu core time on spinner rendering. + +gtk's speedup is near 1.7x, not such huge as pure cairo ~7-8x on results above +It looks that gtk has some problems in caching cairo surfaces +and recreates them every frame with initial black fill. +--- + src/win32/cairo-win32-gdi-compositor.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +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) +-- +2.17.0 + diff --git a/mingw-w64-cairo/PKGBUILD b/mingw-w64-cairo/PKGBUILD index a0b79dc4da..faaf70413c 100644 --- a/mingw-w64-cairo/PKGBUILD +++ b/mingw-w64-cairo/PKGBUILD @@ -5,7 +5,7 @@ _realname=cairo pkgbase=mingw-w64-${_realname} pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" pkgver=1.15.12 -pkgrel=1 +pkgrel=2 pkgdesc="Cairo vector graphics library (mingw-w64)" arch=('any') url="https://cairographics.org/" @@ -32,11 +32,17 @@ source=(#"https://cairographics.org/releases/cairo-${pkgver}.tar.xz" https://cairographics.org/snapshots/cairo-${pkgver}.tar.xz 0009-standalone-headers.mingw.patch 0026-create-argb-fonts.all.patch - 0027-win32-print-fix-unbounded-surface-assertion.patch) + 0027-win32-print-fix-unbounded-surface-assertion.patch + 0001-win32-introduce-new-flag-to-mark-surfaces-supporting.patch + 0002-win32-CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH-and-other-ar.patch + 0003-win32-Allow-gdi-operations-for-argb32-surfaces-allow.patch) sha256sums=('7623081b94548a47ee6839a7312af34e9322997806948b6eec421a8c6d0594c9' '234de8c5d4c28b03c19e638a353e8defb2de0367a634c002b0ea7d2877bd0756' '6db6c44fbdb4926d09afa978fe80430186c4b7b7d255059602b1f94c6a079975' - '7e244c20eec8c7b287dbee1d34de178d9b0c419dc4c2b11c90eaf626c92bf781') + '7e244c20eec8c7b287dbee1d34de178d9b0c419dc4c2b11c90eaf626c92bf781' + 'f4fc46accb941c08fa017efe05ee871dd23ab630adc261f0ddf55d2d1e6e6722' + 'f9deb2b1d74e8d2b94e4fe742bd81329e76e52383ba53446eba9ab3a2fd180e9' + 'ea3eff7cf71ae074b846a28987e0d8f4dcf836e34bdbb04f38e7344398f43126') prepare() { cd "${srcdir}"/${_realname}-${pkgver} @@ -44,6 +50,11 @@ prepare() { patch -p1 -i ${srcdir}/0026-create-argb-fonts.all.patch patch -p1 -i ${srcdir}/0027-win32-print-fix-unbounded-surface-assertion.patch + # https://lists.cairographics.org/archives/cairo/2018-April/028606.html + patch -p1 -i ${srcdir}/0001-win32-introduce-new-flag-to-mark-surfaces-supporting.patch + patch -p1 -i ${srcdir}/0002-win32-CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH-and-other-ar.patch + patch -p1 -i ${srcdir}/0003-win32-Allow-gdi-operations-for-argb32-surfaces-allow.patch + autoreconf -fi }