summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-12-07 17:47:34 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2011-12-07 18:00:18 +0000
commitd828c724c06cea151fc87ef2bb98e57be0cdba46 (patch)
treecd91079bf5d99001f3d8535aca542068eac97687
parent98335b43907b25585c597ae0ff657fdb45c29b05 (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.c4
-rw-r--r--src/cairo-gl-glyphs.c55
-rw-r--r--src/cairo-gl-private.h7
-rw-r--r--src/cairo-rtree-private.h6
-rw-r--r--src/cairo-rtree.c99
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]);