From 909cc30cc3f2be78c0ca9a0961c89c8af3bf4acf Mon Sep 17 00:00:00 2001 From: "zed-zippy[bot]" <234243425+zed-zippy[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 09:13:29 +0000 Subject: [PATCH] gpui: Remove all (unsound) `ManuallyDrop` usages, panic on device loss (#42114) (cherry-pick to stable) (#42603) Cherry-pick of #42114 to stable ---- Given that when we lose our devices unrecoverably we will panic anyways, might as well do so eagerly which makes it clearer. Additionally this PR replaces all uses of `ManuallyDrop` with `Option`, as otherwise we need to do manual bookkeeping of what is and isn't initialized when we try to recover devices as we can bail out halfway while recovering. In other words, the code prior to this was fairly unsound due to freely using `ManuallyDrop::drop`. Fixes ZED-1SS Release Notes: - N/A *or* Added/Fixed/Improved ... Co-authored-by: Lukas Wirth --- .../gpui/src/platform/windows/direct_write.rs | 21 +- .../src/platform/windows/directx_devices.rs | 31 +- .../src/platform/windows/directx_renderer.rs | 386 +++++++++--------- crates/gpui/src/platform/windows/events.rs | 4 +- crates/gpui/src/platform/windows/platform.rs | 55 +-- 5 files changed, 239 insertions(+), 258 deletions(-) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index 5449378ffd5d987849c8b00b546738d4519d1e2c..cb22948898fd496d6820e29088a9be7c5c502341 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -211,8 +211,8 @@ impl DirectWriteTextSystem { }))) } - pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) { - self.0.write().handle_gpu_lost(directx_devices); + pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> { + self.0.write().handle_gpu_lost(directx_devices) } } @@ -1215,18 +1215,11 @@ impl DirectWriteState { result } - fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) { - try_to_recover_from_device_lost( - || GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite"), - |gpu_state| self.components.gpu_state = gpu_state, - || { - log::error!( - "Failed to recreate GPU state for DirectWrite after multiple attempts." - ); - // Do something here? - // At this point, the device loss is considered unrecoverable. - }, - ); + fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> { + try_to_recover_from_device_lost(|| { + GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite") + }) + .map(|gpu_state| self.components.gpu_state = gpu_state) } } diff --git a/crates/gpui/src/platform/windows/directx_devices.rs b/crates/gpui/src/platform/windows/directx_devices.rs index a6a2381777b11fd1863735f3c7f4b71aafbf6a39..980093719ab72232706f8a72c07d44470fe08df3 100644 --- a/crates/gpui/src/platform/windows/directx_devices.rs +++ b/crates/gpui/src/platform/windows/directx_devices.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Result}; +use itertools::Itertools; use util::ResultExt; use windows::Win32::{ Foundation::HMODULE, @@ -20,24 +21,18 @@ use windows::Win32::{ }; use windows::core::Interface; -pub(crate) fn try_to_recover_from_device_lost( - mut f: impl FnMut() -> Result, - on_success: impl FnOnce(T), - on_error: impl FnOnce(), -) { - let result = (0..5).find_map(|i| { - if i > 0 { - // Add a small delay before retrying - std::thread::sleep(std::time::Duration::from_millis(100)); - } - f().log_err() - }); - - if let Some(result) = result { - on_success(result); - } else { - on_error(); - } +pub(crate) fn try_to_recover_from_device_lost(mut f: impl FnMut() -> Result) -> Result { + (0..5) + .map(|i| { + if i > 0 { + // Add a small delay before retrying + std::thread::sleep(std::time::Duration::from_millis(100 + i * 10)); + } + f() + }) + .find_or_last(Result::is_ok) + .unwrap() + .context("DirectXRenderer failed to recover from lost device after multiple attempts") } #[derive(Clone)] diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 220876b4a98693f514886c14ca4b58725f2583d2..b4180708aa510158456e6b9b0fe1ba1e0dfea85b 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1,5 +1,5 @@ use std::{ - mem::ManuallyDrop, + slice, sync::{Arc, OnceLock}, }; @@ -39,12 +39,15 @@ pub(crate) struct FontInfo { pub(crate) struct DirectXRenderer { hwnd: HWND, atlas: Arc, - devices: ManuallyDrop, - resources: ManuallyDrop, + devices: Option, + resources: Option, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, direct_composition: Option, font_info: &'static FontInfo, + + width: u32, + height: u32, } /// Direct3D objects @@ -60,19 +63,17 @@ pub(crate) struct DirectXRendererDevices { struct DirectXResources { // Direct3D rendering objects swap_chain: IDXGISwapChain1, - render_target: ManuallyDrop, - render_target_view: [Option; 1], + render_target: Option, + render_target_view: Option, // Path intermediate textures (with MSAA) path_intermediate_texture: ID3D11Texture2D, - path_intermediate_srv: [Option; 1], + path_intermediate_srv: Option, path_intermediate_msaa_texture: ID3D11Texture2D, - path_intermediate_msaa_view: [Option; 1], + path_intermediate_msaa_view: Option, - // Cached window size and viewport - width: u32, - height: u32, - viewport: [D3D11_VIEWPORT; 1], + // Cached viewport + viewport: D3D11_VIEWPORT, } struct DirectXRenderPipelines { @@ -86,8 +87,8 @@ struct DirectXRenderPipelines { } struct DirectXGlobalElements { - global_params_buffer: [Option; 1], - sampler: [Option; 1], + global_params_buffer: Option, + sampler: Option, } struct DirectComposition { @@ -100,7 +101,7 @@ impl DirectXRendererDevices { pub(crate) fn new( directx_devices: &DirectXDevices, disable_direct_composition: bool, - ) -> Result> { + ) -> Result { let DirectXDevices { adapter, dxgi_factory, @@ -113,13 +114,13 @@ impl DirectXRendererDevices { Some(device.cast().context("Creating DXGI device")?) }; - Ok(ManuallyDrop::new(Self { + Ok(Self { adapter: adapter.clone(), dxgi_factory: dxgi_factory.clone(), device: device.clone(), device_context: device_context.clone(), dxgi_device, - })) + }) } } @@ -158,12 +159,14 @@ impl DirectXRenderer { Ok(DirectXRenderer { hwnd, atlas, - devices, - resources, + devices: Some(devices), + resources: Some(resources), globals, pipelines, direct_composition, font_info: Self::get_font_info(), + width: 1, + height: 1, }) } @@ -172,55 +175,49 @@ impl DirectXRenderer { } fn pre_draw(&self) -> Result<()> { + let resources = self.resources.as_ref().expect("resources missing"); + let device_context = &self + .devices + .as_ref() + .expect("devices missing") + .device_context; update_buffer( - &self.devices.device_context, - self.globals.global_params_buffer[0].as_ref().unwrap(), + device_context, + self.globals.global_params_buffer.as_ref().unwrap(), &[GlobalParams { gamma_ratios: self.font_info.gamma_ratios, - viewport_size: [ - self.resources.viewport[0].Width, - self.resources.viewport[0].Height, - ], + viewport_size: [resources.viewport.Width, resources.viewport.Height], grayscale_enhanced_contrast: self.font_info.grayscale_enhanced_contrast, _pad: 0, }], )?; unsafe { - self.devices.device_context.ClearRenderTargetView( - self.resources.render_target_view[0].as_ref().unwrap(), - &[0.0; 4], - ); - self.devices - .device_context - .OMSetRenderTargets(Some(&self.resources.render_target_view), None); - self.devices - .device_context - .RSSetViewports(Some(&self.resources.viewport)); + device_context + .ClearRenderTargetView(resources.render_target_view.as_ref().unwrap(), &[0.0; 4]); + device_context + .OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None); + device_context.RSSetViewports(Some(slice::from_ref(&resources.viewport))); } Ok(()) } #[inline] fn present(&mut self) -> Result<()> { - let result = unsafe { self.resources.swap_chain.Present(0, DXGI_PRESENT(0)) }; + let result = unsafe { + self.resources + .as_ref() + .expect("resources missing") + .swap_chain + .Present(0, DXGI_PRESENT(0)) + }; result.ok().context("Presenting swap chain failed") } - pub(crate) fn handle_device_lost(&mut self, directx_devices: &DirectXDevices) { - try_to_recover_from_device_lost( - || { - self.handle_device_lost_impl(directx_devices) - .context("DirectXRenderer handling device lost") - }, - |_| {}, - || { - log::error!( - "DirectXRenderer failed to recover from device lost after multiple attempts" - ); - // Do something here? - // At this point, the device loss is considered unrecoverable. - }, - ); + pub(crate) fn handle_device_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> { + try_to_recover_from_device_lost(|| { + self.handle_device_lost_impl(directx_devices) + .context("DirectXRenderer handling device lost") + }) } fn handle_device_lost_impl(&mut self, directx_devices: &DirectXDevices) -> Result<()> { @@ -228,35 +225,41 @@ impl DirectXRenderer { unsafe { #[cfg(debug_assertions)] - report_live_objects(&self.devices.device) - .context("Failed to report live objects after device lost") - .log_err(); - - ManuallyDrop::drop(&mut self.resources); - self.devices.device_context.OMSetRenderTargets(None, None); - self.devices.device_context.ClearState(); - self.devices.device_context.Flush(); + if let Some(devices) = &self.devices { + report_live_objects(&devices.device) + .context("Failed to report live objects after device lost") + .log_err(); + } - #[cfg(debug_assertions)] - report_live_objects(&self.devices.device) - .context("Failed to report live objects after device lost") - .log_err(); + self.resources.take(); + if let Some(devices) = &self.devices { + devices.device_context.OMSetRenderTargets(None, None); + devices.device_context.ClearState(); + devices.device_context.Flush(); + #[cfg(debug_assertions)] + report_live_objects(&devices.device) + .context("Failed to report live objects after device lost") + .log_err(); + } - drop(self.direct_composition.take()); - ManuallyDrop::drop(&mut self.devices); + self.direct_composition.take(); + self.devices.take(); } let devices = DirectXRendererDevices::new(directx_devices, disable_direct_composition) .context("Recreating DirectX devices")?; let resources = DirectXResources::new( &devices, - self.resources.width, - self.resources.height, + self.width, + self.height, self.hwnd, disable_direct_composition, - )?; - let globals = DirectXGlobalElements::new(&devices.device)?; - let pipelines = DirectXRenderPipelines::new(&devices.device)?; + ) + .context("Creating DirectX resources")?; + let globals = DirectXGlobalElements::new(&devices.device) + .context("Creating DirectXGlobalElements")?; + let pipelines = DirectXRenderPipelines::new(&devices.device) + .context("Creating DirectXRenderPipelines")?; let direct_composition = if disable_direct_composition { None @@ -269,17 +272,17 @@ impl DirectXRenderer { self.atlas .handle_device_lost(&devices.device, &devices.device_context); - self.devices = devices; - self.resources = resources; - self.globals = globals; - self.pipelines = pipelines; - self.direct_composition = direct_composition; unsafe { - self.devices + devices .device_context - .OMSetRenderTargets(Some(&self.resources.render_target_view), None); + .OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None); } + self.devices = Some(devices); + self.resources = Some(resources); + self.globals = globals; + self.pipelines = pipelines; + self.direct_composition = direct_composition; Ok(()) } @@ -318,23 +321,25 @@ impl DirectXRenderer { pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { let width = new_size.width.0.max(1) as u32; let height = new_size.height.0.max(1) as u32; - if self.resources.width == width && self.resources.height == height { + if self.width == width && self.height == height { return Ok(()); } - self.resources.width = width; - self.resources.height = height; + self.width = width; + self.height = height; // Clear the render target before resizing - unsafe { self.devices.device_context.OMSetRenderTargets(None, None) }; - unsafe { ManuallyDrop::drop(&mut self.resources.render_target) }; - drop(self.resources.render_target_view[0].take().unwrap()); + let devices = self.devices.as_ref().context("devices missing")?; + unsafe { devices.device_context.OMSetRenderTargets(None, None) }; + let resources = self.resources.as_mut().context("resources missing")?; + resources.render_target.take(); + resources.render_target_view.take(); // Resizing the swap chain requires a call to the underlying DXGI adapter, which can return the device removed error. // The app might have moved to a monitor that's attached to a different graphics device. // When a graphics device is removed or reset, the desktop resolution often changes, resulting in a window size change. // But here we just return the error, because we are handling device lost scenarios elsewhere. unsafe { - self.resources + resources .swap_chain .ResizeBuffers( BUFFER_COUNT as u32, @@ -346,12 +351,11 @@ impl DirectXRenderer { .context("Failed to resize swap chain")?; } - self.resources - .recreate_resources(&self.devices, width, height)?; + resources.recreate_resources(devices, width, height)?; unsafe { - self.devices + devices .device_context - .OMSetRenderTargets(Some(&self.resources.render_target_view), None); + .OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None); } Ok(()) @@ -361,15 +365,22 @@ impl DirectXRenderer { if shadows.is_empty() { return Ok(()); } + let devices = self.devices.as_ref().context("devices missing")?; self.pipelines.shadow_pipeline.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, shadows, )?; self.pipelines.shadow_pipeline.draw( - &self.devices.device_context, - &self.resources.viewport, - &self.globals.global_params_buffer, + &devices.device_context, + slice::from_ref( + &self + .resources + .as_ref() + .context("resources missing")? + .viewport, + ), + slice::from_ref(&self.globals.global_params_buffer), D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, shadows.len() as u32, @@ -380,15 +391,22 @@ impl DirectXRenderer { if quads.is_empty() { return Ok(()); } + let devices = self.devices.as_ref().context("devices missing")?; self.pipelines.quad_pipeline.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, quads, )?; self.pipelines.quad_pipeline.draw( - &self.devices.device_context, - &self.resources.viewport, - &self.globals.global_params_buffer, + &devices.device_context, + slice::from_ref( + &self + .resources + .as_ref() + .context("resources missing")? + .viewport, + ), + slice::from_ref(&self.globals.global_params_buffer), D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, quads.len() as u32, @@ -400,18 +418,19 @@ impl DirectXRenderer { return Ok(()); } + let devices = self.devices.as_ref().context("devices missing")?; + let resources = self.resources.as_ref().context("resources missing")?; // Clear intermediate MSAA texture unsafe { - self.devices.device_context.ClearRenderTargetView( - self.resources.path_intermediate_msaa_view[0] - .as_ref() - .unwrap(), + devices.device_context.ClearRenderTargetView( + resources.path_intermediate_msaa_view.as_ref().unwrap(), &[0.0; 4], ); // Set intermediate MSAA texture as render target - self.devices - .device_context - .OMSetRenderTargets(Some(&self.resources.path_intermediate_msaa_view), None); + devices.device_context.OMSetRenderTargets( + Some(slice::from_ref(&resources.path_intermediate_msaa_view)), + None, + ); } // Collect all vertices and sprites for a single draw call @@ -427,14 +446,15 @@ impl DirectXRenderer { } self.pipelines.path_rasterization_pipeline.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, &vertices, )?; + self.pipelines.path_rasterization_pipeline.draw( - &self.devices.device_context, - &self.resources.viewport, - &self.globals.global_params_buffer, + &devices.device_context, + slice::from_ref(&resources.viewport), + slice::from_ref(&self.globals.global_params_buffer), D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, vertices.len() as u32, 1, @@ -442,17 +462,17 @@ impl DirectXRenderer { // Resolve MSAA to non-MSAA intermediate texture unsafe { - self.devices.device_context.ResolveSubresource( - &self.resources.path_intermediate_texture, + devices.device_context.ResolveSubresource( + &resources.path_intermediate_texture, 0, - &self.resources.path_intermediate_msaa_texture, + &resources.path_intermediate_msaa_texture, 0, RENDER_TARGET_FORMAT, ); // Restore main render target - self.devices + devices .device_context - .OMSetRenderTargets(Some(&self.resources.render_target_view), None); + .OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None); } Ok(()) @@ -485,19 +505,21 @@ impl DirectXRenderer { vec![PathSprite { bounds }] }; + let devices = self.devices.as_ref().context("devices missing")?; + let resources = self.resources.as_ref().context("resources missing")?; self.pipelines.path_sprite_pipeline.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, &sprites, )?; // Draw the sprites with the path texture self.pipelines.path_sprite_pipeline.draw_with_texture( - &self.devices.device_context, - &self.resources.path_intermediate_srv, - &self.resources.viewport, - &self.globals.global_params_buffer, - &self.globals.sampler, + &devices.device_context, + slice::from_ref(&resources.path_intermediate_srv), + slice::from_ref(&resources.viewport), + slice::from_ref(&self.globals.global_params_buffer), + slice::from_ref(&self.globals.sampler), sprites.len() as u32, ) } @@ -506,15 +528,17 @@ impl DirectXRenderer { if underlines.is_empty() { return Ok(()); } + let devices = self.devices.as_ref().context("devices missing")?; + let resources = self.resources.as_ref().context("resources missing")?; self.pipelines.underline_pipeline.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, underlines, )?; self.pipelines.underline_pipeline.draw( - &self.devices.device_context, - &self.resources.viewport, - &self.globals.global_params_buffer, + &devices.device_context, + slice::from_ref(&resources.viewport), + slice::from_ref(&self.globals.global_params_buffer), D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, underlines.len() as u32, @@ -529,18 +553,20 @@ impl DirectXRenderer { if sprites.is_empty() { return Ok(()); } + let devices = self.devices.as_ref().context("devices missing")?; + let resources = self.resources.as_ref().context("resources missing")?; self.pipelines.mono_sprites.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, sprites, )?; let texture_view = self.atlas.get_texture_view(texture_id); self.pipelines.mono_sprites.draw_with_texture( - &self.devices.device_context, + &devices.device_context, &texture_view, - &self.resources.viewport, - &self.globals.global_params_buffer, - &self.globals.sampler, + slice::from_ref(&resources.viewport), + slice::from_ref(&self.globals.global_params_buffer), + slice::from_ref(&self.globals.sampler), sprites.len() as u32, ) } @@ -553,18 +579,21 @@ impl DirectXRenderer { if sprites.is_empty() { return Ok(()); } + + let devices = self.devices.as_ref().context("devices missing")?; + let resources = self.resources.as_ref().context("resources missing")?; self.pipelines.poly_sprites.update_buffer( - &self.devices.device, - &self.devices.device_context, + &devices.device, + &devices.device_context, sprites, )?; let texture_view = self.atlas.get_texture_view(texture_id); self.pipelines.poly_sprites.draw_with_texture( - &self.devices.device_context, + &devices.device_context, &texture_view, - &self.resources.viewport, - &self.globals.global_params_buffer, - &self.globals.sampler, + slice::from_ref(&resources.viewport), + slice::from_ref(&self.globals.global_params_buffer), + slice::from_ref(&self.globals.sampler), sprites.len() as u32, ) } @@ -577,7 +606,8 @@ impl DirectXRenderer { } pub(crate) fn gpu_specs(&self) -> Result { - let desc = unsafe { self.devices.adapter.GetDesc1() }?; + let devices = self.devices.as_ref().context("devices missing")?; + let desc = unsafe { devices.adapter.GetDesc1() }?; let is_software_emulated = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE.0 as u32) != 0; let device_name = String::from_utf16_lossy(&desc.Description) .trim_matches(char::from(0)) @@ -592,7 +622,7 @@ impl DirectXRenderer { 0x10DE => nvidia::get_driver_version(), 0x1002 => amd::get_driver_version(), // For Intel and other vendors, we use the DXGI API to get the driver version. - _ => dxgi::get_driver_version(&self.devices.adapter), + _ => dxgi::get_driver_version(&devices.adapter), } .context("Failed to get gpu driver info") .log_err() @@ -626,7 +656,7 @@ impl DirectXResources { height: u32, hwnd: HWND, disable_direct_composition: bool, - ) -> Result> { + ) -> Result { let swap_chain = if disable_direct_composition { create_swap_chain(&devices.dxgi_factory, &devices.device, hwnd, width, height)? } else { @@ -649,18 +679,16 @@ impl DirectXResources { ) = create_resources(devices, &swap_chain, width, height)?; set_rasterizer_state(&devices.device, &devices.device_context)?; - Ok(ManuallyDrop::new(Self { + Ok(Self { swap_chain, - render_target, + render_target: Some(render_target), render_target_view, path_intermediate_texture, path_intermediate_msaa_texture, path_intermediate_msaa_view, path_intermediate_srv, viewport, - width, - height, - })) + }) } #[inline] @@ -679,7 +707,7 @@ impl DirectXResources { path_intermediate_msaa_view, viewport, ) = create_resources(devices, &self.swap_chain, width, height)?; - self.render_target = render_target; + self.render_target = Some(render_target); self.render_target_view = render_target_view; self.path_intermediate_texture = path_intermediate_texture; self.path_intermediate_msaa_texture = path_intermediate_msaa_texture; @@ -789,7 +817,7 @@ impl DirectXGlobalElements { }; let mut buffer = None; device.CreateBuffer(&desc, None, Some(&mut buffer))?; - [buffer] + buffer }; let sampler = unsafe { @@ -807,7 +835,7 @@ impl DirectXGlobalElements { }; let mut output = None; device.CreateSamplerState(&desc, Some(&mut output))?; - [output] + output }; Ok(Self { @@ -832,7 +860,7 @@ struct PipelineState { fragment: ID3D11PixelShader, buffer: ID3D11Buffer, buffer_size: usize, - view: [Option; 1], + view: Option, blend_state: ID3D11BlendState, _marker: std::marker::PhantomData, } @@ -902,7 +930,7 @@ impl PipelineState { ) -> Result<()> { set_pipeline_state( device_context, - &self.view, + slice::from_ref(&self.view), topology, viewport, &self.vertex, @@ -927,7 +955,7 @@ impl PipelineState { ) -> Result<()> { set_pipeline_state( device_context, - &self.view, + slice::from_ref(&self.view), D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, viewport, &self.vertex, @@ -964,18 +992,8 @@ struct PathSprite { impl Drop for DirectXRenderer { fn drop(&mut self) { #[cfg(debug_assertions)] - report_live_objects(&self.devices.device).ok(); - unsafe { - ManuallyDrop::drop(&mut self.devices); - ManuallyDrop::drop(&mut self.resources); - } - } -} - -impl Drop for DirectXResources { - fn drop(&mut self) { - unsafe { - ManuallyDrop::drop(&mut self.render_target); + if let Some(devices) = &self.devices { + report_live_objects(&devices.device).ok(); } } } @@ -1049,13 +1067,13 @@ fn create_resources( width: u32, height: u32, ) -> Result<( - ManuallyDrop, - [Option; 1], ID3D11Texture2D, - [Option; 1], + Option, + ID3D11Texture2D, + Option, ID3D11Texture2D, - [Option; 1], - [D3D11_VIEWPORT; 1], + Option, + D3D11_VIEWPORT, )> { let (render_target, render_target_view) = create_render_target_and_its_view(swap_chain, &devices.device)?; @@ -1079,17 +1097,11 @@ fn create_resources( fn create_render_target_and_its_view( swap_chain: &IDXGISwapChain1, device: &ID3D11Device, -) -> Result<( - ManuallyDrop, - [Option; 1], -)> { +) -> Result<(ID3D11Texture2D, Option)> { let render_target: ID3D11Texture2D = unsafe { swap_chain.GetBuffer(0) }?; let mut render_target_view = None; unsafe { device.CreateRenderTargetView(&render_target, None, Some(&mut render_target_view))? }; - Ok(( - ManuallyDrop::new(render_target), - [Some(render_target_view.unwrap())], - )) + Ok((render_target, render_target_view)) } #[inline] @@ -1097,7 +1109,7 @@ fn create_path_intermediate_texture( device: &ID3D11Device, width: u32, height: u32, -) -> Result<(ID3D11Texture2D, [Option; 1])> { +) -> Result<(ID3D11Texture2D, Option)> { let texture = unsafe { let mut output = None; let desc = D3D11_TEXTURE2D_DESC { @@ -1122,7 +1134,7 @@ fn create_path_intermediate_texture( let mut shader_resource_view = None; unsafe { device.CreateShaderResourceView(&texture, None, Some(&mut shader_resource_view))? }; - Ok((texture, [Some(shader_resource_view.unwrap())])) + Ok((texture, Some(shader_resource_view.unwrap()))) } #[inline] @@ -1130,7 +1142,7 @@ fn create_path_intermediate_msaa_texture_and_view( device: &ID3D11Device, width: u32, height: u32, -) -> Result<(ID3D11Texture2D, [Option; 1])> { +) -> Result<(ID3D11Texture2D, Option)> { let msaa_texture = unsafe { let mut output = None; let desc = D3D11_TEXTURE2D_DESC { @@ -1153,15 +1165,11 @@ fn create_path_intermediate_msaa_texture_and_view( }; let mut msaa_view = None; unsafe { device.CreateRenderTargetView(&msaa_texture, None, Some(&mut msaa_view))? }; - Ok((msaa_texture, [Some(msaa_view.unwrap())])) + Ok((msaa_texture, Some(msaa_view.unwrap()))) } #[inline] -fn set_viewport( - device_context: &ID3D11DeviceContext, - width: f32, - height: f32, -) -> [D3D11_VIEWPORT; 1] { +fn set_viewport(device_context: &ID3D11DeviceContext, width: f32, height: f32) -> D3D11_VIEWPORT { let viewport = [D3D11_VIEWPORT { TopLeftX: 0.0, TopLeftY: 0.0, @@ -1171,7 +1179,7 @@ fn set_viewport( MaxDepth: 1.0, }]; unsafe { device_context.RSSetViewports(Some(&viewport)) }; - viewport + viewport[0] } #[inline] @@ -1299,10 +1307,10 @@ fn create_buffer( fn create_buffer_view( device: &ID3D11Device, buffer: &ID3D11Buffer, -) -> Result<[Option; 1]> { +) -> Result> { let mut view = None; unsafe { device.CreateShaderResourceView(buffer, None, Some(&mut view)) }?; - Ok([view]) + Ok(view) } #[inline] diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index e3b50bcebd5fa8edb12e0ca18a15d6e364552f7a..2a962b0c235e9900ded1496352521033fa8de667 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -1133,7 +1133,9 @@ impl WindowsWindowInner { let mut lock = self.state.borrow_mut(); let devices = lparam.0 as *const DirectXDevices; let devices = unsafe { &*devices }; - lock.renderer.handle_device_lost(&devices); + if let Err(err) = lock.renderer.handle_device_lost(&devices) { + panic!("Device lost: {err}"); + } Some(0) } diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index a8e13469427eecbdc64afea534366e73d04e7e2d..72d0914f5ea76cd51dd8e5ed78bc368aad89b1aa 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -1,7 +1,6 @@ use std::{ cell::RefCell, ffi::OsStr, - mem::ManuallyDrop, path::{Path, PathBuf}, rc::{Rc, Weak}, sync::{Arc, atomic::Ordering}, @@ -57,7 +56,7 @@ pub(crate) struct WindowsPlatformState { jump_list: JumpList, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Option, - directx_devices: ManuallyDrop, + directx_devices: Option, } #[derive(Default)] @@ -76,7 +75,7 @@ impl WindowsPlatformState { let callbacks = PlatformCallbacks::default(); let jump_list = JumpList::new(); let current_cursor = load_cursor(CursorStyle::Arrow); - let directx_devices = ManuallyDrop::new(directx_devices); + let directx_devices = Some(directx_devices); Self { callbacks, @@ -190,7 +189,7 @@ impl WindowsPlatform { main_receiver: self.inner.main_receiver.clone(), platform_window_handle: self.handle, disable_direct_composition: self.disable_direct_composition, - directx_devices: (*self.inner.state.borrow().directx_devices).clone(), + directx_devices: self.inner.state.borrow().directx_devices.clone().unwrap(), } } @@ -238,7 +237,7 @@ impl WindowsPlatform { } fn begin_vsync_thread(&self) { - let mut directx_device = (*self.inner.state.borrow().directx_devices).clone(); + let mut directx_device = self.inner.state.borrow().directx_devices.clone().unwrap(); let platform_window: SafeHwnd = self.handle.into(); let validation_number = self.inner.validation_number; let all_windows = Arc::downgrade(&self.raw_window_handles); @@ -250,13 +249,15 @@ impl WindowsPlatform { loop { vsync_provider.wait_for_vsync(); if check_device_lost(&directx_device.device) { - handle_gpu_device_lost( + if let Err(err) = handle_gpu_device_lost( &mut directx_device, platform_window.as_raw(), validation_number, &all_windows, &text_system, - ); + ) { + panic!("Device lost: {err}"); + } } let Some(all_windows) = all_windows.upgrade() else { break; @@ -826,10 +827,8 @@ impl WindowsPlatformInner { let mut lock = self.state.borrow_mut(); let directx_devices = lparam.0 as *const DirectXDevices; let directx_devices = unsafe { &*directx_devices }; - unsafe { - ManuallyDrop::drop(&mut lock.directx_devices); - } - lock.directx_devices = ManuallyDrop::new(directx_devices.clone()); + lock.directx_devices.take(); + lock.directx_devices = Some(directx_devices.clone()); Some(0) } @@ -846,14 +845,6 @@ impl Drop for WindowsPlatform { } } -impl Drop for WindowsPlatformState { - fn drop(&mut self) { - unsafe { - ManuallyDrop::drop(&mut self.directx_devices); - } - } -} - pub(crate) struct WindowCreationInfo { pub(crate) icon: HICON, pub(crate) executor: ForegroundExecutor, @@ -1077,37 +1068,28 @@ fn handle_gpu_device_lost( validation_number: usize, all_windows: &std::sync::Weak>>, text_system: &std::sync::Weak, -) { +) -> Result<()> { // Here we wait a bit to ensure the system has time to recover from the device lost state. // If we don't wait, the final drawing result will be blank. std::thread::sleep(std::time::Duration::from_millis(350)); - try_to_recover_from_device_lost( - || { - DirectXDevices::new() - .context("Failed to recreate new DirectX devices after device lost") - }, - |new_devices| *directx_devices = new_devices, - || { - log::error!("Failed to recover DirectX devices after multiple attempts."); - // Do something here? - // At this point, the device loss is considered unrecoverable. - // std::process::exit(1); - }, - ); + *directx_devices = try_to_recover_from_device_lost(|| { + DirectXDevices::new().context("Failed to recreate new DirectX devices after device lost") + })?; log::info!("DirectX devices successfully recreated."); + let lparam = LPARAM(directx_devices as *const _ as _); unsafe { SendMessageW( platform_window, WM_GPUI_GPU_DEVICE_LOST, Some(WPARAM(validation_number)), - Some(LPARAM(directx_devices as *const _ as _)), + Some(lparam), ); } if let Some(text_system) = text_system.upgrade() { - text_system.handle_gpu_lost(&directx_devices); + text_system.handle_gpu_lost(&directx_devices)?; } if let Some(all_windows) = all_windows.upgrade() { for window in all_windows.read().iter() { @@ -1116,7 +1098,7 @@ fn handle_gpu_device_lost( window.as_raw(), WM_GPUI_GPU_DEVICE_LOST, Some(WPARAM(validation_number)), - Some(LPARAM(directx_devices as *const _ as _)), + Some(lparam), ); } } @@ -1132,6 +1114,7 @@ fn handle_gpu_device_lost( } } } + Ok(()) } const PLATFORM_WINDOW_CLASS_NAME: PCWSTR = w!("Zed::PlatformWindow");