optimize font glyph cache

This commit is contained in:
Vadim Lopatin 2014-04-01 22:36:15 +04:00
parent da09eeed1c
commit 0fd29831ab
2 changed files with 38 additions and 41 deletions

View File

@ -105,7 +105,7 @@ extern (C) int UIAppMain(string[] args) {
ListWidget list = new ListWidget("tab2", Orientation.Vertical); ListWidget list = new ListWidget("tab2", Orientation.Vertical);
WidgetListAdapter listAdapter = new WidgetListAdapter(); WidgetListAdapter listAdapter = new WidgetListAdapter();
for (int i = 0; i < 30; i++) for (int i = 0; i < 3000; i++)
listAdapter.widgets.add((new TextWidget()).text("List item "d ~ to!dstring(i))); listAdapter.widgets.add((new TextWidget()).text("List item "d ~ to!dstring(i)));
list.ownAdapter = listAdapter; list.ownAdapter = listAdapter;
list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);

View File

@ -37,77 +37,70 @@ version (USE_OPENGL) {
uint nextGlyphId() { return _nextGlyphId++; } uint nextGlyphId() { return _nextGlyphId++; }
} }
/// font glyph cache
struct GlyphCache struct GlyphCache
{ {
Glyph[] _data; Glyph[ushort] _map;
uint _len;
// find glyph in cache // find glyph in cache
Glyph * find(ushort glyphIndex) { Glyph * find(ushort glyphIndex) {
for (uint i = 0; i < _len; i++) { Glyph * res = (glyphIndex in _map);
Glyph * item = &_data[i]; if (res !is null)
if (item.glyphIndex == glyphIndex) { res.lastUsage = 1;
item.lastUsage = 1; return res;
return item;
}
}
return null;
} }
/// put glyph to cache
Glyph * put(ushort glyphIndex, Glyph * glyph) { Glyph * put(ushort glyphIndex, Glyph * glyph) {
if (_len >= _data.length) { _map[glyphIndex] = *glyph;
uint newsize = (_len < 32) ? 32 : _len * 2; Glyph * res = glyphIndex in _map;
_data.length = newsize;
}
_data[_len++] = *glyph;
Glyph * res = &_data[_len - 1];
res.lastUsage = 1; res.lastUsage = 1;
return res; return res;
} }
// clear usage flags for all entries // clear usage flags for all entries
void checkpoint() { void checkpoint() {
for (uint src = 0; src < _len; src++) { foreach(ref Glyph item; _map) {
_data[src].lastUsage = 0; item.lastUsage = 0;
} }
} }
// removes entries not used after last call of checkpoint() or cleanup() /// removes entries not used after last call of checkpoint() or cleanup()
void cleanup() { void cleanup() {
uint dst = 0; uint dst = 0;
// notify about destroyed glyphs // notify about destroyed glyphs
version (USE_OPENGL) { version (USE_OPENGL) {
if (_glyphDestroyCallback !is null) if (_glyphDestroyCallback !is null)
for (uint src = 0; src < _len; src++) foreach(ref Glyph item; _map) {
if (_data[src].lastUsage == 0) if (item.lastUsage == 0)
_glyphDestroyCallback(_data[src].id); _glyphDestroyCallback(item.id);
}
for (uint src = 0; src < _len; src++) {
if (_data[src].lastUsage != 0) {
_data[src].lastUsage = 0;
if (src != dst) {
_data[dst++] = _data[src];
} }
} }
} ushort[] forDelete;
_len = dst; foreach(ref Glyph item; _map)
if (item.lastUsage == 0)
forDelete ~= item.glyphIndex;
foreach(ushort index; forDelete)
_map.remove(index);
} }
// removes all entries /// removes all entries
void clear() { void clear() {
version (USE_OPENGL) { version (USE_OPENGL) {
if (_glyphDestroyCallback !is null) if (_glyphDestroyCallback !is null)
for (uint src = 0; src < _len; src++) foreach(ref Glyph item; _map) {
_glyphDestroyCallback(_data[src].id); if (item.lastUsage == 0)
_glyphDestroyCallback(item.id);
}
} }
_data = null; _map.clear();
_len = 0;
} }
~this() { ~this() {
clear(); clear();
} }
} }
/// Font object
class Font : RefCountedObject { class Font : RefCountedObject {
abstract @property int size(); abstract @property int size();
abstract @property int height(); abstract @property int height();
@ -127,13 +120,14 @@ class Font : RefCountedObject {
return Point(0,0); return Point(0,0);
return Point(widths[charsMeasured - 1], height); return Point(widths[charsMeasured - 1], height);
} }
// draw text string to buffer /// draw text string to buffer
abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color); abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
/// get character glyph information
abstract Glyph * getCharGlyph(dchar ch, bool withImage = true); abstract Glyph * getCharGlyph(dchar ch, bool withImage = true);
// clear usage flags for all entries /// clear usage flags for all entries
abstract void checkpoint(); abstract void checkpoint();
// removes entries not used after last call of checkpoint() or cleanup() /// removes entries not used after last call of checkpoint() or cleanup()
abstract void cleanup(); abstract void cleanup();
void clear() {} void clear() {}
@ -142,6 +136,7 @@ class Font : RefCountedObject {
} }
alias FontRef = Ref!Font; alias FontRef = Ref!Font;
/// font instance collection - utility class, for font manager implementations
struct FontList { struct FontList {
FontRef[] _list; FontRef[] _list;
uint _len; uint _len;
@ -223,7 +218,8 @@ struct FontList {
/// Access points to fonts. /// Access points to fonts.
class FontManager { class FontManager {
static __gshared FontManager _instance; protected static __gshared FontManager _instance;
/// sets new font manager singleton instance /// sets new font manager singleton instance
static @property void instance(FontManager manager) { static @property void instance(FontManager manager) {
if (_instance !is null) { if (_instance !is null) {
@ -232,6 +228,7 @@ class FontManager {
} }
_instance = manager; _instance = manager;
} }
/// returns font manager singleton instance /// returns font manager singleton instance
static @property FontManager instance() { static @property FontManager instance() {
return _instance; return _instance;