[pango/speed-up-format-filtering] Move expensive fontconfig calls to a thread




commit e62ce31587aee016ef98ccdfb0fa77b09dfcac90
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Aug 18 21:55:58 2020 -0400

    Move expensive fontconfig calls to a thread
    
    fontconfig is thread-safe, so we can do calls that
    can take several milliseconds to complete to a thread,
    such as FcFontSetMatch and FcFontSetSort. This patch
    is a win, at least for FcFontSetSort, since it reduces
    the time that the main thread spends in
    pango_fc_patterns_get_font_pattern for i > 0 from
    around 10 to 6 milliseconds.
    
    For bigger wins from this, we would have to restructure
    things to allow itemization to proceed without blocking
    on fonts being available.

 pango/pangofc-fontmap.c | 191 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 149 insertions(+), 42 deletions(-)
---
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index b2a6285e9..774cd8713 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -744,15 +744,105 @@ struct _PangoFcPatterns {
 
   PangoFcFontMap *fontmap;
 
+  /* match and fontset are initialized in a thread,
+   * and are protected by a mutex. The thread signals
+   * the cond when match or fonset become available.
+   */
+  GMutex mutex;
+  GCond cond;
+
   FcPattern *pattern;
   FcPattern *match;
   FcFontSet *fontset;
 };
 
+typedef struct {
+  FcConfig *config;
+  FcFontSet **sets;
+  int nsets;
+  FcPattern *pattern;
+  PangoFcPatterns *patterns;
+} ThreadData;
+
+static FcFontSet **pango_fc_font_map_get_config_fonts (PangoFcFontMap *fcfontmap,
+                                                       int            *nsets);
+
+static ThreadData *
+thread_data_new (PangoFcPatterns *patterns)
+{
+  ThreadData *td;
+
+  td = g_new (ThreadData, 1);
+  td->patterns = pango_fc_patterns_ref (patterns);
+  td->pattern = patterns->pattern;
+  td->config = FcConfigReference (pango_fc_font_map_get_config (patterns->fontmap));
+  /* FIXME: FcFontSet not refcounted */
+  td->sets = pango_fc_font_map_get_config_fonts (patterns->fontmap, &td->nsets);
+
+  return td;
+}
+
+static void
+thread_data_free (gpointer data)
+{
+  ThreadData *td = data;
+
+  FcConfigDestroy (td->config);
+  pango_fc_patterns_unref (td->patterns);
+  g_free (td);
+}
+
+static void
+match_in_thread (GTask        *task,
+                 gpointer      source_object,
+                 gpointer      task_data,
+                 GCancellable *cancellable)
+{
+  ThreadData *td = task_data;
+  FcResult result;
+  FcPattern *match;
+
+  match = FcFontSetMatch (td->config,
+                          td->sets, td->nsets,
+                          td->pattern,
+                          &result);
+
+  g_mutex_lock (&td->patterns->mutex);
+  td->patterns->match = match;
+  g_cond_signal (&td->patterns->cond);
+  g_mutex_unlock (&td->patterns->mutex);
+}
+
+static void
+sort_in_thread (GTask        *task,
+                gpointer      source_object,
+                gpointer      task_data,
+                GCancellable *cancellable)
+{
+  ThreadData *td = task_data;
+  FcResult result;
+  FcFontSet *fontset;
+
+  fontset = FcFontSetSort (td->config,
+                           td->sets, td->nsets,
+                           td->pattern,
+                           FcTrue,
+                           NULL,
+                           &result);
+
+  g_mutex_lock (&td->patterns->mutex);
+  td->patterns->fontset = fontset;
+  FcPatternDestroy (td->patterns->match);
+  td->patterns->match = NULL;
+  g_cond_signal (&td->patterns->cond);
+  g_mutex_unlock (&td->patterns->mutex);
+}
+
 static PangoFcPatterns *
 pango_fc_patterns_new (FcPattern *pat, PangoFcFontMap *fontmap)
 {
   PangoFcPatterns *pats;
+  GTask *task;
 
   pat = uniquify_pattern (fontmap, pat);
   pats = g_hash_table_lookup (fontmap->priv->patterns_hash, pat);
@@ -767,8 +857,23 @@ pango_fc_patterns_new (FcPattern *pat, PangoFcFontMap *fontmap)
   FcPatternReference (pat);
   pats->pattern = pat;
 
+  g_mutex_init (&pats->mutex);
+  g_cond_init (&pats->cond);
+
+  task = g_task_new (NULL, NULL, NULL, NULL);
+  g_task_set_name (task, "[pango] FcFontSetMatch");
+  g_task_set_task_data (task, thread_data_new (pats), thread_data_free);
+  g_task_run_in_thread (task, match_in_thread);
+  g_object_unref (task);
+
+  task = g_task_new (NULL, NULL, NULL, NULL);
+  g_task_set_name (task, "[pango] FcFontSetSort");
+  g_task_set_task_data (task, thread_data_new (pats), thread_data_free);
+  g_task_run_in_thread (task, sort_in_thread);
+  g_object_unref (task);
+
   g_hash_table_insert (fontmap->priv->patterns_hash,
-                      pats->pattern, pats);
+                       pats->pattern, pats);
 
   return pats;
 }
