pango-glyph-cache: Try to put glyphs in the global atlas

If mipmapping is disabled, it will now try to create a standalone
atlas texture for a glyph rather than putting it in the atlas.

If the atlas texture can't be created then it will fallback to the
glyph cache.
This commit is contained in:
Neil Roberts 2010-02-18 17:35:14 +00:00 committed by Robert Bragg
parent c76a4f8e24
commit 25c36c452f

View File

@ -30,6 +30,7 @@
#include "cogl-pango-glyph-cache.h" #include "cogl-pango-glyph-cache.h"
#include "cogl-pango-private.h" #include "cogl-pango-private.h"
#include "cogl/cogl-atlas.h" #include "cogl/cogl-atlas.h"
#include "cogl/cogl-atlas-texture-private.h"
typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey; typedef struct _CoglPangoGlyphCacheKey CoglPangoGlyphCacheKey;
@ -49,6 +50,10 @@ struct _CoglPangoGlyphCache
optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid optimization in _cogl_pango_glyph_cache_set_dirty_glyphs to avoid
iterating the hash table if we know none of them are dirty */ iterating the hash table if we know none of them are dirty */
gboolean has_dirty_glyphs; gboolean has_dirty_glyphs;
/* Whether mipmapping is being used for this cache. This only
affects whether we decide to put the glyph in the global atlas */
gboolean use_mipmapping;
}; };
struct _CoglPangoGlyphCacheKey struct _CoglPangoGlyphCacheKey
@ -118,6 +123,8 @@ cogl_pango_glyph_cache_new (gboolean use_mipmapping)
cache->has_dirty_glyphs = FALSE; cache->has_dirty_glyphs = FALSE;
cache->use_mipmapping = use_mipmapping;
return cache; return cache;
} }
@ -179,6 +186,86 @@ cogl_pango_glyph_cache_reorganize_cb (void *user_data)
g_hook_list_invoke (&cache->reorganize_callbacks, FALSE); g_hook_list_invoke (&cache->reorganize_callbacks, FALSE);
} }
static gboolean
cogl_pango_glyph_cache_add_to_global_atlas (CoglPangoGlyphCache *cache,
PangoFont *font,
PangoGlyph glyph,
CoglPangoGlyphCacheValue *value)
{
CoglHandle texture;
/* If the cache is using mipmapping then we can't use the global
atlas because it would just get migrated back out */
if (cache->use_mipmapping)
return FALSE;
texture = _cogl_atlas_texture_new_with_size (value->draw_width,
value->draw_height,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
if (texture == COGL_INVALID_HANDLE)
return FALSE;
value->texture = texture;
value->tx1 = 0;
value->ty1 = 0;
value->tx2 = 1;
value->ty2 = 1;
value->tx_pixel = 0;
value->ty_pixel = 0;
return TRUE;
}
static gboolean
cogl_pango_glyph_cache_add_to_local_atlas (CoglPangoGlyphCache *cache,
PangoFont *font,
PangoGlyph glyph,
CoglPangoGlyphCacheValue *value)
{
CoglAtlas *atlas = NULL;
GSList *l;
/* Look for an atlas that can reserve the space */
for (l = cache->atlases; l; l = l->next)
if (_cogl_atlas_reserve_space (l->data,
value->draw_width + 1,
value->draw_height + 1,
value))
{
atlas = l->data;
break;
}
/* If we couldn't find one then start a new atlas */
if (atlas == NULL)
{
atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8,
COGL_ATLAS_CLEAR_TEXTURE |
COGL_ATLAS_DISABLE_MIGRATION,
cogl_pango_glyph_cache_update_position_cb);
COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas);
/* If we still can't reserve space then something has gone
seriously wrong so we'll just give up */
if (!_cogl_atlas_reserve_space (atlas,
value->draw_width + 1,
value->draw_height + 1,
value))
{
cogl_object_unref (atlas);
return FALSE;
}
_cogl_atlas_add_reorganize_callback
(atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache);
cache->atlases = g_slist_prepend (cache->atlases, atlas);
}
return TRUE;
}
CoglPangoGlyphCacheValue * CoglPangoGlyphCacheValue *
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache, cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
gboolean create, gboolean create,
@ -197,55 +284,33 @@ cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
{ {
CoglPangoGlyphCacheKey *key; CoglPangoGlyphCacheKey *key;
PangoRectangle ink_rect; PangoRectangle ink_rect;
CoglAtlas *atlas = NULL;
GSList *l; value = g_slice_new (CoglPangoGlyphCacheValue);
value->texture = COGL_INVALID_HANDLE;
value->dirty = TRUE;
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL); pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL); pango_extents_to_pixels (&ink_rect, NULL);
value = g_slice_new (CoglPangoGlyphCacheValue);
value->texture = COGL_INVALID_HANDLE;
value->draw_x = ink_rect.x; value->draw_x = ink_rect.x;
value->draw_y = ink_rect.y; value->draw_y = ink_rect.y;
value->draw_width = ink_rect.width; value->draw_width = ink_rect.width;
value->draw_height = ink_rect.height; value->draw_height = ink_rect.height;
value->dirty = TRUE;
/* Look for an atlas that can reserve the space */ /* Try adding the glyph to the global atlas... */
for (l = cache->atlases; l; l = l->next) if (!cogl_pango_glyph_cache_add_to_global_atlas (cache,
if (_cogl_atlas_reserve_space (l->data, font,
ink_rect.width + 1, ink_rect.height + 1, glyph,
value) &&
!cogl_pango_glyph_cache_add_to_local_atlas (cache,
font,
glyph,
value)) value))
{ {
atlas = l->data;
break;
}
/* If we couldn't find one then start a new atlas */
if (atlas == NULL)
{
atlas = _cogl_atlas_new (COGL_PIXEL_FORMAT_A_8,
COGL_ATLAS_CLEAR_TEXTURE |
COGL_ATLAS_DISABLE_MIGRATION,
cogl_pango_glyph_cache_update_position_cb);
COGL_NOTE (ATLAS, "Created new atlas for glyphs: %p", atlas);
/* If we still can't reserve space then something has gone
seriously wrong so we'll just give up */
if (!_cogl_atlas_reserve_space (atlas,
ink_rect.width + 1,
ink_rect.height + 1, value))
{
cogl_object_unref (atlas);
cogl_pango_glyph_cache_value_free (value); cogl_pango_glyph_cache_value_free (value);
return NULL; return NULL;
} }
_cogl_atlas_add_reorganize_callback
(atlas, cogl_pango_glyph_cache_reorganize_cb, NULL, cache);
cache->atlases = g_slist_prepend (cache->atlases, atlas);
}
key = g_slice_new (CoglPangoGlyphCacheKey); key = g_slice_new (CoglPangoGlyphCacheKey);
key->font = g_object_ref (font); key->font = g_object_ref (font);
key->glyph = glyph; key->glyph = glyph;