Skip to content

Commit

Permalink
Allow WebGPU & WebGL in same wasm and detect WebGPU availability (#5044)
Browse files Browse the repository at this point in the history
* Rename backends: web -> webgpu, direct -> wgpu_core

* rename context objects for web & core

* allow webgpu & webgl features side-by-side

* make sure webgl ci doesn't use webgpu

* update any_backend_feature_enabled

* add panicing generate_report method for compatibility

* RequestDeviceErrorKind::Web rename, fixup various cfg attributes

* automatic webgpu support detection

* changelog entry

* fix emscripten

* fix weird cfg, fix comment typo

* remove try_generate_report again

* Make get_mapped_range_as_array_buffer WebGPU only again
  • Loading branch information
Wumpf committed Jan 14, 2024
1 parent f89bd3b commit 7774f31
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 212 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 367,7 @@ jobs:
- name: execute tests
run: |
cd wgpu
wasm-pack test --headless --chrome --features webgl --workspace
wasm-pack test --headless --chrome --no-default-features --features wgsl,webgl --workspace
gpu-test:
# runtime is normally 5-15 minutes
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 67,15 @@ Conversion to `wgpu::SurfaceTarget` is automatic for anything implementing `raw-
meaning that you can continue to e.g. pass references to winit windows as before.
By @wumpf in [#4984](https://github.com/gfx-rs/wgpu/pull/4984)

### WebGPU & WebGL in the same binary

Enabling `webgl` no longer removes the `webgpu` backend.
Instead, there's a new (default enabled) `webgpu` feature that allows to explicitly opt-out of `webgpu` if so desired.
If both `webgl` & `webgpu` are enabled, `wgpu::Instance` decides upon creation whether to target wgpu-core/WebGL or WebGPU.
This means that adapter selection is not handled as with regular adapters, but still allows to decide at runtime whether
`webgpu` or the `webgl` backend should be used using a single wasm binary.
By @wumpf in [#5044](https://github.com/gfx-rs/wgpu/pull/5044)

### New Features

#### General
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 174,7 @@ To run the test suite on WebGL (currently incomplete):

```
cd wgpu
wasm-pack test --headless --chrome --features webgl --workspace
wasm-pack test --headless --chrome --no-default-features --features webgl --workspace
```

This will automatically run the tests using a packaged browser. Remove `--headless` to run the tests with whatever browser you wish at `http://localhost:8000`.
Expand Down
12 changes: 11 additions & 1 deletion tests/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 16,17 @@ pub fn initialize_instance() -> Instance {
//
// We can potentially work support back into the test runner in the future, but as the adapters are matched up
// based on adapter index, removing some backends messes up the indexes in annoying ways.
let backends = Backends::all();
//
// WORKAROUND for https://github.com/rust-lang/cargo/issues/7160:
// `--no-default-features` is not passed through correctly to the test runner.
// We use it whenever we want to explicitly run with webgl instead of webgpu.
// To "disable" webgpu regardless, we do this by removing the webgpu backend whenever we see
// the webgl feature.
let backends = if cfg!(feature = "webgl") {
Backends::all() - Backends::BROWSER_WEBGPU
} else {
Backends::all()
};
let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default();
let gles_minor_version = wgpu::util::gles_minor_version_from_env().unwrap_or_default();
Instance::new(wgpu::InstanceDescriptor {
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 52,11 @@ fn device_lifetime_check() {

instance.poll_all(false);

let pre_report = instance.generate_report();
let pre_report = instance.generate_report().unwrap().unwrap();

drop(queue);
drop(device);
let post_report = instance.generate_report();
let post_report = instance.generate_report().unwrap().unwrap();
assert_ne!(
pre_report, post_report,
"Queue and Device has not been dropped as expected"
Expand Down
32 changes: 16 additions & 16 deletions tests/tests/mem_leaks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 12,7 @@ async fn draw_test_with_reports(

use wgpu::util::DeviceExt;

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.devices.num_allocated, 1);
assert_eq!(report.queues.num_allocated, 1);
Expand All @@ -21,7 21,7 @@ async fn draw_test_with_reports(
.device
.create_shader_module(wgpu::include_wgsl!("./vertex_indices/draw.vert.wgsl"));

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.shader_modules.num_allocated, 1);

Expand All @@ -41,7 41,7 @@ async fn draw_test_with_reports(
}],
});

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 0);
assert_eq!(report.bind_groups.num_allocated, 0);
Expand All @@ -54,7 54,7 @@ async fn draw_test_with_reports(
mapped_at_creation: false,
});

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);

