mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Allow WebGPU & WebGL in same wasm and detect WebGPU availability (#5044)
* 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
This commit is contained in:
parent
f89bd3b978
commit
7774f31021
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -367,7 +367,7 @@ jobs:
|
|||||||
- name: execute tests
|
- name: execute tests
|
||||||
run: |
|
run: |
|
||||||
cd wgpu
|
cd wgpu
|
||||||
wasm-pack test --headless --chrome --features webgl --workspace
|
wasm-pack test --headless --chrome --no-default-features --features wgsl,webgl --workspace
|
||||||
|
|
||||||
gpu-test:
|
gpu-test:
|
||||||
# runtime is normally 5-15 minutes
|
# runtime is normally 5-15 minutes
|
||||||
|
@ -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.
|
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)
|
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
|
### New Features
|
||||||
|
|
||||||
#### General
|
#### General
|
||||||
|
@ -174,7 +174,7 @@ To run the test suite on WebGL (currently incomplete):
|
|||||||
|
|
||||||
```
|
```
|
||||||
cd wgpu
|
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`.
|
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`.
|
||||||
|
@ -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
|
// 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.
|
// 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 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();
|
let gles_minor_version = wgpu::util::gles_minor_version_from_env().unwrap_or_default();
|
||||||
Instance::new(wgpu::InstanceDescriptor {
|
Instance::new(wgpu::InstanceDescriptor {
|
||||||
|
@ -52,11 +52,11 @@ fn device_lifetime_check() {
|
|||||||
|
|
||||||
instance.poll_all(false);
|
instance.poll_all(false);
|
||||||
|
|
||||||
let pre_report = instance.generate_report();
|
let pre_report = instance.generate_report().unwrap().unwrap();
|
||||||
|
|
||||||
drop(queue);
|
drop(queue);
|
||||||
drop(device);
|
drop(device);
|
||||||
let post_report = instance.generate_report();
|
let post_report = instance.generate_report().unwrap().unwrap();
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
pre_report, post_report,
|
pre_report, post_report,
|
||||||
"Queue and Device has not been dropped as expected"
|
"Queue and Device has not been dropped as expected"
|
||||||
|
@ -12,7 +12,7 @@ async fn draw_test_with_reports(
|
|||||||
|
|
||||||
use wgpu::util::DeviceExt;
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.devices.num_allocated, 1);
|
assert_eq!(report.devices.num_allocated, 1);
|
||||||
assert_eq!(report.queues.num_allocated, 1);
|
assert_eq!(report.queues.num_allocated, 1);
|
||||||
@ -21,7 +21,7 @@ async fn draw_test_with_reports(
|
|||||||
.device
|
.device
|
||||||
.create_shader_module(wgpu::include_wgsl!("./vertex_indices/draw.vert.wgsl"));
|
.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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.shader_modules.num_allocated, 1);
|
assert_eq!(report.shader_modules.num_allocated, 1);
|
||||||
|
|
||||||
@ -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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 0);
|
assert_eq!(report.buffers.num_allocated, 0);
|
||||||
assert_eq!(report.bind_groups.num_allocated, 0);
|
assert_eq!(report.bind_groups.num_allocated, 0);
|
||||||
@ -54,7 +54,7 @@ async fn draw_test_with_reports(
|
|||||||
mapped_at_creation: false,
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
|
|
||||||
@ -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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.bind_groups.num_allocated, 1);
|
assert_eq!(report.bind_groups.num_allocated, 1);
|
||||||
@ -81,7 +81,7 @@ async fn draw_test_with_reports(
|
|||||||
push_constant_ranges: &[],
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.pipeline_layouts.num_allocated, 1);
|
assert_eq!(report.pipeline_layouts.num_allocated, 1);
|
||||||
@ -113,7 +113,7 @@ async fn draw_test_with_reports(
|
|||||||
multiview: None,
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.bind_groups.num_allocated, 1);
|
assert_eq!(report.bind_groups.num_allocated, 1);
|
||||||
@ -125,7 +125,7 @@ async fn draw_test_with_reports(
|
|||||||
|
|
||||||
drop(shader);
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.shader_modules.num_allocated, 1);
|
assert_eq!(report.shader_modules.num_allocated, 1);
|
||||||
assert_eq!(report.shader_modules.num_kept_from_user, 0);
|
assert_eq!(report.shader_modules.num_kept_from_user, 0);
|
||||||
@ -153,7 +153,7 @@ async fn draw_test_with_reports(
|
|||||||
);
|
);
|
||||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.texture_views.num_allocated, 1);
|
assert_eq!(report.texture_views.num_allocated, 1);
|
||||||
@ -161,7 +161,7 @@ async fn draw_test_with_reports(
|
|||||||
|
|
||||||
drop(texture);
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.texture_views.num_allocated, 1);
|
assert_eq!(report.texture_views.num_allocated, 1);
|
||||||
@ -173,7 +173,7 @@ async fn draw_test_with_reports(
|
|||||||
.device
|
.device
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
.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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.command_buffers.num_allocated, 1);
|
assert_eq!(report.command_buffers.num_allocated, 1);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
@ -193,7 +193,7 @@ async fn draw_test_with_reports(
|
|||||||
rpass.set_pipeline(&pipeline);
|
rpass.set_pipeline(&pipeline);
|
||||||
rpass.set_bind_group(0, &bg, &[]);
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.buffers.num_allocated, 1);
|
assert_eq!(report.buffers.num_allocated, 1);
|
||||||
assert_eq!(report.bind_groups.num_allocated, 1);
|
assert_eq!(report.bind_groups.num_allocated, 1);
|
||||||
@ -216,7 +216,7 @@ async fn draw_test_with_reports(
|
|||||||
drop(bg);
|
drop(bg);
|
||||||
drop(buffer);
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.command_buffers.num_kept_from_user, 1);
|
assert_eq!(report.command_buffers.num_kept_from_user, 1);
|
||||||
assert_eq!(report.render_pipelines.num_kept_from_user, 0);
|
assert_eq!(report.render_pipelines.num_kept_from_user, 0);
|
||||||
@ -237,7 +237,7 @@ async fn draw_test_with_reports(
|
|||||||
|
|
||||||
let submit_index = ctx.queue.submit(Some(encoder.finish()));
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
assert_eq!(report.command_buffers.num_allocated, 0);
|
assert_eq!(report.command_buffers.num_allocated, 0);
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ async fn draw_test_with_reports(
|
|||||||
.await
|
.await
|
||||||
.panic_on_timeout();
|
.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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
|
|
||||||
assert_eq!(report.render_pipelines.num_allocated, 0);
|
assert_eq!(report.render_pipelines.num_allocated, 0);
|
||||||
@ -260,7 +260,7 @@ async fn draw_test_with_reports(
|
|||||||
drop(ctx.device);
|
drop(ctx.device);
|
||||||
drop(ctx.adapter);
|
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);
|
let report = global_report.hub_report(ctx.adapter_info.backend);
|
||||||
|
|
||||||
assert_eq!(report.queues.num_kept_from_user, 0);
|
assert_eq!(report.queues.num_kept_from_user, 0);
|
||||||
|
@ -155,7 +155,12 @@ bitflags::bitflags! {
|
|||||||
const METAL = 1 << Backend::Metal as u32;
|
const METAL = 1 << Backend::Metal as u32;
|
||||||
/// Supported on Windows 10
|
/// Supported on Windows 10
|
||||||
const DX12 = 1 << Backend::Dx12 as u32;
|
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;
|
const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
|
||||||
/// All the apis that wgpu offers first tier of support for.
|
/// All the apis that wgpu offers first tier of support for.
|
||||||
///
|
///
|
||||||
|
@ -24,7 +24,7 @@ targets = [
|
|||||||
[lib]
|
[lib]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["wgsl", "dx12", "metal"]
|
default = ["wgsl", "dx12", "metal", "webgpu"]
|
||||||
|
|
||||||
#! ### Backends
|
#! ### Backends
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
@ -44,10 +44,12 @@ angle = ["wgc?/gles"]
|
|||||||
## Enables the Vulkan backend on macOS & iOS.
|
## Enables the Vulkan backend on macOS & iOS.
|
||||||
vulkan-portability = ["wgc?/vulkan"]
|
vulkan-portability = ["wgc?/vulkan"]
|
||||||
|
|
||||||
|
## Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`.
|
||||||
|
webgpu = []
|
||||||
|
|
||||||
## Enables the GLES backend on Wasm
|
## Enables the GLES backend on Wasm
|
||||||
##
|
##
|
||||||
## * ⚠️ WIP: Currently will also enable GLES dependencies on any other targets.
|
## * ⚠️ 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"]
|
webgl = ["hal", "wgc/gles"]
|
||||||
|
|
||||||
#! ### Shading language support
|
#! ### Shading language support
|
||||||
|
@ -2,8 +2,9 @@ fn main() {
|
|||||||
cfg_aliases::cfg_aliases! {
|
cfg_aliases::cfg_aliases! {
|
||||||
native: { not(target_arch = "wasm32") },
|
native: { not(target_arch = "wasm32") },
|
||||||
webgl: { all(target_arch = "wasm32", not(target_os = "emscripten"), feature = "webgl") },
|
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") },
|
Emscripten: { all(target_arch = "wasm32", target_os = "emscripten") },
|
||||||
|
wgpu_core: { any(native, webgl, emscripten) },
|
||||||
send_sync: { any(
|
send_sync: { any(
|
||||||
not(target_arch = "wasm32"),
|
not(target_arch = "wasm32"),
|
||||||
all(feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics"))
|
all(feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics"))
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
mod web;
|
mod webgpu;
|
||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
pub(crate) use web::Context;
|
pub(crate) use webgpu::{get_browser_gpu_property, ContextWebGpu};
|
||||||
|
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
mod direct;
|
mod wgpu_core;
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub(crate) use direct::Context;
|
pub(crate) use wgpu_core::ContextWgpuCore;
|
||||||
|
@ -69,19 +69,21 @@ unsafe impl<T> Send for Identified<T> {}
|
|||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
unsafe impl<T> Sync for Identified<T> {}
|
unsafe impl<T> Sync for Identified<T> {}
|
||||||
|
|
||||||
pub(crate) struct Context(web_sys::Gpu);
|
pub(crate) struct ContextWebGpu(web_sys::Gpu);
|
||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
unsafe impl Send for Context {}
|
unsafe impl Send for ContextWebGpu {}
|
||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
unsafe impl Sync for Context {}
|
unsafe impl Sync for ContextWebGpu {}
|
||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
unsafe impl Send for BufferMappedRange {}
|
unsafe impl Send for BufferMappedRange {}
|
||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
unsafe impl Sync for BufferMappedRange {}
|
unsafe impl Sync for BufferMappedRange {}
|
||||||
|
|
||||||
impl fmt::Debug for Context {
|
impl fmt::Debug for ContextWebGpu {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Context").field("type", &"Web").finish()
|
f.debug_struct("ContextWebGpu")
|
||||||
|
.field("type", &"Web")
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +542,8 @@ fn map_texture_view_dimension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn map_buffer_copy_view(view: crate::ImageCopyBuffer<'_>) -> web_sys::GpuImageCopyBuffer {
|
fn map_buffer_copy_view(view: crate::ImageCopyBuffer<'_>) -> web_sys::GpuImageCopyBuffer {
|
||||||
let buffer: &<Context as crate::Context>::BufferData = downcast_ref(view.buffer.data.as_ref());
|
let buffer: &<ContextWebGpu as crate::Context>::BufferData =
|
||||||
|
downcast_ref(view.buffer.data.as_ref());
|
||||||
let mut mapped = web_sys::GpuImageCopyBuffer::new(&buffer.0.buffer);
|
let mut mapped = web_sys::GpuImageCopyBuffer::new(&buffer.0.buffer);
|
||||||
if let Some(bytes_per_row) = view.layout.bytes_per_row {
|
if let Some(bytes_per_row) = view.layout.bytes_per_row {
|
||||||
mapped.bytes_per_row(bytes_per_row);
|
mapped.bytes_per_row(bytes_per_row);
|
||||||
@ -553,7 +556,7 @@ fn map_buffer_copy_view(view: crate::ImageCopyBuffer<'_>) -> web_sys::GpuImageCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn map_texture_copy_view(view: crate::ImageCopyTexture<'_>) -> web_sys::GpuImageCopyTexture {
|
fn map_texture_copy_view(view: crate::ImageCopyTexture<'_>) -> web_sys::GpuImageCopyTexture {
|
||||||
let texture: &<Context as crate::Context>::TextureData =
|
let texture: &<ContextWebGpu as crate::Context>::TextureData =
|
||||||
downcast_ref(view.texture.data.as_ref());
|
downcast_ref(view.texture.data.as_ref());
|
||||||
let mut mapped = web_sys::GpuImageCopyTexture::new(&texture.0);
|
let mut mapped = web_sys::GpuImageCopyTexture::new(&texture.0);
|
||||||
mapped.mip_level(view.mip_level);
|
mapped.mip_level(view.mip_level);
|
||||||
@ -564,7 +567,7 @@ fn map_texture_copy_view(view: crate::ImageCopyTexture<'_>) -> web_sys::GpuImage
|
|||||||
fn map_tagged_texture_copy_view(
|
fn map_tagged_texture_copy_view(
|
||||||
view: crate::ImageCopyTextureTagged<'_>,
|
view: crate::ImageCopyTextureTagged<'_>,
|
||||||
) -> web_sys::GpuImageCopyTextureTagged {
|
) -> web_sys::GpuImageCopyTextureTagged {
|
||||||
let texture: &<Context as crate::Context>::TextureData =
|
let texture: &<ContextWebGpu as crate::Context>::TextureData =
|
||||||
downcast_ref(view.texture.data.as_ref());
|
downcast_ref(view.texture.data.as_ref());
|
||||||
let mut mapped = web_sys::GpuImageCopyTextureTagged::new(&texture.0);
|
let mut mapped = web_sys::GpuImageCopyTextureTagged::new(&texture.0);
|
||||||
mapped.mip_level(view.mip_level);
|
mapped.mip_level(view.mip_level);
|
||||||
@ -821,7 +824,7 @@ fn future_request_device(
|
|||||||
(device_id, device_data, queue_id, queue_data)
|
(device_id, device_data, queue_id, queue_data)
|
||||||
})
|
})
|
||||||
.map_err(|error_value| crate::RequestDeviceError {
|
.map_err(|error_value| crate::RequestDeviceError {
|
||||||
inner: crate::RequestDeviceErrorKind::Web(error_value),
|
inner: crate::RequestDeviceErrorKind::WebGpu(error_value),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,7 +880,7 @@ where
|
|||||||
*rc_callback.borrow_mut() = Some((closure_success, closure_rejected, callback));
|
*rc_callback.borrow_mut() = Some((closure_success, closure_rejected, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl ContextWebGpu {
|
||||||
/// Common portion of the internal branches of the public `instance_create_surface` function.
|
/// Common portion of the internal branches of the public `instance_create_surface` function.
|
||||||
///
|
///
|
||||||
/// Note: Analogous code also exists in the WebGL2 backend at
|
/// Note: Analogous code also exists in the WebGL2 backend at
|
||||||
@ -929,6 +932,15 @@ impl Context {
|
|||||||
|
|
||||||
Ok(create_identified((canvas, context)))
|
Ok(create_identified((canvas, context)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get mapped buffer range directly as a `js_sys::ArrayBuffer`.
|
||||||
|
pub fn buffer_get_mapped_range_as_array_buffer(
|
||||||
|
&self,
|
||||||
|
buffer_data: &<ContextWebGpu as crate::Context>::BufferData,
|
||||||
|
sub_range: Range<wgt::BufferAddress>,
|
||||||
|
) -> js_sys::ArrayBuffer {
|
||||||
|
buffer_data.0.get_mapped_array_buffer(sub_range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents the global object in the JavaScript context.
|
// Represents the global object in the JavaScript context.
|
||||||
@ -952,7 +964,31 @@ pub enum Canvas {
|
|||||||
Offscreen(web_sys::OffscreenCanvas),
|
Offscreen(web_sys::OffscreenCanvas),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::context::Context for Context {
|
/// Returns the browsers gpu object or `None` if the current context is neither the main thread nor a dedicated worker.
|
||||||
|
///
|
||||||
|
/// If WebGPU is not supported, the Gpu property is `undefined` (but *not* necessarily `None`).
|
||||||
|
///
|
||||||
|
/// See:
|
||||||
|
/// * <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/gpu>
|
||||||
|
/// * <https://developer.mozilla.org/en-US/docs/Web/API/WorkerNavigator/gpu>
|
||||||
|
pub fn get_browser_gpu_property() -> Option<web_sys::Gpu> {
|
||||||
|
let global: Global = js_sys::global().unchecked_into();
|
||||||
|
|
||||||
|
if !global.window().is_undefined() {
|
||||||
|
Some(global.unchecked_into::<web_sys::Window>().navigator().gpu())
|
||||||
|
} else if !global.worker().is_undefined() {
|
||||||
|
Some(
|
||||||
|
global
|
||||||
|
.unchecked_into::<web_sys::WorkerGlobalScope>()
|
||||||
|
.navigator()
|
||||||
|
.gpu(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::context::Context for ContextWebGpu {
|
||||||
type AdapterId = Identified<web_sys::GpuAdapter>;
|
type AdapterId = Identified<web_sys::GpuAdapter>;
|
||||||
type AdapterData = Sendable<web_sys::GpuAdapter>;
|
type AdapterData = Sendable<web_sys::GpuAdapter>;
|
||||||
type DeviceId = Identified<web_sys::GpuDevice>;
|
type DeviceId = Identified<web_sys::GpuDevice>;
|
||||||
@ -1022,20 +1058,12 @@ impl crate::context::Context for Context {
|
|||||||
MakeSendFuture<wasm_bindgen_futures::JsFuture, fn(JsFutureResult) -> Option<crate::Error>>;
|
MakeSendFuture<wasm_bindgen_futures::JsFuture, fn(JsFutureResult) -> Option<crate::Error>>;
|
||||||
|
|
||||||
fn init(_instance_desc: wgt::InstanceDescriptor) -> Self {
|
fn init(_instance_desc: wgt::InstanceDescriptor) -> Self {
|
||||||
let global: Global = js_sys::global().unchecked_into();
|
let Some(gpu) = get_browser_gpu_property() else {
|
||||||
let gpu = if !global.window().is_undefined() {
|
|
||||||
global.unchecked_into::<web_sys::Window>().navigator().gpu()
|
|
||||||
} else if !global.worker().is_undefined() {
|
|
||||||
global
|
|
||||||
.unchecked_into::<web_sys::WorkerGlobalScope>()
|
|
||||||
.navigator()
|
|
||||||
.gpu()
|
|
||||||
} else {
|
|
||||||
panic!(
|
panic!(
|
||||||
"Accessing the GPU is only supported on the main thread or from a dedicated worker"
|
"Accessing the GPU is only supported on the main thread or from a dedicated worker"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
Context(gpu)
|
ContextWebGpu(gpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn instance_create_surface(
|
unsafe fn instance_create_surface(
|
||||||
@ -1587,7 +1615,7 @@ impl crate::context::Context for Context {
|
|||||||
offset,
|
offset,
|
||||||
size,
|
size,
|
||||||
}) => {
|
}) => {
|
||||||
let buffer: &<Context as crate::Context>::BufferData =
|
let buffer: &<ContextWebGpu as crate::Context>::BufferData =
|
||||||
downcast_ref(buffer.data.as_ref());
|
downcast_ref(buffer.data.as_ref());
|
||||||
let mut mapped_buffer_binding =
|
let mut mapped_buffer_binding =
|
||||||
web_sys::GpuBufferBinding::new(&buffer.0.buffer);
|
web_sys::GpuBufferBinding::new(&buffer.0.buffer);
|
||||||
@ -1601,7 +1629,7 @@ impl crate::context::Context for Context {
|
|||||||
panic!("Web backend does not support arrays of buffers")
|
panic!("Web backend does not support arrays of buffers")
|
||||||
}
|
}
|
||||||
crate::BindingResource::Sampler(sampler) => {
|
crate::BindingResource::Sampler(sampler) => {
|
||||||
let sampler: &<Context as crate::Context>::SamplerData =
|
let sampler: &<ContextWebGpu as crate::Context>::SamplerData =
|
||||||
downcast_ref(sampler.data.as_ref());
|
downcast_ref(sampler.data.as_ref());
|
||||||
JsValue::from(&sampler.0)
|
JsValue::from(&sampler.0)
|
||||||
}
|
}
|
||||||
@ -1609,7 +1637,7 @@ impl crate::context::Context for Context {
|
|||||||
panic!("Web backend does not support arrays of samplers")
|
panic!("Web backend does not support arrays of samplers")
|
||||||
}
|
}
|
||||||
crate::BindingResource::TextureView(texture_view) => {
|
crate::BindingResource::TextureView(texture_view) => {
|
||||||
let texture_view: &<Context as crate::Context>::TextureViewData =
|
let texture_view: &<ContextWebGpu as crate::Context>::TextureViewData =
|
||||||
downcast_ref(texture_view.data.as_ref());
|
downcast_ref(texture_view.data.as_ref());
|
||||||
JsValue::from(&texture_view.0)
|
JsValue::from(&texture_view.0)
|
||||||
}
|
}
|
||||||
@ -1622,7 +1650,7 @@ impl crate::context::Context for Context {
|
|||||||
})
|
})
|
||||||
.collect::<js_sys::Array>();
|
.collect::<js_sys::Array>();
|
||||||
|
|
||||||
let bgl: &<Context as crate::Context>::BindGroupLayoutData =
|
let bgl: &<ContextWebGpu as crate::Context>::BindGroupLayoutData =
|
||||||
downcast_ref(desc.layout.data.as_ref());
|
downcast_ref(desc.layout.data.as_ref());
|
||||||
let mut mapped_desc = web_sys::GpuBindGroupDescriptor::new(&mapped_entries, &bgl.0);
|
let mut mapped_desc = web_sys::GpuBindGroupDescriptor::new(&mapped_entries, &bgl.0);
|
||||||
if let Some(label) = desc.label {
|
if let Some(label) = desc.label {
|
||||||
@ -1641,7 +1669,7 @@ impl crate::context::Context for Context {
|
|||||||
.bind_group_layouts
|
.bind_group_layouts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|bgl| {
|
.map(|bgl| {
|
||||||
let bgl: &<Context as crate::Context>::BindGroupLayoutData =
|
let bgl: &<ContextWebGpu as crate::Context>::BindGroupLayoutData =
|
||||||
downcast_ref(bgl.data.as_ref());
|
downcast_ref(bgl.data.as_ref());
|
||||||
&bgl.0
|
&bgl.0
|
||||||
})
|
})
|
||||||
@ -1659,7 +1687,7 @@ impl crate::context::Context for Context {
|
|||||||
device_data: &Self::DeviceData,
|
device_data: &Self::DeviceData,
|
||||||
desc: &crate::RenderPipelineDescriptor<'_>,
|
desc: &crate::RenderPipelineDescriptor<'_>,
|
||||||
) -> (Self::RenderPipelineId, Self::RenderPipelineData) {
|
) -> (Self::RenderPipelineId, Self::RenderPipelineData) {
|
||||||
let module: &<Context as crate::Context>::ShaderModuleData =
|
let module: &<ContextWebGpu as crate::Context>::ShaderModuleData =
|
||||||
downcast_ref(desc.vertex.module.data.as_ref());
|
downcast_ref(desc.vertex.module.data.as_ref());
|
||||||
let mut mapped_vertex_state =
|
let mut mapped_vertex_state =
|
||||||
web_sys::GpuVertexState::new(desc.vertex.entry_point, &module.0);
|
web_sys::GpuVertexState::new(desc.vertex.entry_point, &module.0);
|
||||||
@ -1696,7 +1724,7 @@ impl crate::context::Context for Context {
|
|||||||
let mut mapped_desc = web_sys::GpuRenderPipelineDescriptor::new(
|
let mut mapped_desc = web_sys::GpuRenderPipelineDescriptor::new(
|
||||||
&match desc.layout {
|
&match desc.layout {
|
||||||
Some(layout) => {
|
Some(layout) => {
|
||||||
let layout: &<Context as crate::Context>::PipelineLayoutData =
|
let layout: &<ContextWebGpu as crate::Context>::PipelineLayoutData =
|
||||||
downcast_ref(layout.data.as_ref());
|
downcast_ref(layout.data.as_ref());
|
||||||
JsValue::from(&layout.0)
|
JsValue::from(&layout.0)
|
||||||
}
|
}
|
||||||
@ -1734,7 +1762,7 @@ impl crate::context::Context for Context {
|
|||||||
None => wasm_bindgen::JsValue::null(),
|
None => wasm_bindgen::JsValue::null(),
|
||||||
})
|
})
|
||||||
.collect::<js_sys::Array>();
|
.collect::<js_sys::Array>();
|
||||||
let module: &<Context as crate::Context>::ShaderModuleData =
|
let module: &<ContextWebGpu as crate::Context>::ShaderModuleData =
|
||||||
downcast_ref(frag.module.data.as_ref());
|
downcast_ref(frag.module.data.as_ref());
|
||||||
let mapped_fragment_desc =
|
let mapped_fragment_desc =
|
||||||
web_sys::GpuFragmentState::new(frag.entry_point, &module.0, &targets);
|
web_sys::GpuFragmentState::new(frag.entry_point, &module.0, &targets);
|
||||||
@ -1759,7 +1787,7 @@ impl crate::context::Context for Context {
|
|||||||
device_data: &Self::DeviceData,
|
device_data: &Self::DeviceData,
|
||||||
desc: &crate::ComputePipelineDescriptor<'_>,
|
desc: &crate::ComputePipelineDescriptor<'_>,
|
||||||
) -> (Self::ComputePipelineId, Self::ComputePipelineData) {
|
) -> (Self::ComputePipelineId, Self::ComputePipelineData) {
|
||||||
let shader_module: &<Context as crate::Context>::ShaderModuleData =
|
let shader_module: &<ContextWebGpu as crate::Context>::ShaderModuleData =
|
||||||
downcast_ref(desc.module.data.as_ref());
|
downcast_ref(desc.module.data.as_ref());
|
||||||
let mapped_compute_stage =
|
let mapped_compute_stage =
|
||||||
web_sys::GpuProgrammableStage::new(desc.entry_point, &shader_module.0);
|
web_sys::GpuProgrammableStage::new(desc.entry_point, &shader_module.0);
|
||||||
@ -1767,7 +1795,7 @@ impl crate::context::Context for Context {
|
|||||||
let mut mapped_desc = web_sys::GpuComputePipelineDescriptor::new(
|
let mut mapped_desc = web_sys::GpuComputePipelineDescriptor::new(
|
||||||
&match desc.layout {
|
&match desc.layout {
|
||||||
Some(layout) => {
|
Some(layout) => {
|
||||||
let layout: &<Context as crate::Context>::PipelineLayoutData =
|
let layout: &<ContextWebGpu as crate::Context>::PipelineLayoutData =
|
||||||
downcast_ref(layout.data.as_ref());
|
downcast_ref(layout.data.as_ref());
|
||||||
JsValue::from(&layout.0)
|
JsValue::from(&layout.0)
|
||||||
}
|
}
|
||||||
@ -2029,15 +2057,6 @@ impl crate::context::Context for Context {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_get_mapped_range_as_array_buffer(
|
|
||||||
&self,
|
|
||||||
_buffer: &Self::BufferId,
|
|
||||||
buffer_data: &Self::BufferData,
|
|
||||||
sub_range: Range<wgt::BufferAddress>,
|
|
||||||
) -> js_sys::ArrayBuffer {
|
|
||||||
buffer_data.0.get_mapped_array_buffer(sub_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buffer_unmap(&self, _buffer: &Self::BufferId, buffer_data: &Self::BufferData) {
|
fn buffer_unmap(&self, _buffer: &Self::BufferId, buffer_data: &Self::BufferData) {
|
||||||
buffer_data.0.buffer.unmap();
|
buffer_data.0.buffer.unmap();
|
||||||
buffer_data.0.mapping.borrow_mut().mapped_buffer = None;
|
buffer_data.0.mapping.borrow_mut().mapped_buffer = None;
|
||||||
@ -2322,7 +2341,7 @@ impl crate::context::Context for Context {
|
|||||||
crate::LoadOp::Load => web_sys::GpuLoadOp::Load,
|
crate::LoadOp::Load => web_sys::GpuLoadOp::Load,
|
||||||
};
|
};
|
||||||
|
|
||||||
let view: &<Context as crate::Context>::TextureViewData =
|
let view: &<ContextWebGpu as crate::Context>::TextureViewData =
|
||||||
downcast_ref(ca.view.data.as_ref());
|
downcast_ref(ca.view.data.as_ref());
|
||||||
|
|
||||||
let mut mapped_color_attachment = web_sys::GpuRenderPassColorAttachment::new(
|
let mut mapped_color_attachment = web_sys::GpuRenderPassColorAttachment::new(
|
||||||
@ -2334,7 +2353,7 @@ impl crate::context::Context for Context {
|
|||||||
mapped_color_attachment.clear_value(&cv);
|
mapped_color_attachment.clear_value(&cv);
|
||||||
}
|
}
|
||||||
if let Some(rt) = ca.resolve_target {
|
if let Some(rt) = ca.resolve_target {
|
||||||
let resolve_target_view: &<Context as crate::Context>::TextureViewData =
|
let resolve_target_view: &<ContextWebGpu as crate::Context>::TextureViewData =
|
||||||
downcast_ref(rt.data.as_ref());
|
downcast_ref(rt.data.as_ref());
|
||||||
mapped_color_attachment.resolve_target(&resolve_target_view.0);
|
mapped_color_attachment.resolve_target(&resolve_target_view.0);
|
||||||
}
|
}
|
||||||
@ -2353,7 +2372,7 @@ impl crate::context::Context for Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(dsa) = &desc.depth_stencil_attachment {
|
if let Some(dsa) = &desc.depth_stencil_attachment {
|
||||||
let depth_stencil_attachment: &<Context as crate::Context>::TextureViewData =
|
let depth_stencil_attachment: &<ContextWebGpu as crate::Context>::TextureViewData =
|
||||||
downcast_ref(dsa.view.data.as_ref());
|
downcast_ref(dsa.view.data.as_ref());
|
||||||
let mut mapped_depth_stencil_attachment =
|
let mut mapped_depth_stencil_attachment =
|
||||||
web_sys::GpuRenderPassDepthStencilAttachment::new(&depth_stencil_attachment.0);
|
web_sys::GpuRenderPassDepthStencilAttachment::new(&depth_stencil_attachment.0);
|
||||||
@ -2430,7 +2449,8 @@ impl crate::context::Context for Context {
|
|||||||
offset: wgt::BufferAddress,
|
offset: wgt::BufferAddress,
|
||||||
size: Option<wgt::BufferAddress>,
|
size: Option<wgt::BufferAddress>,
|
||||||
) {
|
) {
|
||||||
let buffer: &<Context as crate::Context>::BufferData = downcast_ref(buffer.data.as_ref());
|
let buffer: &<ContextWebGpu as crate::Context>::BufferData =
|
||||||
|
downcast_ref(buffer.data.as_ref());
|
||||||
match size {
|
match size {
|
||||||
Some(size) => encoder_data.0.clear_buffer_with_f64_and_f64(
|
Some(size) => encoder_data.0.clear_buffer_with_f64_and_f64(
|
||||||
&buffer.0.buffer,
|
&buffer.0.buffer,
|
@ -29,21 +29,23 @@ use wgt::WasmNotSendSync;
|
|||||||
|
|
||||||
const LABEL: &str = "label";
|
const LABEL: &str = "label";
|
||||||
|
|
||||||
pub struct Context(wgc::global::Global<wgc::identity::IdentityManagerFactory>);
|
pub struct ContextWgpuCore(wgc::global::Global<wgc::identity::IdentityManagerFactory>);
|
||||||
|
|
||||||
impl Drop for Context {
|
impl Drop for ContextWgpuCore {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
//nothing
|
//nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Context {
|
impl fmt::Debug for ContextWgpuCore {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Context").field("type", &"Native").finish()
|
f.debug_struct("ContextWgpuCore")
|
||||||
|
.field("type", &"Native")
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl ContextWgpuCore {
|
||||||
pub unsafe fn from_hal_instance<A: wgc::hal_api::HalApi>(hal_instance: A::Instance) -> Self {
|
pub unsafe fn from_hal_instance<A: wgc::hal_api::HalApi>(hal_instance: A::Instance) -> Self {
|
||||||
Self(unsafe {
|
Self(unsafe {
|
||||||
wgc::global::Global::from_hal_instance::<A>(
|
wgc::global::Global::from_hal_instance::<A>(
|
||||||
@ -443,7 +445,7 @@ pub struct CommandEncoder {
|
|||||||
open: bool,
|
open: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::Context for Context {
|
impl crate::Context for ContextWgpuCore {
|
||||||
type AdapterId = wgc::id::AdapterId;
|
type AdapterId = wgc::id::AdapterId;
|
||||||
type AdapterData = ();
|
type AdapterData = ();
|
||||||
type DeviceId = wgc::id::DeviceId;
|
type DeviceId = wgc::id::DeviceId;
|
@ -320,13 +320,6 @@ pub trait Context: Debug + WasmNotSendSync + Sized {
|
|||||||
buffer_data: &Self::BufferData,
|
buffer_data: &Self::BufferData,
|
||||||
sub_range: Range<BufferAddress>,
|
sub_range: Range<BufferAddress>,
|
||||||
) -> Box<dyn BufferMappedRange>;
|
) -> Box<dyn BufferMappedRange>;
|
||||||
#[cfg(webgpu)]
|
|
||||||
fn buffer_get_mapped_range_as_array_buffer(
|
|
||||||
&self,
|
|
||||||
buffer: &Self::BufferId,
|
|
||||||
buffer_data: &Self::BufferData,
|
|
||||||
sub_range: Range<BufferAddress>,
|
|
||||||
) -> js_sys::ArrayBuffer;
|
|
||||||
fn buffer_unmap(&self, buffer: &Self::BufferId, buffer_data: &Self::BufferData);
|
fn buffer_unmap(&self, buffer: &Self::BufferId, buffer_data: &Self::BufferData);
|
||||||
fn texture_create_view(
|
fn texture_create_view(
|
||||||
&self,
|
&self,
|
||||||
@ -1037,6 +1030,7 @@ impl ObjectId {
|
|||||||
global_id: None,
|
global_id: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn new(id: NonZeroU64, global_id: NonZeroU64) -> Self {
|
pub fn new(id: NonZeroU64, global_id: NonZeroU64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: Some(id),
|
id: Some(id),
|
||||||
@ -1346,13 +1340,6 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync {
|
|||||||
buffer_data: &crate::Data,
|
buffer_data: &crate::Data,
|
||||||
sub_range: Range<BufferAddress>,
|
sub_range: Range<BufferAddress>,
|
||||||
) -> Box<dyn BufferMappedRange>;
|
) -> Box<dyn BufferMappedRange>;
|
||||||
#[cfg(webgpu)]
|
|
||||||
fn buffer_get_mapped_range_as_array_buffer(
|
|
||||||
&self,
|
|
||||||
buffer: &ObjectId,
|
|
||||||
buffer_data: &crate::Data,
|
|
||||||
sub_range: Range<BufferAddress>,
|
|
||||||
) -> js_sys::ArrayBuffer;
|
|
||||||
fn buffer_unmap(&self, buffer: &ObjectId, buffer_data: &crate::Data);
|
fn buffer_unmap(&self, buffer: &ObjectId, buffer_data: &crate::Data);
|
||||||
fn texture_create_view(
|
fn texture_create_view(
|
||||||
&self,
|
&self,
|
||||||
@ -2465,18 +2452,6 @@ where
|
|||||||
Context::buffer_get_mapped_range(self, &buffer, buffer_data, sub_range)
|
Context::buffer_get_mapped_range(self, &buffer, buffer_data, sub_range)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(webgpu)]
|
|
||||||
fn buffer_get_mapped_range_as_array_buffer(
|
|
||||||
&self,
|
|
||||||
buffer: &ObjectId,
|
|
||||||
buffer_data: &crate::Data,
|
|
||||||
sub_range: Range<BufferAddress>,
|
|
||||||
) -> js_sys::ArrayBuffer {
|
|
||||||
let buffer = <T::BufferId>::from(*buffer);
|
|
||||||
let buffer_data = downcast_ref(buffer_data);
|
|
||||||
Context::buffer_get_mapped_range_as_array_buffer(self, &buffer, buffer_data, sub_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn buffer_unmap(&self, buffer: &ObjectId, buffer_data: &crate::Data) {
|
fn buffer_unmap(&self, buffer: &ObjectId, buffer_data: &crate::Data) {
|
||||||
let buffer = <T::BufferId>::from(*buffer);
|
let buffer = <T::BufferId>::from(*buffer);
|
||||||
let buffer_data = downcast_ref(buffer_data);
|
let buffer_data = downcast_ref(buffer_data);
|
||||||
|
263
wgpu/src/lib.rs
263
wgpu/src/lib.rs
@ -16,11 +16,10 @@
|
|||||||
//! - **`angle`** --- Enables the GLES backend via [ANGLE](https://github.com/google/angle) on macOS
|
//! - **`angle`** --- Enables the GLES backend via [ANGLE](https://github.com/google/angle) on macOS
|
||||||
//! using.
|
//! using.
|
||||||
//! - **`vulkan-portability`** --- Enables the Vulkan backend on macOS & iOS.
|
//! - **`vulkan-portability`** --- Enables the Vulkan backend on macOS & iOS.
|
||||||
|
//! - **`webgpu`** --- Enables the WebGPU backend on Wasm. Disabled when targeting `emscripten`.
|
||||||
//! - **`webgl`** --- Enables the GLES backend on Wasm
|
//! - **`webgl`** --- Enables the GLES backend on Wasm
|
||||||
//!
|
//!
|
||||||
//! - ⚠️ WIP: Currently will also enable GLES dependencies on any other targets.
|
//! - ⚠️ 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).
|
|
||||||
//!
|
//!
|
||||||
//! ### Shading language support
|
//! ### Shading language support
|
||||||
//!
|
//!
|
||||||
@ -73,7 +72,10 @@ use std::{
|
|||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
use context::{Context, DeviceRequest, DynContext, ObjectId};
|
#[allow(unused_imports)] // Unused if all backends are disabled.
|
||||||
|
use context::Context;
|
||||||
|
|
||||||
|
use context::{DeviceRequest, DynContext, ObjectId};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||||
@ -1722,8 +1724,6 @@ impl Instance {
|
|||||||
/// See <https://github.com/gfx-rs/wgpu/issues/3514>
|
/// See <https://github.com/gfx-rs/wgpu/issues/3514>
|
||||||
/// * Windows: always enables Vulkan and GLES with no way to opt out
|
/// * Windows: always enables Vulkan and GLES with no way to opt out
|
||||||
/// * Linux: always enables Vulkan and GLES with no way to opt out
|
/// * Linux: always enables Vulkan and GLES with no way to opt out
|
||||||
/// * Web: either targets WebGPU backend or, if `webgl` enabled, WebGL
|
|
||||||
/// * TODO: Support both WebGPU and WebGL at the same time, see <https://github.com/gfx-rs/wgpu/issues/2804>
|
|
||||||
pub const fn any_backend_feature_enabled() -> bool {
|
pub const fn any_backend_feature_enabled() -> bool {
|
||||||
// Method intentionally kept verbose to keep it a bit easier to follow!
|
// Method intentionally kept verbose to keep it a bit easier to follow!
|
||||||
|
|
||||||
@ -1733,6 +1733,9 @@ impl Instance {
|
|||||||
cfg!(feature = "metal")
|
cfg!(feature = "metal")
|
||||||
|| cfg!(feature = "vulkan-portability")
|
|| cfg!(feature = "vulkan-portability")
|
||||||
|| cfg!(feature = "angle")
|
|| cfg!(feature = "angle")
|
||||||
|
// On the web, either WebGPU or WebGL must be enabled.
|
||||||
|
} else if cfg!(target_arch = "wasm32") {
|
||||||
|
cfg!(feature = "webgpu") || cfg!(feature = "webgl")
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -1745,11 +1748,21 @@ impl Instance {
|
|||||||
/// - `instance_desc` - Has fields for which [backends][Backends] wgpu will choose
|
/// - `instance_desc` - Has fields for which [backends][Backends] wgpu will choose
|
||||||
/// during instantiation, and which [DX12 shader compiler][Dx12Compiler] wgpu will use.
|
/// during instantiation, and which [DX12 shader compiler][Dx12Compiler] wgpu will use.
|
||||||
///
|
///
|
||||||
|
/// [`Backends::BROWSER_WEBGPU`] takes a special role:
|
||||||
|
/// If it is set and WebGPU support is detected, this instance will *only* be able to create
|
||||||
|
/// WebGPU adapters. If you instead want to force use of WebGL, either
|
||||||
|
/// disable the `webgpu` compile-time feature or do add the [`Backends::BROWSER_WEBGPU`]
|
||||||
|
/// flag to the the `instance_desc`'s `backends` field.
|
||||||
|
/// If it is set and WebGPU support is *not* detected, the instance will use wgpu-core
|
||||||
|
/// to create adapters. Meaning that if the `webgl` feature is enabled, it is able to create
|
||||||
|
/// a WebGL adapter.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If no backend feature for the active target platform is enabled,
|
/// If no backend feature for the active target platform is enabled,
|
||||||
/// this method will panic, see [`Instance::any_backend_feature_enabled()`].
|
/// this method will panic, see [`Instance::any_backend_feature_enabled()`].
|
||||||
pub fn new(instance_desc: InstanceDescriptor) -> Self {
|
#[allow(unreachable_code)]
|
||||||
|
pub fn new(_instance_desc: InstanceDescriptor) -> Self {
|
||||||
if !Self::any_backend_feature_enabled() {
|
if !Self::any_backend_feature_enabled() {
|
||||||
panic!(
|
panic!(
|
||||||
"No wgpu backend feature that is implemented for the target platform was enabled. \
|
"No wgpu backend feature that is implemented for the target platform was enabled. \
|
||||||
@ -1757,9 +1770,25 @@ impl Instance {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
#[cfg(webgpu)]
|
||||||
context: Arc::from(crate::backend::Context::init(instance_desc)),
|
if _instance_desc.backends.contains(Backends::BROWSER_WEBGPU)
|
||||||
|
&& crate::backend::get_browser_gpu_property().map_or(false, |gpu| !gpu.is_undefined())
|
||||||
|
{
|
||||||
|
return Self {
|
||||||
|
context: Arc::from(crate::backend::ContextWebGpu::init(_instance_desc)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(wgpu_core)]
|
||||||
|
{
|
||||||
|
return Self {
|
||||||
|
context: Arc::from(crate::backend::ContextWgpuCore::init(_instance_desc)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!(
|
||||||
|
"Earlier check of `any_backend_feature_enabled` should have prevented getting here!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an new instance of wgpu from a wgpu-hal instance.
|
/// Create an new instance of wgpu from a wgpu-hal instance.
|
||||||
@ -1771,11 +1800,11 @@ impl Instance {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Refer to the creation of wgpu-hal Instance for every backend.
|
/// Refer to the creation of wgpu-hal Instance for every backend.
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn from_hal<A: wgc::hal_api::HalApi>(hal_instance: A::Instance) -> Self {
|
pub unsafe fn from_hal<A: wgc::hal_api::HalApi>(hal_instance: A::Instance) -> Self {
|
||||||
Self {
|
Self {
|
||||||
context: Arc::new(unsafe {
|
context: Arc::new(unsafe {
|
||||||
crate::backend::Context::from_hal_instance::<A>(hal_instance)
|
crate::backend::ContextWgpuCore::from_hal_instance::<A>(hal_instance)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1790,15 +1819,13 @@ impl Instance {
|
|||||||
/// - The raw instance handle returned must not be manually destroyed.
|
/// - The raw instance handle returned must not be manually destroyed.
|
||||||
///
|
///
|
||||||
/// [`Instance`]: hal::Api::Instance
|
/// [`Instance`]: hal::Api::Instance
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi>(&self) -> Option<&A::Instance> {
|
pub unsafe fn as_hal<A: wgc::hal_api::HalApi>(&self) -> Option<&A::Instance> {
|
||||||
unsafe {
|
self.context
|
||||||
self.context
|
.as_any()
|
||||||
.as_any()
|
// If we don't have a wgpu-core instance, we don't have a hal instance either.
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.unwrap()
|
.and_then(|ctx| unsafe { ctx.instance_as_hal::<A>() })
|
||||||
.instance_as_hal::<A>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an new instance of wgpu from a wgpu-core instance.
|
/// Create an new instance of wgpu from a wgpu-core instance.
|
||||||
@ -1810,34 +1837,40 @@ impl Instance {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Refer to the creation of wgpu-core Instance.
|
/// Refer to the creation of wgpu-core Instance.
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn from_core(core_instance: wgc::instance::Instance) -> Self {
|
pub unsafe fn from_core(core_instance: wgc::instance::Instance) -> Self {
|
||||||
Self {
|
Self {
|
||||||
context: Arc::new(unsafe {
|
context: Arc::new(unsafe {
|
||||||
crate::backend::Context::from_core_instance(core_instance)
|
crate::backend::ContextWgpuCore::from_core_instance(core_instance)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves all available [`Adapter`]s that match the given [`Backends`].
|
/// Retrieves all available [`Adapter`]s that match the given [`Backends`].
|
||||||
///
|
///
|
||||||
|
/// Always returns an empty vector if the instance decided upon creation to
|
||||||
|
/// target WebGPU since adapter creation is always async on WebGPU.
|
||||||
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// - `backends` - Backends from which to enumerate adapters.
|
/// - `backends` - Backends from which to enumerate adapters.
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub fn enumerate_adapters(&self, backends: Backends) -> impl ExactSizeIterator<Item = Adapter> {
|
pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
|
||||||
let context = Arc::clone(&self.context);
|
let context = Arc::clone(&self.context);
|
||||||
self.context
|
self.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.unwrap()
|
.map(|ctx| {
|
||||||
.enumerate_adapters(backends)
|
ctx.enumerate_adapters(backends)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(move |id| crate::Adapter {
|
.map(move |id| crate::Adapter {
|
||||||
context: Arc::clone(&context),
|
context: Arc::clone(&context),
|
||||||
id: ObjectId::from(id),
|
id: ObjectId::from(id),
|
||||||
data: Box::new(()),
|
data: Box::new(()),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
})
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
|
/// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
|
||||||
@ -1863,7 +1896,7 @@ impl Instance {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `hal_adapter` must be created from this instance internal handle.
|
/// `hal_adapter` must be created from this instance internal handle.
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn create_adapter_from_hal<A: wgc::hal_api::HalApi>(
|
pub unsafe fn create_adapter_from_hal<A: wgc::hal_api::HalApi>(
|
||||||
&self,
|
&self,
|
||||||
hal_adapter: hal::ExposedAdapter<A>,
|
hal_adapter: hal::ExposedAdapter<A>,
|
||||||
@ -1872,7 +1905,7 @@ impl Instance {
|
|||||||
let id = unsafe {
|
let id = unsafe {
|
||||||
context
|
context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_adapter_from_hal(hal_adapter)
|
.create_adapter_from_hal(hal_adapter)
|
||||||
.into()
|
.into()
|
||||||
@ -2000,13 +2033,15 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates memory report.
|
/// Generates memory report.
|
||||||
#[cfg(not(webgpu))]
|
///
|
||||||
pub fn generate_report(&self) -> wgc::global::GlobalReport {
|
/// Returns `None` if the feature is not supported by the backend
|
||||||
|
/// which happens only when WebGPU is pre-selected by the instance creation.
|
||||||
|
#[cfg(wgpu_core)]
|
||||||
|
pub fn generate_report(&self) -> Option<wgc::global::GlobalReport> {
|
||||||
self.context
|
self.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.unwrap()
|
.map(|ctx| ctx.generate_report())
|
||||||
.generate_report()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2071,7 +2106,7 @@ impl Adapter {
|
|||||||
///
|
///
|
||||||
/// - `hal_device` must be created from this adapter internal handle.
|
/// - `hal_device` must be created from this adapter internal handle.
|
||||||
/// - `desc.features` must be a subset of `hal_device` features.
|
/// - `desc.features` must be a subset of `hal_device` features.
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn create_device_from_hal<A: wgc::hal_api::HalApi>(
|
pub unsafe fn create_device_from_hal<A: wgc::hal_api::HalApi>(
|
||||||
&self,
|
&self,
|
||||||
hal_device: hal::OpenDevice<A>,
|
hal_device: hal::OpenDevice<A>,
|
||||||
@ -2082,7 +2117,9 @@ impl Adapter {
|
|||||||
unsafe {
|
unsafe {
|
||||||
self.context
|
self.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
|
// Part of the safety requirements is that the device was generated from the same adapter.
|
||||||
|
// Therefore, unwrap is fine here since only WgpuCoreContext based adapters have the ability to create hal devices.
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_device_from_hal(&self.id.into(), hal_device, desc, trace_path)
|
.create_device_from_hal(&self.id.into(), hal_device, desc, trace_path)
|
||||||
}
|
}
|
||||||
@ -2121,17 +2158,19 @@ impl Adapter {
|
|||||||
/// - The raw handle passed to the callback must not be manually destroyed.
|
/// - The raw handle passed to the callback must not be manually destroyed.
|
||||||
///
|
///
|
||||||
/// [`A::Adapter`]: hal::Api::Adapter
|
/// [`A::Adapter`]: hal::Api::Adapter
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
|
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
|
||||||
&self,
|
&self,
|
||||||
hal_adapter_callback: F,
|
hal_adapter_callback: F,
|
||||||
) -> R {
|
) -> R {
|
||||||
unsafe {
|
if let Some(ctx) = self
|
||||||
self.context
|
.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.unwrap()
|
{
|
||||||
.adapter_as_hal::<A, F, R>(self.id.into(), hal_adapter_callback)
|
unsafe { ctx.adapter_as_hal::<A, F, R>(self.id.into(), hal_adapter_callback) }
|
||||||
|
} else {
|
||||||
|
hal_adapter_callback(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2463,7 +2502,7 @@ impl Device {
|
|||||||
/// - `hal_texture` must be created from this device internal handle
|
/// - `hal_texture` must be created from this device internal handle
|
||||||
/// - `hal_texture` must be created respecting `desc`
|
/// - `hal_texture` must be created respecting `desc`
|
||||||
/// - `hal_texture` must be initialized
|
/// - `hal_texture` must be initialized
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn create_texture_from_hal<A: wgc::hal_api::HalApi>(
|
pub unsafe fn create_texture_from_hal<A: wgc::hal_api::HalApi>(
|
||||||
&self,
|
&self,
|
||||||
hal_texture: A::Texture,
|
hal_texture: A::Texture,
|
||||||
@ -2472,7 +2511,9 @@ impl Device {
|
|||||||
let texture = unsafe {
|
let texture = unsafe {
|
||||||
self.context
|
self.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
|
// Part of the safety requirements is that the texture was generated from the same hal device.
|
||||||
|
// Therefore, unwrap is fine here since only WgpuCoreContext has the ability to create hal textures.
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_texture_from_hal::<A>(
|
.create_texture_from_hal::<A>(
|
||||||
hal_texture,
|
hal_texture,
|
||||||
@ -2500,7 +2541,7 @@ impl Device {
|
|||||||
/// - `hal_buffer` must be created from this device internal handle
|
/// - `hal_buffer` must be created from this device internal handle
|
||||||
/// - `hal_buffer` must be created respecting `desc`
|
/// - `hal_buffer` must be created respecting `desc`
|
||||||
/// - `hal_buffer` must be initialized
|
/// - `hal_buffer` must be initialized
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn create_buffer_from_hal<A: wgc::hal_api::HalApi>(
|
pub unsafe fn create_buffer_from_hal<A: wgc::hal_api::HalApi>(
|
||||||
&self,
|
&self,
|
||||||
hal_buffer: A::Buffer,
|
hal_buffer: A::Buffer,
|
||||||
@ -2514,7 +2555,9 @@ impl Device {
|
|||||||
let (id, buffer) = unsafe {
|
let (id, buffer) = unsafe {
|
||||||
self.context
|
self.context
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
|
// Part of the safety requirements is that the buffer was generated from the same hal device.
|
||||||
|
// Therefore, unwrap is fine here since only WgpuCoreContext has the ability to create hal buffers.
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.create_buffer_from_hal::<A>(
|
.create_buffer_from_hal::<A>(
|
||||||
hal_buffer,
|
hal_buffer,
|
||||||
@ -2604,21 +2647,20 @@ impl Device {
|
|||||||
/// - The raw handle passed to the callback must not be manually destroyed.
|
/// - The raw handle passed to the callback must not be manually destroyed.
|
||||||
///
|
///
|
||||||
/// [`A::Device`]: hal::Api::Device
|
/// [`A::Device`]: hal::Api::Device
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
|
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
|
||||||
&self,
|
&self,
|
||||||
hal_device_callback: F,
|
hal_device_callback: F,
|
||||||
) -> R {
|
) -> Option<R> {
|
||||||
unsafe {
|
self.context
|
||||||
self.context
|
.as_any()
|
||||||
.as_any()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.map(|ctx| unsafe {
|
||||||
.unwrap()
|
ctx.device_as_hal::<A, F, R>(
|
||||||
.device_as_hal::<A, F, R>(
|
|
||||||
self.data.as_ref().downcast_ref().unwrap(),
|
self.data.as_ref().downcast_ref().unwrap(),
|
||||||
hal_device_callback,
|
hal_device_callback,
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy this device.
|
/// Destroy this device.
|
||||||
@ -2657,14 +2699,14 @@ pub struct RequestDeviceError {
|
|||||||
enum RequestDeviceErrorKind {
|
enum RequestDeviceErrorKind {
|
||||||
/// Error from [`wgpu_core`].
|
/// Error from [`wgpu_core`].
|
||||||
// must match dependency cfg
|
// must match dependency cfg
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
Core(core::instance::RequestDeviceError),
|
Core(wgc::instance::RequestDeviceError),
|
||||||
|
|
||||||
/// Error from web API that was called by `wgpu` to request a device.
|
/// Error from web API that was called by `wgpu` to request a device.
|
||||||
///
|
///
|
||||||
/// (This is currently never used by the webgl backend, but it could be.)
|
/// (This is currently never used by the webgl backend, but it could be.)
|
||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
Web(wasm_bindgen::JsValue),
|
WebGpu(wasm_bindgen::JsValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(send_sync)]
|
#[cfg(send_sync)]
|
||||||
@ -2676,15 +2718,17 @@ unsafe impl Sync for RequestDeviceErrorKind {}
|
|||||||
static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
|
static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
|
||||||
|
|
||||||
impl fmt::Display for RequestDeviceError {
|
impl fmt::Display for RequestDeviceError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
RequestDeviceErrorKind::Core(error) => error.fmt(f),
|
RequestDeviceErrorKind::Core(error) => error.fmt(_f),
|
||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
RequestDeviceErrorKind::Web(error_js_value) => {
|
RequestDeviceErrorKind::WebGpu(error_js_value) => {
|
||||||
// wasm-bindgen provides a reasonable error stringification via `Debug` impl
|
// wasm-bindgen provides a reasonable error stringification via `Debug` impl
|
||||||
write!(f, "{error_js_value:?}")
|
write!(_f, "{error_js_value:?}")
|
||||||
}
|
}
|
||||||
|
#[cfg(not(any(webgpu, wgpu_core)))]
|
||||||
|
_ => unimplemented!("unknown `RequestDeviceErrorKind`"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2692,17 +2736,19 @@ impl fmt::Display for RequestDeviceError {
|
|||||||
impl error::Error for RequestDeviceError {
|
impl error::Error for RequestDeviceError {
|
||||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
RequestDeviceErrorKind::Core(error) => error.source(),
|
RequestDeviceErrorKind::Core(error) => error.source(),
|
||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
RequestDeviceErrorKind::Web(_) => None,
|
RequestDeviceErrorKind::WebGpu(_) => None,
|
||||||
|
#[cfg(not(any(webgpu, wgpu_core)))]
|
||||||
|
_ => unimplemented!("unknown `RequestDeviceErrorKind`"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
impl From<core::instance::RequestDeviceError> for RequestDeviceError {
|
impl From<wgc::instance::RequestDeviceError> for RequestDeviceError {
|
||||||
fn from(error: core::instance::RequestDeviceError) -> Self {
|
fn from(error: wgc::instance::RequestDeviceError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: RequestDeviceErrorKind::Core(error),
|
inner: RequestDeviceErrorKind::Core(error),
|
||||||
}
|
}
|
||||||
@ -2718,7 +2764,7 @@ pub struct CreateSurfaceError {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum CreateSurfaceErrorKind {
|
enum CreateSurfaceErrorKind {
|
||||||
/// Error from [`wgpu_hal`].
|
/// Error from [`wgpu_hal`].
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
Hal(hal::InstanceError),
|
Hal(hal::InstanceError),
|
||||||
|
|
||||||
/// Error from WebGPU surface creation.
|
/// Error from WebGPU surface creation.
|
||||||
@ -2734,7 +2780,7 @@ static_assertions::assert_impl_all!(CreateSurfaceError: Send, Sync);
|
|||||||
impl fmt::Display for CreateSurfaceError {
|
impl fmt::Display for CreateSurfaceError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
CreateSurfaceErrorKind::Hal(e) => e.fmt(f),
|
CreateSurfaceErrorKind::Hal(e) => e.fmt(f),
|
||||||
CreateSurfaceErrorKind::Web(e) => e.fmt(f),
|
CreateSurfaceErrorKind::Web(e) => e.fmt(f),
|
||||||
CreateSurfaceErrorKind::RawHandle(e) => e.fmt(f),
|
CreateSurfaceErrorKind::RawHandle(e) => e.fmt(f),
|
||||||
@ -2745,7 +2791,7 @@ impl fmt::Display for CreateSurfaceError {
|
|||||||
impl error::Error for CreateSurfaceError {
|
impl error::Error for CreateSurfaceError {
|
||||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
CreateSurfaceErrorKind::Hal(e) => e.source(),
|
CreateSurfaceErrorKind::Hal(e) => e.source(),
|
||||||
CreateSurfaceErrorKind::Web(_) => None,
|
CreateSurfaceErrorKind::Web(_) => None,
|
||||||
CreateSurfaceErrorKind::RawHandle(e) => e.source(),
|
CreateSurfaceErrorKind::RawHandle(e) => e.source(),
|
||||||
@ -2753,7 +2799,7 @@ impl error::Error for CreateSurfaceError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
impl From<hal::InstanceError> for CreateSurfaceError {
|
impl From<hal::InstanceError> for CreateSurfaceError {
|
||||||
fn from(e: hal::InstanceError) -> Self {
|
fn from(e: hal::InstanceError) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -2986,20 +3032,24 @@ impl<'a> BufferSlice<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
|
/// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
|
||||||
/// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will panic.
|
/// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
|
||||||
///
|
///
|
||||||
/// This is useful in wasm builds when you want to pass mapped data directly to js. Unlike `get_mapped_range`
|
/// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
|
||||||
/// which unconditionally copies mapped data into the wasm heap, this function directly hands you the
|
/// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
|
||||||
/// ArrayBuffer that we mapped the data into in js.
|
/// this function directly hands you the ArrayBuffer that we mapped the data into in js.
|
||||||
|
///
|
||||||
|
/// This is only available on WebGPU, on any other backends this will return `None`.
|
||||||
#[cfg(webgpu)]
|
#[cfg(webgpu)]
|
||||||
pub fn get_mapped_range_as_array_buffer(&self) -> js_sys::ArrayBuffer {
|
pub fn get_mapped_range_as_array_buffer(&self) -> Option<js_sys::ArrayBuffer> {
|
||||||
let end = self.buffer.map_context.lock().add(self.offset, self.size);
|
self.buffer
|
||||||
DynContext::buffer_get_mapped_range_as_array_buffer(
|
.context
|
||||||
&*self.buffer.context,
|
.as_any()
|
||||||
&self.buffer.id,
|
.downcast_ref::<crate::backend::ContextWebGpu>()
|
||||||
self.buffer.data.as_ref(),
|
.map(|ctx| {
|
||||||
self.offset..end,
|
let buffer_data = crate::context::downcast_ref(self.buffer.data.as_ref());
|
||||||
)
|
let end = self.buffer.map_context.lock().add(self.offset, self.size);
|
||||||
|
ctx.buffer_get_mapped_range_as_array_buffer(buffer_data, self.offset..end)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronously and immediately map a buffer for writing. If the buffer is not immediately mappable
|
/// Synchronously and immediately map a buffer for writing. If the buffer is not immediately mappable
|
||||||
@ -3035,18 +3085,21 @@ impl Texture {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - The raw handle obtained from the hal Texture must not be manually destroyed
|
/// - The raw handle obtained from the hal Texture must not be manually destroyed
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Texture>)>(
|
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Texture>)>(
|
||||||
&self,
|
&self,
|
||||||
hal_texture_callback: F,
|
hal_texture_callback: F,
|
||||||
) {
|
) {
|
||||||
let texture = self.data.as_ref().downcast_ref().unwrap();
|
let texture = self.data.as_ref().downcast_ref().unwrap();
|
||||||
unsafe {
|
|
||||||
self.context
|
if let Some(ctx) = self
|
||||||
.as_any()
|
.context
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.as_any()
|
||||||
.unwrap()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.texture_as_hal::<A, F>(texture, hal_texture_callback)
|
{
|
||||||
|
unsafe { ctx.texture_as_hal::<A, F>(texture, hal_texture_callback) }
|
||||||
|
} else {
|
||||||
|
hal_texture_callback(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4783,18 +4836,20 @@ impl Surface<'_> {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - The raw handle obtained from the hal Surface must not be manually destroyed
|
/// - The raw handle obtained from the hal Surface must not be manually destroyed
|
||||||
#[cfg(not(webgpu))]
|
#[cfg(wgpu_core)]
|
||||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
|
pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hal_surface_callback: F,
|
hal_surface_callback: F,
|
||||||
) -> R {
|
) -> Option<R> {
|
||||||
unsafe {
|
self.context
|
||||||
self.context
|
.as_any()
|
||||||
.as_any()
|
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||||
.downcast_ref::<crate::backend::Context>()
|
.map(|ctx| unsafe {
|
||||||
.unwrap()
|
ctx.surface_as_hal::<A, F, R>(
|
||||||
.surface_as_hal::<A, F, R>(self.data.downcast_ref().unwrap(), hal_surface_callback)
|
self.data.downcast_ref().unwrap(),
|
||||||
}
|
hal_surface_callback,
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ pub(crate) fn run_wasm(mut args: Arguments) -> Result<(), anyhow::Error> {
|
|||||||
|
|
||||||
xshell::cmd!(
|
xshell::cmd!(
|
||||||
shell,
|
shell,
|
||||||
"cargo build --target wasm32-unknown-unknown --bin wgpu-examples --features webgl {release_flag...}"
|
"cargo build --target wasm32-unknown-unknown --bin wgpu-examples --no-default-features --features wgsl,webgl {release_flag...}"
|
||||||
)
|
)
|
||||||
.args(&cargo_args)
|
.args(&cargo_args)
|
||||||
.quiet()
|
.quiet()
|
||||||
|
Loading…
Reference in New Issue
Block a user