diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 117399110..995dff90c 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -564,8 +564,13 @@ simple_render_screen(PyObject UNUSED *self, PyObject *args) { Py_RETURN_NONE; } -static inline void -render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id) { +static inline bool +prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id) { +#define TD os_window->tab_bar_render_data + bool needs_render = false; + if (TD.screen && os_window->num_tabs > 1) { + if (send_cell_data_to_gpu(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window)) needs_render = true; + } if (OPT(mouse_hide_wait) > 0 && now - os_window->last_mouse_activity_at > OPT(mouse_hide_wait)) hide_mouse(os_window); Tab *tab = os_window->tabs + os_window->active_tab; for (unsigned int i = 0; i < tab->num_windows; i++) { @@ -577,6 +582,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id if (drag_scroll(w, os_window)) { w->last_drag_scroll_at = now; set_maximum_wait(0.02); + needs_render = true; } else w->last_drag_scroll_at = 0; } else set_maximum_wait(now - w->last_drag_scroll_at); } @@ -586,6 +592,23 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window); update_window_title(w, os_window); } else WD.screen->cursor_render_info.is_visible = false; + if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true; + if (WD.screen->start_visual_bell_at != 0) needs_render = true; + } + } + return needs_render; +} + +static inline void +render_os_window(OSWindow *os_window, double now, unsigned int active_window_id) { + Tab *tab = os_window->tabs + os_window->active_tab; + BorderRects *br = &tab->border_rects; + draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, os_window->viewport_width, os_window->viewport_height); + if (TD.screen && os_window->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, os_window, true); + for (unsigned int i = 0; i < tab->num_windows; i++) { + Window *w = tab->windows + i; + if (w->visible && WD.screen) { + bool is_active_window = i == tab->active_window; draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window, is_active_window); if (is_active_window && WD.screen->cursor_render_info.is_visible && (!WD.screen->cursor_render_info.is_focused || WD.screen->cursor_render_info.shape != CURSOR_BLOCK)) { draw_cursor(&WD.screen->cursor_render_info, os_window->is_focused); @@ -596,7 +619,12 @@ render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id } } } + swap_window_buffers(os_window); + br->is_dirty = false; + os_window->last_active_tab = os_window->active_tab; os_window->last_num_tabs = os_window->num_tabs; os_window->last_active_window_id = active_window_id; + os_window->focused_at_last_render = os_window->is_focused; #undef WD +#undef TD } static inline void @@ -606,26 +634,22 @@ render(double now) { set_maximum_wait(OPT(repaint_delay) - time_since_last_render); return; } -#define TD w->tab_bar_render_data for (size_t i = 0; i < global_state.num_os_windows; i++) { OSWindow *w = global_state.os_windows + i; if (!w->num_tabs || !should_os_window_be_rendered(w)) continue; + bool needs_render = w->is_focused; make_os_window_context_current(w); if (w->viewport_size_dirty) { w->clear_count = 0; update_surface_size(w->viewport_width, w->viewport_height, w->offscreen_texture_id); w->viewport_size_dirty = false; + needs_render = true; } unsigned int active_window_id = 0; - Tab *active_tab = w->tabs + w->active_tab; - BorderRects *br = &active_tab->border_rects; - draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, w->viewport_width, w->viewport_height); - if (TD.screen && w->num_tabs > 1) draw_cells(TD.vao_idx, 0, TD.xstart, TD.ystart, TD.dx, TD.dy, TD.screen, w, true); - render_os_window(w, now, &active_window_id); - swap_window_buffers(w); - w->last_active_tab = w->active_tab; w->last_num_tabs = w->num_tabs; w->last_active_window_id = active_window_id; - br->is_dirty = false; + if (prepare_to_render_os_window(w, now, &active_window_id)) needs_render = true; + if (w->last_active_window_id != active_window_id || w->last_active_tab != w->active_tab || w->focused_at_last_render != w->is_focused) needs_render = true; + if (needs_render) render_os_window(w, now, active_window_id); } last_render_at = now; #undef TD diff --git a/kitty/shaders.c b/kitty/shaders.c index 8705090ce..2bfe336f1 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -252,11 +252,12 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, G unmap_vao_buffer(vao_idx, uniform_buffer); rd = NULL; } -static inline void +static inline bool cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy) { size_t sz; CELL_BUFFERS; void *address; + bool changed = false; ensure_sprite_map(); @@ -265,6 +266,7 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa address = alloc_and_map_vao_buffer(vao_idx, sz, cell_data_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY); screen_update_cell_data(screen, address, sz); unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL; + changed = true; } if (screen_is_selection_dirty(screen)) { @@ -272,6 +274,7 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa 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 (gvao_idx && grman_update_layers(screen->grman, screen->scrolled_by, xstart, ystart, dx, dy, screen->columns, screen->lines)) { @@ -279,13 +282,9 @@ cell_prepare_to_render(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, GLfloa GLfloat *a = alloc_and_map_vao_buffer(gvao_idx, sz, 0, GL_STREAM_DRAW, GL_WRITE_ONLY); for (size_t i = 0; i < screen->grman->count; i++, a += 16) memcpy(a, screen->grman->render_data[i].vertices, sizeof(screen->grman->render_data[0].vertices)); unmap_vao_buffer(gvao_idx, 0); a = NULL; + changed = true; } - bool inverted = screen_invert_colors(screen); - - cell_update_uniform_block(vao_idx, screen, uniform_buffer, xstart, ystart, dx, dy, &screen->cursor_render_info, inverted); - - bind_vao_uniform_buffer(vao_idx, uniform_buffer, cell_program_layouts[CELL_PROGRAM].render_data.index); - bind_vertex_array(vao_idx); + return changed; } static void @@ -412,17 +411,32 @@ set_cell_uniforms(float current_inactive_text_alpha) { } } -void -draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window, bool is_active_window) { +bool +send_cell_data_to_gpu(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) { + bool changed = false; if (os_window->clear_count < 2) { os_window->clear_count++; #define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f) glClearColor(C(16), C(8), C(0), os_window->is_semi_transparent ? OPT(background_opacity) : 1.0f); #undef C glClear(GL_COLOR_BUFFER_BIT); + changed = true; } + if (cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy)) changed = true; + return changed; + +} + +void +draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window, bool is_active_window) { + CELL_BUFFERS; + bool inverted = screen_invert_colors(screen); + + cell_update_uniform_block(vao_idx, screen, uniform_buffer, xstart, ystart, dx, dy, &screen->cursor_render_info, inverted); + + bind_vao_uniform_buffer(vao_idx, uniform_buffer, cell_program_layouts[CELL_PROGRAM].render_data.index); + bind_vertex_array(vao_idx); - cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy); float current_inactive_text_alpha = screen->cursor_render_info.is_focused && is_active_window ? 1.0 : OPT(inactive_text_alpha); set_cell_uniforms(current_inactive_text_alpha); GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy; diff --git a/kitty/state.h b/kitty/state.h index a0f3cd0b4..eb5d48071 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -98,6 +98,7 @@ typedef struct { double viewport_x_ratio, viewport_y_ratio; Tab *tabs; unsigned int active_tab, num_tabs, capacity, last_active_tab, last_num_tabs, last_active_window_id; + bool focused_at_last_render; ScreenRenderData tab_bar_render_data; bool is_focused; double cursor_blink_zero_time, last_mouse_activity_at; @@ -168,6 +169,7 @@ void draw_borders(ssize_t vao_idx, unsigned int num_border_rects, BorderRect *re ssize_t create_cell_vao(); ssize_t create_graphics_vao(); ssize_t create_border_vao(); +bool send_cell_data_to_gpu(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *); void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *, bool); void draw_cursor(CursorRenderInfo *, bool); void update_surface_size(int, int, uint32_t);