egui-wgpu: don't panic if we can't find a device (#2427) (#2428)

This commit is contained in:
Ryan Hileman 2022-12-12 01:36:48 -08:00 committed by GitHub
parent 059e6f719d
commit c8dd5d1b2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 38 deletions

View file

@ -941,7 +941,7 @@ mod wgpu_integration {
self.window = Some(window); self.window = Some(window);
if let Some(running) = &mut self.running { if let Some(running) = &mut self.running {
unsafe { unsafe {
running.painter.set_window(self.window.as_ref()); running.painter.set_window(self.window.as_ref()).unwrap();
} }
} }
} }
@ -952,7 +952,7 @@ mod wgpu_integration {
self.window = None; self.window = None;
if let Some(running) = &mut self.running { if let Some(running) = &mut self.running {
unsafe { unsafe {
running.painter.set_window(None); running.painter.set_window(None).unwrap();
} }
} }
} }
@ -970,7 +970,7 @@ mod wgpu_integration {
self.native_options.multisampling.max(1) as _, self.native_options.multisampling.max(1) as _,
self.native_options.depth_buffer, self.native_options.depth_buffer,
); );
painter.set_window(Some(&window)); painter.set_window(Some(&window)).unwrap();
painter painter
}; };

View file

@ -3,6 +3,7 @@ All notable changes to the `egui-wgpu` integration will be noted in this file.
## Unreleased ## Unreleased
* Fix panic if we can't find a device ([#2428](https://github.com/emilk/egui/pull/2428))
## 0.20.0 - 2022-12-08 - web support ## 0.20.0 - 2022-12-08 - web support

View file

@ -60,26 +60,27 @@ impl Painter {
/// ///
/// Will return [`None`] if the render state has not been initialized yet. /// Will return [`None`] if the render state has not been initialized yet.
pub fn render_state(&self) -> Option<RenderState> { pub fn render_state(&self) -> Option<RenderState> {
self.render_state.as_ref().cloned() self.render_state.clone()
} }
async fn init_render_state( async fn init_render_state(
&self, &self,
adapter: &Adapter, adapter: &Adapter,
target_format: wgpu::TextureFormat, target_format: wgpu::TextureFormat,
) -> RenderState { ) -> Result<RenderState, wgpu::RequestDeviceError> {
let (device, queue) = adapter
pollster::block_on(adapter.request_device(&self.configuration.device_descriptor, None)) .request_device(&self.configuration.device_descriptor, None)
.unwrap(); .await
.map(|(device, queue)| {
let renderer = Renderer::new(&device, target_format, self.depth_format, self.msaa_samples); let renderer =
Renderer::new(&device, target_format, self.depth_format, self.msaa_samples);
RenderState { RenderState {
device: Arc::new(device), device: Arc::new(device),
queue: Arc::new(queue), queue: Arc::new(queue),
target_format, target_format,
renderer: Arc::new(RwLock::new(renderer)), renderer: Arc::new(RwLock::new(renderer)),
} }
})
} }
// We want to defer the initialization of our render state until we have a surface // We want to defer the initialization of our render state until we have a surface
@ -87,25 +88,31 @@ impl Painter {
// //
// After we've initialized our render state once though we expect all future surfaces // After we've initialized our render state once though we expect all future surfaces
// will have the same format and so this render state will remain valid. // will have the same format and so this render state will remain valid.
fn ensure_render_state_for_surface(&mut self, surface: &Surface) { fn ensure_render_state_for_surface(
self.adapter.get_or_insert_with(|| { &mut self,
surface: &Surface,
) -> Result<(), wgpu::RequestDeviceError> {
if self.adapter.is_none() {
self.adapter =
pollster::block_on(self.instance.request_adapter(&wgpu::RequestAdapterOptions { pollster::block_on(self.instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: self.configuration.power_preference, power_preference: self.configuration.power_preference,
compatible_surface: Some(surface), compatible_surface: Some(surface),
force_fallback_adapter: false, force_fallback_adapter: false,
})) }));
.unwrap() }
});
if self.render_state.is_none() { if self.render_state.is_none() {
let adapter = self.adapter.as_ref().unwrap(); match &self.adapter {
Some(adapter) => {
let swapchain_format = let swapchain_format = crate::preferred_framebuffer_format(
crate::preferred_framebuffer_format(&surface.get_supported_formats(adapter)); &surface.get_supported_formats(adapter),
);
let rs = pollster::block_on(self.init_render_state(adapter, swapchain_format)); let rs = pollster::block_on(self.init_render_state(adapter, swapchain_format))?;
self.render_state = Some(rs); self.render_state = Some(rs);
} }
None => return Err(wgpu::RequestDeviceError {}),
}
}
Ok(())
} }
fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) { fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
@ -161,12 +168,18 @@ impl Painter {
/// The raw Window handle associated with the given `window` must be a valid object to create a /// The raw Window handle associated with the given `window` must be a valid object to create a
/// surface upon and must remain valid for the lifetime of the created surface. (The surface may /// surface upon and must remain valid for the lifetime of the created surface. (The surface may
/// be cleared by passing `None`). /// be cleared by passing `None`).
pub unsafe fn set_window(&mut self, window: Option<&winit::window::Window>) { ///
/// # Errors
/// If the provided wgpu configuration does not match an available device.
pub unsafe fn set_window(
&mut self,
window: Option<&winit::window::Window>,
) -> Result<(), wgpu::RequestDeviceError> {
match window { match window {
Some(window) => { Some(window) => {
let surface = self.instance.create_surface(&window); let surface = self.instance.create_surface(&window);
self.ensure_render_state_for_surface(&surface); self.ensure_render_state_for_surface(&surface)?;
let size = window.inner_size(); let size = window.inner_size();
let width = size.width; let width = size.width;
@ -182,6 +195,7 @@ impl Painter {
self.surface_state = None; self.surface_state = None;
} }
} }
Ok(())
} }
/// Returns the maximum texture dimension supported if known /// Returns the maximum texture dimension supported if known
@ -195,7 +209,7 @@ impl Painter {
.map(|rs| rs.device.limits().max_texture_dimension_2d as usize) .map(|rs| rs.device.limits().max_texture_dimension_2d as usize)
} }
pub fn resize_and_generate_depth_texture_view( fn resize_and_generate_depth_texture_view(
&mut self, &mut self,
width_in_pixels: u32, width_in_pixels: u32,
height_in_pixels: u32, height_in_pixels: u32,