diff options
-rw-r--r-- | src/cairo-color.c | 7 | ||||
-rw-r--r-- | src/cairo-debug.c | 2 | ||||
-rw-r--r-- | src/cairo-mutex-list.h | 2 | ||||
-rw-r--r-- | src/cairo-pattern.c | 63 | ||||
-rwxr-xr-x | src/cairoint.h | 7 | ||||
-rw-r--r-- | test/Makefile.am | 1 | ||||
-rw-r--r-- | test/solid-pattern-cache-stress.c | 83 |
7 files changed, 163 insertions, 2 deletions
diff --git a/src/cairo-color.c b/src/cairo-color.c index ad6316e10..257f8d261 100644 --- a/src/cairo-color.c +++ b/src/cairo-color.c @@ -160,3 +160,10 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, *blue = color->blue * color->alpha; *alpha = color->alpha; } + +cairo_bool_t +_cairo_color_equal (const cairo_color_t *color_a, + const cairo_color_t *color_b) +{ + return memcmp (color_a, color_b, sizeof (cairo_color_t)) == 0; +} diff --git a/src/cairo-debug.c b/src/cairo-debug.c index 7c299325f..dd57dd780 100644 --- a/src/cairo-debug.c +++ b/src/cairo-debug.c @@ -68,4 +68,6 @@ cairo_debug_reset_static_data (void) #if CAIRO_HAS_FT_FONT _cairo_ft_font_reset_static_data (); #endif + + _cairo_pattern_reset_static_data (); } diff --git a/src/cairo-mutex-list.h b/src/cairo-mutex-list.h index 7c7bf8f8d..c054e11aa 100644 --- a/src/cairo-mutex-list.h +++ b/src/cairo-mutex-list.h @@ -34,6 +34,8 @@ #ifndef CAIRO_MUTEX_LIST_H #define CAIRO_MUTEX_LIST_H +CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_cache_lock); + CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex); CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex); diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 263907118..6ebe0caba 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -259,18 +259,77 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1)); } +/* We use a small cache here, because we don't want to constantly + * reallocate simple colors. */ +#define MAX_PATTERN_CACHE_SIZE 16 +static struct { + struct { + cairo_color_t color; + cairo_solid_pattern_t *pattern; + } cache[MAX_PATTERN_CACHE_SIZE]; + int size; +} solid_pattern_cache; + cairo_pattern_t * _cairo_pattern_create_solid (const cairo_color_t *color) { - cairo_solid_pattern_t *pattern; + static int cache_index; + void *pattern; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock); + + /* Check cache first. */ + if (cache_index < solid_pattern_cache.size && + _cairo_color_equal ( + &solid_pattern_cache.cache[cache_index].color, color)) + goto DONE; + for (cache_index = 0; cache_index < solid_pattern_cache.size; cache_index++) + if (_cairo_color_equal ( + &solid_pattern_cache.cache[cache_index].color, color)) + goto DONE; + + /* Not cached, need to create a new pattern. */ pattern = malloc (sizeof (cairo_solid_pattern_t)); if (pattern == NULL) return (cairo_pattern_t *) &cairo_pattern_nil.base; _cairo_pattern_init_solid (pattern, color); - return &pattern->base; + /* And insert it into the cache. */ + if (solid_pattern_cache.size < MAX_PATTERN_CACHE_SIZE) { + solid_pattern_cache.size ++; + /* cache_index == solid_pattern_cache.size */ + } else { + /* Evict an old pattern. */ + cache_index = rand () % MAX_PATTERN_CACHE_SIZE; + cairo_pattern_destroy ( + &solid_pattern_cache.cache[cache_index].pattern->base); + } + + solid_pattern_cache.cache[cache_index].color = *color; + solid_pattern_cache.cache[cache_index].pattern = pattern; + +DONE: + pattern = cairo_pattern_reference ( + &solid_pattern_cache.cache[cache_index].pattern->base); + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock); + + return pattern; +} + +void +_cairo_pattern_reset_static_data (void) +{ + int i; + + CAIRO_MUTEX_LOCK (_cairo_pattern_solid_cache_lock); + + for (i = 0; i < solid_pattern_cache.size; i++) + cairo_pattern_destroy (&solid_pattern_cache.cache[i].pattern->base); + solid_pattern_cache.size = 0; + + CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_cache_lock); } static const cairo_pattern_t * diff --git a/src/cairoint.h b/src/cairoint.h index 35f211759..7ce7cd1b9 100755 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -1546,6 +1546,10 @@ _cairo_color_get_rgba_premultiplied (cairo_color_t *color, double *blue, double *alpha); +cairo_private cairo_bool_t +_cairo_color_equal (const cairo_color_t *color_a, + const cairo_color_t *color_b); + /* cairo-font.c */ cairo_private void @@ -2407,6 +2411,9 @@ cairo_private cairo_status_t _cairo_pattern_get_extents (cairo_pattern_t *pattern, cairo_rectangle_int16_t *extents); +cairo_private void +_cairo_pattern_reset_static_data (void); + cairo_private cairo_status_t _cairo_gstate_set_antialias (cairo_gstate_t *gstate, cairo_antialias_t antialias); diff --git a/test/Makefile.am b/test/Makefile.am index 11e988130..792584efd 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -86,6 +86,7 @@ self-intersecting \ set-source \ show-text-current-point \ skew-extreme \ +solid-pattern-cache-stress \ source-clip \ source-clip-scale \ source-surface-scale-paint \ diff --git a/test/solid-pattern-cache-stress.c b/test/solid-pattern-cache-stress.c new file mode 100644 index 000000000..93e2f697f --- /dev/null +++ b/test/solid-pattern-cache-stress.c @@ -0,0 +1,83 @@ +/* + * Copyright ? 2007 Chris Wilson. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson <chris at chris-wilson.co.uk> + */ + +#include "cairo-test.h" + +static cairo_test_draw_function_t draw; + +cairo_test_t test = { + "solid-pattern-cache-stress", + "Stress the solid pattern cache and ensure it behaves", + 0, 0, + draw +}; +#include <cairo.h> +#include <stdlib.h> + +#define LOOPS 10 +#define NRAND 100 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int loop; + int i; + + for (loop = 0; loop < LOOPS; loop++) { + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); /* green */ + cairo_set_source_rgb (cr, 1.0, 1.0, 0.0); /* yellow */ + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */ + cairo_set_source_rgb (cr, 1.0, 0.0, 1.0); /* magenta */ + cairo_set_source_rgb (cr, 0.0, 1.0, 1.0); /* cyan */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); /* black */ + cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0); /* red */ + cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 1.0); /* green */ + cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0); /* yellow */ + cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0); /* blue */ + cairo_set_source_rgba (cr, 1.0, 0.0, 1.0, 1.0); /* magenta */ + cairo_set_source_rgba (cr, 0.0, 1.0, 1.0, 1.0); /* cyan */ + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); /* white */ + + for (i = 0; i < NRAND; i++) + cairo_set_source_rgba (cr, + drand48 (), + drand48 (), + drand48 (), + drand48 ()); + } + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test); +} + |