diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-07 17:47:34 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-12-07 18:00:18 +0000 |
commit | d828c724c06cea151fc87ef2bb98e57be0cdba46 (patch) | |
tree | cd91079bf5d99001f3d8535aca542068eac97687 | |
parent | 98335b43907b25585c597ae0ff657fdb45c29b05 (diff) |
gl: Decouple the glyph upon eviction
In order to decouple the texture node from the scaled glyph cache, we
need to add a callback from the rtree for when the node is removed.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/cairo-gl-composite.c | 4 | ||||
-rw-r--r-- | src/cairo-gl-glyphs.c | 55 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 7 | ||||
-rw-r--r-- | src/cairo-rtree-private.h | 6 | ||||
-rw-r--r-- | src/cairo-rtree.c | 99 |
5 files changed, 81 insertions, 90 deletions
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index 777a7148..ebd94558 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -614,6 +614,7 @@ void _cairo_gl_composite_flush (cairo_gl_context_t *ctx) { unsigned int count; + int i; if (_cairo_gl_context_is_flushed (ctx)) return; @@ -637,6 +638,9 @@ _cairo_gl_composite_flush (cairo_gl_context_t *ctx) } else { _cairo_gl_composite_draw (ctx, count); } + + for (i = 0; i < ARRAY_LENGTH (&ctx->glyph_cache); i++) + _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]); } static void diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index 63678ff6..c553d7d4 100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -54,11 +54,30 @@ typedef struct _cairo_gl_glyph { cairo_rtree_node_t node; cairo_scaled_glyph_private_t base; + cairo_scaled_glyph_t *glyph; cairo_gl_glyph_cache_t *cache; struct { float x, y; } p1, p2; } cairo_gl_glyph_t; static void +_cairo_gl_node_destroy (cairo_rtree_node_t *node) +{ + cairo_gl_glyph_t *priv = cairo_container_of (node, cairo_gl_glyph_t, node); + cairo_scaled_glyph_t *glyph; + + glyph = priv->glyph; + if (glyph == NULL) + return; + + if (glyph->dev_private_key == priv->cache) { + glyph->dev_private = NULL; + glyph->dev_private_key = NULL; + } + cairo_list_del (&priv->base.link); + priv->glyph = NULL; +} + +static void _cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *glyph_private, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font) @@ -67,13 +86,15 @@ _cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *glyph_private, cairo_gl_glyph_t, base); - cairo_list_del (&glyph_private->link); + assert (priv->glyph); + + _cairo_gl_node_destroy (&priv->node); - priv->node.owner = NULL; - if (! priv->node.pinned) { - /* XXX thread-safety? Probably ok due to the frozen scaled-font. */ + /* XXX thread-safety? Probably ok due to the frozen scaled-font. */ + if (! priv->node.pinned) _cairo_rtree_node_remove (&priv->cache->rtree, &priv->node); - } + + assert (priv->glyph == NULL); } static cairo_int_status_t @@ -119,11 +140,11 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx, glyph_private = (cairo_gl_glyph_t *) node; glyph_private->cache = cache; + glyph_private->glyph = scaled_glyph; _cairo_scaled_glyph_attach_private (scaled_glyph, &glyph_private->base, cache, _cairo_gl_glyph_fini); - glyph_private->node.owner = (void*)scaled_glyph; scaled_glyph->dev_private = glyph_private; scaled_glyph->dev_private_key = cache; @@ -198,12 +219,6 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, return CAIRO_STATUS_SUCCESS; } -static void -_cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache) -{ - _cairo_rtree_unpin (&cache->rtree); -} - static cairo_status_t render_glyphs (cairo_gl_surface_t *dst, int dst_x, int dst_y, @@ -445,26 +460,14 @@ _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache) GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, GLYPH_CACHE_MIN_SIZE, - sizeof (cairo_gl_glyph_t)); -} - -static void -_cairo_gl_glyph_cache_fini_glyph (cairo_rtree_node_t *node, - void *cache) -{ - cairo_gl_glyph_t *glyph_private = (cairo_gl_glyph_t *) node; - if (glyph_private->node.owner) { - cairo_list_del (&glyph_private->base.link); - glyph_private->node.owner = NULL; - } + sizeof (cairo_gl_glyph_t), + _cairo_gl_node_destroy); } void _cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx, cairo_gl_glyph_cache_t *cache) { - _cairo_rtree_foreach (&cache->rtree, - _cairo_gl_glyph_cache_fini_glyph, NULL); _cairo_rtree_fini (&cache->rtree); cairo_surface_destroy (&cache->surface->base); } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 856f5220..05d1567c 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -721,6 +721,13 @@ source_to_operand (cairo_surface_t *surface) return source ? &source->operand : NULL; } +static inline void +_cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache) +{ + _cairo_rtree_unpin (&cache->rtree); +} + + slim_hidden_proto (cairo_gl_surface_create); slim_hidden_proto (cairo_gl_surface_create_for_texture); diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h index 3289f795..b8db477a 100644 --- a/src/cairo-rtree-private.h +++ b/src/cairo-rtree-private.h @@ -52,7 +52,6 @@ enum { typedef struct _cairo_rtree_node { struct _cairo_rtree_node *children[4], *parent; - void **owner; cairo_list_t link; uint16_t pinned; uint16_t state; @@ -66,6 +65,7 @@ typedef struct _cairo_rtree { cairo_list_t pinned; cairo_list_t available; cairo_list_t evictable; + void (*destroy) (cairo_rtree_node_t *); cairo_freepool_t node_freepool; } cairo_rtree_t; @@ -98,7 +98,8 @@ _cairo_rtree_init (cairo_rtree_t *rtree, int width, int height, int min_size, - int node_size); + int node_size, + void (*destroy)(cairo_rtree_node_t *)); cairo_private cairo_int_status_t _cairo_rtree_insert (cairo_rtree_t *rtree, @@ -120,6 +121,7 @@ _cairo_rtree_foreach (cairo_rtree_t *rtree, static inline void * _cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node) { + assert (node->state == CAIRO_RTREE_NODE_OCCUPIED); if (! node->pinned) { cairo_list_move (&node->link, &rtree->pinned); node->pinned = 1; diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c index 94af45b8..dbc04092 100644 --- a/src/cairo-rtree.c +++ b/src/cairo-rtree.c @@ -57,7 +57,6 @@ _cairo_rtree_node_create (cairo_rtree_t *rtree, node->children[0] = NULL; node->parent = parent; - node->owner = NULL; node->state = CAIRO_RTREE_NODE_AVAILABLE; node->pinned = FALSE; node->x = x; @@ -78,8 +77,7 @@ _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) cairo_list_del (&node->link); if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { - if (node->owner != NULL) - *node->owner = NULL; + rtree->destroy (node); } else { for (i = 0; i < 4 && node->children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, node->children[i]); @@ -186,6 +184,8 @@ _cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node) assert (node->state == CAIRO_RTREE_NODE_OCCUPIED); assert (node->pinned == FALSE); + rtree->destroy (node); + node->state = CAIRO_RTREE_NODE_AVAILABLE; cairo_list_move (&node->link, &rtree->available); @@ -225,15 +225,22 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, int height, cairo_rtree_node_t **out) { + cairo_int_status_t ret = CAIRO_INT_STATUS_UNSUPPORTED; cairo_rtree_node_t *node, *next; + cairo_list_t tmp_pinned; int i, cnt; + cairo_list_init (&tmp_pinned); + /* propagate pinned from children to root */ - cairo_list_foreach_entry_safe (node, next, cairo_rtree_node_t, - &rtree->pinned, link) - { - if (node->parent != NULL) - _cairo_rtree_pin (rtree, node->parent); + cairo_list_foreach_entry_safe (node, next, + cairo_rtree_node_t, &rtree->pinned, link) { + node = node->parent; + while (node && ! node->pinned) { + node->pinned = 1; + cairo_list_move (&node->link, &tmp_pinned); + node = node->parent; + } } cnt = 0; @@ -245,7 +252,7 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, } if (cnt == 0) - return CAIRO_INT_STATUS_UNSUPPORTED; + goto out; cnt = hars_petruska_f54_1_random () % cnt; cairo_list_foreach_entry (node, cairo_rtree_node_t, @@ -253,8 +260,7 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, { if (node->width >= width && node->height >= height && cnt-- == 0) { if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { - if (node->owner != NULL) - *node->owner = NULL; + rtree->destroy (node); } else { for (i = 0; i < 4 && node->children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, node->children[i]); @@ -265,60 +271,29 @@ _cairo_rtree_evict_random (cairo_rtree_t *rtree, cairo_list_move (&node->link, &rtree->available); *out = node; - return CAIRO_STATUS_SUCCESS; + ret = CAIRO_STATUS_SUCCESS; + break; } } - return CAIRO_INT_STATUS_UNSUPPORTED; +out: + while (! cairo_list_is_empty (&tmp_pinned)) { + node = cairo_list_first_entry (&tmp_pinned, cairo_rtree_node_t, link); + node->pinned = 0; + cairo_list_move (&node->link, &rtree->evictable); + } + return ret; } void _cairo_rtree_unpin (cairo_rtree_t *rtree) { - cairo_rtree_node_t *node, *next; - cairo_list_t can_collapse; - - if (cairo_list_is_empty (&rtree->pinned)) - return; - - cairo_list_init (&can_collapse); - - cairo_list_foreach_entry_safe (node, next, - cairo_rtree_node_t, - &rtree->pinned, - link) - { - node->pinned = FALSE; - if (node->state == CAIRO_RTREE_NODE_OCCUPIED && node->owner == NULL) { - cairo_bool_t all_available; - int i; - - node->state = CAIRO_RTREE_NODE_AVAILABLE; - cairo_list_move (&node->link, &rtree->available); - - all_available = TRUE; - node = node->parent; - for (i = 0; i < 4 && node->children[i] != NULL && all_available; i++) - all_available &= node->children[i]->state == CAIRO_RTREE_NODE_AVAILABLE; - - if (all_available) { - cairo_list_move (&node->link, &can_collapse); - for (i = 0; i < 4 && node->children[i] != NULL; i++) - cairo_list_del (&node->children[i]->link); - } - } - else - { - cairo_list_move (&node->link, &rtree->evictable); - } - } - - cairo_list_foreach_entry_safe (node, next, - cairo_rtree_node_t, - &can_collapse, - link) - { - _cairo_rtree_node_collapse (rtree, node); + while (! cairo_list_is_empty (&rtree->pinned)) { + cairo_rtree_node_t *node = cairo_list_first_entry (&rtree->pinned, + cairo_rtree_node_t, + link); + node->pinned = 0; + cairo_list_move (&node->link, &rtree->evictable); } } @@ -327,7 +302,8 @@ _cairo_rtree_init (cairo_rtree_t *rtree, int width, int height, int min_size, - int node_size) + int node_size, + void (*destroy) (cairo_rtree_node_t *)) { assert (node_size >= (int) sizeof (cairo_rtree_node_t)); _cairo_freepool_init (&rtree->node_freepool, node_size); @@ -337,6 +313,7 @@ _cairo_rtree_init (cairo_rtree_t *rtree, cairo_list_init (&rtree->evictable); rtree->min_size = min_size; + rtree->destroy = destroy; memset (&rtree->root, 0, sizeof (rtree->root)); rtree->root.width = width; @@ -351,8 +328,7 @@ _cairo_rtree_reset (cairo_rtree_t *rtree) int i; if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { - if (rtree->root.owner != NULL) - *rtree->root.owner = NULL; + rtree->destroy (&rtree->root); } else { for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); @@ -402,8 +378,7 @@ _cairo_rtree_fini (cairo_rtree_t *rtree) int i; if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { - if (rtree->root.owner != NULL) - *rtree->root.owner = NULL; + rtree->destroy (&rtree->root); } else { for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); |