diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9d8183724..99cb30116 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,8 +25,8 @@ version 0.8.0 [future] variation presentation selector. - Prevent video tearing during high speed scrolling by syncing draws - to the monitor's refresh rate (only works if supported by the graphics - drivers). + to the monitor's refresh rate. There is a new configuration option to + control this ``sync_to_monitor``. - Add some non standard terminfo capabilities used by neovim and tmux. diff --git a/README.asciidoc b/README.asciidoc index e73f117ec..146493947 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -351,6 +351,8 @@ smoothness. There are two parameters you can tune to adjust the performance. ``repaint_delay`` and ``input_delay``. These control the artificial delays introduced into the render loop to reduce CPU usage. See the link:kitty/kitty.conf[config file] for details. +See also the ``sync_to_monitor`` option to further decrease latency at the cost +of some link:https://en.wikipedia.org/wiki/Screen_tearing[tearing] while scrolling. You can generate detailed per-function performance data using link:https://github.com/gperftools/gperftools[gperftools]. Build kitty with diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index 179f2903c..95ed5582a 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -591,6 +591,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ if (is_active_window) { *active_window_id = w->id; collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window); + if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible) needs_render = true; 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; @@ -618,6 +619,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id) double bell_left = global_state.opts.visual_bell_duration - (now - WD.screen->start_visual_bell_at); set_maximum_wait(bell_left); } + w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; } } swap_window_buffers(os_window); @@ -640,7 +642,7 @@ render(double now) { 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 || w->is_damaged; + bool needs_render = w->is_damaged; make_os_window_context_current(w); if (w->viewport_size_dirty) { w->clear_count = 0; diff --git a/kitty/config.py b/kitty/config.py index 5d4ac4f49..3a864aff3 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -271,6 +271,7 @@ type_map = { 'rectangle_select_modifiers': to_modifiers, 'repaint_delay': positive_int, 'input_delay': positive_int, + 'sync_to_monitor': to_bool, 'window_border_width': positive_float, 'window_margin_width': positive_float, 'window_padding_width': positive_float, diff --git a/kitty/glfw.c b/kitty/glfw.c index 2cdeb0f27..de3ccd53c 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -346,7 +346,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { glfwMakeContextCurrent(glfw_window); if (x != -1 && y != -1) glfwSetWindowPos(glfw_window, x, y); current_os_window_ctx = glfw_window; - glfwSwapInterval(0); // a value of 1 makes mouse selection laggy + glfwSwapInterval(OPT(sync_to_monitor) ? 1 : 0); // a value of 1 makes mouse selection laggy if (is_first_window) { set_dpi_from_os_window(NULL); gl_init(); diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 90baa2035..bd070f651 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -127,7 +127,9 @@ initial_window_height 400 # Delay (in milliseconds) between screen updates. Decreasing it, increases # frames-per-second (FPS) at the cost of more CPU usage. The default value -# yields ~100 FPS which is more than sufficient for most uses. +# yields ~100 FPS which is more than sufficient for most uses. Note that to +# actually achieve 100FPS you have to either set sync_to_monitor to no or use a +# monitor with a high refresh rate. repaint_delay 10 # Delay (in milliseconds) before input from the program running in the terminal @@ -137,6 +139,13 @@ repaint_delay 10 # screen updates will be drawn. input_delay 3 +# Sync screen updates to the refresh rate of the monitor. This prevents +# tearing (https://en.wikipedia.org/wiki/Screen_tearing) when scrolling. However, +# it limits the rendering speed to the refresh rate of your monitor. With a +# very high speed mouse/high keyboard repeat rate, you may notice some slight input latency. +# If so, set this to no. +sync_to_monitor yes + # Visual bell duration. Flash the screen when a bell occurs for the specified number of # seconds. Set to zero to disable. visual_bell_duration 0.0 diff --git a/kitty/state.c b/kitty/state.c index 2aff05181..97e25b13f 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -349,6 +349,7 @@ PYWRAP1(set_options) { S(background, color_as_int); S(repaint_delay, repaint_delay); S(input_delay, repaint_delay); + S(sync_to_monitor, PyObject_IsTrue); S(macos_option_as_alt, PyObject_IsTrue); S(macos_hide_titlebar, PyObject_IsTrue); diff --git a/kitty/state.h b/kitty/state.h index 0f68c8094..e0c019656 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -30,6 +30,7 @@ typedef struct { float background_opacity; float inactive_text_alpha; Edge tab_bar_edge; + bool sync_to_monitor; } Options; typedef struct { @@ -55,7 +56,7 @@ typedef struct { typedef struct { id_type id; - bool visible; + bool visible, cursor_visible_at_last_render; PyObject *title; ScreenRenderData render_data; unsigned int mouse_cell_x, mouse_cell_y; @@ -108,10 +109,7 @@ typedef struct { bool is_key_pressed[MAX_KEY_COUNT]; bool viewport_size_dirty; double last_resize_event_at; - bool has_pending_resizes; - bool is_semi_transparent; - bool shown_once; - bool is_damaged; + bool has_pending_resizes, is_semi_transparent, shown_once, is_damaged; uint32_t offscreen_texture_id; unsigned int clear_count; } OSWindow;