term: runtime switch between a ‘fast’ and a ‘generic’ ASCII print function

term_print() is called whenever the client application “prints”
something to the grid. It is called for both ASCII and UTF-8
characters, and needs to handle sixels, insert mode and ASCII
vs. graphical charsets.

Since it’s on the hot path, this becomes unnecessarily slow.

This patch adds a “fast” version of term_print(), tailored for the
common case: ASCII characters in non-insert mode, without any sixels
and non-graphical charsets.

A new function, term_update_ascii_printer(), has been added, and must
be called whenever:

* The currently selected charset *index* changes
* The currently selected charset changes (from ASCII to graphical, or
  vice verse)
* Sixels are added to the grid
* Sixels are removed from the grid
* Insert mode is enabled/disabled
This commit is contained in:
Daniel Eklöf 2021-03-14 19:19:10 +01:00
parent d8f0e701b5
commit 60b3ccc641
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
5 changed files with 84 additions and 16 deletions

2
csi.c
View file

@ -1136,6 +1136,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
case 4: /* Insert Mode - IRM */
term->insert_mode = true;
term_update_ascii_printer(term);
break;
case 12: /* Send/receive Mode - SRM */
@ -1156,6 +1157,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
switch (vt_param_get(term, 0, 0)) {
case 4: /* Insert Mode - IRM */
term->insert_mode = false;
term_update_ascii_printer(term);
break;
case 2: /* Keyboard Action Mode - AM */

View file

@ -331,6 +331,7 @@ sixel_scroll_up(struct terminal *term, int rows)
}
}
term_update_ascii_printer(term);
verify_sixels(term);
}
@ -353,6 +354,7 @@ sixel_scroll_down(struct terminal *term, int rows)
break;
}
term_update_ascii_printer(term);
verify_sixels(term);
}
@ -552,6 +554,8 @@ sixel_overwrite_by_rectangle(
_sixel_overwrite_by_rectangle(term, 0, col, height - rows_to_wrap_around, width);
} else
_sixel_overwrite_by_rectangle(term, start, col, height, width);
term_update_ascii_printer(term);
}
/* Row numbers are relative to grid offset */
@ -605,6 +609,8 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
}
}
}
term_update_ascii_printer(term);
}
void
@ -859,6 +865,7 @@ sixel_unhook(struct terminal *term)
LOG_DBG("you now have %zu sixels in current grid",
tll_length(term->grid->sixel_images));
term_update_ascii_printer(term);
render_refresh(term);
}

View file

