mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 00:03:29 +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
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -153,7 +153,7 @@ 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);
|
||||
@ -161,7 +161,7 @@ async fn draw_test_with_reports(
|
||||
|
||||
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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -237,7 +237,7 @@ 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);
|
||||
|
||||
@ -245,7 +245,7 @@ async fn draw_test_with_reports(
|
||||
.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);
|
||||
@ -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);
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -24,7 +24,7 @@ targets = [
|
||||
[lib]
|
||||
|
||||
[features]
|
||||
default = ["wgsl", "dx12", "metal"]
|
||||
default = ["wgsl", "dx12", "metal", "webgpu"]
|
||||
|
||||
#! ### Backends
|
||||
# --------------------------------------------------------------------
|
||||
@ -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
|
||||
|
@ -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"))
|
||||
|
@ -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;
|
||||
|
@ -69,19 +69,21 @@ unsafe impl<T> Send for Identified<T> {}
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl<T> Sync for Identified<T> {}
|
||||
|
||||
pub(crate) struct Context(web_sys::Gpu);
|
||||
pub(crate) struct ContextWebGpu(web_sys::Gpu);
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Send for Context {}
|
||||
unsafe impl Send for ContextWebGpu {}
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Sync for Context {}
|
||||
unsafe impl Sync for ContextWebGpu {}
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Send for BufferMappedRange {}
|
||||
#[cfg(send_sync)]
|
||||
unsafe impl Sync for BufferMappedRange {}
|
||||
|
||||
impl fmt::Debug for Context {
|
||||
impl fmt::Debug for ContextWebGpu {
|
||||
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 {
|
||||
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);
|
||||
if let Some(bytes_per_row) = view.layout.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 {
|
||||
let texture: &<Context as crate::Context>::TextureData =
|
||||
let texture: &<ContextWebGpu as crate::Context>::TextureData =
|
||||
downcast_ref(view.texture.data.as_ref());
|
||||
let mut mapped = web_sys::GpuImageCopyTexture::new(&texture.0);
|
||||
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(
|
||||
view: crate::ImageCopyTextureTagged<'_>,
|
||||
) -> web_sys::GpuImageCopyTextureTagged {
|
||||
let texture: &<Context as crate::Context>::TextureData =
|
||||
let texture: &<ContextWebGpu as crate::Context>::TextureData =
|
||||
downcast_ref(view.texture.data.as_ref());
|
||||
let mut mapped = web_sys::GpuImageCopyTextureTagged::new(&texture.0);
|
||||
mapped.mip_level(view.mip_level);
|
||||
@ -821,7 +824,7 @@ fn future_request_device(
|
||||
(device_id, device_data, queue_id, queue_data)
|
||||
})
|
||||
.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));
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl ContextWebGpu {
|
||||
/// Common portion of the internal branches of the public `instance_create_surface` function.
|
||||
///
|
||||
/// Note: Analogous code also exists in the WebGL2 backend at
|
||||
@ -929,6 +932,15 @@ impl 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.
|
||||
@ -952,7 +964,31 @@ pub enum Canvas {
|
||||
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 AdapterData = Sendable<web_sys::GpuAdapter>;
|
||||
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>>;
|
||||
|
||||
fn init(_instance_desc: wgt::InstanceDescriptor) -> Self {
|
||||
let global: Global = js_sys::global().unchecked_into();
|
||||
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 {
|
||||
let Some(gpu) = get_browser_gpu_property() else {
|
||||
panic!(
|
||||
"Accessing the GPU is only supported on the main thread or from a dedicated worker"
|
||||
);
|
||||
};
|
||||
Context(gpu)
|
||||
ContextWebGpu(gpu)
|
||||
}
|
||||
|
||||
unsafe fn instance_create_surface(
|
||||
@ -1587,7 +1615,7 @@ impl crate::context::Context for Context {
|
||||
offset,
|
||||
size,
|
||||
}) => {
|
||||
let buffer: &<Context as crate::Context>::BufferData =
|
||||
let buffer: &<ContextWebGpu as crate::Context>::BufferData =
|
||||
downcast_ref(buffer.data.as_ref());
|
||||
let mut mapped_buffer_binding =
|
||||
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")
|
||||
}
|
||||
crate::BindingResource::Sampler(sampler) => {
|
||||
let sampler: &<Context as crate::Context>::SamplerData =
|
||||
let sampler: &<ContextWebGpu as crate::Context>::SamplerData =
|
||||
downcast_ref(sampler.data.as_ref());
|
||||
JsValue::from(&sampler.0)
|
||||
}
|
||||
@ -1609,7 +1637,7 @@ impl crate::context::Context for Context {
|
||||
panic!("Web backend does not support arrays of samplers")
|
||||
}
|
||||
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());
|
||||
JsValue::from(&texture_view.0)
|
||||
}
|
||||
@ -1622,7 +1650,7 @@ impl crate::context::Context for Context {
|
||||
})
|
||||
.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());
|
||||
let mut mapped_desc = web_sys::GpuBindGroupDescriptor::new(&mapped_entries, &bgl.0);
|
||||
if let Some(label) = desc.label {
|
||||
@ -1641,7 +1669,7 @@ impl crate::context::Context for Context {
|
||||
.bind_group_layouts
|
||||
.iter()
|
||||
.map(|bgl| {
|
||||
let bgl: &<Context as crate::Context>::BindGroupLayoutData =
|
||||
let bgl: &<ContextWebGpu as crate::Context>::BindGroupLayoutData =
|
||||
downcast_ref(bgl.data.as_ref());
|
||||
&bgl.0
|
||||
})
|
||||
@ -1659,7 +1687,7 @@ impl crate::context::Context for Context {
|
||||
device_data: &Self::DeviceData,
|
||||
desc: &crate::RenderPipelineDescriptor<'_>,
|
||||
) -> (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());
|
||||
let mut mapped_vertex_state =
|
||||
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(
|
||||
&match desc.layout {
|
||||
Some(layout) => {
|
||||
let layout: &<Context as crate::Context>::PipelineLayoutData =
|
||||
let layout: &<ContextWebGpu as crate::Context>::PipelineLayoutData =
|
||||
downcast_ref(layout.data.as_ref());
|
||||
JsValue::from(&layout.0)
|
||||
}
|
||||
@ -1734,7 +1762,7 @@ impl crate::context::Context for Context {
|
||||
None => wasm_bindgen::JsValue::null(),
|
||||
})
|
||||
.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());
|
||||
let mapped_fragment_desc =
|
||||
web_sys::GpuFragmentState::new(frag.entry_point, &module.0, &targets);
|
||||
@ -1759,7 +1787,7 @@ impl crate::context::Context for Context {
|
||||
device_data: &Self::DeviceData,
|
||||
desc: &crate::ComputePipelineDescriptor<'_>,
|
||||
) -> (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());
|
||||
let mapped_compute_stage =
|
||||
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(
|
||||
&match desc.layout {
|
||||
Some(layout) => {
|
||||
let layout: &<Context as crate::Context>::PipelineLayoutData =
|
||||
let layout: &<ContextWebGpu as crate::Context>::PipelineLayoutData =
|
||||
downcast_ref(layout.data.as_ref());
|
||||
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) {
|
||||
buffer_data.0.buffer.unmap();
|
||||
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,
|
||||
};
|
||||
|
||||
let view: &<Context as crate::Context>::TextureViewData =
|
||||
let view: &<ContextWebGpu as crate::Context>::TextureViewData =
|
||||
downcast_ref(ca.view.data.as_ref());
|
||||
|
||||
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);
|
||||
}
|
||||
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());
|
||||
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 {
|
||||
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());
|
||||
let mut mapped_depth_stencil_attachment =
|
||||
web_sys::GpuRenderPassDepthStencilAttachment::new(&depth_stencil_attachment.0);
|
||||
@ -2430,7 +2449,8 @@ impl crate::context::Context for Context {
|
||||
offset: 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 {
|
||||
Some(size) => encoder_data.0.clear_buffer_with_f64_and_f64(
|
||||
&buffer.0.buffer,
|
@ -29,21 +29,23 @@ use wgt::WasmNotSendSync;
|
||||
|
||||
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) {
|
||||
//nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Context {
|
||||
impl fmt::Debug for ContextWgpuCore {
|
||||
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 {
|
||||
Self(unsafe {
|
||||
wgc::global::Global::from_hal_instance::<A>(
|
||||
@ -443,7 +445,7 @@ pub struct CommandEncoder {
|
||||
open: bool,
|
||||
}
|
||||
|
||||
impl crate::Context for Context {
|
||||
impl crate::Context for ContextWgpuCore {
|
||||
type AdapterId = wgc::id::AdapterId;
|
||||
type AdapterData = ();
|
||||
type DeviceId = wgc::id::DeviceId;
|
@ -320,13 +320,6 @@ pub trait Context: Debug + WasmNotSendSync + Sized {
|
||||
buffer_data: &Self::BufferData,
|
||||
sub_range: Range<BufferAddress>,
|
||||
) -> 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 texture_create_view(
|
||||
&self,
|
||||
@ -1037,6 +1030,7 @@ impl ObjectId {
|
||||
global_id: None,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn new(id: NonZeroU64, global_id: NonZeroU64) -> Self {
|
||||
Self {
|
||||
id: Some(id),
|
||||
@ -1346,13 +1340,6 @@ pub(crate) trait DynContext: Debug + WasmNotSendSync {
|
||||
buffer_data: &crate::Data,
|
||||
sub_range: Range<BufferAddress>,
|
||||
) -> 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 texture_create_view(
|
||||
&self,
|
||||
@ -2465,18 +2452,6 @@ where
|
||||
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) {
|
||||
let buffer = <T::BufferId>::from(*buffer);
|
||||
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
|
||||
//! using.
|
||||
//! - **`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
|
||||
//!
|
||||
//! - ⚠️ 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
|
||||
//!
|
||||
@ -73,7 +72,10 @@ use std::{
|
||||
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 raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
@ -1722,8 +1724,6 @@ impl Instance {
|
||||
/// See <https://github.com/gfx-rs/wgpu/issues/3514>
|
||||
/// * Windows: 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 {
|
||||
// Method intentionally kept verbose to keep it a bit easier to follow!
|
||||
|
||||
@ -1733,6 +1733,9 @@ impl Instance {
|
||||
cfg!(feature = "metal")
|
||||
|| cfg!(feature = "vulkan-portability")
|
||||
|| 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 {
|
||||
true
|
||||
}
|
||||
@ -1745,11 +1748,21 @@ impl Instance {
|
||||
/// - `instance_desc` - Has fields for which [backends][Backends] wgpu will choose
|
||||
/// 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
|
||||
///
|
||||
/// If no backend feature for the active target platform is 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() {
|
||||
panic!(
|
||||
"No wgpu backend feature that is implemented for the target platform was enabled. \
|
||||
@ -1757,9 +1770,25 @@ impl Instance {
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
context: Arc::from(crate::backend::Context::init(instance_desc)),
|
||||
#[cfg(webgpu)]
|
||||
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.
|
||||
@ -1771,11 +1800,11 @@ impl Instance {
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 {
|
||||
Self {
|
||||
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.
|
||||
///
|
||||
/// [`Instance`]: hal::Api::Instance
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
pub unsafe fn as_hal<A: wgc::hal_api::HalApi>(&self) -> Option<&A::Instance> {
|
||||
unsafe {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.instance_as_hal::<A>()
|
||||
}
|
||||
self.context
|
||||
.as_any()
|
||||
// If we don't have a wgpu-core instance, we don't have a hal instance either.
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.and_then(|ctx| unsafe { ctx.instance_as_hal::<A>() })
|
||||
}
|
||||
|
||||
/// Create an new instance of wgpu from a wgpu-core instance.
|
||||
@ -1810,34 +1837,40 @@ impl Instance {
|
||||
/// # Safety
|
||||
///
|
||||
/// 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 {
|
||||
Self {
|
||||
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`].
|
||||
///
|
||||
/// Always returns an empty vector if the instance decided upon creation to
|
||||
/// target WebGPU since adapter creation is always async on WebGPU.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `backends` - Backends from which to enumerate adapters.
|
||||
#[cfg(not(webgpu))]
|
||||
pub fn enumerate_adapters(&self, backends: Backends) -> impl ExactSizeIterator<Item = Adapter> {
|
||||
#[cfg(wgpu_core)]
|
||||
pub fn enumerate_adapters(&self, backends: Backends) -> Vec<Adapter> {
|
||||
let context = Arc::clone(&self.context);
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.enumerate_adapters(backends)
|
||||
.into_iter()
|
||||
.map(move |id| crate::Adapter {
|
||||
context: Arc::clone(&context),
|
||||
id: ObjectId::from(id),
|
||||
data: Box::new(()),
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.map(|ctx| {
|
||||
ctx.enumerate_adapters(backends)
|
||||
.into_iter()
|
||||
.map(move |id| crate::Adapter {
|
||||
context: Arc::clone(&context),
|
||||
id: ObjectId::from(id),
|
||||
data: Box::new(()),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
|
||||
@ -1863,7 +1896,7 @@ impl Instance {
|
||||
/// # Safety
|
||||
///
|
||||
/// `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>(
|
||||
&self,
|
||||
hal_adapter: hal::ExposedAdapter<A>,
|
||||
@ -1872,7 +1905,7 @@ impl Instance {
|
||||
let id = unsafe {
|
||||
context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.unwrap()
|
||||
.create_adapter_from_hal(hal_adapter)
|
||||
.into()
|
||||
@ -2000,13 +2033,15 @@ impl Instance {
|
||||
}
|
||||
|
||||
/// 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
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.generate_report()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.map(|ctx| ctx.generate_report())
|
||||
}
|
||||
}
|
||||
|
||||
@ -2071,7 +2106,7 @@ impl Adapter {
|
||||
///
|
||||
/// - `hal_device` must be created from this adapter internal handle.
|
||||
/// - `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>(
|
||||
&self,
|
||||
hal_device: hal::OpenDevice<A>,
|
||||
@ -2082,7 +2117,9 @@ impl Adapter {
|
||||
unsafe {
|
||||
self.context
|
||||
.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()
|
||||
.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.
|
||||
///
|
||||
/// [`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>(
|
||||
&self,
|
||||
hal_adapter_callback: F,
|
||||
) -> R {
|
||||
unsafe {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.adapter_as_hal::<A, F, R>(self.id.into(), hal_adapter_callback)
|
||||
if let Some(ctx) = self
|
||||
.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
{
|
||||
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 respecting `desc`
|
||||
/// - `hal_texture` must be initialized
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
pub unsafe fn create_texture_from_hal<A: wgc::hal_api::HalApi>(
|
||||
&self,
|
||||
hal_texture: A::Texture,
|
||||
@ -2472,7 +2511,9 @@ impl Device {
|
||||
let texture = unsafe {
|
||||
self.context
|
||||
.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()
|
||||
.create_texture_from_hal::<A>(
|
||||
hal_texture,
|
||||
@ -2500,7 +2541,7 @@ impl Device {
|
||||
/// - `hal_buffer` must be created from this device internal handle
|
||||
/// - `hal_buffer` must be created respecting `desc`
|
||||
/// - `hal_buffer` must be initialized
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
pub unsafe fn create_buffer_from_hal<A: wgc::hal_api::HalApi>(
|
||||
&self,
|
||||
hal_buffer: A::Buffer,
|
||||
@ -2514,7 +2555,9 @@ impl Device {
|
||||
let (id, buffer) = unsafe {
|
||||
self.context
|
||||
.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()
|
||||
.create_buffer_from_hal::<A>(
|
||||
hal_buffer,
|
||||
@ -2604,21 +2647,20 @@ impl Device {
|
||||
/// - The raw handle passed to the callback must not be manually destroyed.
|
||||
///
|
||||
/// [`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>(
|
||||
&self,
|
||||
hal_device_callback: F,
|
||||
) -> R {
|
||||
unsafe {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.device_as_hal::<A, F, R>(
|
||||
) -> Option<R> {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.map(|ctx| unsafe {
|
||||
ctx.device_as_hal::<A, F, R>(
|
||||
self.data.as_ref().downcast_ref().unwrap(),
|
||||
hal_device_callback,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Destroy this device.
|
||||
@ -2657,14 +2699,14 @@ pub struct RequestDeviceError {
|
||||
enum RequestDeviceErrorKind {
|
||||
/// Error from [`wgpu_core`].
|
||||
// must match dependency cfg
|
||||
#[cfg(not(webgpu))]
|
||||
Core(core::instance::RequestDeviceError),
|
||||
#[cfg(wgpu_core)]
|
||||
Core(wgc::instance::RequestDeviceError),
|
||||
|
||||
/// 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.)
|
||||
#[cfg(webgpu)]
|
||||
Web(wasm_bindgen::JsValue),
|
||||
WebGpu(wasm_bindgen::JsValue),
|
||||
}
|
||||
|
||||
#[cfg(send_sync)]
|
||||
@ -2676,15 +2718,17 @@ unsafe impl Sync for RequestDeviceErrorKind {}
|
||||
static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
|
||||
|
||||
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 {
|
||||
#[cfg(not(webgpu))]
|
||||
RequestDeviceErrorKind::Core(error) => error.fmt(f),
|
||||
#[cfg(wgpu_core)]
|
||||
RequestDeviceErrorKind::Core(error) => error.fmt(_f),
|
||||
#[cfg(webgpu)]
|
||||
RequestDeviceErrorKind::Web(error_js_value) => {
|
||||
RequestDeviceErrorKind::WebGpu(error_js_value) => {
|
||||
// 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 {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match &self.inner {
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
RequestDeviceErrorKind::Core(error) => error.source(),
|
||||
#[cfg(webgpu)]
|
||||
RequestDeviceErrorKind::Web(_) => None,
|
||||
RequestDeviceErrorKind::WebGpu(_) => None,
|
||||
#[cfg(not(any(webgpu, wgpu_core)))]
|
||||
_ => unimplemented!("unknown `RequestDeviceErrorKind`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(webgpu))]
|
||||
impl From<core::instance::RequestDeviceError> for RequestDeviceError {
|
||||
fn from(error: core::instance::RequestDeviceError) -> Self {
|
||||
#[cfg(wgpu_core)]
|
||||
impl From<wgc::instance::RequestDeviceError> for RequestDeviceError {
|
||||
fn from(error: wgc::instance::RequestDeviceError) -> Self {
|
||||
Self {
|
||||
inner: RequestDeviceErrorKind::Core(error),
|
||||
}
|
||||
@ -2718,7 +2764,7 @@ pub struct CreateSurfaceError {
|
||||
#[derive(Clone, Debug)]
|
||||
enum CreateSurfaceErrorKind {
|
||||
/// Error from [`wgpu_hal`].
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
Hal(hal::InstanceError),
|
||||
|
||||
/// Error from WebGPU surface creation.
|
||||
@ -2734,7 +2780,7 @@ static_assertions::assert_impl_all!(CreateSurfaceError: Send, Sync);
|
||||
impl fmt::Display for CreateSurfaceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self.inner {
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
CreateSurfaceErrorKind::Hal(e) => e.fmt(f),
|
||||
CreateSurfaceErrorKind::Web(e) => e.fmt(f),
|
||||
CreateSurfaceErrorKind::RawHandle(e) => e.fmt(f),
|
||||
@ -2745,7 +2791,7 @@ impl fmt::Display for CreateSurfaceError {
|
||||
impl error::Error for CreateSurfaceError {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match &self.inner {
|
||||
#[cfg(not(webgpu))]
|
||||
#[cfg(wgpu_core)]
|
||||
CreateSurfaceErrorKind::Hal(e) => e.source(),
|
||||
CreateSurfaceErrorKind::Web(_) => None,
|
||||
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 {
|
||||
fn from(e: hal::InstanceError) -> 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
|
||||
/// 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`
|
||||
/// which unconditionally copies mapped data into the wasm heap, this function directly hands you the
|
||||
/// ArrayBuffer that we mapped the data into in js.
|
||||
/// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
|
||||
/// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
|
||||
/// 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)]
|
||||
pub fn get_mapped_range_as_array_buffer(&self) -> js_sys::ArrayBuffer {
|
||||
let end = self.buffer.map_context.lock().add(self.offset, self.size);
|
||||
DynContext::buffer_get_mapped_range_as_array_buffer(
|
||||
&*self.buffer.context,
|
||||
&self.buffer.id,
|
||||
self.buffer.data.as_ref(),
|
||||
self.offset..end,
|
||||
)
|
||||
pub fn get_mapped_range_as_array_buffer(&self) -> Option<js_sys::ArrayBuffer> {
|
||||
self.buffer
|
||||
.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::ContextWebGpu>()
|
||||
.map(|ctx| {
|
||||
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
|
||||
@ -3035,18 +3085,21 @@ impl Texture {
|
||||
/// # Safety
|
||||
///
|
||||
/// - 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>)>(
|
||||
&self,
|
||||
hal_texture_callback: F,
|
||||
) {
|
||||
let texture = self.data.as_ref().downcast_ref().unwrap();
|
||||
unsafe {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.texture_as_hal::<A, F>(texture, hal_texture_callback)
|
||||
|
||||
if let Some(ctx) = self
|
||||
.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
{
|
||||
unsafe { ctx.texture_as_hal::<A, F>(texture, hal_texture_callback) }
|
||||
} else {
|
||||
hal_texture_callback(None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4783,18 +4836,20 @@ impl Surface<'_> {
|
||||
/// # Safety
|
||||
///
|
||||
/// - 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>(
|
||||
&mut self,
|
||||
hal_surface_callback: F,
|
||||
) -> R {
|
||||
unsafe {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::Context>()
|
||||
.unwrap()
|
||||
.surface_as_hal::<A, F, R>(self.data.downcast_ref().unwrap(), hal_surface_callback)
|
||||
}
|
||||
) -> Option<R> {
|
||||
self.context
|
||||
.as_any()
|
||||
.downcast_ref::<crate::backend::ContextWgpuCore>()
|
||||
.map(|ctx| unsafe {
|
||||
ctx.surface_as_hal::<A, F, R>(
|
||||
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!(
|
||||
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)
|
||||
.quiet()
|
||||
|
Loading…
Reference in New Issue
Block a user