[Bf-blender-cvs] [d39abb74a0a] master: BLF: FreeType Optional Caching

Harley Acheson noreply at git.blender.org
Wed Aug 17 00:04:59 CEST 2022


Commit: d39abb74a0a99fde2c9d845821d52c198ae4da24
Author: Harley Acheson
Date:   Tue Aug 16 15:02:56 2022 -0700
Branches: master
https://developer.blender.org/rBd39abb74a0a99fde2c9d845821d52c198ae4da24

BLF: FreeType Optional 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.
This time with the option of opening FontBLFs that are not cached.

See D15686 for more details.

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

Reviewed by Brecht Van Lommel

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

M	source/blender/blenfont/BLF_api.h
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_thumbs.c

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

diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 75824ae056f..d3226a8f609 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -353,6 +353,8 @@ enum {
   BLF_LAST_RESORT = 1 << 15,
   /** Failure to load this font. Don't try again. */
   BLF_BAD_FONT = 1 << 16,
+  /** This font is managed by the FreeType cache subsystem. */
+  BLF_CACHED = 1 << 17,
 };
 
 #define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 36475321d4c..6fcb74e9cb0 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -22,6 +22,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_math.h"
+#include "BLI_string.h"
 #include "BLI_threads.h"
 
 #include "BLF_api.h"
@@ -885,12 +886,21 @@ void BLF_draw_buffer(int fontid, const char *str, const size_t str_len)
 
 char *BLF_display_name_from_file(const char *filepath)
 {
-  FontBLF *font = blf_font_new("font_name", filepath);
-  if (!font) {
-    return NULL;
+  /* While listing font directories this function can be called simultaneously from a greater
+   * number of threads than we want the FreeType cache to keep open at a time. Therefore open
+   * with own FT_Library object and use FreeType calls directly to avoid any contention. */
+  char *name = NULL;
+  FT_Library ft_library;
+  if (FT_Init_FreeType(&ft_library) == FT_Err_Ok) {
+    FT_Face face;
+    if (FT_New_Face(ft_library, filepath, 0, &face) == FT_Err_Ok) {
+      if (face->family_name) {
+        name = BLI_sprintfN("%s %s", face->family_name, face->style_name);
+      }
+      FT_Done_Face(face);
+    }
+    FT_Done_FreeType(ft_library);
   }
-  char *name = blf_display_name(font);
-  blf_font_free(font);
   return name;
 }
 
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 226752bffd8..f820ec14507 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. */
@@ -55,6 +56,8 @@ BatchBLF g_batch;
 
 /* freetype2 handle ONLY for this file! */
 static FT_Library ft_lib = NULL;
+static FTC_Manager ftc_manager = NULL;
+static FTC_CMapCache ftc_charmap_cache = NULL;
 
 /* Lock for FreeType library, used around face creation and deletion.  */
 static ThreadMutex ft_lib_mutex;
@@ -67,19 +70,75 @@ static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font);
 
 /* -------------------------------------------------------------------- */
 
-/* Return glyph id from charcode. */
-uint blf_get_char_index(struct FontBLF *font, uint charcode)
+/** \name FreeType Caching
+ * \{ */
+
+/* Called when a face is removed by the cache. FreeType will call FT_Done_Face. */
+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. Now 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_mutex_lock(&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_mutex_unlock(&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;
+}
+
+/* Called when the FreeType cache is removing a font size. */
+static void blf_size_finalizer(void *object)
 {
-  return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0;
+  FT_Size size = object;
+  FontBLF *font = (FontBLF *)size->generic.data;
+  font->ft_size = NULL;
 }
 
 /* -------------------------------------------------------------------- */
 /** \name FreeType Utilities (Internal)
  * \{ */
 
+/* Return glyph id from charcode. */
+uint blf_get_char_index(struct FontBLF *font, uint charcode)
+{
+  if (font->flags & BLF_CACHED) {
+    /* Use charmap cache for much faster lookup. */
+    return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode);
+  }
+  else {
+    /* Fonts that are not cached need to use the regular lookup function. */
+    return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0;
+  }
+}
+
 /* Convert a FreeType 26.6 value representing an unscaled design size to fractional pixels. */
 static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
 {
+  /* Make sure we have a valid font->ft_size. */
+  blf_ensure_size(font);
+
   /* Scale value by font size using integer-optimized multiplication. */
   FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale);
 
