Display error message when WebGPU not enabled

Detect the case where creating the WebGPU surface fails, and insert a message explaning the failure into the DOM, rather than panicking.
This commit is contained in:
Raph Levien 2023-04-28 13:49:12 -07:00
parent 299b47ea06
commit e399f4792d
3 changed files with 39 additions and 10 deletions

View file

@ -45,4 +45,4 @@ android_logger = "0.13.0"
console_error_panic_hook = "0.1.7"
console_log = "0.2"
wasm-bindgen-futures = "0.4.33"
web-sys = "0.3.60"
web-sys = { version = "0.3.60", features = [ "HtmlCollection", "Text" ] }

View file

@ -413,7 +413,7 @@ fn run(
let size = window.inner_size();
let surface_future = render_cx.create_surface(&window, size.width, size.height);
// We need to block here, in case a Suspended event appeared
let surface = pollster::block_on(surface_future);
let surface = pollster::block_on(surface_future).expect("Error creating surface");
render_state = {
let render_state = RenderState { window, surface };
renderers.resize_with(render_cx.devices.len(), || None);
@ -453,6 +453,23 @@ enum UserEvent {
HotReload,
}
#[cfg(target_arch = "wasm32")]
fn display_error_message() -> Option<()> {
let window = web_sys::window()?;
let document = window.document()?;
let elements = document.get_elements_by_tag_name("body");
let body = elements.item(0)?;
let canvas = body.first_child()?;
// TODO: style the notice at least a little, maybe link?
let text = document.create_text_node(
"WebGPU is not enabled. Make sure your browser is updated to
Chrome M113 or another browser compatible with WebGPU.",
);
let _ = body.insert_before(&text, Some(&canvas));
web_sys::console::log_1(&"got body".into());
Some(())
}
pub fn main() -> Result<()> {
// TODO: initializing both env_logger and console_logger fails on wasm.
// Figure out a more principled approach.
@ -496,9 +513,13 @@ pub fn main() -> Result<()> {
let surface = render_cx
.create_surface(&window, size.width, size.height)
.await;
let render_state = RenderState { window, surface };
// No error handling here; if the event loop has finished, we don't need to send them the surface
run(event_loop, args, scenes, render_cx, render_state);
if let Ok(surface) = surface {
let render_state = RenderState { window, surface };
// No error handling here; if the event loop has finished, we don't need to send them the surface
run(event_loop, args, scenes, render_cx, render_state);
} else {
_ = display_error_message();
}
});
}
}

View file

@ -50,12 +50,20 @@ impl RenderContext {
}
/// Creates a new surface for the specified window and dimensions.
pub async fn create_surface<W>(&mut self, window: &W, width: u32, height: u32) -> RenderSurface
pub async fn create_surface<W>(
&mut self,
window: &W,
width: u32,
height: u32,
) -> Result<RenderSurface>
where
W: HasRawWindowHandle + HasRawDisplayHandle,
{
let surface = unsafe { self.instance.create_surface(window) }.unwrap();
let dev_id = self.device(Some(&surface)).await.unwrap();
let surface = unsafe { self.instance.create_surface(window) }?;
let dev_id = self
.device(Some(&surface))
.await
.ok_or("Error creating device")?;
let device_handle = &self.devices[dev_id];
let capabilities = surface.get_capabilities(&device_handle.adapter);
@ -75,12 +83,12 @@ impl RenderContext {
view_formats: vec![],
};
surface.configure(&self.devices[dev_id].device, &config);
RenderSurface {
Ok(RenderSurface {
surface,
config,
dev_id,
format,
}
})
}
/// Resizes the surface to the new dimensions.