diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 59e875e54..ea69b578f 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -724,6 +724,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int * Window *w = tab->windows + i; #define WD w->render_data if (w->visible && WD.screen) { + screen_check_pause_rendering(WD.screen, now); *num_visible_windows += 1; color_type window_bg = colorprofile_to_color(WD.screen->color_profile, WD.screen->color_profile->overridden.default_bg, WD.screen->color_profile->configured.default_bg).rgb; if (*num_visible_windows == 1) first_window_bg = window_bg; diff --git a/kitty/screen.c b/kitty/screen.c index 2710c0740..264f9ffd5 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -473,6 +473,7 @@ dealloc(Screen* self) { PyMem_Free(self->overlay_line.original_line.gpu_cells); Py_CLEAR(self->overlay_line.overlay_text); PyMem_Free(self->main_tabstops); + Py_CLEAR(self->paused_rendering.linebuf); free(self->selections.items); free(self->url_ranges.items); free_hyperlink_pool(self->hyperlink_pool); @@ -2362,19 +2363,38 @@ screen_request_capabilities(Screen *self, char c, const char *query) { // Rendering {{{ +void +screen_check_pause_rendering(Screen *self, monotonic_t now) { + if (self->paused_rendering.expires_at && now > self->paused_rendering.expires_at) screen_pause_rendering(self, false, 0); +} + bool screen_pause_rendering(Screen *self, bool pause, int for_in_ms) { if (!pause) { if (!self->paused_rendering.expires_at) return false; self->paused_rendering.expires_at = 0; + self->is_dirty = true; return true; } if (self->paused_rendering.expires_at) return false; if (for_in_ms <= 0) for_in_ms = 2000; self->paused_rendering.expires_at = monotonic() + ms_to_monotonic_t(for_in_ms); self->paused_rendering.inverted = self->modes.mDECSCNM ? true : false; + self->paused_rendering.scrolled_by = self->scrolled_by; + self->paused_rendering.cell_data_updated = false; memcpy(&self->paused_rendering.cursor, self->cursor, sizeof(self->paused_rendering.cursor)); memcpy(&self->paused_rendering.color_profile, self->color_profile, sizeof(self->paused_rendering.color_profile)); + if (!self->paused_rendering.linebuf || self->paused_rendering.linebuf->xnum != self->columns || self->paused_rendering.linebuf->ynum != self->lines) { + if (self->paused_rendering.linebuf) Py_CLEAR(self->paused_rendering.linebuf); + self->paused_rendering.linebuf = alloc_linebuf(self->lines, self->columns); + if (!self->paused_rendering.linebuf) { PyErr_Clear(); self->paused_rendering.expires_at = 0; return false; } + } + for (index_type y = 0; y < self->lines; y++) { + Line *src = visual_line_(self, y); + linebuf_init_line(self->paused_rendering.linebuf, y); + copy_line(src, self->linebuf->line); + self->paused_rendering.linebuf->line_attrs[y] = src->attrs; + } return true; } @@ -2571,6 +2591,22 @@ screen_update_only_line_graphics_data(Screen *self) { void screen_update_cell_data(Screen *self, void *address, FONTS_DATA_HANDLE fonts_data, bool cursor_has_moved) { + if (self->paused_rendering.expires_at) { + if (!self->paused_rendering.cell_data_updated) { + LineBuf *linebuf = self->paused_rendering.linebuf; + for (index_type y = 0; y < self->lines; y++) { + linebuf_init_line(linebuf, y); + if (linebuf->line->attrs.has_dirty_text) { + render_line(fonts_data, linebuf->line, y, &self->paused_rendering.cursor, self->disable_ligatures); + screen_render_line_graphics(self, linebuf->line, y); + if (linebuf->line->attrs.has_dirty_text && screen_has_marker(self)) mark_text_in_line(self->marker, linebuf->line); + linebuf_mark_line_clean(linebuf, y); + } + update_line_data(linebuf->line, y, address); + } + } + return; + } const bool is_overlay_active = screen_is_overlay_active(self); unsigned int history_line_added_count = self->history_line_added_count; index_type lnum; diff --git a/kitty/screen.h b/kitty/screen.h index f6837b2a0..f33e86c4d 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -154,7 +154,9 @@ typedef struct { monotonic_t expires_at; Cursor cursor; ColorProfile color_profile; - bool inverted; + bool inverted, cell_data_updated; + unsigned int scrolled_by; + LineBuf *linebuf; } paused_rendering; } Screen; @@ -268,6 +270,7 @@ bool screen_send_signal_for_key(Screen *, char key); bool get_line_edge_colors(Screen *self, color_type *left, color_type *right); bool parse_sgr(Screen *screen, const uint8_t *buf, unsigned int num, const char *report_name, bool is_deccara); bool screen_pause_rendering(Screen *self, bool pause, int for_in_ms); +void screen_check_pause_rendering(Screen *self, monotonic_t now); #define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen); DECLARE_CH_SCREEN_HANDLER(bell) DECLARE_CH_SCREEN_HANDLER(backspace) diff --git a/kitty/shaders.c b/kitty/shaders.c index dd3fb32f1..a4c2dc2a8 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -389,12 +389,19 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat bool disable_ligatures = screen->disable_ligatures == DISABLE_LIGATURES_CURSOR; bool screen_resized = screen->last_rendered.columns != screen->columns || screen->last_rendered.lines != screen->lines; - if (screen->reload_all_gpu_data || screen->scroll_changed || screen->is_dirty || screen_resized || (disable_ligatures && cursor_pos_changed)) { - sz = sizeof(GPUCell) * screen->lines * screen->columns; - address = alloc_and_map_vao_buffer(vao_idx, sz, cell_data_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); - screen_update_cell_data(screen, address, fonts_data, disable_ligatures && cursor_pos_changed); - unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL; +#define update_cell_data \ + sz = sizeof(GPUCell) * screen->lines * screen->columns; \ + address = alloc_and_map_vao_buffer(vao_idx, sz, cell_data_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); \ + screen_update_cell_data(screen, address, fonts_data, disable_ligatures && cursor_pos_changed); \ + unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL; \ changed = true; + + if (screen->paused_rendering.expires_at) { + if (!screen->paused_rendering.cell_data_updated) { + update_cell_data; + } + } else if (screen->reload_all_gpu_data || screen->scroll_changed || screen->is_dirty || screen_resized || (disable_ligatures && cursor_pos_changed)) { + update_cell_data; } if (cursor_pos_changed) { @@ -402,18 +409,25 @@ cell_prepare_to_render(ssize_t vao_idx, Screen *screen, GLfloat xstart, GLfloat screen->last_rendered.cursor_y = cursor->y; } - if (screen->reload_all_gpu_data || screen_resized || screen_is_selection_dirty(screen)) { - sz = (size_t)screen->lines * screen->columns; - address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); - screen_apply_selection(screen, address, sz); - unmap_vao_buffer(vao_idx, selection_buffer); address = NULL; - changed = true; - } + if (screen->paused_rendering.expires_at) { + if (!screen->paused_rendering.cell_data_updated) { + } + screen->paused_rendering.cell_data_updated = true; + screen->last_rendered.scrolled_by = screen->paused_rendering.scrolled_by; + } else { + if (screen->reload_all_gpu_data || screen_resized || screen_is_selection_dirty(screen)) { + sz = (size_t)screen->lines * screen->columns; + address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); + screen_apply_selection(screen, address, sz); + unmap_vao_buffer(vao_idx, selection_buffer); address = NULL; + changed = true; + } - if (grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)) { - changed = true; + if (grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines, screen->cell_size)) { + changed = true; + } + screen->last_rendered.scrolled_by = screen->scrolled_by; } - screen->last_rendered.scrolled_by = screen->scrolled_by; screen->last_rendered.columns = screen->columns; screen->last_rendered.lines = screen->lines; return changed;