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).
This commit is contained in:
Daniel Eklöf 2019-07-18 10:33:58 +02:00
parent c9803a2018
commit 6e55be1557
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
4 changed files with 47 additions and 8 deletions

2
main.c
View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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 {