From d70956da08c987af639fd8e03e669ca59c4c542b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 1 Jul 2019 12:23:38 +0200 Subject: [PATCH] wip: use a sliding window instead of memmove() to scroll Instead of memmoving a large amount of data on every scroll, use a sliding window. That is, each time we scroll, we offset origin. --- csi.c | 2 +- grid.c | 34 +++++++++++++++ grid.h | 4 ++ main.c | 66 ++++++++++++++++++++--------- terminal.c | 120 ++++++++++++++++++----------------------------------- terminal.h | 16 +++---- vt.c | 6 ++- 7 files changed, 140 insertions(+), 108 deletions(-) diff --git a/csi.c b/csi.c index 647d5052..9e3b8675 100644 --- a/csi.c +++ b/csi.c @@ -280,7 +280,7 @@ csi_dispatch(struct terminal *term, uint8_t final) i == term->vt.params.idx - 1 ? "" : ";"); } - c += snprintf(&log[c], sizeof(log) - c, "%c (%zu parameters)", + c += snprintf(&log[c], sizeof(log) - c, "%c (%d parameters)", final, term->vt.params.idx); LOG_DBG("%s", log); #endif diff --git a/grid.c b/grid.c index 67f6e57a..bb8d46eb 100644 --- a/grid.c +++ b/grid.c @@ -6,3 +6,37 @@ #define LOG_MODULE "grid" #define LOG_ENABLE_DBG 1 #include "log.h" + +struct cell * +grid_get_range(struct grid *grid, size_t start, size_t *length) +{ +#define min(x, y) ((x) < (y) ? (x) : (y)) + assert(*length <= grid->size); + + size_t real_start = (grid->offset + start) % grid->size; + assert(real_start < grid->size); + + *length = min(*length, grid->size - real_start); + assert(real_start + *length <= grid->size); + + return &grid->cells[real_start]; +#undef min +} + +void +grid_memset(struct grid *grid, size_t start, int c, size_t length) +{ + size_t left = length; + while (left > 0) { + size_t count = left; + struct cell *cells = grid_get_range(grid, start, &count); + + assert(count > 0); + assert(count <= left); + + memset(cells, c, count * sizeof(cells[0])); + + left -= count; + start += count; + } +} diff --git a/grid.h b/grid.h index 580ef343..3a5f3f4b 100644 --- a/grid.h +++ b/grid.h @@ -1,3 +1,7 @@ #pragma once +#include #include "terminal.h" + +struct cell *grid_get_range(struct grid *grid, size_t start, size_t *length); +void grid_memset(struct grid *grid, size_t start, int c, size_t length); diff --git a/main.c b/main.c index f4f9eaa7..a1e7f5ee 100644 --- a/main.c +++ b/main.c @@ -79,24 +79,42 @@ attrs_to_font(struct context *c, const struct attributes *attrs) static void grid_render_update(struct context *c, struct buffer *buf, const struct damage *dmg) { - LOG_DBG("damage: UPDATE: %d -> %d", - dmg->range.start, dmg->range.start + dmg->range.length); + LOG_DBG("damage: UPDATE: %d -> %d (offset = %d)", + (dmg->range.start - c->term.grid->offset) % c->term.grid->size, + (dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length, + c->term.grid->offset); + + int start = dmg->range.start; + int length = dmg->range.length; + + if (start < c->term.grid->offset) { + int end = start + length; + if (end >= c->term.grid->offset) { + start = c->term.grid->offset; + length = end - start; + } else + return; + } const int cols = c->term.cols; - for (int linear_cursor = dmg->range.start, - row = dmg->range.start / cols, - col = dmg->range.start % cols; - linear_cursor < dmg->range.start + dmg->range.length; + for (int linear_cursor = start, + row = ((start - c->term.grid->offset) % c->term.grid->size) / cols, + col = ((start - c->term.grid->offset) % c->term.grid->size) % cols; + linear_cursor < start + length; linear_cursor++, //col = (col + 1) % cols, col = col + 1 >= c->term.cols ? 0 : col + 1, row += col == 0 ? 1 : 0) { + //LOG_DBG("UPDATE: %d (%dx%d)", linear_cursor, row, col); - const struct cell *cell = &c->term.grid->cells[linear_cursor]; - bool has_cursor = c->term.cursor.linear == linear_cursor; + //assert(linear_cursor < c->term.grid->size); + const struct cell *cell = &c->term.grid->cells[linear_cursor % c->term.grid->size]; + + bool has_cursor = c->term.cursor.linear == linear_cursor - c->term.grid->offset; + //bool has_cursor = false; int x = col * c->term.cell_width; int y = row * c->term.cell_height; @@ -160,15 +178,19 @@ grid_render_update(struct context *c, struct buffer *buf, const struct damage *d wl_surface_damage_buffer( c->wl.surface, - 0, (dmg->range.start / cols) * c->term.cell_height, + 0, ((dmg->range.start - c->term.grid->offset) / cols) * c->term.cell_height, buf->width, (dmg->range.length + cols - 1) / cols * c->term.cell_height); } static void grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dmg) { - LOG_DBG("damage: ERASE: %d -> %d", - dmg->range.start, dmg->range.start + dmg->range.length); + LOG_DBG("damage: ERASE: %d -> %d (offset = %d)", + (dmg->range.start - c->term.grid->offset) % c->term.grid->size, + (dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length, + c->term.grid->offset); + + assert(dmg->range.start >= c->term.grid->offset); cairo_set_source_rgba( buf->cairo, default_background.r, default_background.g, @@ -176,7 +198,7 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm const int cols = c->term.cols; - int start = dmg->range.start; + int start = (dmg->range.start - c->term.grid->offset) % c->term.grid->size; int left = dmg->range.length; int row = start / cols; @@ -238,17 +260,21 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm cairo_fill(buf->cairo); wl_surface_damage_buffer(c->wl.surface, x, y, width, height); } - +#if 0 /* Redraw cursor, if it's inside the erased range */ - if (c->term.cursor.linear >= dmg->range.start && - c->term.cursor.linear < dmg->range.start + dmg->range.length) + if (c->term.grid->offset + c->term.cursor.linear >= dmg->range.start && + c->term.grid->offset + c->term.cursor.linear < dmg->range.start + dmg->range.length) { grid_render_update( c, buf, &(struct damage){ .type = DAMAGE_UPDATE, - .range = {.start = c->term.cursor.linear, .length = 1}}); + .range = { + .start = (c->term.grid->offset + c->term.cursor.linear) % c->term.grid->size, + .length = 1} + }); } + #endif } static void @@ -284,7 +310,7 @@ grid_render_scroll(struct context *c, struct buffer *buf, struct damage erase = { .type = DAMAGE_ERASE, .range = { - .start = max(dmg->scroll.region.end - dmg->scroll.lines, + .start = c->term.grid->offset + max(dmg->scroll.region.end - dmg->scroll.lines, dmg->scroll.region.start) * cols, .length = min(dmg->scroll.region.end - dmg->scroll.region.start, dmg->scroll.lines) * cols, @@ -383,6 +409,8 @@ grid_render(struct context *c) tll_remove(c->term.grid->damage, it); } + c->term.grid->offset %= c->term.grid->size; + //cairo_surface_flush(buf->cairo_surface); wl_surface_attach(c->wl.surface, buf->wl_buf, 0, 0); @@ -450,8 +478,8 @@ resize(struct context *c, int width, int height) /* Update environment variables */ char cols_s[12], rows_s[12]; - sprintf(cols_s, "%u", c->term.cols); - sprintf(rows_s, "%u", c->term.rows); + sprintf(cols_s, "%d", c->term.cols); + sprintf(rows_s, "%d", c->term.rows); setenv("COLUMNS", cols_s, 1); setenv("LINES", rows_s, 1); diff --git a/terminal.c b/terminal.c index 482452c5..0bd38915 100644 --- a/terminal.c +++ b/terminal.c @@ -6,6 +6,7 @@ #define LOG_MODULE "terminal" #define LOG_ENABLE_DBG 1 #include "log.h" +#include "grid.h" #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) @@ -37,10 +38,6 @@ damage_merge_range(struct terminal *term, const struct damage *dmg) old->range.start = new_start; old->range.length = new_end - new_start; - assert(old->range.start >= 0); - assert(old->range.start < term->rows * term->cols); - assert(old->range.length >= 0); - assert(old->range.start + old->range.length <= term->rows * term->cols); return true; } @@ -53,14 +50,8 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type, { struct damage dmg = { .type = damage_type, - .range = {.start = start, .length = length}, + .range = {.start = term->grid->offset + start, .length = length}, }; - - assert(dmg.range.start >= 0); - assert(dmg.range.start < term->rows * term->cols); - assert(dmg.range.length >= 0); - assert(dmg.range.start + dmg.range.length <= term->rows * term->cols); - if (damage_merge_range(term, &dmg)) return; @@ -70,12 +61,14 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type, void term_damage_update(struct terminal *term, int start, int length) { + assert(start + length <= term->rows * term->cols); term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length); } void term_damage_erase(struct terminal *term, int start, int length) { + assert(start + length <= term->rows * term->cols); term_damage_update_or_erase(term, DAMAGE_ERASE, start, length); } @@ -87,82 +80,30 @@ term_damage_all(struct terminal *term) term_damage_update(term, 0, term->rows * term->cols); } +#if 0 static void damage_adjust_after_scroll(struct terminal *term, enum damage_type damage_type, struct scroll_region region, int lines) { - const int adjustment - = lines * term->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1); - - const int scroll_start = region.start * term->cols; - const int scroll_end = region.end * term->cols; - tll_foreach(term->grid->damage, it) { - int start = it->item.range.start; - int length = it->item.range.length; - int end = start + length; - - if (start < scroll_start && end > scroll_start) { - /* Start outside, end either inside or on the other side */ - struct damage outside = { - .type = it->item.type, - .range = {.start = start, .length = scroll_start - start}, - }; - - tll_push_back(term->grid->damage, outside); - start = scroll_start; - length = end - start; - - } - - if (start < scroll_end && end > scroll_end) { - /* End outside, start either inside or on the other side */ - struct damage outside = { - .type = it->item.type, - .range = {.start = scroll_end, .length = length - scroll_end}, - }; - - tll_push_back(term->grid->damage, outside); - end = scroll_end; - length = end - start; - } - - if (start >= scroll_start && end <= scroll_end) { - /* Completely inside scroll region */ - start -= adjustment; - it->item.range.start = start; - - if (start < scroll_start) { - /* Scrolled up outside scroll region */ - int new_length = length - (scroll_start - start); - assert(new_length < length); - - if (new_length <= 0) - tll_remove(term->grid->damage, it); - else { - it->item.range.start = scroll_start; - it->item.range.length = new_length; - } - } - - if (start + length > scroll_end) { - /* Scrolled down outside scroll region */ - if (start >= scroll_end) - tll_remove(term->grid->damage, it); - else { - it->item.range.start = start; - it->item.range.length = scroll_end - start; - } + if (it->item.range.start < term->grid->offset) { + int end = it->item.range.start + it->item.range.length; + if (end >= term->grid->offset) { + it->item.range.start = term->grid->offset; + it->item.range.length = end - it->item.range.start; + } else { + tll_remove(term->grid->damage, it); } } } } +#endif void term_damage_scroll(struct terminal *term, enum damage_type damage_type, struct scroll_region region, int lines) { - damage_adjust_after_scroll(term, damage_type, region, lines); + //damage_adjust_after_scroll(term, damage_type, region, lines); if (tll_length(term->grid->scroll_damage) > 0) { struct damage *dmg = &tll_back(term->grid->scroll_damage); @@ -185,8 +126,11 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type, void term_erase(struct terminal *term, int start, int end) { + LOG_DBG("erase: %d-%d", start, end); assert(end >= start); - memset(&term->grid->cells[start], 0, (end - start) * sizeof(term->grid->cells[0])); + assert(end <= term->rows * term->cols); + + grid_memset(term->grid, start, 0, end - start); term_damage_erase(term, start, end - start); } @@ -199,13 +143,10 @@ term_cursor_linear(const struct terminal *term, int row, int col) void term_cursor_to(struct terminal *term, int row, int col) { - assert(row >= 0); assert(row < term->rows); - assert(col >= 0); assert(col < term->cols); int new_linear = row * term->cols + col; - assert(new_linear >= 0); assert(new_linear < term->rows * term->cols); term_damage_update(term, term->cursor.linear, 1); @@ -248,11 +189,13 @@ term_cursor_down(struct terminal *term, int count) void term_scroll_partial(struct terminal *term, struct scroll_region region, int rows) { + LOG_DBG("scroll: %d rows", rows); if (rows >= region.end - region.start) { assert(false && "untested"); return; } +#if 0 int cell_dst = (region.start + 0) * term->cols; int cell_src = (region.start + rows) * term->cols; int cell_count = (region.end - region.start - rows) * term->cols; @@ -260,7 +203,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols, cell_src / term->cols, cell_dst / term->cols); - const size_t bytes = cell_count * sizeof(term->grid->cells[0]); + const int bytes = cell_count * sizeof(term->grid->cells[0]); memmove( &term->grid->cells[cell_dst], &term->grid->cells[cell_src], bytes); @@ -269,6 +212,15 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows rows * term->cols * sizeof(term->grid->cells[0])); term_damage_scroll(term, DAMAGE_SCROLL, region, rows); +#else + /* TODO */ + assert(region.start == 0 && region.end == term->rows); + assert(rows < term->rows); + + term->grid->offset += rows * term->cols; + grid_memset(term->grid, (region.end - rows) * term->cols, 0, rows * term->cols); + term_damage_scroll(term, DAMAGE_SCROLL, region, rows); +#endif } void @@ -286,6 +238,7 @@ term_scroll_reverse_partial(struct terminal *term, return; } +#if 0 int cell_dst = (region.start + rows) * term->cols; int cell_src = (region.start + 0) * term->cols; int cell_count = (region.end - region.start - rows) * term->cols; @@ -293,7 +246,7 @@ term_scroll_reverse_partial(struct terminal *term, LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols, cell_src / term->cols, cell_dst / term->cols); - const size_t bytes = cell_count * sizeof(term->grid->cells[0]); + const int bytes = cell_count * sizeof(term->grid->cells[0]); memmove( &term->grid->cells[cell_dst], &term->grid->cells[cell_src], bytes); @@ -302,6 +255,15 @@ term_scroll_reverse_partial(struct terminal *term, rows * term->cols * sizeof(term->grid->cells[0])); term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); +#else + /* TODO */ + assert(false); + assert(region.start == 0 && region.end == 0); + assert(rows < term->rows); + + term->grid->offset -= rows * term->cols; + term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); +#endif } void diff --git a/terminal.h b/terminal.h index cceaa6b6..4efaab9f 100644 --- a/terminal.h +++ b/terminal.h @@ -62,8 +62,8 @@ struct damage { }; struct grid { - size_t size; - size_t offset; + int size; + int offset; struct cell *cells; @@ -73,7 +73,7 @@ struct grid { struct vt_subparams { unsigned value[16]; - size_t idx; + int idx; }; struct vt_param { @@ -85,20 +85,20 @@ struct vt { int state; /* enum state */ struct { struct vt_param v[16]; - size_t idx; + int idx; } params; struct { uint8_t data[2]; - size_t idx; + int idx; } intermediates; struct { uint8_t data[1024]; - size_t idx; + int idx; } osc; struct { uint8_t data[4]; - size_t idx; - size_t left; + int idx; + int left; } utf8; struct attributes attrs; bool dim; diff --git a/vt.c b/vt.c index c7e75a94..f52b6d0f 100644 --- a/vt.c +++ b/vt.c @@ -678,7 +678,11 @@ action(struct terminal *term, enum action action, uint8_t c) term_cursor_to(term, term->cursor.row + 1, 0); } - struct cell *cell = &term->grid->cells[term->cursor.linear]; + size_t cell_count = 1; + struct cell *cell = grid_get_range( + term->grid, term->cursor.linear, &cell_count); + assert(cell_count == 1); + term_damage_update(term, term->cursor.linear, 1); if (term->vt.utf8.idx > 0) {