From 494fb0738e541883371b17f31c2a94471476c6f5 Mon Sep 17 00:00:00 2001 From: divverent Date: Sat, 22 Jan 2011 19:09:48 +0000 Subject: [PATCH] cache multiple loaded instances of the same font (TODO: can we also cache the freetype object itself? probably not without major changes, as these are size specific); saves about 150M memory use in Xonotic git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10715 d7cf8633-e32d-0410-b094-e92efae38249 --- ft2.c | 90 +++++++++++++++++++++++++++++++++++++++++++++----- ft2.h | 2 +- ft2_fontdefs.h | 2 +- 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/ft2.c b/ft2.c index 782a185f..91a6f871 100644 --- a/ft2.c +++ b/ft2.c @@ -152,6 +152,79 @@ typedef struct font_postprocess_t; static font_postprocess_t pp; +typedef struct fontfilecache_s +{ + unsigned char *buf; + fs_offset_t len; + int refcount; + char path[MAX_QPATH]; +} +fontfilecache_t; +#define MAX_FONTFILES 8 +static fontfilecache_t fontfiles[MAX_FONTFILES]; +static const unsigned char *fontfilecache_LoadFile(const char *path, qboolean quiet, fs_offset_t *filesizepointer) +{ + int i; + unsigned char *buf; + + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + if(!strcmp(path, fontfiles[i].path)) + { + *filesizepointer = fontfiles[i].len; + ++fontfiles[i].refcount; + return fontfiles[i].buf; + } + } + + buf = FS_LoadFile(path, font_mempool, quiet, filesizepointer); + if(buf) + { + for(i = 0; i < MAX_FONTFILES; ++i) + if(fontfiles[i].refcount <= 0) + { + strlcpy(fontfiles[i].path, path, sizeof(fontfiles[i].path)); + fontfiles[i].len = *filesizepointer; + fontfiles[i].buf = buf; + fontfiles[i].refcount = 1; + return buf; + } + } + + return buf; +} +static void fontfilecache_Free(const unsigned char *buf) +{ + int i; + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + if(fontfiles[i].buf == buf) + { + if(--fontfiles[i].refcount <= 0) + { + Mem_Free(fontfiles[i].buf); + fontfiles[i].buf = NULL; + } + return; + } + } + // if we get here, it used regular allocation + Mem_Free((void *) buf); +} +static void fontfilecache_FreeAll(void) +{ + int i; + for(i = 0; i < MAX_FONTFILES; ++i) + { + if(fontfiles[i].refcount > 0) + Mem_Free(fontfiles[i].buf); + fontfiles[i].buf = NULL; + fontfiles[i].refcount = 0; + } +} + /* ==================== Font_CloseLibrary @@ -161,6 +234,7 @@ Unload the FreeType2 DLL */ void Font_CloseLibrary (void) { + fontfilecache_FreeAll(); if (font_mempool) Mem_FreePool(&font_mempool); if (font_texturepool) @@ -448,7 +522,7 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti char filename[MAX_QPATH]; int status; size_t i; - unsigned char *data; + const unsigned char *data; fs_offset_t datasize; memset(font, 0, sizeof(*font)); @@ -470,18 +544,18 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti // try load direct file memcpy(filename, name, namelen+1); - data = FS_LoadFile(filename, font_mempool, false, &datasize); + data = fontfilecache_LoadFile(filename, false, &datasize); // try load .ttf if (!data) { memcpy(filename + namelen, ".ttf", 5); - data = FS_LoadFile(filename, font_mempool, false, &datasize); + data = fontfilecache_LoadFile(filename, false, &datasize); } // try load .otf if (!data) { memcpy(filename + namelen, ".otf", 5); - data = FS_LoadFile(filename, font_mempool, false, &datasize); + data = fontfilecache_LoadFile(filename, false, &datasize); } // try load .pfb/afm if (!data) @@ -489,12 +563,12 @@ static qboolean Font_LoadFile(const char *name, int _face, ft2_settings_t *setti ft2_attachment_t afm; memcpy(filename + namelen, ".pfb", 5); - data = FS_LoadFile(filename, font_mempool, false, &datasize); + data = fontfilecache_LoadFile(filename, false, &datasize); if (data) { memcpy(filename + namelen, ".afm", 5); - afm.data = FS_LoadFile(filename, font_mempool, false, &afm.size); + afm.data = fontfilecache_LoadFile(filename, false, &afm.size); if (afm.data) Font_Attach(font, &afm); @@ -969,7 +1043,7 @@ void Font_UnloadFont(ft2_font_t *font) { for (i = 0; i < (int)font->attachmentcount; ++i) { if (font->attachments[i].data) - Mem_Free(font->attachments[i].data); + fontfilecache_Free(font->attachments[i].data); } Mem_Free(font->attachments); font->attachmentcount = 0; @@ -992,7 +1066,7 @@ void Font_UnloadFont(ft2_font_t *font) } } if (font->data) { - Mem_Free(font->data); + fontfilecache_Free(font->data); font->data = NULL; } } diff --git a/ft2.h b/ft2.h index 78728c2d..e8110a72 100644 --- a/ft2.h +++ b/ft2.h @@ -43,7 +43,7 @@ typedef struct ft2_font_s // TODO: clean this up and do not expose everything. - unsigned char *data; // TODO: See if FT2 actually needs it to stay... probably does + const unsigned char *data; // FT2 needs it to stay //fs_offset_t datasize; void *face; diff --git a/ft2_fontdefs.h b/ft2_fontdefs.h index 87fba4c5..34c16370 100644 --- a/ft2_fontdefs.h +++ b/ft2_fontdefs.h @@ -50,7 +50,7 @@ struct ft2_font_map_s struct ft2_attachment_s { - unsigned char *data; + const unsigned char *data; fs_offset_t size; }; -- 2.39.2