gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.4k stars 908 forks source link

WebGPU support detection doesn't handle failure at `getContext()` #5332

Open kpreid opened 7 months ago

kpreid commented 7 months ago

Description Enabling the "webgpu" backend can cause WebGL support to be lost.

Repro steps

  1. Use Firefox 123.0 on macOS.
  2. Set dom.webgpu.enabled to true.
  3. Visit https://wgpu.rs/examples/?backend=webgl2&example=bunnymark

Expected vs observed behavior Expected: The demo should display, using either webgpu or webgl2. Observed: it fails to initialize: CreateSurfaceError { inner: Web("canvas.getContext() returned null; webgpu not available or canvas already in use") }

WebGPU detection is presumably concluding WebGPU is supported because navigator.gpu exists, but that is evidently not sufficient.

(Note that it is also possible for a canvas to return null for the context simply because it was previously used as "webgl2" rather than "webgpu". That would be nice to support too, but since it would require a simultaneous WebGPU-or-WebGL2 backend, understandable to skip.)

Platform

Wumpf commented 7 months ago

As I understand navigator.gpu existence is supposed to signify webgpu support, but I ran into the same issue and had to do an elaborate workaround. The whole situation is surprisingly hard to solve with the way things are set up right now: In order to check whether the Instance should be a WebGPU instance, we have to first instantiate the adapter and if that fails turn around and create a different instance. So fixing this likely needs us to step back a bit and rethink how all of this works.

Wumpf commented 7 months ago

Related to:

kpreid commented 7 months ago

In order to check whether the Instance should be a WebGPU instance, we have to first instantiate the adapter and if that fails turn around and create a different instance. So fixing this likely needs us to step back a bit and rethink how all of this works.

Oh, this is actually a feasible workaround in applications which create the instance and adapter together, since it can be done purely using the wgpu API! I'll have to try that. Would be nice to have it mentioned in wgpu's docs until this bug can be fixed (or Firefox can be ?more conformant?).

kpreid commented 7 months ago

I tried implementing the workaround: creating an instance, surface, and adapter first with Backends::BROWSER_WEBGPU, and then wgpu::Backends::GL if that fails. But, I got a panic when WebGPU isn't supported/enabled in the browser at all:

panicked at /Users/kpreid/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-core-0.19.3/src/instance.rs:521:39: called Option::unwrap() on a None value

This appears to be the bug already fixed by https://github.com/gfx-rs/wgpu/pull/5166. But it can be avoided by using Backends::all() in the first attempt, and then initialization succeeds in all cases I've tested.

dv29 commented 2 months ago

I'm getting this as well. Tried running it locally and https://wgpu.rs/examples/?backend=webgpu&example=bunnymark both give the same error. I'm going to investigate it unless a fix is already in the works

panicked at examples/src/framework.rs:148:65:
called `Result::unwrap()` on an `Err` value: CreateSurfaceError { inner: Web("canvas.getContext() returned null; webgpu not available or canvas already in use") }
cwfitzgerald commented 2 months ago

There is not, go ahead :)

dv29 commented 2 months ago

So it seems that firefox only supports WebGPU API on Nightly, I tried it with nightly and its works. I'm not sure why dom.webgpu.enabled did not work though, i'm guessing that it only affects on Nightly builds. I'm going to try to fall back on WebGL as you suggested on #5142 (btw this is my first time with this project)

Wumpf commented 2 months ago

I for one observed that issue on Linux Chrome where they (afaik as of writing) still don't support WebGPU. wgpu incorrectly picks webgpu over webgl there