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");