Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instance::request_adapter silently fails when browser doesn't support WebGPU and wgpu compiled without webgl feature. #6196

Closed
BGR360 opened this issue Sep 2, 2024 · 0 comments · Fixed by #6197

Comments

@BGR360
Copy link
Contributor

BGR360 commented Sep 2, 2024

Description

When wgpu is compiled with webgpu support but not with webgl support, Instance::request_adapter will silently fail in the JavaScript bindings because the gpu property of the Navigator object is undefined:

image
[eframe::web::web_painter_wgpu] eframe-0.28.1/src/web/web_painter_wgpu.rs:87: Creating wgpu painter [eframe_playground-4f32d0779d5ce992.js:355:17](http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js)
[eframe::web::web_painter_wgpu] eframe-0.28.1/src/web/web_painter_wgpu.rs:108: Creating wgpu instance with backends Backends(VULKAN | GL | METAL | DX12 | BROWSER_WEBGPU) [eframe_playground-4f32d0779d5ce992.js:355:17](http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js)
[eframe::web::web_painter_wgpu] eframe-0.28.1/src/web/web_painter_wgpu.rs:133: Attempting to create WebGPU adapter to check for support. [eframe_playground-4f32d0779d5ce992.js:355:17](http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js)
Uncaught TypeError: getObject(...) is undefined
   __wbg_requestAdapter_e6f12701c7a38391 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:593
    eframe_playground-48dc8705e159ba07.wasm.<wgpu::backend::webgpu::ContextWebGpu as wgpu::context::Context>::instance_request_adapter::hadf591a74423c947 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2242345
    eframe_playground-48dc8705e159ba07.wasm.<T as wgpu::context::DynContext>::instance_request_adapter::h1703fd936174fd32 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2323304
    h6fe9b80c9ca94af0 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2321486
    h647f146a6e64bf74 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:132062
    h8db8326439fec966 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:379486
    h502255be13bbe6eb http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:567807
    h96675c010ef6ac33 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:873248
    hbfe20424c414c393 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:1840992
    hd9850ef0b1f32ef7 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2317335
    eframe_playground-48dc8705e159ba07.wasm.<dyn core::ops::function::FnMut<(A,)>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hf44c2d097134f68e http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2440395
    __wbg_adapter_41 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:237
    real http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:200
    (Async: VoidFunction)
    __wbg_queueMicrotask_12a30234db4045d3 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:896
    hade5a56ce01b34cb http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2107289
    h8109c4df9a7e514c http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2240165
    h50cd6afe6cb6ebc3 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2358847
    h6a88423b0971bda0 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:1982201
    h6db9c6983f17410f http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2412272
    h85d20172bbd387bb http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2412116
    h04ef72bb8494faea http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2320016
    h74eda17738e2d5ac http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2187987
    h95f28351807ad7f3 http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2314583
    main http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2440064
    wasm http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992_bg.wasm:2445515
    __wbg_finalize_init http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:1633
    __wbg_init http://127.0.0.1:8080/eframe_playground-4f32d0779d5ce992.js:1681
    InterpretGeneratorResume self-hosted:1420
    AsyncFunctionNext self-hosted:807
    (Async: async)
    <anonymous> http://127.0.0.1:8080/:16

Repro steps

I am brand new to compiling web apps with Rust, so I don't know how to minimize my reproduction. I discovered this bug by trying to use eframe_template.

If you clone this branch of my eframe_playground repository, you should be able to reproduce the problem on the latest (not-nightly) FireFox.

The repo is built with Trunk:

$ git clone -b wgpu-firefox-bug https://github.com/BGR360/eframe_playground.git
$ cd eframe_playground
$ trunk serve
<...>
2024-09-02T00:02:33.965564Z  INFO ✅ success
2024-09-02T00:02:33.965609Z  INFO 📡 serving static assets at -> /
2024-09-02T00:02:33.965654Z  INFO 📡 server listening at:
2024-09-02T00:02:33.965656Z  INFO     🏠 http://127.0.0.1:8080/
2024-09-02T00:02:33.965658Z  INFO     🏠 http://[::1]:8080/

Expected vs observed behavior

The behavior I would expect in this case is that Instance::request_adapter returns None. Instead, the WASM crashes in the JavaScript bindings due to invoking bindings on an undefined GPU object.

Platform

MacOS Sonoma 14.4.1 (23E224), Apple Silicon
FireFox 129.0.2
Chrome 127.0.6533.89 (Official Build) (arm64)

The latest eframe uses wgpu version 0.20.1, but I'm fairly certain the bug still exists on the latest wgpu, see below.

Root cause

Here's what I believe is happening:

In Instance::new, is_only_available_backend is true and support_webgpu is false (because gpu.is_undefined() is true):

#[cfg(webgpu)]
{
let is_only_available_backend = !cfg!(wgpu_core);
let requested_webgpu = _instance_desc.backends.contains(Backends::BROWSER_WEBGPU);
let support_webgpu =
crate::backend::get_browser_gpu_property().map_or(false, |gpu| !gpu.is_undefined());
if is_only_available_backend || (requested_webgpu && support_webgpu) {
return Self {
context: Arc::from(crate::backend::ContextWebGpu::init(_instance_desc)),
};
}
}

Because is_only_available_backend overrides the other check, ContextWebGpu::init is called even though Navigator.gpu is undefined.

In ContextWebGpu::init, it checks whether the gpu property can be fetched from the current thread, but it does not check whether gpu is undefined:

fn init(_instance_desc: wgt::InstanceDescriptor) -> Self {
let Some(gpu) = get_browser_gpu_property() else {
panic!(
"Accessing the GPU is only supported on the main thread or from a dedicated worker"
);
};
ContextWebGpu(gpu)
}

Finally, we hit this line in ContextWebGpu::request_adapter which calls the JS binding with an undefined arg0:

let adapter_promise = self.0.request_adapter_with_options(&mapped_options);

Possible Solutions

The easiest thing to do would be to panic inside ContextWebGpu::init if gpu.is_undefined(). But this doesn't seem like the right thing to do.

The better thing to do would be to check if self.0.is_undefined() before calling out to the JS bindings, and to return a Future that immediately resolves to None if it is undefined. We should probably also put a check-for-undefined in ContextWebGpu::surface_get_capabilities. In that case I think it's okay to panic.

I can send a PR sketching out a solution.

BGR360 added a commit to BGR360/wgpu that referenced this issue Sep 2, 2024
…U is the only compiled backend.

Previously, `Instance::request_adapter` would invoke a wasm binding with an undefined arg0,
thus crashing the program. Now it will cleanly return `None` instead.

Fixes gfx-rs#6196.
BGR360 added a commit to BGR360/wgpu that referenced this issue Sep 14, 2024
…U is the only compiled backend.

Previously, `Instance::request_adapter` would invoke a wasm binding with an undefined arg0,
thus crashing the program. Now it will cleanly return `None` instead.

Fixes gfx-rs#6196.
@Wumpf Wumpf closed this as completed in 2fac5e9 Sep 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant