diff options
author | Benjamin Otte <otte@redhat.com> | 2010-06-04 12:25:52 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2010-06-07 13:37:49 +0200 |
commit | 39143400ddd0d4e63a72ce91c423f764e466e405 (patch) | |
tree | f5d76f7aae1d35d68b1c88e1062245e2a0b88c13 | |
parent | 932ab2641ea3183171c3b5699c96c4709fc6bd49 (diff) |
gl: Add a gradient texture cache
For firefox-planet-gnome, 19135 times a gradient gets rendered using
only 10 different gradients. So we get a 100% hit rate in the cache.
Unfortunately, texture upload is not the biggest problem of this test,
as the performance increase is only moderate - at least on i965:
34.3s => 33.5s
-rw-r--r-- | src/cairo-gl-device.c | 12 | ||||
-rw-r--r-- | src/cairo-gl-gradient-private.h | 18 | ||||
-rw-r--r-- | src/cairo-gl-gradient.c | 58 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 2 |
4 files changed, 81 insertions, 9 deletions
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c index 54a2fde8..51b72e00 100644 --- a/src/cairo-gl-device.c +++ b/src/cairo-gl-device.c @@ -104,6 +104,8 @@ _gl_finish (void *device) _gl_lock (device); + _cairo_cache_fini (&ctx->gradients); + _cairo_gl_context_fini_shaders (ctx); _gl_unlock (device); @@ -201,7 +203,15 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) status = _cairo_gl_context_init_shaders (ctx); if (unlikely (status)) - return status; + return status; + + status = _cairo_cache_init (&ctx->gradients, + _cairo_gl_gradient_equal, + NULL, + (cairo_destroy_func_t) _cairo_gl_gradient_destroy, + CAIRO_GL_GRADIENT_CACHE_SIZE); + if (unlikely (status)) + return status; /* Set up the dummy texture for tex_env_combine with constant color. */ glGenTextures (1, &ctx->dummy_tex); diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h index 3c3b52e2..60e0525a 100644 --- a/src/cairo-gl-gradient-private.h +++ b/src/cairo-gl-gradient-private.h @@ -41,6 +41,7 @@ #ifndef CAIRO_GL_GRADIENT_PRIVATE_H #define CAIRO_GL_GRADIENT_PRIVATE_H +#include "cairo-cache-private.h" #include "cairo-device-private.h" #include "cairo-reference-count-private.h" #include "cairo-types-private.h" @@ -53,15 +54,19 @@ #define GL_GLEXT_PROTOTYPES #include <GL/glext.h> +#define CAIRO_GL_GRADIENT_CACHE_SIZE 4096 + /* XXX: Declare in a better place */ typedef struct _cairo_gl_context cairo_gl_context_t; typedef struct _cairo_gl_gradient { - cairo_reference_count_t ref_count; - cairo_device_t *device; /* NB: we don't hold a reference */ - GLuint tex; - unsigned int n_stops; - cairo_gradient_stop_t stops[2]; + cairo_cache_entry_t cache_entry; + cairo_reference_count_t ref_count; + cairo_device_t *device; /* NB: we don't hold a reference */ + GLuint tex; + unsigned int n_stops; + const cairo_gradient_stop_t *stops; + cairo_gradient_stop_t stops_embedded[2]; } cairo_gl_gradient_t; cairo_private cairo_int_status_t @@ -76,5 +81,8 @@ _cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient); cairo_private void _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient); +cairo_private cairo_bool_t +_cairo_gl_gradient_equal (const void *key_a, const void *key_b); + #endif /* CAIRO_GL_GRADIENT_PRIVATE_H */ diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c index 78d74f14..cad38d46 100644 --- a/src/cairo-gl-gradient.c +++ b/src/cairo-gl-gradient.c @@ -149,12 +149,49 @@ _cairo_gl_gradient_render (const cairo_gl_context_t *ctx, return CAIRO_STATUS_SUCCESS; } +static unsigned long +_cairo_gl_gradient_hash (unsigned int n_stops, + const cairo_gradient_stop_t *stops) +{ + return _cairo_hash_bytes (n_stops, + stops, + sizeof (cairo_gradient_stop_t) * n_stops); +} + +static cairo_gl_gradient_t * +_cairo_gl_gradient_lookup (cairo_gl_context_t *ctx, + unsigned long hash, + unsigned int n_stops, + const cairo_gradient_stop_t *stops) +{ + cairo_gl_gradient_t lookup; + + lookup.cache_entry.hash = hash, + lookup.n_stops = n_stops; + lookup.stops = stops; + + return _cairo_cache_lookup (&ctx->gradients, &lookup.cache_entry); +} + +cairo_bool_t +_cairo_gl_gradient_equal (const void *key_a, const void *key_b) +{ + const cairo_gl_gradient_t *a = key_a; + const cairo_gl_gradient_t *b = key_b; + + if (a->n_stops != b->n_stops) + return FALSE; + + return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0; +} + cairo_int_status_t _cairo_gl_gradient_create (cairo_gl_context_t *ctx, unsigned int n_stops, const cairo_gradient_stop_t *stops, cairo_gl_gradient_t **gradient_out) { + unsigned long hash; cairo_gl_gradient_t *gradient; int tex_width; void *data; @@ -163,16 +200,27 @@ _cairo_gl_gradient_create (cairo_gl_context_t *ctx, if ((unsigned int) ctx->max_texture_size / 2 <= n_stops) return CAIRO_INT_STATUS_UNSUPPORTED; + hash = _cairo_gl_gradient_hash (n_stops, stops); + + gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops); + if (gradient) { + *gradient_out = _cairo_gl_gradient_reference (gradient); + return CAIRO_STATUS_SUCCESS; + } + gradient = malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 2)); if (gradient == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + tex_width = _cairo_gl_gradient_sample_width (n_stops, stops); + CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1); + gradient->cache_entry.hash = hash; + gradient->cache_entry.size = tex_width; gradient->device = &ctx->base; gradient->n_stops = n_stops; - memcpy (gradient->stops, stops, n_stops * sizeof (cairo_gradient_stop_t)); - - tex_width = _cairo_gl_gradient_sample_width (n_stops, stops); + gradient->stops = gradient->stops_embedded; + memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t)); glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, ctx->texture_load_pbo); glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, tex_width * sizeof (uint32_t), 0, GL_STREAM_DRAW); @@ -190,6 +238,10 @@ _cairo_gl_gradient_create (cairo_gl_context_t *ctx, glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0); + /* we ignore errors here and just return an uncached gradient */ + if (likely (! _cairo_cache_insert (&ctx->gradients, &gradient->cache_entry))) + _cairo_gl_gradient_reference (gradient); + *gradient_out = gradient; return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 689c7696..a02e279f 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -181,6 +181,8 @@ struct _cairo_gl_context { cairo_gl_shader_t fill_rectangles_shader; cairo_cache_t shaders; + cairo_cache_t gradients; + cairo_gl_glyph_cache_t glyph_cache[2]; cairo_list_t fonts; |