mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-04 06:34:26 +00:00
windows: more frequent frame requests (#8921)
Note rust analyzer running in background now without keyboard/mouse movement. ![](https://media.discordapp.net/attachments/1208481909676576818/1214769879098597416/high-framerate-windows.gif?ex=65fa519c&is=65e7dc9c&hm=4c9ba72fa3c3c548964e46d9c07f0c0bf9545ed9a9ae11495101dcae5db06d59&=) Release Notes: - Improved frame rate on Windows
This commit is contained in:
parent
8357039419
commit
06035dadea
3 changed files with 63 additions and 53 deletions
|
@ -313,6 +313,7 @@ sys-locale = "0.3.1"
|
|||
version = "0.53.0"
|
||||
features = [
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_Graphics_DirectComposition",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_System_SystemServices",
|
||||
|
|
|
@ -18,12 +18,13 @@ use parking_lot::Mutex;
|
|||
use time::UtcOffset;
|
||||
use util::{ResultExt, SemanticVersion};
|
||||
use windows::Win32::{
|
||||
Foundation::{CloseHandle, GetLastError, HANDLE, HWND, WAIT_EVENT},
|
||||
System::Threading::{CreateEventW, INFINITE},
|
||||
Foundation::{CloseHandle, BOOL, HANDLE, HWND, LPARAM, TRUE},
|
||||
Graphics::DirectComposition::DCompositionWaitForCompositorClock,
|
||||
System::Threading::{CreateEventW, GetCurrentThreadId, INFINITE},
|
||||
UI::WindowsAndMessaging::{
|
||||
DispatchMessageW, GetMessageW, MsgWaitForMultipleObjects, PostQuitMessage,
|
||||
SystemParametersInfoW, TranslateMessage, MSG, QS_ALLINPUT, SPI_GETWHEELSCROLLCHARS,
|
||||
SPI_GETWHEELSCROLLLINES, SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
|
||||
DispatchMessageW, EnumThreadWindows, PeekMessageW, PostQuitMessage, SystemParametersInfoW,
|
||||
TranslateMessage, MSG, PM_REMOVE, SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES,
|
||||
SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS, WM_QUIT, WM_SETTINGCHANGE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -169,26 +170,31 @@ impl WindowsPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
fn wait_message(&self) -> WindowsMessageWaitResult {
|
||||
let wait_result = unsafe {
|
||||
MsgWaitForMultipleObjects(Some(&[self.inner.event]), false, INFINITE, QS_ALLINPUT)
|
||||
};
|
||||
|
||||
match wait_result {
|
||||
WAIT_EVENT(0) => WindowsMessageWaitResult::ForegroundExecution,
|
||||
WAIT_EVENT(1) => {
|
||||
let mut msg = MSG::default();
|
||||
unsafe { GetMessageW(&mut msg, HWND::default(), 0, 0) };
|
||||
WindowsMessageWaitResult::WindowsMessage(msg)
|
||||
}
|
||||
_ => {
|
||||
log::error!("unhandled windows wait message: {}", wait_result.0);
|
||||
WindowsMessageWaitResult::Error
|
||||
}
|
||||
fn run_foreground_tasks(&self) {
|
||||
for runnable in self.inner.main_receiver.drain() {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn invalidate_window_callback(hwnd: HWND, _: LPARAM) -> BOOL {
|
||||
if let Some(inner) = try_get_window_inner(hwnd) {
|
||||
inner.invalidate_client_area();
|
||||
}
|
||||
TRUE
|
||||
}
|
||||
|
||||
/// invalidates all windows belonging to a thread causing a paint message to be scheduled
|
||||
fn invalidate_thread_windows(win32_thread_id: u32) {
|
||||
unsafe {
|
||||
EnumThreadWindows(
|
||||
win32_thread_id,
|
||||
Some(invalidate_window_callback),
|
||||
LPARAM::default(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl Platform for WindowsPlatform {
|
||||
fn background_executor(&self) -> BackgroundExecutor {
|
||||
self.inner.background_executor.clone()
|
||||
|
@ -204,16 +210,21 @@ impl Platform for WindowsPlatform {
|
|||
|
||||
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
||||
on_finish_launching();
|
||||
loop {
|
||||
match self.wait_message() {
|
||||
WindowsMessageWaitResult::ForegroundExecution => {
|
||||
for runnable in self.inner.main_receiver.drain() {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
WindowsMessageWaitResult::WindowsMessage(msg) => {
|
||||
'a: loop {
|
||||
let mut msg = MSG::default();
|
||||
// will be 0 if woken up by self.inner.event or 1 if the compositor clock ticked
|
||||
// SEE: https://learn.microsoft.com/en-us/windows/win32/directcomp/compositor-clock/compositor-clock
|
||||
let wait_result =
|
||||
unsafe { DCompositionWaitForCompositorClock(Some(&[self.inner.event]), INFINITE) };
|
||||
|
||||
// compositor clock ticked so we should draw a frame
|
||||
if wait_result == 1 {
|
||||
unsafe { invalidate_thread_windows(GetCurrentThreadId()) };
|
||||
|
||||
while unsafe { PeekMessageW(&mut msg, HWND::default(), 0, 0, PM_REMOVE) }.as_bool()
|
||||
{
|
||||
if msg.message == WM_QUIT {
|
||||
break;
|
||||
break 'a;
|
||||
}
|
||||
|
||||
if !self.run_immediate_msg_handlers(&msg) {
|
||||
|
@ -221,8 +232,9 @@ impl Platform for WindowsPlatform {
|
|||
unsafe { DispatchMessageW(&msg) };
|
||||
}
|
||||
}
|
||||
WindowsMessageWaitResult::Error => {}
|
||||
}
|
||||
|
||||
self.run_foreground_tasks();
|
||||
}
|
||||
|
||||
let mut callbacks = self.inner.callbacks.lock();
|
||||
|
|
|
@ -17,7 +17,8 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
|||
use windows::{
|
||||
core::{w, HSTRING, PCWSTR},
|
||||
Win32::{
|
||||
Foundation::{HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
|
||||
Foundation::{FALSE, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
|
||||
Graphics::Gdi::{BeginPaint, EndPaint, InvalidateRect, PAINTSTRUCT},
|
||||
System::SystemServices::{
|
||||
MK_LBUTTON, MK_MBUTTON, MK_RBUTTON, MK_XBUTTON1, MK_XBUTTON2, MODIFIERKEYS_FLAGS,
|
||||
},
|
||||
|
@ -158,6 +159,12 @@ impl WindowsWindowInner {
|
|||
}
|
||||
}
|
||||
|
||||
/// mark window client rect to be re-drawn
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-invalidaterect
|
||||
pub(crate) fn invalidate_client_area(&self) {
|
||||
unsafe { InvalidateRect(self.hwnd, None, FALSE) };
|
||||
}
|
||||
|
||||
/// returns true if message is handled and should not dispatch
|
||||
pub(crate) fn handle_immediate_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> bool {
|
||||
match msg {
|
||||
|
@ -245,16 +252,20 @@ impl WindowsWindowInner {
|
|||
height: Pixels(height.0),
|
||||
},
|
||||
1.0,
|
||||
)
|
||||
);
|
||||
}
|
||||
self.invalidate_client_area();
|
||||
LRESULT(0)
|
||||
}
|
||||
|
||||
fn handle_paint_msg(&self) -> LRESULT {
|
||||
let mut paint_struct = PAINTSTRUCT::default();
|
||||
let hdc = unsafe { BeginPaint(self.hwnd, &mut paint_struct) };
|
||||
let mut callbacks = self.callbacks.borrow_mut();
|
||||
if let Some(callback) = callbacks.request_frame.as_mut() {
|
||||
callback()
|
||||
if let Some(request_frame) = callbacks.request_frame.as_mut() {
|
||||
request_frame();
|
||||
}
|
||||
unsafe { EndPaint(self.hwnd, &paint_struct) };
|
||||
LRESULT(0)
|
||||
}
|
||||
|
||||
|
@ -403,18 +414,12 @@ impl WindowsWindowInner {
|
|||
};
|
||||
|
||||
if callback(PlatformInput::KeyDown(event)) {
|
||||
if let Some(request_frame) = callbacks.request_frame.as_mut() {
|
||||
request_frame();
|
||||
}
|
||||
CallbackResult::Handled { by_callback: true }
|
||||
} else if let Some(mut input_handler) = self.input_handler.take() {
|
||||
if let Some(ime_key) = ime_key {
|
||||
input_handler.replace_text_in_range(None, &ime_key);
|
||||
}
|
||||
self.input_handler.set(Some(input_handler));
|
||||
if let Some(request_frame) = callbacks.request_frame.as_mut() {
|
||||
request_frame();
|
||||
}
|
||||
CallbackResult::Handled { by_callback: true }
|
||||
} else {
|
||||
CallbackResult::Handled { by_callback: false }
|
||||
|
@ -433,9 +438,8 @@ impl WindowsWindowInner {
|
|||
if let Some(keystroke) = keystroke {
|
||||
if let Some(callback) = callbacks.input.as_mut() {
|
||||
let event = KeyUpEvent { keystroke };
|
||||
CallbackResult::Handled {
|
||||
by_callback: callback(PlatformInput::KeyUp(event)),
|
||||
}
|
||||
let by_callback = callback(PlatformInput::KeyUp(event));
|
||||
CallbackResult::Handled { by_callback }
|
||||
} else {
|
||||
CallbackResult::Handled { by_callback: false }
|
||||
}
|
||||
|
@ -527,12 +531,8 @@ impl WindowsWindowInner {
|
|||
modifiers: self.current_modifiers(),
|
||||
touch_phase: TouchPhase::Moved,
|
||||
};
|
||||
if callback(PlatformInput::ScrollWheel(event)) {
|
||||
if let Some(request_frame) = callbacks.request_frame.as_mut() {
|
||||
request_frame();
|
||||
}
|
||||
return LRESULT(0);
|
||||
}
|
||||
callback(PlatformInput::ScrollWheel(event));
|
||||
return LRESULT(0);
|
||||
}
|
||||
LRESULT(1)
|
||||
}
|
||||
|
@ -554,9 +554,6 @@ impl WindowsWindowInner {
|
|||
touch_phase: TouchPhase::Moved,
|
||||
};
|
||||
if callback(PlatformInput::ScrollWheel(event)) {
|
||||
if let Some(request_frame) = callbacks.request_frame.as_mut() {
|
||||
request_frame();
|
||||
}
|
||||
return LRESULT(0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue