[Bf-blender-cvs] [9d77b5a0ed7] master: BLF: Implement FreeType Caching

Harley Acheson noreply at git.blender.org
Thu Aug 4 22:06:58 CEST 2022


Commit: 9d77b5a0ed7bed48dcb7483e79945067666eac0b
Author: Harley Acheson
Date:   Thu Aug 4 13:05:19 2022 -0700
Branches: master
https://developer.blender.org/rB9d77b5a0ed7bed48dcb7483e79945067666eac0b

BLF: Implement FreeType Caching

Implementation of the FreeType 2 cache subsystem, which limits the
number of concurrently-opened FT_Face and FT_Size objects, as well as
caching information like character maps to speed up glyph id lookups.

See D13137 for much more detail.

Differential Revision: https://developer.blender.org/D13137

Reviewed by Brecht Van Lommel

===================================================================

M	source/blender/blenfont/intern/blf.c
M	source/blender/blenfont/intern/blf_font.c
M	source/blender/blenfont/intern/blf_glyph.c
M	source/blender/blenfont/intern/blf_internal.h
M	source/blender/blenfont/intern/blf_internal_types.h

===================================================================

diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a1fcc17ca3f..36475321d4c 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -122,7 +122,7 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
 {
   FontBLF *font = blf_get(fontid);
   if (font) {
-    return FT_Get_Char_Index(font->face, unicode) != FT_Err_Ok;
+    return blf_get_char_index(font, unicode) != FT_Err_Ok;
   }
   return false;
 }
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 339df9eb269..372dc19d64a 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -17,6 +17,7 @@
 #include <ft2build.h>
 
 #include FT_FREETYPE_H
+#include FT_CACHE_H /* FreeType Cache. */
 #include FT_GLYPH_H
 #include FT_MULTIPLE_MASTERS_H /* Variable font support. */
 #include FT_TRUETYPE_IDS_H     /* Codepoint coverage constants. */
@@ -54,7 +55,10 @@
 BatchBLF g_batch;
 
 /* freetype2 handle ONLY for this file! */
-static FT_Library ft_lib;
+static FT_Library ft_lib = NULL;
+static FTC_Manager ftc_manager = NULL;
+static FTC_CMapCache ftc_charmap_cache = NULL;
+
 static SpinLock ft_lib_mutex;
 static SpinLock blf_glyph_cache_mutex;
 
@@ -64,6 +68,53 @@ static void (*blf_draw_cache_flush)(void) = NULL;
 static ft_pix blf_font_height_max_ft_pix(struct FontBLF *font);
 static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font);
 
+/* -------------------------------------------------------------------- */
+/** \name FreeType Caching
+ * \{ */
+
+/* Called when a face is removed. FreeType will call FT_Done_Face itself. */
+static void blf_face_finalizer(void *object)
+{
+  FT_Face face = object;
+  FontBLF *font = (FontBLF *)face->generic.data;
+  font->face = NULL;
+}
+
+/* Called in response to FTC_Manager_LookupFace. Add a face to our font. */
+FT_Error blf_cache_face_requester(FTC_FaceID faceID,
+                                  FT_Library lib,
+                                  FT_Pointer reqData,
+                                  FT_Face *face)
+{
+  FontBLF *font = (FontBLF *)faceID;
+  int err = FT_Err_Cannot_Open_Resource;
+
+  BLI_spin_lock(font->ft_lib_mutex);
+
+  if (font->filepath) {
+    err = FT_New_Face(lib, font->filepath, 0, face);
+  }
+  else if (font->mem) {
+    err = FT_New_Memory_Face(lib, font->mem, (FT_Long)font->mem_size, 0, face);
+  }
+
+  BLI_spin_unlock(font->ft_lib_mutex);
+
+  if (err == FT_Err_Ok) {
+    font->face = *face;
+    font->face->generic.data = font;
+    font->face->generic.finalizer = blf_face_finalizer;
+  }
+
+  return err;
+}
+
+/* Use cache, not blf_get_char_index, to return glyph id from charcode. */
+uint blf_get_char_index(struct FontBLF *font, uint charcode)
+{
+  return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode);
+}
+
 /* -------------------------------------------------------------------- */
 /** \name FreeType Utilities (Internal)
  * \{ */