@@ -809,6 +914,9 @@ pango_fc_patterns_unref (PangoFcPatterns *pats)
   if (pats->fontset)
     FcFontSetDestroy (pats->fontset);
 
+  g_cond_clear (&pats->cond);
+  g_mutex_clear (&pats->mutex);
+
   g_slice_free (PangoFcPatterns, pats);
 }
 
@@ -839,9 +947,6 @@ pango_fc_is_supported_font_format (FcPattern* pattern)
   return FALSE;
 }
 
-static FcFontSet **pango_fc_font_map_get_config_fonts (PangoFcFontMap *fcfontmap,
-                                                       int            *nsets);
-
 static FcFontSet *
 filter_fontset_by_format (FcFontSet *fontset)
 {
@@ -867,50 +972,54 @@ pango_fc_patterns_get_font_pattern (PangoFcPatterns *pats, int i, gboolean *prep
 {
   if (i == 0)
     {
-      FcResult result;
+      FcPattern *match;
+      FcFontSet *fontset;
 
-      if (!pats->match && !pats->fontset)
-        {
-          FcFontSet **sets;
-          int nsets;
+      g_mutex_lock (&pats->mutex);
+
+      while (!pats->match && !pats->fontset)
+        g_cond_wait (&pats->cond, &pats->mutex);
 
-          sets = pango_fc_font_map_get_config_fonts (pats->fontmap, &nsets);
+      match = pats->match;
+      fontset = pats->fontset;
 
-         pats->match = FcFontSetMatch (pats->fontmap->priv->config,
-                                        sets, nsets,
-                                        pats->pattern,
-                                        &result);
+      g_mutex_unlock (&pats->mutex);
+
+      if (match)
+        {
+          *prepare = FALSE;
+          return match;
         }
 
-      if (pats->match)
-       {
-         *prepare = FALSE;
-         return pats->match;
-       }
+      if (fontset && i < fontset->nfont)
+        {
+          *prepare = TRUE;
+          return fontset->fonts[i];
+        }
+      else
+        return NULL;
     }
-
-  if (!pats->fontset)
+  else
     {
-      FcResult result;
-      FcFontSet **sets;
-      int nsets;
+      FcFontSet *fontset;
+
+      g_mutex_lock (&pats->mutex);
 
-      sets = pango_fc_font_map_get_config_fonts (pats->fontmap, &nsets);
+      while (!pats->fontset)
+        g_cond_wait (&pats->cond, &pats->mutex);
 
-      pats->fontset = FcFontSetSort (pats->fontmap->priv->config, sets, nsets, pats->pattern, FcTrue, NULL, 
&result);
+      fontset = pats->fontset;
 
-      if (pats->match)
+      g_mutex_unlock (&pats->mutex);
+
+      if (fontset && i < fontset->nfont)
         {
-          FcPatternDestroy (pats->match);
-          pats->match = NULL;
+          *prepare = TRUE;
+          return fontset->fonts[i];
         }
+      else
+        return NULL;
     }
-
-  *prepare = TRUE;
-  if (pats->fontset && i < pats->fontset->nfont)
-    return pats->fontset->fonts[i];
-  else
-    return NULL;
 }
 
 
@@ -1223,8 +1332,8 @@ pango_fc_font_map_fini (PangoFcFontMap *fcfontmap)
 
   for (i = 0; i < 2; i++)
     {
-      if (priv->filtered_fonts[i])
-        FcFontSetDestroy (priv->filtered_fonts[i]);
+      g_clear_pointer (&priv->filtered_fonts[i], FcFontSetDestroy);
+      fcfontmap->priv->config_fonts[i] = NULL;
     }
 
   g_queue_free (priv->fontset_cache);
@@ -2008,7 +2117,7 @@ pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap)
 
   pango_fc_font_map_fini (fcfontmap);
   pango_fc_font_map_init (fcfontmap);
-   
+
   ensure_families (fcfontmap);
 
   added = fcfontmap->priv->n_families;
@@ -2065,7 +2174,7 @@ pango_fc_font_map_config_changed (PangoFcFontMap *fcfontmap)
  **/
 void
 pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
-                             FcConfig       *fcconfig)
+                              FcConfig       *fcconfig)
 {
   FcConfig *oldconfig;
   int i;
@@ -2081,9 +2190,7 @@ pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
 
   for (i = 0; i < 2; i++)
     {
-      if (fcfontmap->priv->filtered_fonts[i])
-        FcFontSetDestroy (fcfontmap->priv->filtered_fonts[i]);
-      fcfontmap->priv->filtered_fonts[i] = NULL;
+      g_clear_pointer (&fcfontmap->priv->filtered_fonts[i], FcFontSetDestroy);
       fcfontmap->priv->config_fonts[i] = NULL;
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]