summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-10-21 09:04:30 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-10-21 11:37:16 +0100
commit7c9ebd4a852ad709e57ed48b9610db00de79de7e (patch)
tree0714cd10893f8b63ddd93679d7fbe472564c9d35
parent723055722f1d9a133fe9e78bb19165f2c7be720e (diff)
Make the surface->is_clear logic common
A nasty surprise whilst profiling is that performing redundant clear operations is extremely painful. We can mitigate this somewhat by tracking the cleared state of surfaces and skipping repeated attempts to clear a surface.
-rw-r--r--src/cairo-gl-surface.c2
-rw-r--r--src/cairo-image-surface.c47
-rw-r--r--src/cairo-surface-private.h6
-rw-r--r--src/cairo-surface.c66
-rw-r--r--src/cairoint.h1
5 files changed, 68 insertions, 54 deletions
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 64ae29ba..5d4853dd 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -527,6 +527,8 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
glClear (GL_COLOR_BUFFER_BIT);
_cairo_gl_context_release (ctx);
+ surface->base.is_clear = TRUE;
+
return &surface->base;
}
slim_hidden_def (cairo_gl_surface_create);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 4dbc2fee..d4b607e1 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -190,7 +190,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->height = height;
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
- surface->is_clear = FALSE;
surface->clip_region = NULL;
@@ -393,7 +392,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
}
/* we can not make any assumptions about the initial state of user data */
- ((cairo_image_surface_t *) surface)->is_clear = data == NULL;
+ surface->is_clear = data == NULL;
return surface;
}
@@ -1154,8 +1153,6 @@ _cairo_image_surface_composite (cairo_operator_t op,
_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
_cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
- if (op != CAIRO_OPERATOR_CLEAR)
- dst->is_clear = FALSE;
return status;
}
@@ -1214,9 +1211,6 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
if (pixman_rects != stack_rects)
free (pixman_rects);
- if (op != CAIRO_OPERATOR_CLEAR)
- surface->is_clear = FALSE;
-
return status;
}
@@ -1345,9 +1339,6 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
pixman_image_unref (mask);
- if (op != CAIRO_OPERATOR_CLEAR)
- dst->is_clear = FALSE;
-
if (! _cairo_operator_bounded_by_mask (op)) {
status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
&attributes,
@@ -1506,9 +1497,6 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
rects->width, rects->height,
dst->clip_region);
}
-
- if (renderer->op != CAIRO_OPERATOR_CLEAR)
- dst->is_clear = FALSE;
}
if (status != CAIRO_STATUS_SUCCESS)
return _cairo_span_renderer_set_error (abstract_renderer,
@@ -1615,35 +1603,6 @@ _cairo_image_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
}
-static cairo_status_t
-_cairo_image_surface_mark_dirty_rectangle (void *abstract_surface,
- int x, int y,
- int width, int height)
-{
- cairo_image_surface_t *surface = abstract_surface;
- surface->is_clear = FALSE;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_clip_t *clip)
-{
- /* we know that surfaces are calloc, so ignore any redundant clears */
- if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
- cairo_image_surface_t *surface = abstract_surface;
-
- if (surface->is_clear)
- return CAIRO_STATUS_SUCCESS;
-
- surface->is_clear = TRUE;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
/**
* _cairo_surface_is_image:
* @surface: a #cairo_surface_t
@@ -1678,11 +1637,11 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
NULL, /* old_show_glyphs */
_cairo_image_surface_get_font_options,
NULL, /* flush */
- _cairo_image_surface_mark_dirty_rectangle,
+ NULL, /* mark dirty */
NULL, /* font_fini */
NULL, /* glyph_fini */
- _cairo_image_surface_paint,
+ NULL, /* paint */
NULL, /* mask */
NULL, /* stroke */
NULL, /* fill */
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 5c80d43f..994df0e5 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -58,9 +58,12 @@ struct _cairo_surface {
cairo_reference_count_t ref_count;
cairo_status_t status;
- cairo_bool_t finished;
unsigned int unique_id;
+ unsigned finished : 1;
+ unsigned is_clear : 1;
+ unsigned has_font_options : 1;
+
cairo_user_data_array_t user_data;
cairo_user_data_array_t mime_data;
@@ -89,7 +92,6 @@ struct _cairo_surface {
* and set using _cairo_surface_set_font_options(), and propagated by
* cairo_surface_create_similar().
*/
- cairo_bool_t has_font_options;
cairo_font_options_t font_options;
};
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e080c31e..aaab3134 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -51,8 +51,10 @@ const cairo_surface_t name = { \
CAIRO_CONTENT_COLOR, /* content */ \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
status, /* status */ \
- FALSE, /* finished */ \
0, /* unique id */ \
+ FALSE, /* finished */ \
+ TRUE, /* is_clear */ \
+ FALSE, /* has_font_options */ \
{ 0, 0, 0, NULL, }, /* user_data */ \
{ 0, 0, 0, NULL, }, /* mime_data */ \
{ 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \
@@ -68,7 +70,6 @@ const cairo_surface_t name = { \
0, /* element_size */ \
NULL, /* elements */ \
}, /* snapshots */ \
- FALSE, /* has_font_options */ \
{ CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
@@ -343,8 +344,9 @@ _cairo_surface_init (cairo_surface_t *surface,
CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
surface->status = CAIRO_STATUS_SUCCESS;
- surface->finished = FALSE;
surface->unique_id = _cairo_surface_allocate_unique_id ();
+ surface->finished = FALSE;
+ surface->is_clear = FALSE;
_cairo_user_data_array_init (&surface->user_data);
_cairo_user_data_array_init (&surface->mime_data);
@@ -1030,6 +1032,8 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
* call mark_dirty()). */
assert (! _cairo_surface_has_snapshots (surface));
+ surface->is_clear = FALSE;
+
if (surface->backend->mark_dirty_rectangle != NULL) {
/* XXX: FRAGILE: We're ignoring the scaling component of
* device_transform here. I don't know what the right thing to
@@ -1924,6 +1928,14 @@ _cairo_surface_paint (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ if (surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip == NULL)
+ surface->is_clear = TRUE;
+ }
+
_cairo_surface_begin_modification (surface);
if (surface->backend->paint != NULL) {
@@ -1935,6 +1947,8 @@ _cairo_surface_paint (cairo_surface_t *surface,
status = _cairo_surface_fallback_paint (surface, op, source, clip);
FINISH:
+ surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
return _cairo_surface_set_error (surface, status);
}
@@ -1953,6 +1967,16 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* If the mask is blank, this is just an expensive no-op */
+ if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ const cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *) mask;
+ if (spattern->surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+ }
+
_cairo_surface_begin_modification (surface);
if (surface->backend->mask != NULL) {
@@ -1964,6 +1988,8 @@ _cairo_surface_mask (cairo_surface_t *surface,
status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
FINISH:
+ surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
return _cairo_surface_set_error (surface, status);
}
@@ -1992,6 +2018,13 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (surface->is_clear &&
+ fill_op == CAIRO_OPERATOR_CLEAR &&
+ stroke_op == CAIRO_OPERATOR_CLEAR)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
_cairo_surface_begin_modification (surface);
if (surface->backend->fill_stroke) {
@@ -2009,23 +2042,27 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
clip);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return _cairo_surface_set_error (surface, status);
+ goto FINISH;
}
status = _cairo_surface_fill (surface, fill_op, fill_source, path,
fill_rule, fill_tolerance, fill_antialias,
clip);
if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ goto FINISH;
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse,
stroke_tolerance, stroke_antialias,
clip);
if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
+ goto FINISH;
- return CAIRO_STATUS_SUCCESS;
+ FINISH:
+ surface->is_clear &= fill_op == CAIRO_OPERATOR_CLEAR;
+ surface->is_clear &= stroke_op == CAIRO_OPERATOR_CLEAR;
+
+ return _cairo_surface_set_error (surface, status);
}
cairo_status_t
@@ -2048,6 +2085,9 @@ _cairo_surface_stroke (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
if (surface->backend->stroke != NULL) {
@@ -2068,6 +2108,8 @@ _cairo_surface_stroke (cairo_surface_t *surface,
clip);
FINISH:
+ surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
return _cairo_surface_set_error (surface, status);
}
@@ -2089,6 +2131,9 @@ _cairo_surface_fill (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
if (surface->backend->fill != NULL) {
@@ -2107,6 +2152,8 @@ _cairo_surface_fill (cairo_surface_t *surface,
clip);
FINISH:
+ surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
return _cairo_surface_set_error (surface, status);
}
@@ -2408,6 +2455,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
+ if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_surface_begin_modification (surface);
if (_cairo_surface_has_device_transform (surface) &&
@@ -2504,6 +2554,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (dev_scaled_font != scaled_font)
cairo_scaled_font_destroy (dev_scaled_font);
+ surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
return _cairo_surface_set_error (surface, status);
}
diff --git a/src/cairoint.h b/src/cairoint.h
index b9139138..fc1046e3 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -861,7 +861,6 @@ struct _cairo_image_surface {
pixman_image_t *pixman_image;
cairo_region_t *clip_region;
- unsigned is_clear : 1;
unsigned owns_data : 1;
unsigned transparency : 2;
};