mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-14 15:40:39 +01:00
[pattern] Generalise the freed pattern pool
Also cache recently freed surface and gradient patterns. With thanks to Jonathan Morton for the inspiration and initial pointer pool code for pixman.
This commit is contained in:
parent
132f44dce1
commit
f4d9a4482f
3 changed files with 112 additions and 60 deletions
|
|
@ -54,6 +54,7 @@ typedef int cairo_atomic_int_t;
|
|||
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
|
||||
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
|
||||
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
|
||||
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#define CAIRO_MUTEX_DECLARE(mutex)
|
||||
#endif
|
||||
|
||||
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock)
|
||||
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
|
||||
|
||||
CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex)
|
||||
|
|
|
|||
|
|
@ -408,10 +408,92 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
|
|||
/* We use a small freed pattern cache here, because we don't want to
|
||||
* constantly reallocate simple colors. */
|
||||
#define MAX_PATTERN_CACHE_SIZE 4
|
||||
static struct {
|
||||
cairo_solid_pattern_t *patterns[MAX_PATTERN_CACHE_SIZE];
|
||||
int size;
|
||||
} solid_pattern_cache;
|
||||
typedef struct {
|
||||
void *pool[MAX_PATTERN_CACHE_SIZE];
|
||||
int top;
|
||||
} freed_pool_t;
|
||||
|
||||
static freed_pool_t freed_pattern_pool[4];
|
||||
|
||||
static void *
|
||||
_atomic_fetch (void **slot)
|
||||
{
|
||||
return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_atomic_store (void **slot, void *pattern)
|
||||
{
|
||||
return _cairo_atomic_ptr_cmpxchg (slot, NULL, pattern) == NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
_freed_pattern_get (freed_pool_t *pool)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
int i;
|
||||
|
||||
i = pool->top - 1;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
|
||||
pattern = _atomic_fetch (&pool->pool[i]);
|
||||
if (pattern != NULL) {
|
||||
pool->top = i;
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/* either empty or contended */
|
||||
for (i = ARRAY_LENGTH (pool->pool); i--;) {
|
||||
pattern = _atomic_fetch (&pool->pool[i]);
|
||||
if (pattern != NULL) {
|
||||
pool->top = i;
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
/* empty */
|
||||
pool->top = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_freed_pattern_put (freed_pool_t *pool,
|
||||
cairo_pattern_t *pattern)
|
||||
{
|
||||
int i = pool->top;
|
||||
|
||||
if (_atomic_store (&pool->pool[i], pattern)) {
|
||||
pool->top = i + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* either full or contended */
|
||||
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
|
||||
if (_atomic_store (&pool->pool[i], pattern)) {
|
||||
pool->top = i + 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* full */
|
||||
pool->top = ARRAY_LENGTH (pool->pool);
|
||||
free (pattern);
|
||||
}
|
||||
|
||||
static void
|
||||
_freed_patterns_reset (void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) {
|
||||
freed_pool_t *pool = &freed_pattern_pool[i];
|
||||
for (j = 0; j < ARRAY_LENGTH (pool->pool); j++) {
|
||||
free (pool->pool[j]);
|
||||
pool->pool[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cairo_pattern_t *
|
||||
_cairo_pattern_create_solid (const cairo_color_t *color,
|
||||
|
|
@ -419,17 +501,8 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
|
|||
{
|
||||
cairo_solid_pattern_t *pattern = NULL;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
|
||||
if (solid_pattern_cache.size) {
|
||||
int i = --solid_pattern_cache.size %
|
||||
ARRAY_LENGTH (solid_pattern_cache.patterns);
|
||||
pattern = solid_pattern_cache.patterns[i];
|
||||
solid_pattern_cache.patterns[i] = NULL;
|
||||
}
|
||||
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
|
||||
pattern =
|
||||
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
|
||||
if (unlikely (pattern == NULL)) {
|
||||
/* None cached, need to create a new pattern. */
|
||||
pattern = malloc (sizeof (cairo_solid_pattern_t));
|
||||
|
|
@ -445,23 +518,6 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
|
|||
return &pattern->base;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_pattern_reset_solid_pattern_cache (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
|
||||
for (i = 0; i < MIN (ARRAY_LENGTH (solid_pattern_cache.patterns), solid_pattern_cache.size); i++) {
|
||||
if (solid_pattern_cache.patterns[i])
|
||||
free (solid_pattern_cache.patterns[i]);
|
||||
solid_pattern_cache.patterns[i] = NULL;
|
||||
}
|
||||
solid_pattern_cache.size = 0;
|
||||
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
}
|
||||
|
||||
static const cairo_pattern_t *
|
||||
_cairo_pattern_create_in_error (cairo_status_t status)
|
||||
{
|
||||
|
|
@ -584,10 +640,14 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
|
|||
if (surface->status)
|
||||
return (cairo_pattern_t*) _cairo_pattern_create_in_error (surface->status);
|
||||
|
||||
pattern = malloc (sizeof (cairo_surface_pattern_t));
|
||||
pattern =
|
||||
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *)&_cairo_pattern_nil.base;
|
||||
pattern = malloc (sizeof (cairo_surface_pattern_t));
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *)&_cairo_pattern_nil.base;
|
||||
}
|
||||
}
|
||||
|
||||
CAIRO_MUTEX_INITIALIZE ();
|
||||
|
|
@ -630,10 +690,14 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
|
|||
{
|
||||
cairo_linear_pattern_t *pattern;
|
||||
|
||||
pattern = malloc (sizeof (cairo_linear_pattern_t));
|
||||
pattern =
|
||||
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
|
||||
pattern = malloc (sizeof (cairo_linear_pattern_t));
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
|
||||
}
|
||||
}
|
||||
|
||||
CAIRO_MUTEX_INITIALIZE ();
|
||||
|
|
@ -678,10 +742,14 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
|
|||
{
|
||||
cairo_radial_pattern_t *pattern;
|
||||
|
||||
pattern = malloc (sizeof (cairo_radial_pattern_t));
|
||||
pattern =
|
||||
_freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
|
||||
pattern = malloc (sizeof (cairo_radial_pattern_t));
|
||||
if (unlikely (pattern == NULL)) {
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
|
||||
}
|
||||
}
|
||||
|
||||
CAIRO_MUTEX_INITIALIZE ();
|
||||
|
|
@ -780,23 +848,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
|
|||
_cairo_pattern_fini (pattern);
|
||||
|
||||
/* maintain a small cache of freed patterns */
|
||||
if (type == CAIRO_PATTERN_TYPE_SOLID) {
|
||||
int i;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
|
||||
i = solid_pattern_cache.size++ %
|
||||
ARRAY_LENGTH (solid_pattern_cache.patterns);
|
||||
/* swap an old pattern for this 'cache-hot' pattern */
|
||||
if (solid_pattern_cache.patterns[i])
|
||||
free (solid_pattern_cache.patterns[i]);
|
||||
|
||||
solid_pattern_cache.patterns[i] = (cairo_solid_pattern_t *) pattern;
|
||||
|
||||
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
|
||||
} else {
|
||||
free (pattern);
|
||||
}
|
||||
_freed_pattern_put (&freed_pattern_pool[type], pattern);
|
||||
}
|
||||
slim_hidden_def (cairo_pattern_destroy);
|
||||
|
||||
|
|
@ -2931,6 +2983,6 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
|
|||
void
|
||||
_cairo_pattern_reset_static_data (void)
|
||||
{
|
||||
_cairo_pattern_reset_solid_pattern_cache ();
|
||||
_freed_patterns_reset ();
|
||||
_cairo_pattern_reset_solid_surface_cache ();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue