cairo: add some patches posted upstream for improving the drawing performance (#3675)
See https://lists.cairographics.org/archives/cairo/2018-April/028606.html This should help gtk3 apps without CSD.
This commit is contained in:
committed by
Алексей
parent
f83bcac7c8
commit
f1eba2b29f
@@ -0,0 +1,104 @@
|
||||
From ba41e2203ea32e459cd26dfb20d748cead547d82 Mon Sep 17 00:00:00 2001
|
||||
From: Vasily Galkin <galkin-vv@yandex.ru>
|
||||
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
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
From 4534b8cbbd032451da6f56f012cdf7b034b86159 Mon Sep 17 00:00:00 2001
|
||||
From: Vasily Galkin <galkin-vv@yandex.ru>
|
||||
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
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
From dfc2a62106416cf57fadf8a94108f1e454ddebd3 Mon Sep 17 00:00:00 2001
|
||||
From: Vasily Galkin <galkin-vv@yandex.ru>
|
||||
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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user