diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c index c6d5f6d19..b8441c968 100644 --- a/src/cairo-gl-glyphs.c +++ b/src/cairo-gl-glyphs.c @@ -33,7 +33,7 @@ #include "cairoint.h" #include "cairo-gl-private.h" -#include "cairo-freelist-private.h" +#include "cairo-rtree-private.h" #define GLYPH_CACHE_WIDTH 1024 #define GLYPH_CACHE_HEIGHT 1024 @@ -41,314 +41,18 @@ #define GLYPH_CACHE_MAX_SIZE 128 typedef struct _cairo_gl_glyph_private { - rtree_node_t node; - void **owner; + cairo_rtree_node_t node; + cairo_gl_glyph_cache_t *cache; struct { float x, y; } p1, p2; } cairo_gl_glyph_private_t; -static void -_rtree_node_evict (rtree_t *rtree, rtree_node_t *node) -{ - rtree->evict (node); - node->state = RTREE_NODE_AVAILABLE; -} - -static rtree_node_t * -_rtree_node_create (rtree_t *rtree, - rtree_node_t *parent, - int x, - int y, - int width, - int height) -{ - rtree_node_t *node; - - /* XXX chunked freelist */ - node = _cairo_freelist_alloc (&rtree->node_freelist); - if (node == NULL) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return NULL; - } - - memset (node->children, 0, sizeof (node->children)); - node->parent = parent; - node->state = RTREE_NODE_AVAILABLE; - node->locked = FALSE; - node->x = x; - node->y = y; - node->width = width; - node->height = height; - - return node; -} - -static void -_rtree_node_destroy (rtree_t *rtree, rtree_node_t *node) -{ - int i; - - if (node == NULL) - return; - - if (node->state == RTREE_NODE_OCCUPIED) { - _rtree_node_evict (rtree, node); - } else { - for (i = 0; i < 4 && node->children[i] != NULL; i++) - _rtree_node_destroy (rtree, node->children[i]); - } - - _cairo_freelist_free (&rtree->node_freelist, node); -} - -static cairo_int_status_t -_rtree_insert (rtree_t *rtree, - rtree_node_t *node, - int width, - int height, - rtree_node_t **out) -{ - cairo_status_t status; - int i; - - switch (node->state) { - case RTREE_NODE_DIVIDED: - for (i = 0; i < 4 && node->children[i] != NULL; i++) { - if (node->children[i]->width >= width && - node->children[i]->height >= height) - { - status = _rtree_insert (rtree, node->children[i], - width, height, - out); - if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - } - } - - default: - case RTREE_NODE_OCCUPIED: - return CAIRO_INT_STATUS_UNSUPPORTED; - - case RTREE_NODE_AVAILABLE: - if (node->width - width > GLYPH_CACHE_MIN_SIZE || - node->height - height > GLYPH_CACHE_MIN_SIZE) - { - int w, h; - - w = node->width - width; - h = node->height - height; - - i = 0; - node->children[i] = _rtree_node_create (rtree, node, - node->x, node->y, - width, height); - if (unlikely (node->children[i] == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - i++; - - if (w > GLYPH_CACHE_MIN_SIZE) { - node->children[i] = _rtree_node_create (rtree, node, - node->x + width, - node->y, - w, height); - if (unlikely (node->children[i] == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - i++; - } - - if (h > GLYPH_CACHE_MIN_SIZE) { - node->children[i] = _rtree_node_create (rtree, node, - node->x, - node->y + height, - width, h); - if (unlikely (node->children[i] == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - i++; - - if (w > GLYPH_CACHE_MIN_SIZE) { - node->children[i] = _rtree_node_create (rtree, node, - node->x + width, - node->y + height, - w, h); - if (unlikely (node->children[i] == NULL)) - return _cairo_error (CAIRO_STATUS_NO_MEMORY); - i++; - } - } - - node->state = RTREE_NODE_DIVIDED; - node = node->children[0]; - } - - node->state = RTREE_NODE_OCCUPIED; - *out = node; - return CAIRO_STATUS_SUCCESS; - } -} - -static cairo_int_status_t -_rtree_add_evictable_nodes (rtree_t *rtree, - rtree_node_t *node, - int width, - int height, - cairo_array_t *evictable_nodes) -{ - cairo_int_status_t status; - cairo_bool_t child_added = FALSE; - int i; - - switch (node->state) { - case RTREE_NODE_DIVIDED: - for (i = 0; i < 4 && node->children[i] != NULL; i++) { - if (node->children[i]->width >= width && - node->children[i]->height >= height) - { - status = _rtree_add_evictable_nodes (rtree, node->children[i], - width, height, - evictable_nodes); - if (_cairo_status_is_error (status)) - return status; - - child_added |= status == CAIRO_STATUS_SUCCESS; - } - } - if (child_added) - return CAIRO_STATUS_SUCCESS; - - /* fall through */ - case RTREE_NODE_AVAILABLE: - case RTREE_NODE_OCCUPIED: - if (node->locked) - return CAIRO_INT_STATUS_UNSUPPORTED; - } - - return _cairo_array_append (evictable_nodes, &node); -} - -static uint32_t -hars_petruska_f54_1_random (void) -{ -#define rol(x,k) ((x << k) | (x >> (32-k))) - static uint32_t x; - return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; -#undef rol -} - -static cairo_int_status_t -_rtree_evict_random (rtree_t *rtree, - rtree_node_t *root, - int width, - int height, - rtree_node_t **out) -{ - cairo_array_t evictable_nodes; - cairo_status_t status; - int i; - - _cairo_array_init (&evictable_nodes, sizeof (rtree_node_t *)); - - status = _rtree_add_evictable_nodes (rtree, root, - width, height, - &evictable_nodes); - if (status == CAIRO_STATUS_SUCCESS) { - rtree_node_t *node; - - node = *(rtree_node_t **) - _cairo_array_index (&evictable_nodes, - hars_petruska_f54_1_random () % evictable_nodes.num_elements); - if (node->state == RTREE_NODE_OCCUPIED) { - _rtree_node_evict (rtree, node); - } else { - for (i = 0; i < 4 && node->children[i] != NULL; i++) { - _rtree_node_destroy (rtree, node->children[i]); - node->children[i] = NULL; - } - } - - node->state = RTREE_NODE_AVAILABLE; - *out = node; - } - - _cairo_array_fini (&evictable_nodes); - - return status; -} - -static void * -_rtree_lock (rtree_t *rtree, rtree_node_t *node) -{ - void *ptr = node; - - while (node != NULL && ! node->locked) { - node->locked = TRUE; - node = node->parent; - } - - return ptr; -} - -static void -_rtree_unlock (rtree_t *rtree, rtree_node_t *node) -{ - int i; - - if (! node->locked) - return; - - node->locked = FALSE; - if (node->state == RTREE_NODE_DIVIDED) { - for (i = 0; i < 4 && node->children[i] != NULL; i++) - _rtree_unlock (rtree, node->children[i]); - } -} - -static void -_rtree_init (rtree_t *rtree, - int width, - int height, - int node_size, - void (*evict) (void *node)) -{ - rtree->evict = evict; - - assert (node_size >= (int) sizeof (rtree_node_t)); - _cairo_freelist_init (&rtree->node_freelist, node_size); - - memset (&rtree->root, 0, sizeof (rtree->root)); - rtree->root.width = width; - rtree->root.height = height; -} - -static void -_rtree_fini (rtree_t *rtree) -{ - int i; - - if (rtree->root.state == RTREE_NODE_OCCUPIED) { - _rtree_node_evict (rtree, &rtree->root); - } else { - for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) - _rtree_node_destroy (rtree, rtree->root.children[i]); - } - - _cairo_freelist_fini (&rtree->node_freelist); -} - -static void -_glyph_evict (void *node) -{ - cairo_gl_glyph_private_t *glyph_private = node; - - if (glyph_private->owner != NULL) - *glyph_private->owner = NULL; -} - static cairo_status_t _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, cairo_scaled_glyph_t *scaled_glyph) { cairo_image_surface_t *glyph_surface = scaled_glyph->surface; cairo_gl_glyph_private_t *glyph_private; - rtree_node_t *node = NULL; + cairo_rtree_node_t *node = NULL; cairo_status_t status; int width, height; GLenum internal_format, format, type; @@ -370,14 +74,15 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, height = GLYPH_CACHE_MIN_SIZE; /* search for an available slot */ - status = _rtree_insert (&cache->rtree, &cache->rtree.root, - width, height, &node); + status = _cairo_rtree_insert (&cache->rtree, width, height, &node); /* search for an unlocked slot */ if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - status = _rtree_evict_random (&cache->rtree, &cache->rtree.root, - width, height, &node); - if (status == CAIRO_STATUS_SUCCESS) - status = _rtree_insert (&cache->rtree, node, width, height, &node); + status = _cairo_rtree_evict_random (&cache->rtree, + width, height, &node); + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_rtree_node_insert (&cache->rtree, + node, width, height, &node); + } } if (status) return status; @@ -394,9 +99,10 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_glyph_cache_t *cache, glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); scaled_glyph->surface_private = node; + node->owner = &scaled_glyph->surface_private; glyph_private = (cairo_gl_glyph_private_t *) node; - glyph_private->owner = &scaled_glyph->surface_private; + glyph_private->cache = cache; /* compute tex coords */ glyph_private->p1.x = node->x / (double) cache->width; @@ -413,59 +119,14 @@ static cairo_gl_glyph_private_t * _cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache, cairo_scaled_glyph_t *scaled_glyph) { - return _rtree_lock (&cache->rtree, scaled_glyph->surface_private); + return _cairo_rtree_pin (&cache->rtree, scaled_glyph->surface_private); } -static cairo_status_t -cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache, - cairo_gl_context_t *ctx, - cairo_format_t format, - int width, int height) -{ - cairo_content_t content; - GLenum internal_format; - - assert ((width & 3) == 0); - assert ((height & 1) == 0); - cache->width = width; - cache->height = height; - - switch (format) { - case CAIRO_FORMAT_A1: - case CAIRO_FORMAT_RGB24: - ASSERT_NOT_REACHED; - case CAIRO_FORMAT_ARGB32: - content = CAIRO_CONTENT_COLOR_ALPHA; - internal_format = GL_RGBA; - break; - case CAIRO_FORMAT_A8: - content = CAIRO_CONTENT_ALPHA; - internal_format = GL_ALPHA; - break; - } - - glGenTextures (1, &cache->tex); - glBindTexture (GL_TEXTURE_2D, cache->tex); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D (GL_TEXTURE_2D, 0, internal_format, - width, height, 0, internal_format, GL_FLOAT, NULL); - - _rtree_init (&cache->rtree, - width, height, - sizeof (cairo_gl_glyph_private_t), - _glyph_evict); - - return CAIRO_STATUS_SUCCESS; -} - -static cairo_status_t +static cairo_gl_glyph_cache_t * cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, - cairo_format_t format, - cairo_gl_glyph_cache_t **out) + cairo_format_t format) { cairo_gl_glyph_cache_t *cache; - cairo_status_t status; switch (format) { case CAIRO_FORMAT_ARGB32: @@ -481,15 +142,33 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx, } if (unlikely (cache->tex == 0)) { - status = cairo_gl_glyph_cache_init (cache, ctx, format, - GLYPH_CACHE_WIDTH, - GLYPH_CACHE_HEIGHT); - if (unlikely (status)) - return status; + GLenum internal_format; + + cache->width = GLYPH_CACHE_WIDTH; + cache->height = GLYPH_CACHE_HEIGHT; + + switch (format) { + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB24: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_ARGB32: + internal_format = GL_RGBA; + break; + case CAIRO_FORMAT_A8: + internal_format = GL_ALPHA; + break; + } + + glGenTextures (1, &cache->tex); + glBindTexture (GL_TEXTURE_2D, cache->tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D (GL_TEXTURE_2D, 0, internal_format, + GLYPH_CACHE_WIDTH, GLYPH_CACHE_HEIGHT, 0, + internal_format, GL_FLOAT, NULL); } - *out = cache; - return CAIRO_STATUS_SUCCESS; + return cache; } static cairo_bool_t @@ -516,8 +195,13 @@ _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_gl_glyph_private_t *glyph_private; glyph_private = scaled_glyph->surface_private; - if (glyph_private != NULL) - glyph_private->owner = NULL; + if (glyph_private != NULL) { + glyph_private->node.owner = NULL; + if (! glyph_private->node.pinned) { + _cairo_rtree_node_collapse (&glyph_private->cache->rtree, + glyph_private->node.parent); + } + } } typedef struct _cairo_gl_glyphs_setup @@ -576,10 +260,8 @@ _cairo_gl_flush_glyphs (cairo_gl_context_t *ctx, } } - for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++) { - _rtree_unlock (&ctx->glyph_cache[i].rtree, - &ctx->glyph_cache[i].rtree.root); - } + for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++) + _cairo_rtree_unpin (&ctx->glyph_cache[i].rtree); } static void @@ -848,11 +530,8 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, _cairo_gl_flush_glyphs (ctx, &setup); glActiveTexture (GL_TEXTURE1); - status = cairo_gl_context_get_glyph_cache (ctx, - scaled_glyph->surface->format, - &cache); - if (unlikely (status)) - goto FINISH; + cache = cairo_gl_context_get_glyph_cache (ctx, + scaled_glyph->surface->format); glBindTexture (GL_TEXTURE_2D, cache->tex); @@ -929,5 +608,18 @@ _cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache) glDeleteTextures (1, &cache->tex); - _rtree_fini (&cache->rtree); + _cairo_rtree_fini (&cache->rtree); +} + +void +_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache) +{ + cache->tex = 0; + + _cairo_rtree_init (&cache->rtree, + GLYPH_CACHE_WIDTH, + GLYPH_CACHE_HEIGHT, + GLYPH_CACHE_MIN_SIZE, + sizeof (cairo_gl_glyph_private_t), + NULL); } diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 5ca48adee..454971f2d 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -40,7 +40,7 @@ #define CAIRO_GL_PRIVATE_H #include "cairoint.h" -#include "cairo-freelist-private.h" +#include "cairo-rtree-private.h" #include @@ -61,27 +61,8 @@ typedef struct _cairo_gl_surface { GLuint fb; /* GL framebuffer object wrapping our data. */ } cairo_gl_surface_t; -enum { - RTREE_NODE_AVAILABLE, - RTREE_NODE_DIVIDED, - RTREE_NODE_OCCUPIED, -}; -typedef struct _rtree_node { - struct _rtree_node *children[4], *parent; - uint16_t state; - uint16_t locked; - uint16_t x, y; - uint16_t width, height; -} rtree_node_t; - -typedef struct _rtree { - rtree_node_t root; - void (*evict) (void *node); - cairo_freelist_t node_freelist; -} rtree_t; - typedef struct cairo_gl_glyph_cache { - rtree_t rtree; + cairo_rtree_t rtree; GLuint tex; unsigned int width, height; } cairo_gl_glyph_cache_t; @@ -133,7 +114,7 @@ typedef struct _cairo_gl_composite_setup { cairo_gl_composite_operand_t mask; } cairo_gl_composite_setup_t; -extern const cairo_surface_backend_t _cairo_gl_surface_backend; +cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend; cairo_private cairo_gl_context_t * _cairo_gl_context_create_in_error (cairo_status_t status); @@ -147,14 +128,14 @@ _cairo_gl_surface_init (cairo_gl_context_t *ctx, cairo_content_t content, int width, int height); -cairo_status_t +cairo_private cairo_status_t _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, int dst_x, int dst_y); -cairo_int_status_t +cairo_private cairo_int_status_t _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand, const cairo_pattern_t *pattern, cairo_gl_surface_t *dst, @@ -162,35 +143,38 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand, int dst_x, int dst_y, int width, int height); -cairo_gl_context_t * +cairo_private cairo_gl_context_t * _cairo_gl_context_acquire (cairo_gl_context_t *ctx); -void +cairo_private void _cairo_gl_context_release (cairo_gl_context_t *ctx); -void +cairo_private void _cairo_gl_set_destination (cairo_gl_surface_t *surface); -int +cairo_private int _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op); -void +cairo_private void _cairo_gl_set_src_operand (cairo_gl_context_t *ctx, cairo_gl_composite_setup_t *setup); -void +cairo_private void _cairo_gl_operand_destroy (cairo_gl_composite_operand_t *operand); -cairo_status_t +cairo_private cairo_status_t _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format, GLenum *internal_format, GLenum *format, GLenum *type, cairo_bool_t *has_alpha); -void +cairo_private void _cairo_gl_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_font_t *scaled_font); -cairo_int_status_t +cairo_private void +_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache); + +cairo_private cairo_int_status_t _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_operator_t op, const cairo_pattern_t *source, @@ -200,7 +184,7 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst, cairo_clip_t *clip, int *remaining_glyphs); -void +cairo_private void _cairo_gl_glyph_cache_fini (cairo_gl_glyph_cache_t *cache); #endif /* CAIRO_GL_PRIVATE_H */ diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c index 7055bc7f3..daa2bbcef 100644 --- a/src/cairo-gl-surface.c +++ b/src/cairo-gl-surface.c @@ -82,6 +82,8 @@ _cairo_gl_context_create_in_error (cairo_status_t status) cairo_status_t _cairo_gl_context_init (cairo_gl_context_t *ctx) { + int n; + ctx->status = CAIRO_STATUS_SUCCESS; CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1); CAIRO_MUTEX_INIT (ctx->mutex); @@ -121,6 +123,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx) ctx->max_texture_size = 0; glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size); + for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++) + _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]); + return CAIRO_STATUS_SUCCESS; }