drw_text: improve performance when there's no match - dmenu - dynamic menu | |
git clone git://git.suckless.org/dmenu | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 22511c41d55a38a770541ae617a09383d5e6ad1c | |
parent 77526f756e23e362081ac807521f901f2e5cd5e6 | |
Author: NRK <[email protected]> | |
Date: Thu, 24 Mar 2022 00:37:55 +0600 | |
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 | |
Diffstat: | |
M drw.c | 13 ++++++++++++- | |
1 file changed, 12 insertions(+), 1 deletion(-) | |
--- | |
diff --git a/drw.c b/drw.c | |
@@ -251,7 +251,7 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned i… | |
int | |
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int … | |
{ | |
- int ty, ellipsis_x = 0; | |
+ int i, ty, ellipsis_x = 0; | |
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, ellipsis_width; | |
XftDraw *d = NULL; | |
Fnt *usedfont, *curfont, *nextfont; | |
@@ -263,6 +263,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned i… | |
FcPattern *match; | |
XftResult result; | |
int charexists = 0, overflow = 0; | |
+ /* keep track of a couple codepoints for which we have no match. */ | |
+ enum { nomatches_len = 64 }; | |
+ static struct { long codepoint[nomatches_len]; unsigned int idx; } nom… | |
if (!drw || (render && !drw->scheme) || !text || !drw->fonts) | |
return 0; | |
@@ -346,6 +349,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned … | |
* character must be drawn. */ | |
charexists = 1; | |
+ for (i = 0; i < nomatches_len; ++i) { | |
+ /* avoid calling XftFontMatch if we know we wo… | |
+ if (utf8codepoint == nomatches.codepoint[i]) | |
+ goto no_match; | |
+ } | |
+ | |
fccharset = FcCharSetCreate(); | |
FcCharSetAddChar(fccharset, utf8codepoint); | |
@@ -374,6 +383,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned i… | |
curfont->next = usedfont; | |
} else { | |
xfont_free(usedfont); | |
+ nomatches.codepoint[++nomatches.idx % … | |
+no_match: | |
usedfont = drw->fonts; | |
} | |
} |