[PATCH] [pattern] Tweak REFLECT HACK
Chris Wilson
chris at chris-wilson.co.uk
Mon Oct 20 08:49:23 PDT 2008
In order to workaound a directfb bug, tweak the reflect->repeat pattern so
that it covers the destination rectangle. Although the number of paint()
increases, the number of read/written pixels remain the same so that
performance should not deteriorate, but instead be improved by using a
cloned source. The early return of the REFLECT surface is discarded so
that the latter optimisations for surface sources can be applied. One side
effect of this is that acquire_source_image() is removed due to its lax
reference counting which thereby exposes the ROI optimisations for image
destinations as well.
---
src/cairo-matrix.c | 9 ++-
src/cairo-pattern.c | 273 ++++++++++++++++++++++++---------------------------
src/cairoint.h | 1 -
3 files changed, 137 insertions(+), 146 deletions(-)
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index ca18323..724facd 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -371,6 +371,13 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double min_x, max_x;
double min_y, max_y;
+ if (_cairo_matrix_is_identity (matrix)) {
+ if (is_tight)
+ *is_tight = TRUE;
+
+ return;
+ }
+
quad_x[0] = *x1;
quad_y[0] = *y1;
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
@@ -406,7 +413,7 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
*y1 = min_y;
*x2 = max_x;
*y2 = max_y;
-
+
if (is_tight) {
/* it's tight if and only if the four corner points form an axis-aligned
rectangle.
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index d83142a..f3e05b8 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1354,7 +1354,6 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
attr->matrix = matrix;
attr->extend = pattern->base.extend;
attr->filter = CAIRO_FILTER_NEAREST;
- attr->acquired = FALSE;
*out = &image->base;
@@ -1445,7 +1444,6 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
cairo_matrix_init_identity (&attr->matrix);
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
- attr->acquired = FALSE;
return status;
}
@@ -1596,7 +1594,6 @@ NOCACHE:
cairo_matrix_init_identity (&attribs->matrix);
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
- attribs->acquired = FALSE;
status = CAIRO_STATUS_SUCCESS;
@@ -1773,31 +1770,32 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_t **out,
cairo_surface_attributes_t *attr)
{
- cairo_int_status_t status;
+ cairo_surface_t *surface;
+ cairo_rectangle_int_t extents;
+ cairo_rectangle_int_t sampled_area;
+ double x1, y1, x2, y2;
int tx, ty;
double pad;
+ cairo_int_status_t status;
- attr->acquired = FALSE;
+ surface = cairo_surface_reference (pattern->surface);
+ attr->matrix = pattern->base.matrix;
attr->extend = pattern->base.extend;
attr->filter = _cairo_pattern_analyze_filter (pattern, &pad);
- if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
- &tx, &ty))
- {
+ attr->x_offset = attr->y_offset = tx = ty = 0;
+ if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
cairo_matrix_init_identity (&attr->matrix);
attr->x_offset = tx;
attr->y_offset = ty;
- }
- else if (attr->filter == CAIRO_FILTER_NEAREST)
- {
+ } else if (attr->filter == CAIRO_FILTER_NEAREST) {
/*
* For NEAREST, we can remove the fractional translation component
* from the transformation - this ensures that the pattern will always
* hit fast-paths in the backends for simple transformations that
* become (almost) identity, without loss of quality.
*/
- attr->matrix = pattern->base.matrix;
attr->matrix.x0 = 0;
attr->matrix.y0 = 0;
if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
@@ -1811,15 +1809,11 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
attr->matrix.y0 = pattern->base.matrix.y0;
}
- attr->x_offset = attr->y_offset = 0;
- tx = ty = 0;
- }
- else
- {
- attr->matrix = pattern->base.matrix;
- attr->x_offset = attr->y_offset = 0;
- tx = 0;
- ty = 0;
+ if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
+ cairo_matrix_init_identity (&attr->matrix);
+ attr->x_offset = tx;
+ attr->y_offset = ty;
+ }
}
/* XXX: Hack:
@@ -1828,153 +1822,159 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
* an image twice bigger on each side, and create a pattern of four
* images such that the new image, when repeated, has the same effect
* of reflecting the original pattern.
- *
- * This is because the reflect support in pixman is broken and we
- * pass repeat instead of reflect to pixman. See
- * _cairo_image_surface_set_attributes() for that.
*/
if (attr->extend == CAIRO_EXTEND_REFLECT) {
cairo_t *cr;
- int w,h;
+ cairo_surface_t *src;
+ int w, h;
- cairo_rectangle_int_t extents;
- status = _cairo_surface_get_extents (pattern->surface, &extents);
+ status = _cairo_surface_get_extents (surface, &extents);
if (status)
- return status;
+ goto BAIL;
- attr->extend = CAIRO_EXTEND_REPEAT;
+ status = _cairo_surface_clone_similar (dst, pattern->surface,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ &extents.x, &extents.y, &src);
+ if (status)
+ goto BAIL;
- /* TODO: Instead of rendering pattern->surface four times to
- * out, we should first copy pattern->surface to surface similar
- * to dst and then copy that four times to out. This may cause
- * an extra copy in the case of image destination, but for X servers,
- * this will send pattern->surface just once over the wire instead
- * of current four.
- */
- x = extents.x;
- y = extents.y;
w = 2 * extents.width;
h = 2 * extents.height;
- *out = cairo_surface_create_similar (dst, dst->content, w, h);
- status = cairo_surface_status (*out);
- if (status) {
- cairo_surface_destroy (*out);
- *out = NULL;
- return status;
+ if (_cairo_matrix_is_identity (&attr->matrix)) {
+ attr->x_offset = -x;
+ x += tx;
+ while (x <= -w)
+ x += w;
+ while (x >= w)
+ x -= w;
+ extents.x += x;
+ tx = x = 0;
+
+ attr->y_offset = -y;
+ y += ty;
+ while (y <= -h)
+ y += h;
+ while (y >= h)
+ y -= h;
+ extents.y += y;
+ ty = y = 0;
}
- (*out)->device_transform = pattern->surface->device_transform;
- (*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
+ cairo_surface_destroy (surface);
+ surface = cairo_surface_create_similar (dst, dst->content, w, h);
+ if (surface->status) {
+ cairo_surface_destroy (src);
+ return surface->status;
+ }
- cr = cairo_create (*out);
+ surface->device_transform = pattern->surface->device_transform;
+ surface->device_transform_inverse = pattern->surface->device_transform_inverse;
- cairo_set_source_surface (cr, pattern->surface, -x, -y);
+ cr = cairo_create (surface);
+
+ cairo_set_source_surface (cr, src, -extents.x, -extents.y);
cairo_paint (cr);
cairo_scale (cr, -1, +1);
- cairo_set_source_surface (cr, pattern->surface, x-w, -y);
+ cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
+ cairo_paint (cr);
+ cairo_set_source_surface (cr, src, extents.x, -extents.y);
cairo_paint (cr);
cairo_scale (cr, +1, -1);
- cairo_set_source_surface (cr, pattern->surface, x-w, y-h);
+ cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
+ cairo_paint (cr);
+ cairo_set_source_surface (cr, src, extents.x, extents.y-h);
+ cairo_paint (cr);
+ cairo_set_source_surface (cr, src, extents.x-w, extents.y);
+ cairo_paint (cr);
+ cairo_set_source_surface (cr, src, extents.x, extents.y);
cairo_paint (cr);
cairo_scale (cr, -1, +1);
- cairo_set_source_surface (cr, pattern->surface, -x, y-h);
+ cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
+ cairo_paint (cr);
+ cairo_set_source_surface (cr, src, -extents.x, extents.y);
cairo_paint (cr);
status = cairo_status (cr);
cairo_destroy (cr);
- if (status) {
- cairo_surface_destroy (*out);
- *out = NULL;
- }
-
- return status;
- }
-
- if (_cairo_surface_is_image (dst)) {
- cairo_image_surface_t *image;
+ cairo_surface_destroy (src);
- status = _cairo_surface_acquire_source_image (pattern->surface,
- &image,
- &attr->extra);
if (status)
- return status;
+ goto BAIL;
- *out = &image->base;
- attr->acquired = TRUE;
- } else {
- cairo_rectangle_int_t extents;
-
- status = _cairo_surface_get_extents (pattern->surface, &extents);
- if (status)
- return status;
+ attr->extend = CAIRO_EXTEND_REPEAT;
+ }
- /* If we're repeating, we just play it safe and clone the
- * entire surface - i.e. we use the existing extents.
- */
- if (attr->extend != CAIRO_EXTEND_REPEAT) {
- cairo_rectangle_int_t sampled_area;
+ status = _cairo_surface_get_extents (surface, &extents);
+ if (status)
+ goto BAIL;
- /* Otherwise, we first transform the rectangle to the
- * coordinate space of the source surface so that we can
- * clone only that portion of the surface that will be
- * read.
- */
- if (_cairo_matrix_is_identity (&attr->matrix)) {
- sampled_area.x = x;
- sampled_area.y = y;
- sampled_area.width = width;
- sampled_area.height = height;
- } else {
- double x1 = x;
- double y1 = y;
- double x2 = x + width;
- double y2 = y + height;
-
- _cairo_matrix_transform_bounding_box (&attr->matrix,
- &x1, &y1, &x2, &y2,
- NULL);
-
- sampled_area.x = floor (x1 - pad);
- sampled_area.y = floor (y1 - pad);
- sampled_area.width = ceil (x2 + pad) - sampled_area.x;
- sampled_area.height = ceil (y2 + pad) - sampled_area.y;
+ /* We first transform the rectangle to the coordinate space of the
+ * source surface so that we only need to clone that portion of the
+ * surface that will be read.
+ */
+ x1 = x;
+ y1 = y;
+ x2 = x + width;
+ y2 = y + height;
+ _cairo_matrix_transform_bounding_box (&attr->matrix,
+ &x1, &y1, &x2, &y2,
+ NULL);
+
+ sampled_area.x = floor (x1 - pad);
+ sampled_area.y = floor (y1 - pad);
+ sampled_area.width = ceil (x2 + pad) - sampled_area.x;
+ sampled_area.height = ceil (y2 + pad) - sampled_area.y;
+
+ sampled_area.x += tx;
+ sampled_area.y += ty;
+
+ if (attr->extend != CAIRO_EXTEND_REPEAT) {
+ /* Never acquire a larger area than the source itself */
+ _cairo_rectangle_intersect (&extents, &sampled_area);
+ } else {
+ if (sampled_area.x >= extents.x &&
+ sampled_area.y >= extents.y &&
+ sampled_area.x + sampled_area.width <= extents.x + extents.width &&
+ sampled_area.y + sampled_area.height <= extents.y + extents.height)
+ {
+ /* source is wholly contained within extents, drop the REPEAT */
+ extents = sampled_area;
+ attr->extend = CAIRO_EXTEND_NONE;
+ }
+ }
- }
+ status = _cairo_surface_clone_similar (dst, surface,
+ extents.x, extents.y,
+ extents.width, extents.height,
+ &x, &y, out);
+ if (status)
+ goto BAIL;
- sampled_area.x += tx;
- sampled_area.y += ty;
+ if (x != 0 || y != 0) {
+ if (_cairo_matrix_is_identity (&attr->matrix)) {
+ attr->x_offset -= x;
+ attr->y_offset -= y;
+ } else {
+ cairo_matrix_t m;
- /* Never acquire a larger area than the source itself */
- _cairo_rectangle_intersect (&extents, &sampled_area);
- }
+ x -= attr->x_offset;
+ y -= attr->y_offset;
+ attr->x_offset = 0;
+ attr->y_offset = 0;
- status = _cairo_surface_clone_similar (dst, pattern->surface,
- extents.x, extents.y,
- extents.width, extents.height,
- &x, &y, out);
- if (status == CAIRO_STATUS_SUCCESS && (x != 0 || y != 0)) {
- if (_cairo_matrix_is_identity (&attr->matrix)) {
- attr->x_offset -= x;
- attr->y_offset -= y;
- } else {
- cairo_matrix_t m;
-
- x -= attr->x_offset;
- y -= attr->y_offset;
- attr->x_offset = 0;
- attr->y_offset = 0;
-
- cairo_matrix_init_translate (&m, -x, -y);
- cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
- }
+ cairo_matrix_init_translate (&m, -x, -y);
+ cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
}
}
+ BAIL:
+ cairo_surface_destroy (surface);
return status;
}
@@ -2012,7 +2012,6 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
if (pattern->status) {
*surface_out = NULL;
- attributes->acquired = FALSE;
return pattern->status;
}
@@ -2095,21 +2094,7 @@ _cairo_pattern_release_surface (cairo_pattern_t *pattern,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
- if (attributes->acquired)
- {
- cairo_surface_pattern_t *surface_pattern;
-
- assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
- surface_pattern = (cairo_surface_pattern_t *) pattern;
-
- _cairo_surface_release_source_image (surface_pattern->surface,
- (cairo_image_surface_t *) surface,
- attributes->extra);
- }
- else
- {
- cairo_surface_destroy (surface);
- }
+ cairo_surface_destroy (surface);
}
cairo_int_status_t
diff --git a/src/cairoint.h b/src/cairoint.h
index cdf28b4..7c96576 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -906,7 +906,6 @@ typedef struct _cairo_surface_attributes {
cairo_filter_t filter;
int x_offset;
int y_offset;
- cairo_bool_t acquired;
void *extra;
} cairo_surface_attributes_t;
--
1.5.6.3
--=-glTF3lOLWkFHT+I3aul5--
More information about the cairo
mailing list