diff options
author | NRK <nrk@disroot.org> | 2022-03-24 00:37:55 +0600 |
---|---|---|
committer | Hiltjo Posthuma <hiltjo@codemadness.org> | 2022-03-25 22:49:07 +0100 |
commit | 22511c41d55a38a770541ae617a09383d5e6ad1c (patch) | |
tree | 2239b8590d3bff0212ccf56e6f3c9fdcefcce5fe | |
parent | 77526f756e23e362081ac807521f901f2e5cd5e6 (diff) |
drw_text: improve performance when there's no match
this was the last piece of the puzzle, the case where we can't find any
font to draw the codepoint.
in such cases, we use XftFontMatch() which is INSANELY slow. but that's
not the real problem. the real problem was we were continuously trying
to match the same thing over and over again.
this patch introduces a small cache, which keeps track a couple
codepoints for which we know we won't find any matches.
with this, i can dump lots of emojies into dmenu where some of them
don't have any matching font, and still not have dmenu lag insanely or
FREEZE completely when scrolling up and down.
this also improves startup time, which will of course depend on the
system and all installed fonts; but on my system and test case i see the
following startup time drop:
before -> after
60ms -> 34ms
-rw-r--r-- | drw.c | 13 |
1 files changed, 12 insertions, 1 deletions
@@ -251,7 +251,7 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int | |||
251 | int | 251 | int |
252 | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) | 252 | drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) |
253 | { | 253 | { |
254 | int ty, ellipsis_x = 0; | 254 | int i, ty, ellipsis_x = 0; |
255 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, ellipsis_width; | 255 | unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, ellipsis_width; |
256 | XftDraw *d = NULL; | 256 | XftDraw *d = NULL; |
257 | Fnt *usedfont, *curfont, *nextfont; | 257 | Fnt *usedfont, *curfont, *nextfont; |
@@ -263,6 +263,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp | |||
263 | FcPattern *match; | 263 | FcPattern *match; |
264 | XftResult result; | 264 | XftResult result; |
265 | int charexists = 0, overflow = 0; | 265 | int charexists = 0, overflow = 0; |
266 | /* keep track of a couple codepoints for which we have no match. */ | ||
267 | enum { nomatches_len = 64 }; | ||
268 | static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches; | ||
266 | 269 | ||
267 | if (!drw || (render && !drw->scheme) || !text || !drw->fonts) | 270 | if (!drw || (render && !drw->scheme) || !text || !drw->fonts) |
268 | return 0; | 271 | return 0; |
@@ -346,6 +349,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp | |||
346 | * character must be drawn. */ | 349 | * character must be drawn. */ |
347 | charexists = 1; | 350 | charexists = 1; |
348 | 351 | ||
352 | for (i = 0; i < nomatches_len; ++i) { | ||
353 | /* avoid calling XftFontMatch if we know we won't find a match */ | ||
354 | if (utf8codepoint == nomatches.codepoint[i]) | ||
355 | goto no_match; | ||
356 | } | ||
357 | |||
349 | fccharset = FcCharSetCreate(); | 358 | fccharset = FcCharSetCreate(); |
350 | FcCharSetAddChar(fccharset, utf8codepoint); | 359 | FcCharSetAddChar(fccharset, utf8codepoint); |
351 | 360 | ||
@@ -374,6 +383,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp | |||
374 | curfont->next = usedfont; | 383 | curfont->next = usedfont; |
375 | } else { | 384 | } else { |
376 | xfont_free(usedfont); | 385 | xfont_free(usedfont); |
386 | nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint; | ||
387 | no_match: | ||
377 | usedfont = drw->fonts; | 388 | usedfont = drw->fonts; |
378 | } | 389 | } |
379 | } | 390 | } |