[cairo] [PATCH] [xlib] Use minimal depth for similar clones.
Chris Wilson
chris at chris-wilson.co.uk
Sat May 9 02:25:24 PDT 2009
Damian Frank noted
[http://lists.cairographics.org/archives/cairo/2009-May/017095.html]
a performance problem with an older XServer with an
unaccelerated composite - similar problems will be seen with non-XRender
servers which will trigger extraneous fallbacks. The problem he found was
that painting an ARGB32 image onto an RGB24 destination window (using
SOURCE) was going via the RENDER protocol and not core. He was able to
demonstrate that this could be worked around by declaring the pixel data as
an RGB24 image. The issue is that the image is uploaded into a temporary
pixmap of matching depth (i.e. 32 bit for ARGB32 and 24 bit for RGB23
data), however the core protocol can only blit between Drawables of
matching depth - so without the work-around the Drawables are mismatched
and we either need to use RENDER or fallback.
This patch adds a content mask to _cairo_surface_clone_similar() to
provide the extra bit of information to the backends for when it is
possible for them to drop channels from the clone. This is used by the
xlib backend to only create a 24 bit source when blitting to a Window.
---
src/cairo-clip.c | 1 +
src/cairo-directfb-surface.c | 1 +
src/cairo-glitz-surface.c | 1 +
src/cairo-image-surface.c | 4 +++
src/cairo-pattern.c | 18 ++++++++++++--
src/cairo-surface-fallback-private.h | 1 +
src/cairo-surface-fallback.c | 3 +-
src/cairo-surface.c | 7 +++++-
src/cairo-xcb-surface.c | 4 +++
src/cairo-xlib-surface.c | 42 +++++++++++++++++++++++++--------
src/cairoint.h | 4 +++
test/surface-source.c | 2 +
12 files changed, 73 insertions(+), 15 deletions(-)
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index c7535fe..a272454 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -773,6 +773,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
if (other->surface) {
int dx, dy;
status = _cairo_surface_clone_similar (target, other->surface,
+ CAIRO_CONTENT_ALPHA,
0,
0,
other->surface_rect.width,
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 3eee33c..9d30e7c 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -763,6 +763,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
}
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
*src_x, *src_y, width, height,
(cairo_surface_t **) &src,
&src_attr);
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 284198b..dee99a1 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -716,6 +716,7 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_int_status_t status;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
x, y, width, height,
(cairo_surface_t **) &src,
&attr->base);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index a027f72..3533bb4 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -784,6 +784,7 @@ _cairo_image_surface_release_dest_image (void *abstract_surfa
static cairo_status_t
_cairo_image_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -963,6 +964,7 @@ _cairo_image_surface_composite (cairo_operator_t op,
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
src_x, src_y,
+ CAIRO_CONTENT_COLOR_ALPHA,
mask_x, mask_y,
width, height,
(cairo_surface_t **) &src,
@@ -1164,6 +1166,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
}
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&attributes);
@@ -1398,6 +1401,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
status = _cairo_pattern_acquire_surface (
renderer->pattern, &renderer->dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
rects->src.x, rects->src.y,
width, height,
(cairo_surface_t **) &renderer->src,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 0fb36bf..67447a5 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1256,6 +1256,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
pixman_transform_t pixman_transform;
cairo_status_t status;
cairo_bool_t repeat = FALSE;
+ cairo_bool_t opaque = TRUE;
pixman_gradient_stop_t pixman_stops_static[2];
pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
@@ -1279,6 +1280,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
pixman_stops[i].color.green = pattern->stops[i].color.green_short;
pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+ if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
+ opaque = FALSE;
}
if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
@@ -1450,6 +1453,9 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
pixman_image_unref (pixman_image);
status = _cairo_surface_clone_similar (dst, &image->base,
+ opaque ?
+ CAIRO_CONTENT_COLOR :
+ CAIRO_CONTENT_COLOR_ALPHA,
0, 0, width, height,
&clone_offset_x,
&clone_offset_y,
@@ -1781,6 +1787,7 @@ _pixman_nearest_sample (double d)
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
cairo_surface_t *dst,
+ cairo_content_t content,
int x,
int y,
unsigned int width,
@@ -1855,7 +1862,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
if (unlikely (status))
goto BAIL;
- status = _cairo_surface_clone_similar (dst, surface,
+ status = _cairo_surface_clone_similar (dst, surface, content,
extents.x, extents.y,
extents.width, extents.height,
&extents.x, &extents.y, &src);
@@ -1978,7 +1985,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
/* XXX can we use is_empty? */
- status = _cairo_surface_clone_similar (dst, surface,
+ status = _cairo_surface_clone_similar (dst, surface, content,
extents.x, extents.y,
extents.width, extents.height,
&x, &y, out);
@@ -2052,6 +2059,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_int_status_t
_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t *dst,
+ cairo_content_t content,
int x,
int y,
unsigned int width,
@@ -2144,6 +2152,7 @@ _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
status = _cairo_pattern_acquire_surface_for_surface (src, dst,
+ content,
x, y, width, height,
surface_out,
attributes);
@@ -2176,6 +2185,7 @@ cairo_int_status_t
_cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
+ cairo_content_t src_content,
int src_x,
int src_y,
int mask_x,
@@ -2212,13 +2222,14 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&src_tmp.solid, &combined,
- src_solid->content | mask_solid->content);
+ (src_solid->content | mask_solid->content) & src_content);
src = &src_tmp.base;
mask = NULL;
}
status = _cairo_pattern_acquire_surface (src, dst,
+ src_content,
src_x, src_y,
width, height,
src_out, src_attributes);
@@ -2231,6 +2242,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
}
status = _cairo_pattern_acquire_surface (mask, dst,
+ CAIRO_CONTENT_ALPHA,
mask_x, mask_y,
width, height,
mask_out, mask_attributes);
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index 61e5b90..cd18178 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -121,6 +121,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
cairo_private cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 57ac417..39723a6 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1335,6 +1335,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
cairo_status_t
_cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -1348,7 +1349,7 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
cairo_status_t status;
new_surface = _cairo_surface_create_similar_scratch (surface,
- src->content,
+ src->content & content,
width, height);
if (new_surface->status)
return new_surface->status;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 42b101a..26a7a13 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1268,6 +1268,7 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface,
* _cairo_surface_clone_similar:
* @surface: a #cairo_surface_t
* @src: the source image
+ * @content: target content mask
* @src_x: extent for the rectangle in src we actually care about
* @src_y: extent for the rectangle in src we actually care about
* @width: extent for the rectangle in src we actually care about
@@ -1287,6 +1288,7 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_status_t
_cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -1307,6 +1309,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
if (surface->backend->clone_similar) {
status = surface->backend->clone_similar (surface, src,
+ content,
src_x, src_y,
width, height,
clone_offset_x,
@@ -1319,7 +1322,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *similar;
similar = cairo_surface_create_similar (surface,
- src->content,
+ src->content & content,
width, height);
status = similar->status;
if (unlikely (status))
@@ -1344,6 +1347,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
if (status == CAIRO_STATUS_SUCCESS) {
status =
surface->backend->clone_similar (surface, &image->base,
+ content,
src_x, src_y,
width, height,
clone_offset_x,
@@ -1359,6 +1363,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
status =
_cairo_surface_fallback_clone_similar (surface, src,
+ content,
src_x, src_y,
width, height,
clone_offset_x,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 8d0090b..baee539 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1119,6 +1119,7 @@ _cairo_xcb_surface_composite (cairo_operator_t op,
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y,
mask_x, mask_y,
width, height,
@@ -1407,6 +1408,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&attributes);
@@ -2499,6 +2501,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
0, 0, 1, 1,
(cairo_surface_t **) &src,
&attributes);
@@ -2513,6 +2516,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
goto BAIL;
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents.x, glyph_extents.y,
glyph_extents.width, glyph_extents.height,
(cairo_surface_t **) &src,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index b56b340..bbbdc4b 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -950,10 +950,10 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ximage.blue_mask = surface->b_mask;
ximage.xoffset = 0;
- if (image_masks.alpha_mask == surface->a_mask &&
- image_masks.red_mask == surface->r_mask &&
- image_masks.green_mask == surface->g_mask &&
- image_masks.blue_mask == surface->b_mask)
+ if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
+ (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) &&
+ (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
+ (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0))
{
int ret;
@@ -1169,6 +1169,7 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
static cairo_status_t
_cairo_xlib_surface_clone_similar (void *abstract_surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -1201,8 +1202,11 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
format = image_src->format;
- if (format == CAIRO_FORMAT_INVALID)
- format = _cairo_format_from_content (image_src->base.content);
+ if (format == CAIRO_FORMAT_INVALID ||
+ (_cairo_content_from_format (format) & ~content))
+ {
+ format = _cairo_format_from_content (image_src->base.content & content);
+ }
clone = (cairo_xlib_surface_t *)
_cairo_xlib_surface_create_similar_with_format (surface,
format,
@@ -1508,14 +1512,15 @@ _surface_has_alpha (cairo_xlib_surface_t *surface)
*/
static cairo_bool_t
_operator_needs_alpha_composite (cairo_operator_t op,
- cairo_bool_t surface_has_alpha)
+ cairo_bool_t destination_has_alpha,
+ cairo_bool_t source_has_alpha)
{
if (op == CAIRO_OPERATOR_SOURCE ||
- (!surface_has_alpha &&
+ (! source_has_alpha &&
(op == CAIRO_OPERATOR_OVER ||
op == CAIRO_OPERATOR_ATOP ||
op == CAIRO_OPERATOR_IN)))
- return FALSE;
+ return destination_has_alpha;
return TRUE;
}
@@ -1624,7 +1629,9 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst,
return DO_UNSUPPORTED;
needs_alpha_composite =
- _operator_needs_alpha_composite (op, _surface_has_alpha (src));
+ _operator_needs_alpha_composite (op,
+ _surface_has_alpha (dst),
+ _surface_has_alpha (src));
if (! have_mask &&
is_integer_translation &&
@@ -1721,6 +1728,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
composite_operation_t operation;
int itx, ity;
cairo_bool_t is_integer_translation;
+ cairo_bool_t needs_alpha_composite;
+ cairo_content_t src_content;
_cairo_xlib_display_notify (dst->display);
@@ -1729,8 +1738,17 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
if (operation == DO_UNSUPPORTED)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ needs_alpha_composite =
+ _operator_needs_alpha_composite (op,
+ _surface_has_alpha (dst),
+ ! _cairo_pattern_is_opaque (src_pattern));
+ src_content = CAIRO_CONTENT_COLOR_ALPHA;
+ if (! needs_alpha_composite)
+ src_content &= ~CAIRO_CONTENT_ALPHA;
+
status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
&dst->base,
+ src_content,
src_x, src_y,
mask_x, mask_y,
width, height,
@@ -1892,6 +1910,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
return status;
status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
0, 0,
ARRAY_LENGTH (dither_pattern[0]),
ARRAY_LENGTH (dither_pattern),
@@ -2142,6 +2161,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_pattern_acquire_surface (pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&attributes);
@@ -4071,6 +4091,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
0, 0, 1, 1,
(cairo_surface_t **) &src,
&attributes);
@@ -4087,6 +4108,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
goto BAIL0;
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
+ CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents.x, glyph_extents.y,
glyph_extents.width, glyph_extents.height,
(cairo_surface_t **) &src,
diff --git a/src/cairoint.h b/src/cairoint.h
index 3ba236b..27c5977 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -591,6 +591,7 @@ struct _cairo_surface_backend {
cairo_warn cairo_status_t
(*clone_similar) (void *surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -1963,6 +1964,7 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface,
cairo_private cairo_status_t
_cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
+ cairo_content_t content,
int src_x,
int src_y,
int width,
@@ -2482,6 +2484,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern);
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
cairo_surface_t *dst,
+ cairo_content_t content,
int x,
int y,
unsigned int width,
@@ -2498,6 +2501,7 @@ cairo_private cairo_int_status_t
_cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
const cairo_pattern_t *mask,
cairo_surface_t *dst,
+ cairo_content_t src_content,
int src_x,
int src_y,
int mask_x,
diff --git a/test/surface-source.c b/test/surface-source.c
index 0906924..e1e9fca 100644
--- a/test/surface-source.c
+++ b/test/surface-source.c
@@ -94,6 +94,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_source_surface (cr2, surface,
(INTER_SIZE - SOURCE_SIZE)/2,
(INTER_SIZE - SOURCE_SIZE)/2);
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr2);
/* and then paint onto a small surface for checking */
@@ -102,6 +103,7 @@ draw (cairo_t *cr, int width, int height)
(height - INTER_SIZE)/2);
cairo_destroy (cr2);
cairo_rectangle (cr, 15, 15, 60, 60);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_fill (cr);
/* destroy the surface last, as this triggers XCloseDisplay */
--
1.6.2.4
More information about the cairo
mailing list