From e4a631f7f097426e70d24e3a2ec50f7626ae860f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 10 Jul 2019 19:18:53 +0200 Subject: [PATCH] terminal: scrolling: prefetch cells of scrolled in lines Since newly scrolled in lines will be erased, we want them in the cache. So, allocate and prefetch new lines, then repair non-scrolling regions (to give the prefetch time to actually fetch the data). Finally, erase the newly scrolled in lines. This also fixes a bug where the fixup for the non-scrolling regions could crash on an unallocated row (we were accessing rows that would be, but hadn't yet been, scrolled in). --- terminal.c | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/terminal.c b/terminal.c index 7a054692..f0fa3cfc 100644 --- a/terminal.c +++ b/terminal.c @@ -151,15 +151,6 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows assert(rows < term->rows && "unimplemented"); - /* Top non-scrolling region */ - for (int i = region.start - 1; i >= 0; i--) - grid_swap_row(term->grid, i, i + rows); - - /* Bottom non-scrolling region */ - for (int i = term->rows - 1; i >= region.end; i--) - grid_swap_row(term->grid, i, i + rows); - - /* Offset grid origin */ bool view_follows = term->grid->view == term->grid->offset; term->grid->offset += rows; term->grid->offset %= term->grid->num_rows; @@ -167,11 +158,28 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows if (view_follows) term->grid->view = term->grid->offset; - for (int r = max(region.end - rows, 0); r < region.end; r++) { - struct row *row = grid_row(term->grid, r); - erase_line(term, row); + /* + * This loop serves two purposes: + * 1) ensure all visible lines are *allocated* + * 2) prefetch the cells - this makes life easier for erase_line() below + */ + for (int r = max(region.end - rows, 0); r < term->rows; r++) { + struct row *row = grid_row(term->grid, r); + __builtin_prefetch(row->cells, 1, 3); } + /* Top non-scrolling region. */ + for (int i = region.start - 1; i >= 0; i--) + grid_swap_row(term->grid, i - rows, i); + + /* Bottom non-scrolling region */ + for (int i = term->rows - 1; i >= region.end; i--) + grid_swap_row(term->grid, i - rows, i); + + /* Erase scrolled in lines */ + for (int r = max(region.end - rows, 0); r < region.end; r++) + erase_line(term, grid_row(term->grid, r)); + term_damage_scroll(term, DAMAGE_SCROLL, region, rows); term->grid->cur_row = grid_row(term->grid, term->cursor.row); } @@ -192,13 +200,17 @@ term_scroll_reverse_partial(struct terminal *term, assert(rows < term->rows && "unimplemented"); bool view_follows = term->grid->view == term->grid->offset; - term->grid->offset += term->grid->num_rows - rows; term->grid->offset %= term->grid->num_rows; if (view_follows) term->grid->view = term->grid->offset; + for (int r = 0; r < min(region.start + rows, region.end); r++) { + struct row *row = grid_row(term->grid, r); + __builtin_prefetch(row->cells, 1, 3); + } + /* Bottom non-scrolling region */ for (int i = region.end + rows; i < term->rows + rows; i++) grid_swap_row(term->grid, i, i - rows); @@ -207,10 +219,9 @@ term_scroll_reverse_partial(struct terminal *term, for (int i = 0 + rows; i < region.start + rows; i++) grid_swap_row(term->grid, i, i - rows); - term_erase( - term, - &(struct coord){0, region.start}, - &(struct coord){term->cols - 1, min(region.start + rows, region.end) - 1}); + /* Erase scrolled in lines */ + for (int r = region.start; r < min(region.start + rows, region.end); r++) + erase_line(term, grid_row(term->grid, r)); term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); term->grid->cur_row = grid_row(term->grid, term->cursor.row);