@@ -72,12 +123,12 @@ static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font);
 static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
 {
   /* Scale value by font size using integer-optimized multiplication. */
-  FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale);
+  FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale);
 
   /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down */
   /* kerning distances at small ppem values so that they don't become too big. */
-  if (font->face->size->metrics.x_ppem < 25) {
-    scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25);
+  if (font->ft_size->metrics.x_ppem < 25) {
+    scaled = FT_MulDiv(scaled, font->ft_size->metrics.x_ppem, 25);
   }
 
   return (ft_pix)scaled;
@@ -296,7 +347,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph
   /* Small adjust if there is hinting. */
   adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
 
-  if (FT_HAS_KERNING(font->face) && g_prev) {
+  if (FT_HAS_KERNING(font) && g_prev) {
     FT_Vector delta = {KERNING_ENTRY_UNSET};
 
     /* Get unscaled kerning value from our cache if ASCII. */
@@ -305,7 +356,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph
     }
 
     /* If not ASCII or not found in cache, ask FreeType for kerning. */
-    if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) {
+    if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) {
       /* Note that this function sets delta values to zero on any error. */
       FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
     }
@@ -925,8 +976,7 @@ static void blf_font_wrap_apply(FontBLF *font,
   int lines = 0;
   ft_pix pen_x_next = 0;
 
-  /* Space between lines needs to be aligned to the pixel grid (T97310). */
-  ft_pix line_height = FT_PIX_FLOOR(blf_font_height_max_ft_pix(font));
+  ft_pix line_height = blf_font_height_max_ft_pix(font);
 
   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
 
@@ -1090,7 +1140,7 @@ int blf_font_count_missing_chars(FontBLF *font,
     }
     else {
       c = BLI_str_utf8_as_unicode_step(str, str_len, &i);
-      if (FT_Get_Char_Index((font)->face, c) == 0) {
+      if (blf_get_char_index(font, c) == 0) {
         missing++;
       }
     }
@@ -1107,18 +1157,8 @@ int blf_font_count_missing_chars(FontBLF *font,
 
 static ft_pix blf_font_height_max_ft_pix(FontBLF *font)
 {
-  ft_pix height_max;
-  FT_Face face = font->face;
-  if (FT_IS_SCALABLE(face)) {
-    height_max = ft_pix_from_int((int)(face->ascender - face->descender) *
-                                 (int)face->size->metrics.y_ppem) /
-                 (ft_pix)face->units_per_EM;
-  }
-  else {
-    height_max = (ft_pix)face->size->metrics.height;
-  }
-  /* can happen with size 1 fonts */
-  return MAX2(height_max, ft_pix_from_int(1));
+  /* Metrics.height is rounded to pixel. Force minimum of one pixel. */
+  return MAX2((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1));
 }
 
 int blf_font_height_max(FontBLF *font)
@@ -1128,18 +1168,8 @@ int blf_font_height_max(FontBLF *font)
 
 static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
 {
-  ft_pix width_max;
-  const FT_Face face = font->face;
-  if (FT_IS_SCALABLE(face)) {
-    width_max = ft_pix_from_int((int)(face->bbox.xMax - face->bbox.xMin) *
-                                (int)face->size->metrics.x_ppem) /
-                (ft_pix)face->units_per_EM;
-  }
-  else {
-    width_max = (ft_pix)face->size->metrics.max_advance;
-  }
-  /* can happen with size 1 fonts */
-  return MAX2(width_max, ft_pix_from_int(1));
+  /* Metrics.max_advance is rounded to pixel. Force minimum of one pixel. */
+  return MAX2((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1));
 }
 
 int blf_font_width_max(FontBLF *font)
@@ -1149,12 +1179,12 @@ int blf_font_width_max(FontBLF *font)
 
 int blf_font_descender(FontBLF *font)
 {
-  return ft_pix_to_int((ft_pix)font->face->size->metrics.descender);
+  return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender);
 }
 
 int blf_font_ascender(FontBLF *font)
 {
-  return ft_pix_to_int((ft_pix)font->face->size->metrics.ascender);
+  return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender);
 }
 
 char *blf_display_name(FontBLF *font)
@@ -1176,13 +1206,31 @@ int blf_font_init(void)
   memset(&g_batch, 0, sizeof(g_batch));
   BLI_spin_init(&ft_lib_mutex);
   BLI_spin_init(&blf_glyph_cache_mutex);
-  return FT_Init_FreeType(&ft_lib);
+  int err = FT_Init_FreeType(&ft_lib);
+  if (err == FT_Err_Ok) {
+    err = FTC_Manager_New(ft_lib,
+                          BLF_CACHE_MAX_FACES,
+                          BLF_CACHE_MAX_SIZES,
+                          BLF_CACHE_BYTES,
+                          blf_cache_face_requester,
+                          NULL,
+                          &ftc_manager);
+    if (err == FT_Err_Ok) {
+      err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache);
+    }
+  }
+  return err;
 }
 
 void blf_font_exit(void)
 {
-  FT_Done_FreeType(ft_lib);
   BLI_spin_end(&ft_lib_mutex);
+  if (ftc_manager) {
+    FTC_Manager_Done(ftc_manager);
+  }
+  if (ft_lib) {
+    FT_Done_FreeType(ft_lib);
+  }
   BLI_spin_end(&blf_glyph_cache_mutex);
   blf_batch_draw_exit();
 }
