mirror of
https://github.com/neovim/neovim.git
synced 2025-09-17 00:38:17 +00:00
refactor(grid): change schar_T representation to be more compact
Previously, a screen cell would occupy 28+4=32 bytes per cell as we always made space for up to MAX_MCO+1 codepoints in a cell. As an example, even a pretty modest 50*80 screen would consume 50*80*2*32 = 256000, i e a quarter megabyte With the factor of two due to the TUI side buffer, and even more when using msg_grid and/or ext_multigrid. This instead stores a 4-byte union of either: - a valid UTF-8 sequence up to 4 bytes - an escape char which is invalid UTF-8 (0xFF) plus a 24-bit index to a glyph cache This avoids allocating space for huge composed glyphs _upfront_, while still keeping rendering such glyphs reasonably fast (1 hash table lookup + one plain index lookup). If the same large glyphs are using repeatedly on the screen, this is still a net reduction of memory/cache consumption. The only case which really gets worse is if you blast the screen full with crazy emojis and zalgo text and even this case only leads to 4 extra bytes per char. When only <= 4-byte glyphs are used, plus the 4-byte attribute code, i e 8 bytes in total there is a factor of four reduction of memory use. Memory which will be quite hot in cache as the screen buffer is scanned over in win_line() buffer text drawing A slight complication is that the representation depends on host byte order. I've tested this manually by compling and running this in qemu-s390x and it works fine. We might add a qemu based solution to CI at some point.
This commit is contained in:
@@ -833,8 +833,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
||||
bool was_space = false;
|
||||
for (size_t i = 0; i < ncells; i++) {
|
||||
repeat++;
|
||||
if (i == ncells - 1 || attrs[i] != attrs[i + 1]
|
||||
|| strcmp(chunk[i], chunk[i + 1]) != 0) {
|
||||
if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) {
|
||||
if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) {
|
||||
// close to overflowing the redraw buffer. finish this event,
|
||||
// flush, and start a new "grid_line" event at the current position.
|
||||
@@ -859,7 +858,9 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
||||
uint32_t csize = (repeat > 1) ? 3 : ((attrs[i] != last_hl) ? 2 : 1);
|
||||
nelem++;
|
||||
mpack_array(buf, csize);
|
||||
mpack_str(buf, chunk[i]);
|
||||
char sc_buf[MAX_SCHAR_SIZE];
|
||||
schar_get(sc_buf, chunk[i]);
|
||||
mpack_str(buf, sc_buf);
|
||||
if (csize >= 2) {
|
||||
mpack_uint(buf, (uint32_t)attrs[i]);
|
||||
if (csize >= 3) {
|
||||
@@ -869,7 +870,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
||||
data->ncells_pending += MIN(repeat, 2);
|
||||
last_hl = attrs[i];
|
||||
repeat = 0;
|
||||
was_space = strequal(chunk[i], " ");
|
||||
was_space = chunk[i] == schar_from_ascii(' ');
|
||||
}
|
||||
}
|
||||
// If the last chunk was all spaces, add a clearing chunk even if there are
|
||||
@@ -893,8 +894,10 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
|
||||
for (int i = 0; i < endcol - startcol; i++) {
|
||||
remote_ui_cursor_goto(ui, row, startcol + i);
|
||||
remote_ui_highlight_set(ui, attrs[i]);
|
||||
remote_ui_put(ui, chunk[i]);
|
||||
if (utf_ambiguous_width(utf_ptr2char((char *)chunk[i]))) {
|
||||
char sc_buf[MAX_SCHAR_SIZE];
|
||||
schar_get(sc_buf, chunk[i]);
|
||||
remote_ui_put(ui, sc_buf);
|
||||
if (utf_ambiguous_width(utf_ptr2char(sc_buf))) {
|
||||
data->client_col = -1; // force cursor update
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user