@ -1187,6 +1187,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
#endif
};
term_update_ascii_printer(term);
for (size_t i = 0; i < 4; i++) {
size_t j = 0;
tll_foreach(conf->fonts[i], it) {
@ -1702,6 +1704,8 @@ term_reset(struct terminal *term, bool hard)
term_ime_enable(term);
#endif
term_update_ascii_printer(term);
if (!hard)
return;
@ -2335,6 +2339,7 @@ term_restore_cursor(struct terminal *term, const struct cursor *cursor)
term->vt.attrs = term->vt.saved_attrs;
term->charsets = term->saved_charsets;
term_update_ascii_printer(term);
}
void
@ -2813,6 +2818,21 @@ term_print(struct terminal *term, wchar_t wc, int width)
{
xassert(width > 0);
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
wc >= 0x60 && wc <= 0x7e)
{
/* 0x60 - 0x7e */
static const wchar_t vt100_0[] = {
L'', L'', L'', L'', L'', L'', L'°', L'±', /* ` - g */
L'', L'', L'', L'', L'', L'', L'', L'', /* h - o */
L'', L'', L'', L'', L'', L'', L'', L'', /* p - w */
L'', L'', L'', L'π', L'', L'£', L'·', /* x - ~ */
};
xassert(width == 1);
wc = vt100_0[wc - 0x60];
}
print_linewrap(term);
print_insert(term, width);
@ -2855,6 +2875,50 @@ term_print(struct terminal *term, wchar_t wc, int width)
xassert(!term->grid->cursor.lcf);
}
static void
ascii_printer_generic(struct terminal *term, wchar_t wc)
{
term_print(term, wc, 1);
}
static void
ascii_printer_fast(struct terminal *term, wchar_t wc)
{
xassert(term->charsets.set[term->charsets.selected] == CHARSET_ASCII);
xassert(!term->insert_mode);
xassert(tll_length(term->grid->sixel_images) == 0);
print_linewrap(term);
/* *Must* get current cell *after* linewrap+insert */
struct row *row = term->grid->cur_row;
struct cell *cell = &row->cells[term->grid->cursor.point.col];
cell->wc = term->vt.last_printed = wc;
cell->attrs = term->vt.attrs;
row->dirty = true;
cell->attrs.clean = 0;
/* Advance cursor */
if (unlikely(++term->grid->cursor.point.col >= term->cols)) {
term->grid->cursor.lcf = true;
term->grid->cursor.point.col--;
} else
xassert(!term->grid->cursor.lcf);
}
void
term_update_ascii_printer(struct terminal *term)
{
term->ascii_printer =
unlikely(tll_length(term->grid->sixel_images) > 0 ||
term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC ||
term->insert_mode)
? &ascii_printer_generic
: &ascii_printer_fast;
}
enum term_surface
term_surface_kind(const struct terminal *term, const struct wl_surface *surface)
{

View file

@ -266,6 +266,8 @@ struct terminal {
struct reaper *reaper;
const struct config *conf;
void (*ascii_printer)(struct terminal *term, wchar_t c);
pid_t slave;
int ptmx;
@ -607,6 +609,8 @@ struct terminal *term_init(
bool term_shutdown(struct terminal *term);
int term_destroy(struct terminal *term);
void term_update_ascii_printer(struct terminal *term);
void term_reset(struct terminal *term, bool hard);
bool term_to_slave(struct terminal *term, const void *data, size_t len);
bool term_paste_data_to_slave(

23
vt.c
View file

@ -184,11 +184,13 @@ action_execute(struct terminal *term, uint8_t c)
case '\x0e':
/* SO - shift out */
term->charsets.selected = 1; /* G1 */
term_update_ascii_printer(term);
break;
case '\x0f':
/* SI - shift in */
term->charsets.selected = 0; /* G0 */
term_update_ascii_printer(term);
break;
/*
@ -230,21 +232,7 @@ action_execute(struct terminal *term, uint8_t c)
static void
action_print(struct terminal *term, uint8_t c)
{
/* 0x60 - 0x7e */
static const wchar_t vt100_0[] = {
L'', L'', L'', L'', L'', L'', L'°', L'±', /* ` - g */
L'', L'', L'', L'', L'', L'', L'', L'', /* h - o */
L'', L'', L'', L'', L'', L'', L'', L'', /* p - w */
L'', L'', L'', L'π', L'', L'£', L'·', /* x - ~ */
};
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
c >= 0x60 && c <= 0x7e)
{
term_print(term, vt100_0[c - 0x60], 1);
} else {
term_print(term, c, 1);
}
term->ascii_printer(term, c);
}
static void
@ -414,11 +402,13 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
case 'N':
/* SS2 - Single Shift 2 */
term->charsets.selected = 2; /* G2 */
term_update_ascii_printer(term);
break;
case 'O':
/* SS3 - Single Shift 3 */
term->charsets.selected = 3; /* G3 */
term_update_ascii_printer(term);
break;
case '\\':
@ -453,6 +443,7 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
'+' ? 3 : -1;
xassert(idx != -1);
term->charsets.set[idx] = CHARSET_GRAPHIC;
term_update_ascii_printer(term);
break;
}
@ -465,7 +456,7 @@ action_esc_dispatch(struct terminal *term, uint8_t final)
'+' ? 3 : -1;
xassert(idx != -1);
term->charsets.set[idx] = CHARSET_ASCII;
term_update_ascii_printer(term);
break;
}
}