From 07376d11e8b33639df3e002f2631dff27c289802 Mon Sep 17 00:00:00 2001 From: Frizi Date: Thu, 3 Jun 2021 13:02:56 +0200 Subject: [PATCH] Handle winit exception in web to avoid breaking async executor --- wgpu/examples/framework.rs | 23 ++++++++++++++++++++++- wgpu/src/backend/direct.rs | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index 6f8e875af8..493e622643 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -357,10 +357,31 @@ pub fn run(title: &str) { #[cfg(target_arch = "wasm32")] pub fn run(title: &str) { + use wasm_bindgen::{prelude::*, JsCast}; + let title = title.to_owned(); wasm_bindgen_futures::spawn_local(async move { let setup = setup::(&title).await; - start::(setup); + let start_closure = Closure::once_into_js(move || start::(setup)); + + // make sure to handle JS exceptions thrown inside start. + // Otherwise wasm_bindgen_futures Queue would break and never handle any tasks again. + // This is required, because winit uses JS exception for control flow to escape from `run`. + if let Err(error) = call_catch(&start_closure) { + let is_control_flow_exception = error.dyn_ref::().map_or(false, |e| { + e.message().includes("Using exceptions for control flow", 0) + }); + + if !is_control_flow_exception { + web_sys::console::error_1(&error); + } + } + + #[wasm_bindgen] + extern "C" { + #[wasm_bindgen(catch, js_namespace = Function, js_name = "prototype.call.call")] + fn call_catch(this: &JsValue) -> Result<(), JsValue>; + } }); } diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index c50a599c37..878bcbb874 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1940,7 +1940,7 @@ impl fmt::Debug for ErrorSinkRaw { } fn default_error_handler(err: crate::Error) { - eprintln!("wgpu error: {}\n", err); + log::error!("wgpu error: {}\n", err); panic!("Handling wgpu errors as fatal by default"); }