From 6e55be1557104184eb8eaa33ce7d5fd33fa1bdb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 18 Jul 2019 10:33:58 +0200 Subject: [PATCH] render: cache generated glyphs for regular ASCII characters To avoid having to re-generate glyphs, cache the glyphs. For now, we only cache ASCII characters, as this allows us to lookup the cache by simply indexing with the character (into a 256-entry array). --- main.c | 2 ++ render.c | 44 +++++++++++++++++++++++++++++++++++++------- render.h | 2 +- terminal.h | 7 +++++++ 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index 18673401..6db76da5 100644 --- a/main.c +++ b/main.c @@ -795,6 +795,8 @@ out: for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) { if (term.fonts[i].font != NULL) cairo_scaled_font_destroy(term.fonts[i].font); + for (size_t j = 0; j < 256; j++) + free(term.fonts[i].glyph_cache[j].glyphs); } if (term.ptmx != -1) diff --git a/render.c b/render.c index de887efa..e9015ba2 100644 --- a/render.c +++ b/render.c @@ -16,7 +16,7 @@ #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) -const struct font * +struct font * attrs_to_font(struct terminal *term, const struct attributes *attrs) { int idx = attrs->italic << 1 | attrs->bold; @@ -182,13 +182,43 @@ render_cell(struct terminal *term, struct buffer *buf, const struct cell *cell, int new_glyphs = sizeof(gseq.glyphs) / sizeof(gseq.glyphs[0]) - gseq.count; - cairo_status_t status = cairo_scaled_font_text_to_glyphs( - attrs_to_font(term, &cell->attrs)->font, x, y + term->fextents.ascent, - cell->c, strnlen(cell->c, 4), &gseq.g, &new_glyphs, - NULL, NULL, NULL); + struct font *font = attrs_to_font(term, &cell->attrs); - if (status != CAIRO_STATUS_SUCCESS) - return; + struct glyph_cache *entry = cell->c[1] == '\0' + ? &font->glyph_cache[(unsigned char)cell->c[0]] + : NULL; + + if (likely(entry != NULL && entry->glyphs != NULL)) { + /* Copy cached glyph(s) and upate position */ + for (size_t i = 0; i < entry->count; i++) { + gseq.g[i] = entry->glyphs[i]; + gseq.g[i].x += x; + gseq.g[i].y += y; + } + + new_glyphs = entry->count; + } else { + /* Must generate new glyph(s) */ + cairo_status_t status = cairo_scaled_font_text_to_glyphs( + font->font, x, y + term->fextents.ascent, + cell->c, strnlen(cell->c, 4), &gseq.g, &new_glyphs, + NULL, NULL, NULL); + + if (status != CAIRO_STATUS_SUCCESS) + return; + + if (entry != NULL) { + assert(entry->glyphs == NULL); + entry->glyphs = malloc(new_glyphs * sizeof(entry->glyphs[0])); + entry->count = new_glyphs; + + for (size_t i = 0; i < new_glyphs; i++) { + entry->glyphs[i] = gseq.g[i]; + entry->glyphs[i].x -= x; + entry->glyphs[i].y -= y; + } + } + } gseq.g += new_glyphs; gseq.count += new_glyphs; diff --git a/render.h b/render.h index 93220dd8..c34257ec 100644 --- a/render.h +++ b/render.h @@ -2,7 +2,7 @@ #include "terminal.h" -const struct font *attrs_to_font( +struct font *attrs_to_font( struct terminal *term, const struct attributes *attrs); void grid_render(struct terminal *term); diff --git a/terminal.h b/terminal.h index d17d2128..8bfc3918 100644 --- a/terminal.h +++ b/terminal.h @@ -202,6 +202,11 @@ struct primary { uint32_t serial; }; +struct glyph_cache { + cairo_glyph_t *glyphs; + int count; +}; + struct font { cairo_scaled_font_t *font; struct { @@ -212,6 +217,8 @@ struct font { double position; double thickness; } strikeout; + + struct glyph_cache glyph_cache[256]; }; struct terminal {