@@ -1115,6 +1174,7 @@ int blf_font_count_missing_chars(FontBLF *font,
 
 static ft_pix blf_font_height_max_ft_pix(FontBLF *font)
 {
+  blf_ensure_size(font);
   /* 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));
 }
@@ -1126,6 +1186,7 @@ int blf_font_height_max(FontBLF *font)
 
 static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
 {
+  blf_ensure_size(font);
   /* 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));
 }
@@ -1137,11 +1198,13 @@ int blf_font_width_max(FontBLF *font)
 
 int blf_font_descender(FontBLF *font)
 {
+  blf_ensure_size(font);
   return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender);
 }
 
 int blf_font_ascender(FontBLF *font)
 {
+  blf_ensure_size(font);
   return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender);
 }
 
@@ -1164,12 +1227,29 @@ int blf_font_init(void)
   memset(&g_batch, 0, sizeof(g_batch));
   BLI_mutex_init(&ft_lib_mutex);
   int err = FT_Init_FreeType(&ft_lib);
+  if (err == FT_Err_Ok) {
+    /* Create a FreeType cache manager. */
+    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) {
+      /* Create a charmap cache to speed up glyph index lookups. */
+      err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache);
+    }
+  }
   return err;
 }
 
 void blf_font_exit(void)
 {
   BLI_mutex_end(&ft_lib_mutex);
+  if (ftc_manager) {
+    FTC_Manager_Done(ftc_manager);
+  }
   if (ft_lib) {
     FT_Done_FreeType(ft_lib);
   }
@@ -1229,8 +1309,6 @@ static void blf_font_fill(FontBLF *font)
   font->buf_info.col_init[1] = 0;
   font->buf_info.col_init[2] = 0;
   font->buf_info.col_init[3] = 0;
-
-  font->ft_lib = ft_lib;
 }
 
 /**
@@ -1248,14 +1326,20 @@ bool blf_ensure_face(FontBLF *font)
 
   FT_Error err;
 
-  BLI_mutex_lock(&ft_lib_mutex);
-  if (font->filepath) {
-    err = FT_New_Face(ft_lib, font->filepath, 0, &font->face);
+  if (font->flags & BLF_CACHED) {
+    err = FTC_Manager_LookupFace(ftc_manager, font, &font->face);
   }
-  if (font->mem) {
-    err = FT_New_Memory_Face(ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face);
+  else {
+    BLI_mutex_lock(&ft_lib_mutex);
+    if (font->filepath) {
+      err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face);
+    }
+    if (font->mem) {
+      err = FT_New_Memory_Face(font->ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face);
+    }
+    font->face->generic.data = font;
+    BLI_mutex_unlock(&ft_lib_mutex);
   }
-  BLI_mutex_unlock(&ft_lib_mutex);
 
   if (err) {
     if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
@@ -1295,7 +1379,11 @@ bool blf_ensure_face(FontBLF *font)
     }
   }
 
-  font->ft_size = font->face->size;
+  if (!(font->flags & BLF_CACHED)) {
+    /* Not cached so point at the face's size for convenience. */
+    font->ft_size = font->face->size;
+  }
+
   font->face_flags = font->face->face_flags;
 
   if (FT_HAS_MULTIPLE_MASTERS(font)) {
@@ -1366,11 +1454,16 @@ static const eFaceDetails static_face_details[] = {
     {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0},
 };
 
-/* Create a new font from filename OR from passed memory pointer. */
-static FontBLF *blf_font_new_ex(const char *name,
-                                const char *filepath,
-                                const unsigned char *mem,
-                                const size_t mem_size)
+/**
+ * Create a new font from filename OR memory pointer.
+ * For normal operation pass NULL as FT_Library object. Pass a custom FT_Library if you
+ * want to use the font without its lifetime being managed by the FreeType cache subsystem.
+ */
+FontBLF *blf_font_new_ex(const char *name,
+                         const char *filepath,
+                         const unsigned char *mem,
+                         const size_t mem_size,
+                         void *ft_library)
 {
   FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
 
@@ -1382,6 +1475,16 @@ static FontBLF *blf_font_new_ex(const char *name,
   }
   blf_font_fill(font);
 
+  if (ft_library && ((FT_Library)ft_library != ft_lib)) {
+    font->ft_lib = (FT_Library)ft_library;
+  }
+  else {
+    font->ft_lib = ft_lib;
+    font->flags |= BLF_CACHED;
+  }
+
+  font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib;
+
   BLI_mutex_init(&font->glyph_cache_mutex);
 
   /* If we have static details about this font file, we don't have to load the Face yet. */
@@ -1422,12 +1525,12 @@ static FontBLF *blf_font_new_ex(const char *name,
 
 FontBLF *blf_font_new(const char *name, const char *fi

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list