From 1ff1b3a71e8edcad62c98a3c80b6e1d8a77bc26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 10 Jul 2019 16:27:55 +0200 Subject: [PATCH] grid: don't pre-allocate the entire grid (with all scrollback lines) The row array may now contain NULL pointers. This means the corresponding row hasn't yet been allocated and initialized. On a resize, we explicitly allocate the visible rows. Uninitialized rows are then allocated the first time they are referenced. --- commands.c | 4 ++-- grid.c | 19 +++++++++++++++++++ grid.h | 28 ++++++++++++++++++++++------ main.c | 12 ++++-------- render.c | 47 ++++++++++++++++++++--------------------------- terminal.c | 1 - terminal.h | 2 +- 7 files changed, 68 insertions(+), 45 deletions(-) diff --git a/commands.c b/commands.c index 472cf880..75ce8cee 100644 --- a/commands.c +++ b/commands.c @@ -26,7 +26,7 @@ cmd_scrollback_up(struct terminal *term, int rows) assert(new_view < term->grid->num_rows); /* Avoid scrolling in uninitialized rows */ - while (!term->grid->rows[new_view]->initialized) + while (term->grid->rows[new_view] == NULL) new_view = (new_view + 1) % term->grid->num_rows; if (new_view == term->grid->view) { @@ -87,7 +87,7 @@ cmd_scrollback_down(struct terminal *term, int rows) for (int i = 0; i < term->rows; i++) { int row_no = (new_view + i) % term->grid->num_rows; - if (!term->grid->rows[row_no]->initialized) { + if (term->grid->rows[row_no] == NULL) { all_initialized = false; new_view--; break; diff --git a/grid.c b/grid.c index 6b89ad85..2ffae9a3 100644 --- a/grid.c +++ b/grid.c @@ -25,3 +25,22 @@ grid_swap_row(struct grid *grid, int row_a, int row_b) grid->rows[real_a]->dirty = true; grid->rows[real_b]->dirty = true; } + +struct row * +grid_row_alloc(int cols) +{ + struct row *row = malloc(sizeof(*row)); + row->cells = calloc(cols, sizeof(row->cells[0])); + row->dirty = false; /* TODO: parameter? */ + return row; +} + +void +grid_row_free(struct row *row) +{ + if (row == NULL) + return; + + free(row->cells); + free(row); +} diff --git a/grid.h b/grid.h index ba31fe4e..47b68839 100644 --- a/grid.h +++ b/grid.h @@ -3,18 +3,34 @@ #include #include "terminal.h" +void grid_swap_row(struct grid *grid, int row_a, int row_b); +struct row *grid_row_alloc(int cols); +void grid_row_free(struct row *row); + static inline struct row * -grid_row(struct grid *grid, int row) +grid_row(struct grid *grid, int row_no) { assert(grid->offset >= 0); - return grid->rows[(grid->offset + row + grid->num_rows) % grid->num_rows]; + + int real_row = (grid->offset + row_no + grid->num_rows) % grid->num_rows; + struct row *row = grid->rows[real_row]; + + if (row == NULL) { + row = grid_row_alloc(grid->num_cols); + grid->rows[real_row] = row; + } + + return row; } static inline struct row * -grid_row_in_view(struct grid *grid, int row) +grid_row_in_view(struct grid *grid, int row_no) { assert(grid->view >= 0); - return grid->rows[(grid->view + row + grid->num_rows) % grid->num_rows]; -} -void grid_swap_row(struct grid *grid, int row_a, int row_b); + int real_row = (grid->offset + row_no + grid->num_rows) % grid->num_rows; + struct row *row = grid->rows[real_row]; + + assert(row != NULL); + return row; +} diff --git a/main.c b/main.c index dd16d277..0b3485bc 100644 --- a/main.c +++ b/main.c @@ -624,15 +624,11 @@ out: if (term.kbd.xkb != NULL) xkb_context_unref(term.kbd.xkb); - for (int row = 0; row < term.normal.num_rows; row++) { - free(term.normal.rows[row]->cells); - free(term.normal.rows[row]); - } + for (int row = 0; row < term.normal.num_rows; row++) + grid_row_free(term.normal.rows[row]); free(term.normal.rows); - for (int row = 0; row < term.alt.num_rows; row++) { - free(term.alt.rows[row]->cells); - free(term.alt.rows[row]); - } + for (int row = 0; row < term.alt.num_rows; row++) + grid_row_free(term.alt.rows[row]); free(term.alt.rows); for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) { diff --git a/render.c b/render.c index 209d8f6f..65e2ab96 100644 --- a/render.c +++ b/render.c @@ -346,21 +346,27 @@ reflow(struct row **new_grid, int new_cols, int new_rows, size_t copy_cols = min(new_cols, old_cols); size_t clear_cols = new_cols - copy_cols; + if (old_grid[r] == NULL) + continue; + + if (new_grid[r] == NULL) + new_grid[r] = grid_row_alloc(new_cols); + struct cell *new_cells = new_grid[r]->cells; const struct cell *old_cells = old_grid[r]->cells; - new_grid[r]->initialized = old_grid[r]->initialized; new_grid[r]->dirty = old_grid[r]->dirty; - memcpy(new_cells, old_cells, copy_cols * sizeof(new_cells[0])); memset(&new_cells[copy_cols], 0, clear_cols * sizeof(new_cells[0])); } +#if 0 for (int r = min(new_rows, old_rows); r < new_rows; r++) { new_grid[r]->initialized = false; new_grid[r]->dirty = false; memset(new_grid[r]->cells, 0, new_cols * sizeof(new_grid[r]->cells[0])); } +#endif } /* Move to terminal.c? */ @@ -386,20 +392,14 @@ render_resize(struct terminal *term, int width, int height) const int new_alt_grid_rows = new_rows; /* Allocate new 'normal' grid */ - struct row **normal = malloc(new_normal_grid_rows * sizeof(normal[0])); - for (int r = 0; r < new_normal_grid_rows; r++) { - struct row *row = malloc(sizeof(*row)); - row->cells = malloc(new_cols * sizeof(row->cells[0])); - normal[r] = row; - } + struct row **normal = calloc(new_normal_grid_rows, sizeof(normal[0])); + for (int r = 0; r < new_rows; r++) + normal[r] = grid_row_alloc(new_cols); /* Allocate new 'alt' grid */ - struct row **alt = malloc(new_alt_grid_rows * sizeof(alt[0])); - for (int r = 0; r < new_alt_grid_rows; r++) { - struct row *row = malloc(sizeof(*row)); - row->cells = malloc(new_cols * sizeof(row->cells[0])); - alt[r] = row; - } + struct row **alt = calloc(new_alt_grid_rows, sizeof(alt[0])); + for (int r = 0; r < new_rows; r++) + alt[r] = grid_row_alloc(new_cols); /* Reflow content */ reflow(normal, new_cols, new_normal_grid_rows, @@ -407,23 +407,14 @@ render_resize(struct terminal *term, int width, int height) reflow(alt, new_cols, new_alt_grid_rows, term->alt.rows, old_cols, old_alt_grid_rows); - for (int r = 0; r < new_rows; r++) { - normal[r]->initialized = true; - alt[r]->initialized = true; - } - /* Free old 'normal' grid */ - for (int r = 0; r < term->normal.num_rows; r++) { - free(term->normal.rows[r]->cells); - free(term->normal.rows[r]); - } + for (int r = 0; r < term->normal.num_rows; r++) + grid_row_free(term->normal.rows[r]); free(term->normal.rows); /* Free old 'alt' grid */ - for (int r = 0; r < term->alt.num_rows; r++) { - free(term->alt.rows[r]->cells); - free(term->alt.rows[r]); - } + for (int r = 0; r < term->alt.num_rows; r++) + grid_row_free(term->alt.rows[r]); free(term->alt.rows); term->cols = new_cols; @@ -431,8 +422,10 @@ render_resize(struct terminal *term, int width, int height) term->normal.rows = normal; term->normal.num_rows = new_normal_grid_rows; + term->normal.num_cols = new_cols; term->alt.rows = alt; term->alt.num_rows = new_alt_grid_rows; + term->alt.num_cols = new_cols; LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d", term->width, term->height, term->cols, term->rows); diff --git a/terminal.c b/terminal.c index 268639dc..02795797 100644 --- a/terminal.c +++ b/terminal.c @@ -169,7 +169,6 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows for (int r = max(region.end - rows, 0); r < region.end; r++) { struct row *row = grid_row(term->grid, r); erase_line(term, row); - row->initialized = true; } term_damage_scroll(term, DAMAGE_SCROLL, region, rows); diff --git a/terminal.h b/terminal.h index f5e2cfa9..4ddf017e 100644 --- a/terminal.h +++ b/terminal.h @@ -94,11 +94,11 @@ struct damage { struct row { struct cell *cells; bool dirty; - bool initialized; }; struct grid { int num_rows; + int num_cols; int offset; int view;