Expand All @@ -67,7 67,7 @@ async fn draw_test_with_reports(
}],
});

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.bind_groups.num_allocated, 1);
Expand All @@ -81,7 81,7 @@ async fn draw_test_with_reports(
push_constant_ranges: &[],
});

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.pipeline_layouts.num_allocated, 1);
Expand Down Expand Up @@ -113,7 113,7 @@ async fn draw_test_with_reports(
multiview: None,
});

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.bind_groups.num_allocated, 1);
Expand All @@ -125,7 125,7 @@ async fn draw_test_with_reports(

drop(shader);

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.shader_modules.num_allocated, 1);
assert_eq!(report.shader_modules.num_kept_from_user, 0);
Expand Down Expand Up @@ -153,15 153,15 @@ async fn draw_test_with_reports(
);
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.texture_views.num_allocated, 1);
assert_eq!(report.textures.num_allocated, 1);

drop(texture);

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.texture_views.num_allocated, 1);
Expand All @@ -173,7 173,7 @@ async fn draw_test_with_reports(
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.command_buffers.num_allocated, 1);
assert_eq!(report.buffers.num_allocated, 1);
Expand All @@ -193,7 193,7 @@ async fn draw_test_with_reports(
rpass.set_pipeline(&pipeline);
rpass.set_bind_group(0, &bg, &[]);

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.buffers.num_allocated, 1);
assert_eq!(report.bind_groups.num_allocated, 1);
Expand All @@ -216,7 216,7 @@ async fn draw_test_with_reports(
drop(bg);
drop(buffer);

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.command_buffers.num_kept_from_user, 1);
assert_eq!(report.render_pipelines.num_kept_from_user, 0);
Expand All @@ -237,15 237,15 @@ async fn draw_test_with_reports(

let submit_index = ctx.queue.submit(Some(encoder.finish()));

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);
assert_eq!(report.command_buffers.num_allocated, 0);

ctx.async_poll(wgpu::Maintain::wait_for(submit_index))
.await
.panic_on_timeout();

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);

assert_eq!(report.render_pipelines.num_allocated, 0);
Expand All @@ -260,7 260,7 @@ async fn draw_test_with_reports(
drop(ctx.device);
drop(ctx.adapter);

let global_report = ctx.instance.generate_report();
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(ctx.adapter_info.backend);

assert_eq!(report.queues.num_kept_from_user, 0);
Expand Down
7 changes: 6 additions & 1 deletion wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 155,12 @@ bitflags::bitflags! {
const METAL = 1 << Backend::Metal as u32;
/// Supported on Windows 10
const DX12 = 1 << Backend::Dx12 as u32;
/// Supported when targeting the web through webassembly
/// Supported when targeting the web through webassembly with the `webgpu` feature enabled.
///
/// The WebGPU backend is special in several ways:
/// It is not not implemented by `wgpu_core` and instead by the higher level `wgpu` crate.
/// Whether WebGPU is targeted is decided upon the creation of the `wgpu::Instance`,
/// *not* upon adapter creation. See `wgpu::Instance::new`.
const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
/// All the apis that wgpu offers first tier of support for.
///
Expand Down
6 changes: 4 additions & 2 deletions wgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 24,7 @@ targets = [
[lib]

[features]
default = ["wgsl", "dx12", "metal"]
default = ["wgsl", "dx12", "metal", "webgpu"]

#! ### Backends
# --------------------------------------------------------------------
Expand All @@ -44,10 44,12 @@ angle = ["wgc?/gles"]
## Enables the Vulkan backend on macOS & iOS.
vulkan-portability = ["wgc?/vulkan"]

## Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`.
webgpu = []

## Enables the GLES backend on Wasm
##
## * ⚠️ WIP: Currently will also enable GLES dependencies on any other targets.
## * ⚠️ WIP: This automatically disables use of WebGPU. See [#2804](https://github.com/gfx-rs/wgpu/issues/3514).
webgl = ["hal", "wgc/gles"]

#! ### Shading language support
Expand Down
3 changes: 2 additions & 1 deletion wgpu/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 2,9 @@ fn main() {
cfg_aliases::cfg_aliases! {
native: { not(target_arch = "wasm32") },
webgl: { all(target_arch = "wasm32", not(target_os = "emscripten"), feature = "webgl") },
webgpu: { all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "webgl")) },
webgpu: { all(target_arch = "wasm32", not(target_os = "emscripten"), feature = "webgpu") },
Emscripten: { all(target_arch = "wasm32", target_os = "emscripten") },
wgpu_core: { any(native, webgl, emscripten) },
send_sync: { any(
not(target_arch = "wasm32"),
all(feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics"))
Expand Down
12 changes: 6 additions & 6 deletions wgpu/src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 1,9 @@
#[cfg(webgpu)]
mod web;
mod webgpu;
#[cfg(webgpu)]
pub(crate) use web::Context;
pub(crate) use webgpu::{get_browser_gpu_property, ContextWebGpu};

#[cfg(not(webgpu))]
mod direct;
#[cfg(not(webgpu))]
pub(crate) use direct::Context;
#[cfg(wgpu_core)]
mod wgpu_core;
#[cfg(wgpu_core)]
pub(crate) use wgpu_core::ContextWgpuCore;
Loading

0 comments on commit 7774f31

Please sign in to comment.