mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
linux/x11: prioritize input in the event loop (#8253)
With this change, interaction with Zed is actually real-time and usable 🚀 🎉 The gist of it is - trying to process all of the input events before rendering anything. Release Notes: - N/A **Note**: this can be further improved in a follow-up. Currently, once the input and runnables are processed, we'd try to draw + render a frame. Presentation starts with acquiring a new frame. We currently have FIFO presentation method, so acquiring a frame is blocking on that swapchain image to become available. As the result, presentation takes around 16 ms, most of which is just busy wait. Ideally, we'd be able to process more input in this time frame, instead. **Note2**: it's a bit laggy in Debug for me, but that's just because of the extra-long `draw` times, which is unrelated to rendering (or platform support, for the matter). I'm curious how come on MacOS the `draw()` times in Debug are more modest.
This commit is contained in:
parent
cab8b5a9a3
commit
885ae2d863
@ -507,16 +507,16 @@ impl BladeRenderer {
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &Scene) {
|
||||
self.command_encoder.start();
|
||||
self.atlas.before_frame(&mut self.command_encoder);
|
||||
self.rasterize_paths(scene.paths());
|
||||
|
||||
let frame = {
|
||||
profiling::scope!("acquire frame");
|
||||
self.gpu.acquire_frame()
|
||||
};
|
||||
self.command_encoder.start();
|
||||
self.command_encoder.init_texture(frame.texture());
|
||||
|
||||
self.atlas.before_frame(&mut self.command_encoder);
|
||||
self.rasterize_paths(scene.paths());
|
||||
|
||||
let globals = GlobalParams {
|
||||
viewport_size: [
|
||||
self.viewport_size.width as f32,
|
||||
|
@ -4,7 +4,7 @@ use parking_lot::Mutex;
|
||||
use xcb::{x, Xid as _};
|
||||
use xkbcommon::xkb;
|
||||
|
||||
use collections::HashMap;
|
||||
use collections::{HashMap, HashSet};
|
||||
|
||||
use crate::platform::linux::client::Client;
|
||||
use crate::platform::{
|
||||
@ -67,18 +67,33 @@ impl X11Client {
|
||||
impl Client for X11Client {
|
||||
fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
|
||||
on_finish_launching();
|
||||
//Note: here and below, don't keep the lock() open when calling
|
||||
// into window functions as they may invoke callbacks that need
|
||||
// to immediately access the platform (self).
|
||||
let mut windows_to_refresh = HashSet::<x::Window>::default();
|
||||
while !self.platform_inner.state.lock().quit_requested {
|
||||
let event = {
|
||||
// We prioritize work in the following order:
|
||||
// 1. input events from X11
|
||||
// 2. runnables for the main thread
|
||||
// 3. drawing/presentation
|
||||
let event = if let Some(event) = self.xcb_connection.poll_for_event().unwrap() {
|
||||
event
|
||||
} else if let Ok(runnable) = self.platform_inner.main_receiver.try_recv() {
|
||||
runnable.run();
|
||||
continue;
|
||||
} else if let Some(x_window) = windows_to_refresh.iter().next().cloned() {
|
||||
windows_to_refresh.remove(&x_window);
|
||||
let window = self.get_window(x_window);
|
||||
window.refresh();
|
||||
window.request_refresh();
|
||||
continue;
|
||||
} else {
|
||||
profiling::scope!("Wait for event");
|
||||
self.xcb_connection.wait_for_event().unwrap()
|
||||
};
|
||||
|
||||
match event {
|
||||
xcb::Event::X(x::Event::ClientMessage(ev)) => {
|
||||
if let x::ClientMessageData::Data32([atom, ..]) = ev.data() {
|
||||
if atom == self.atoms.wm_del_window.resource_id() {
|
||||
windows_to_refresh.remove(&ev.window());
|
||||
// window "x" button clicked by user, we gracefully exit
|
||||
let window = self.state.lock().windows.remove(&ev.window()).unwrap();
|
||||
window.destroy();
|
||||
@ -89,7 +104,7 @@ impl Client for X11Client {
|
||||
}
|
||||
}
|
||||
xcb::Event::X(x::Event::Expose(ev)) => {
|
||||
self.get_window(ev.window()).refresh();
|
||||
windows_to_refresh.insert(ev.window());
|
||||
}
|
||||
xcb::Event::X(x::Event::ConfigureNotify(ev)) => {
|
||||
let bounds = Bounds {
|
||||
@ -105,9 +120,7 @@ impl Client for X11Client {
|
||||
self.get_window(ev.window()).configure(bounds)
|
||||
}
|
||||
xcb::Event::Present(xcb::present::Event::CompleteNotify(ev)) => {
|
||||
let window = self.get_window(ev.window());
|
||||
window.refresh();
|
||||
window.request_refresh();
|
||||
windows_to_refresh.insert(ev.window());
|
||||
}
|
||||
xcb::Event::Present(xcb::present::Event::IdleNotify(_ev)) => {}
|
||||
xcb::Event::X(x::Event::FocusIn(ev)) => {
|
||||
@ -212,11 +225,6 @@ impl Client for X11Client {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
profiling::scope!("Runnables");
|
||||
if let Ok(runnable) = self.platform_inner.main_receiver.try_recv() {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut fun) = self.platform_inner.callbacks.lock().quit {
|
||||
|
Loading…
Reference in New Issue
Block a user