From 60b3ccc64115fb7e4b303eb1b93ba16d10fff1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 14 Mar 2021 19:19:10 +0100 Subject: [PATCH] =?UTF-8?q?term:=20runtime=20switch=20between=20a=20?= =?UTF-8?q?=E2=80=98fast=E2=80=99=20and=20a=20=E2=80=98generic=E2=80=99=20?= =?UTF-8?q?ASCII=20print=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- csi.c | 2 ++ sixel.c | 7 ++++++ terminal.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ terminal.h | 4 ++++ vt.c | 23 ++++++-------------- 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/csi.c b/csi.c index 5b102f58..4f0814bf 100644 --- a/csi.c +++ b/csi.c @@ -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 */ diff --git a/sixel.c b/sixel.c index be4981cf..3953f735 100644 --- a/sixel.c +++ b/sixel.c @@ -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); } diff --git a/terminal.c b/terminal.c index 85f267e1..0fe53ac1 100644 --- a/terminal.c +++ b/terminal.c @@ -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) { diff --git a/terminal.h b/terminal.h index 0fcd97ea..044fc581 100644 --- a/terminal.h +++ b/terminal.h @@ -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( diff --git a/vt.c b/vt.c index d94420da..af4691ea 100644 --- a/vt.c +++ b/vt.c @@ -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; } }