windows: Port to DirectX 11 (#34374)

Closes #16713
Closes #19739
Closes #33191
Closes #26692
Closes #17374
Closes #35077
Closes https://github.com/zed-industries/zed/issues/35205
Closes https://github.com/zed-industries/zed/issues/35262


Compared to the current Vulkan implementation, this PR brings several
improvements:

- Fewer weird bugs
- Better hardware compatibility
- VSync support
- More accurate colors
- Lower memory usage
- Graceful handling of device loss

---

**TODO:**

- [x] Don’t use AGS binaries directly
- [ ] The message loop is using too much CPU when ths app is idle
- [x] There’s a
[bug](https://github.com/zed-industries/zed/issues/33191#issuecomment-3109306630)
in how `Path` is being rendered.

---

Release Notes:

- N/A

---------

Co-authored-by: Kate <kate@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
张小白 2025-07-31 06:27:58 +08:00 committed by GitHub
parent 0d9715325c
commit 15ad986329
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 3577 additions and 180 deletions

View file

@ -28,13 +28,12 @@ use windows::{
core::*,
};
use crate::{platform::blade::BladeContext, *};
use crate::*;
pub(crate) struct WindowsPlatform {
state: RefCell<WindowsPlatformState>,
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
// The below members will never change throughout the entire lifecycle of the app.
gpu_context: BladeContext,
icon: HICON,
main_receiver: flume::Receiver<Runnable>,
background_executor: BackgroundExecutor,
@ -111,13 +110,11 @@ impl WindowsPlatform {
let icon = load_icon().unwrap_or_default();
let state = RefCell::new(WindowsPlatformState::new());
let raw_window_handles = RwLock::new(SmallVec::new());
let gpu_context = BladeContext::new().context("Unable to init GPU context")?;
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
Ok(Self {
state,
raw_window_handles,
gpu_context,
icon,
main_receiver,
background_executor,
@ -343,27 +340,11 @@ impl Platform for WindowsPlatform {
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
on_finish_launching();
let vsync_event = unsafe { Owned::new(CreateEventW(None, false, false, None).unwrap()) };
begin_vsync(*vsync_event);
'a: loop {
let wait_result = unsafe {
MsgWaitForMultipleObjects(Some(&[*vsync_event]), false, INFINITE, QS_ALLINPUT)
};
match wait_result {
// compositor clock ticked so we should draw a frame
WAIT_EVENT(0) => self.redraw_all(),
// Windows thread messages are posted
WAIT_EVENT(1) => {
if self.handle_events() {
break 'a;
}
}
_ => {
log::error!("Something went wrong while waiting {:?}", wait_result);
break;
}
loop {
if self.handle_events() {
break;
}
self.redraw_all();
}
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
@ -455,12 +436,7 @@ impl Platform for WindowsPlatform {
handle: AnyWindowHandle,
options: WindowParams,
) -> Result<Box<dyn PlatformWindow>> {
let window = WindowsWindow::new(
handle,
options,
self.generate_creation_info(),
&self.gpu_context,
)?;
let window = WindowsWindow::new(handle, options, self.generate_creation_info())?;
let handle = window.get_raw_handle();
self.raw_window_handles.write().push(handle);
@ -846,16 +822,6 @@ fn file_save_dialog(directory: PathBuf, window: Option<HWND>) -> Result<Option<P
Ok(Some(PathBuf::from(file_path_string)))
}
fn begin_vsync(vsync_event: HANDLE) {
let event: SafeHandle = vsync_event.into();
std::thread::spawn(move || unsafe {
loop {
windows::Win32::Graphics::Dwm::DwmFlush().log_err();
SetEvent(*event).log_err();
}
});
}
fn load_icon() -> Result<HICON> {
let module = unsafe { GetModuleHandleW(None).context("unable to get module handle")? };
let handle = unsafe {