@@ -1261,12 +1309,7 @@ bool blf_ensure_face(FontBLF *font)
 
   FT_Error err;
 
-  if (font->filepath) {
-    err = FT_New_Face(ft_lib, font->filepath, 0, &font->face);
-  }
-  if (font->mem) {
-    err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face);
-  }
+  err = FTC_Manager_LookupFace(ftc_manager, font, &font->face);
 
   if (err) {
     if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
@@ -1306,7 +1349,9 @@ bool blf_ensure_face(FontBLF *font)
     }
   }
 
-  if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
+  font->face_flags = font->face->face_flags;
+
+  if (FT_HAS_MULTIPLE_MASTERS(font)) {
     FT_Get_MM_Var(font->face, &(font->variations));
   }
 
@@ -1319,11 +1364,11 @@ bool blf_ensure_face(FontBLF *font)
     font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4;
   }
 
-  if (FT_IS_FIXED_WIDTH(font->face)) {
+  if (FT_IS_FIXED_WIDTH(font)) {
     font->flags |= BLF_MONOSPACED;
   }
 
-  if (FT_HAS_KERNING(font->face) && !font->kerning_cache) {
+  if (FT_HAS_KERNING(font) && !font->kerning_cache) {
     /* Create kerning cache table and fill with value indicating "unset". */
     font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__);
     for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
@@ -1438,7 +1483,9 @@ void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, const siz
   open.flags = FT_OPEN_MEMORY;
   open.memory_base = (const FT_Byte *)mem;
   open.memory_size = (FT_Long)mem_size;
-  FT_Attach_Stream(font->face, &open);
+  if (blf_ensure_face(font)) {
+    FT_Attach_Stream(font->face, &open);
+  }
 }
 
 void blf_font_free(FontBLF *font)
@@ -1454,7 +1501,8 @@ void blf_font_free(FontBLF *font)
   }
 
   if (font->face) {
-    FT_Done_Face(font->face);
+    FTC_Manager_RemoveFaceID(ftc_manager, font);
+    font->face = NULL;
   }
   if (font->filepath) {
     MEM_free

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list