Avoid unnecessary draw calls with multiple OS Windows

Do not ask the GPU to draw and swap buffers for OS Windows that are not
dirtied. See #313
This commit is contained in:
Kovid Goyal 2018-02-06 19:32:24 +05:30
parent fa87ce72a8
commit 0c7d51dd9d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 61 additions and 21 deletions

View File

@ -564,8 +564,13 @@ simple_render_screen(PyObject UNUSED *self, PyObject *args) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static inline void static inline bool
render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id) { 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); 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; Tab *tab = os_window->tabs + os_window->active_tab;
for (unsigned int i = 0; i < tab->num_windows; i++) { 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)) { if (drag_scroll(w, os_window)) {
w->last_drag_scroll_at = now; w->last_drag_scroll_at = now;
set_maximum_wait(0.02); set_maximum_wait(0.02);
needs_render = true;
} else w->last_drag_scroll_at = 0; } else w->last_drag_scroll_at = 0;
} else set_maximum_wait(now - w->last_drag_scroll_at); } 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); collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
update_window_title(w, os_window); update_window_title(w, os_window);
} else WD.screen->cursor_render_info.is_visible = false; } 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); 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)) { 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); 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 WD
#undef TD
} }
static inline void static inline void
@ -606,26 +634,22 @@ render(double now) {
set_maximum_wait(OPT(repaint_delay) - time_since_last_render); set_maximum_wait(OPT(repaint_delay) - time_since_last_render);
return; return;
} }
#define TD w->tab_bar_render_data
for (size_t i = 0; i < global_state.num_os_windows; i++) { for (size_t i = 0; i < global_state.num_os_windows; i++) {
OSWindow *w = global_state.os_windows + i; OSWindow *w = global_state.os_windows + i;
if (!w->num_tabs || !should_os_window_be_rendered(w)) continue; if (!w->num_tabs || !should_os_window_be_rendered(w)) continue;
bool needs_render = w->is_focused;
make_os_window_context_current(w); make_os_window_context_current(w);
if (w->viewport_size_dirty) { if (w->viewport_size_dirty) {
w->clear_count = 0; w->clear_count = 0;
update_surface_size(w->viewport_width, w->viewport_height, w->offscreen_texture_id); update_surface_size(w->viewport_width, w->viewport_height, w->offscreen_texture_id);
w->viewport_size_dirty = false; w->viewport_size_dirty = false;
needs_render = true;
} }
unsigned int active_window_id = 0; unsigned int active_window_id = 0;
Tab *active_tab = w->tabs + w->active_tab; if (prepare_to_render_os_window(w, now, &active_window_id)) needs_render = true;
BorderRects *br = &active_tab->border_rects; 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;
draw_borders(br->vao_idx, br->num_border_rects, br->rect_buf, br->is_dirty, w->viewport_width, w->viewport_height); if (needs_render) render_os_window(w, now, active_window_id);
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;
} }
last_render_at = now; last_render_at = now;
#undef TD #undef TD

View File

@ -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; 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) { 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; size_t sz;
CELL_BUFFERS; CELL_BUFFERS;
void *address; void *address;
bool changed = false;
ensure_sprite_map(); 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); 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); screen_update_cell_data(screen, address, sz);
unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL; unmap_vao_buffer(vao_idx, cell_data_buffer); address = NULL;
changed = true;
} }
if (screen_is_selection_dirty(screen)) { 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); address = alloc_and_map_vao_buffer(vao_idx, sz, selection_buffer, GL_STREAM_DRAW, GL_WRITE_ONLY);
screen_apply_selection(screen, address, sz); screen_apply_selection(screen, address, sz);
unmap_vao_buffer(vao_idx, selection_buffer); address = NULL; 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)) { 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); 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)); 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; unmap_vao_buffer(gvao_idx, 0); a = NULL;
changed = true;
} }
bool inverted = screen_invert_colors(screen); return changed;
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);
} }
static void static void
@ -412,17 +411,32 @@ set_cell_uniforms(float current_inactive_text_alpha) {
} }
} }
void bool
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) { 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) { if (os_window->clear_count < 2) {
os_window->clear_count++; os_window->clear_count++;
#define C(shift) (((GLfloat)((OPT(background) >> shift) & 0xFF)) / 255.0f) #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); glClearColor(C(16), C(8), C(0), os_window->is_semi_transparent ? OPT(background_opacity) : 1.0f);
#undef C #undef C
glClear(GL_COLOR_BUFFER_BIT); 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); 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); set_cell_uniforms(current_inactive_text_alpha);
GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy; GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy;

View File

@ -98,6 +98,7 @@ typedef struct {
double viewport_x_ratio, viewport_y_ratio; double viewport_x_ratio, viewport_y_ratio;
Tab *tabs; Tab *tabs;
unsigned int active_tab, num_tabs, capacity, last_active_tab, last_num_tabs, last_active_window_id; 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; ScreenRenderData tab_bar_render_data;
bool is_focused; bool is_focused;
double cursor_blink_zero_time, last_mouse_activity_at; 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_cell_vao();
ssize_t create_graphics_vao(); ssize_t create_graphics_vao();
ssize_t create_border_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_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *, bool);
void draw_cursor(CursorRenderInfo *, bool); void draw_cursor(CursorRenderInfo *, bool);
void update_surface_size(int, int, uint32_t); void update_surface_size(int, int, uint32_t);