1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-10 15:04:32 +03:00

don't vsync on x11, do our own throttling

Some users mentioned that there's a lag after selecting text
on X11.  Tracing through, I saw that the we invalidate the window
quite a lot when dragging the selection, and the buffer swap could
delay for several ms each time while waiting for the vsync.

Rather than blocking the GUI thread and making it bog down, this
commit adopts a technique similar to the recent Wayland frame sync
changes, except that we enforce a minimum of 33ms between frames
in our own scheduler to avoid blocking for several ms at a time.

This seems to do a decent job of balancing responsiveness during
selection with updating the display, and keeps the buffer swap
delay down to microseconds.

We may want to make this delay configurable.
This commit is contained in:
Wez Furlong 2021-08-19 20:47:12 -07:00
parent 2446ac5d7f
commit fc5ca5a297
2 changed files with 33 additions and 11 deletions

View File

@ -488,17 +488,7 @@ impl GlState {
display: Option<ffi::EGLNativeDisplayType>,
wegl_surface: &wayland_egl::WlEglSurface,
) -> anyhow::Result<Self> {
let state = Self::create(display, wegl_surface.ptr())?;
// Request non-blocking buffer swaps when using egl with wayland:
// <https://emersion.fr/blog/2018/wayland-rendering-loop/>
unsafe {
state
.connection
.egl
.egl
.SwapInterval(state.connection.display, 0);
}
Ok(state)
Self::create(display, wegl_surface.ptr())
}
pub fn create(
@ -651,6 +641,13 @@ impl GlState {
log::trace!("Successfully created a surface using this configuration");
connection.egl.log_config_info(connection.display, config);
// Request non-blocking buffer swaps; we'll manage throttling
// frames at the application level.
unsafe {
connection.egl.egl.SwapInterval(connection.display, 0);
}
return Ok(Self {
connection: Rc::clone(connection),
context,

View File

@ -67,6 +67,8 @@ pub(crate) struct XWindowInner {
title: String,
has_focus: bool,
last_cursor_position: Rect,
invalidated: bool,
paint_throttled: bool,
}
impl Drop for XWindowInner {
@ -782,6 +784,8 @@ impl XWindow {
config: config.clone(),
has_focus: false,
last_cursor_position: Rect::default(),
paint_throttled: false,
invalidated: false,
}))
};
@ -829,8 +833,29 @@ impl XWindowInner {
fn show(&mut self) {
xcb::map_window(self.conn().conn(), self.window_id);
}
fn invalidate(&mut self) {
if self.paint_throttled {
self.invalidated = true;
return;
}
self.invalidated = false;
self.events.dispatch(WindowEvent::NeedRepaint);
self.paint_throttled = true;
let window_id = self.window_id;
promise::spawn::spawn(async move {
// Don't try to paint more frequently than 30 fps
async_io::Timer::after(std::time::Duration::from_millis(1000 / 30)).await;
XConnection::with_window_inner(window_id, |inner| {
inner.paint_throttled = false;
if inner.invalidated {
inner.invalidate();
}
Ok(())
});
})
.detach();
}
fn toggle_fullscreen(&mut self) {