From 87636e92303665204a1b58bc5c46e52f91b62efe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 18 Jan 2024 12:30:30 +0530 Subject: [PATCH] Optimize implementation of clear screen escape code --- kitty/data-types.h | 2 ++ kitty/line-buf.c | 16 ++++++++++++++++ kitty/line.c | 4 ++-- kitty/lineops.h | 3 ++- kitty/screen.c | 12 +++++------- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/kitty/data-types.h b/kitty/data-types.h index f09c3bdb55b..e322ca2cfeb 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -372,6 +372,8 @@ cursor_to_attrs(const Cursor *c, const uint16_t width) { return ans; } +#define cursor_as_gpu_cell(cursor) {.attrs=cursor_to_attrs(cursor, 0), .fg=(cursor->fg & COL_MASK), .bg=(cursor->bg & COL_MASK), .decoration_fg=cursor->decoration_fg & COL_MASK} + static inline void attrs_to_cursor(const CellAttrs attrs, Cursor *c) { c->decoration = attrs.decoration; c->bold = attrs.bold; c->italic = attrs.italic; diff --git a/kitty/line-buf.c b/kitty/line-buf.c index de0a8fe1d9d..05fb72f39cb 100644 --- a/kitty/line-buf.c +++ b/kitty/line-buf.c @@ -146,6 +146,22 @@ linebuf_init_line(LineBuf *self, index_type idx) { init_line(self, self->line, self->line_map[idx]); } +void +linebuf_clear_lines(LineBuf *self, const Cursor *cursor, index_type start, index_type end) { + GPUCell *first_gpu_line = gpu_lineptr(self, start); + GPUCell gc = cursor_as_gpu_cell(cursor); + for (index_type i = 0; i < self->xnum; i++) memcpy(first_gpu_line + i, &gc, sizeof(gc)); + const size_t cpu_stride = sizeof(self->cpu_cell_buf[0]) * self->xnum; + memset(cpu_lineptr(self, start), 0, cpu_stride); + const size_t gpu_stride = sizeof(self->gpu_cell_buf[0]) * self->xnum; + linebuf_clear_attrs_and_dirty(self, start); + for (index_type i = start + 1; i < end; i++) { + memset(cpu_lineptr(self, i), 0, cpu_stride); + memcpy(gpu_lineptr(self, i), first_gpu_line, gpu_stride); + linebuf_clear_attrs_and_dirty(self, i); + } +} + static PyObject* line(LineBuf *self, PyObject *y) { #define line_doc "Return the specified line as a Line object. Note the Line Object is a live view into the underlying buffer. And only a single line object can be used at a time." diff --git a/kitty/line.c b/kitty/line.c index 6e5ee16189c..75f77c5558e 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -539,8 +539,8 @@ clear_text(Line* self, PyObject *args) { } void -line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) { - GPUCell gc = {.attrs=cursor_to_attrs(cursor, 0), .fg=(cursor->fg & COL_MASK), .bg=(cursor->bg & COL_MASK), .decoration_fg=cursor->decoration_fg & COL_MASK}; +line_apply_cursor(Line *self, const Cursor *cursor, unsigned int at, unsigned int num, bool clear_char) { + GPUCell gc = cursor_as_gpu_cell(cursor); if (clear_char) { for (index_type i = at; i < self->xnum && i < at + num; i++) { memset(self->cpu_cells + i, 0, sizeof(self->cpu_cells[0])); diff --git a/kitty/lineops.h b/kitty/lineops.h index aa4c25d416a..277dbee2e18 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -83,7 +83,7 @@ line_is_empty(const Line *line) { typedef Line*(get_line_func)(void *, int); void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch); -void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char); +void line_apply_cursor(Line *self, const Cursor *cursor, unsigned int at, unsigned int num, bool clear_char); char_type line_get_char(Line *self, index_type at); void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, hyperlink_id_type); void line_right_shift(Line *, unsigned int , unsigned int ); @@ -103,6 +103,7 @@ PyObject* line_as_unicode(Line *, bool); void linebuf_init_line(LineBuf *, index_type); void linebuf_init_cells(LineBuf *lb, index_type ynum, CPUCell **c, GPUCell **g); void linebuf_clear(LineBuf *, char_type ch); +void linebuf_clear_lines(LineBuf *self, const Cursor *cursor, index_type start, index_type end); void linebuf_index(LineBuf* self, index_type top, index_type bottom); void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom); void linebuf_clear_line(LineBuf *self, index_type y, bool clear_attrs); diff --git a/kitty/screen.c b/kitty/screen.c index 0db45f90d7f..417c8153722 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1866,16 +1866,14 @@ screen_erase_in_display(Screen *self, unsigned int how, bool private) { } if (b > a) { if (how != 3) screen_dirty_line_graphics(self, a, b, self->linebuf == self->main_linebuf); - for (unsigned int i=a; i < b; i++) { - linebuf_init_line(self->linebuf, i); - if (private) { + if (private) { + for (unsigned int i=a; i < b; i++) { + linebuf_init_line(self->linebuf, i); line_clear_text(self->linebuf->line, 0, self->columns, BLANK_CHAR); linebuf_set_last_char_as_continuation(self->linebuf, i, false); - } else { - line_apply_cursor(self->linebuf->line, self->cursor, 0, self->columns, true); + linebuf_clear_attrs_and_dirty(self->linebuf, i); } - linebuf_clear_attrs_and_dirty(self->linebuf, i); - } + } else linebuf_clear_lines(self->linebuf, self->cursor, a, b); self->is_dirty = true; clear_selection(&self->selections); }