[pango/speed-up-format-filtering] Move expensive fontconfig calls to a thread
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/speed-up-format-filtering] Move expensive fontconfig calls to a thread
- Date: Wed, 19 Aug 2020 03:24:46 +0000 (UTC)
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]