Support extern context impl (#6658)

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Samson 2025-03-04 22:07:03 +01:00 committed by GitHub
parent 7eb69f43b6
commit 7e66495049
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 670 additions and 200 deletions

22
Cargo.lock generated
View File

@ -963,6 +963,14 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
[[package]]
name = "custom-backend"
version = "24.0.0"
dependencies = [
"pollster",
"wgpu",
]
[[package]]
name = "data-encoding"
version = "2.8.0"
@ -3074,6 +3082,20 @@ name = "pollster"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
dependencies = [
"pollster-macro",
]
[[package]]
name = "pollster-macro"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac5da421106a50887c5b51d20806867db377fbb86bacf478ee0500a912e0c113"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "portable-atomic"

View File

@ -16,6 +16,7 @@ be cloned out of the repository to serve as a starting point for your own projec
|--------|-------------|-----------|
| [hello compute](standalone/01_hello_compute/) | Simplest example and shows how to run a compute shader on a given set of input data and get the results back. | Native-Only |
| [hello window](standalone/02_hello_window/) | Shows how to create a window and render into it. | Native-Only |
| [custom backend](standalone/03_custom_backend/) | Shows how to implement and use custom wgpu context | Any |
You can also use [`cargo-generate`](https://github.com/cargo-generate/cargo-generate) to easily use these as a basis for your own projects.

View File

@ -0,0 +1,18 @@
[package]
name = "custom-backend"
description = "Example of creating and loading custom wgpu backend"
edition.workspace = true
rust-version.workspace = true
keywords.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
version.workspace = true
authors.workspace = true
[dependencies]
wgpu = { workspace = true, features = ["custom"], default-features = false }
pollster = { workspace = true, features = ["macro"] }
[lints]
workspace = true

View File

@ -0,0 +1,346 @@
#![allow(dead_code)]
use std::pin::Pin;
use std::sync::Arc;
use wgpu::custom::{
AdapterInterface, DeviceInterface, DispatchAdapter, DispatchDevice, DispatchQueue,
DispatchShaderModule, DispatchSurface, InstanceInterface, QueueInterface, RequestAdapterFuture,
ShaderModuleInterface,
};
#[derive(Debug, Clone)]
pub struct Counter(Arc<()>);
impl Counter {
pub fn new() -> Self {
Self(Arc::new(()))
}
pub fn count(&self) -> usize {
Arc::strong_count(&self.0)
}
}
#[derive(Debug)]
pub struct CustomInstance(pub Counter);
impl InstanceInterface for CustomInstance {
fn new(__desc: &wgpu::InstanceDescriptor) -> Self
where
Self: Sized,
{
Self(Counter::new())
}
unsafe fn create_surface(
&self,
_target: wgpu::SurfaceTargetUnsafe,
) -> Result<DispatchSurface, wgpu::CreateSurfaceError> {
unimplemented!()
}
fn request_adapter(
&self,
_options: &wgpu::RequestAdapterOptions<'_, '_>,
) -> std::pin::Pin<Box<dyn RequestAdapterFuture>> {
Box::pin(std::future::ready(Some(DispatchAdapter::custom(
CustomAdapter(self.0.clone()),
))))
}
fn poll_all_devices(&self, _force_wait: bool) -> bool {
unimplemented!()
}
fn wgsl_language_features(&self) -> wgpu::WgslLanguageFeatures {
unimplemented!()
}
}
#[derive(Debug)]
struct CustomAdapter(Counter);
impl AdapterInterface for CustomAdapter {
fn request_device(
&self,
desc: &wgpu::DeviceDescriptor<'_>,
_trace_dir: Option<&std::path::Path>,
) -> Pin<Box<dyn wgpu::custom::RequestDeviceFuture>> {
assert_eq!(desc.label, Some("device"));
let res: Result<_, wgpu::RequestDeviceError> = Ok((
DispatchDevice::custom(CustomDevice(self.0.clone())),
DispatchQueue::custom(CustomQueue(self.0.clone())),
));
Box::pin(std::future::ready(res))
}
fn is_surface_supported(&self, _surface: &DispatchSurface) -> bool {
unimplemented!()
}
fn features(&self) -> wgpu::Features {
unimplemented!()
}
fn limits(&self) -> wgpu::Limits {
unimplemented!()
}
fn downlevel_capabilities(&self) -> wgpu::DownlevelCapabilities {
unimplemented!()
}
fn get_info(&self) -> wgpu::AdapterInfo {
unimplemented!()
}
fn get_texture_format_features(
&self,
_format: wgpu::TextureFormat,
) -> wgpu::TextureFormatFeatures {
unimplemented!()
}
fn get_presentation_timestamp(&self) -> wgpu::PresentationTimestamp {
unimplemented!()
}
}
#[derive(Debug)]
struct CustomDevice(Counter);
impl DeviceInterface for CustomDevice {
fn features(&self) -> wgpu::Features {
unimplemented!()
}
fn limits(&self) -> wgpu::Limits {
unimplemented!()
}
fn create_shader_module(
&self,
desc: wgpu::ShaderModuleDescriptor<'_>,
_shader_bound_checks: wgpu::ShaderRuntimeChecks,
) -> DispatchShaderModule {
assert_eq!(desc.label, Some("shader"));
DispatchShaderModule::custom(CustomShaderModule(self.0.clone()))
}
unsafe fn create_shader_module_spirv(
&self,
_desc: &wgpu::ShaderModuleDescriptorSpirV<'_>,
) -> DispatchShaderModule {
unimplemented!()
}
fn create_bind_group_layout(
&self,
_desc: &wgpu::BindGroupLayoutDescriptor<'_>,
) -> wgpu::custom::DispatchBindGroupLayout {
unimplemented!()
}
fn create_bind_group(
&self,
_desc: &wgpu::BindGroupDescriptor<'_>,
) -> wgpu::custom::DispatchBindGroup {
unimplemented!()
}
fn create_pipeline_layout(
&self,
_desc: &wgpu::PipelineLayoutDescriptor<'_>,
) -> wgpu::custom::DispatchPipelineLayout {
unimplemented!()
}
fn create_render_pipeline(
&self,
_desc: &wgpu::RenderPipelineDescriptor<'_>,
) -> wgpu::custom::DispatchRenderPipeline {
unimplemented!()
}
fn create_compute_pipeline(
&self,
_desc: &wgpu::ComputePipelineDescriptor<'_>,
) -> wgpu::custom::DispatchComputePipeline {
unimplemented!()
}
unsafe fn create_pipeline_cache(
&self,
_desc: &wgpu::PipelineCacheDescriptor<'_>,
) -> wgpu::custom::DispatchPipelineCache {
unimplemented!()
}
fn create_buffer(&self, _desc: &wgpu::BufferDescriptor<'_>) -> wgpu::custom::DispatchBuffer {
unimplemented!()
}
fn create_texture(&self, _desc: &wgpu::TextureDescriptor<'_>) -> wgpu::custom::DispatchTexture {
unimplemented!()
}
fn create_blas(
&self,
_desc: &wgpu::CreateBlasDescriptor<'_>,
_sizes: wgpu::BlasGeometrySizeDescriptors,
) -> (Option<u64>, wgpu::custom::DispatchBlas) {
unimplemented!()
}
fn create_tlas(&self, _desc: &wgpu::CreateTlasDescriptor<'_>) -> wgpu::custom::DispatchTlas {
unimplemented!()
}
fn create_sampler(&self, _desc: &wgpu::SamplerDescriptor<'_>) -> wgpu::custom::DispatchSampler {
unimplemented!()
}
fn create_query_set(
&self,
_desc: &wgpu::QuerySetDescriptor<'_>,
) -> wgpu::custom::DispatchQuerySet {
unimplemented!()
}
fn create_command_encoder(
&self,
_desc: &wgpu::CommandEncoderDescriptor<'_>,
) -> wgpu::custom::DispatchCommandEncoder {
unimplemented!()
}
fn create_render_bundle_encoder(
&self,
_desc: &wgpu::RenderBundleEncoderDescriptor<'_>,
) -> wgpu::custom::DispatchRenderBundleEncoder {
unimplemented!()
}
fn set_device_lost_callback(&self, _device_lost_callback: wgpu::custom::BoxDeviceLostCallback) {
unimplemented!()
}
fn on_uncaptured_error(&self, _handler: Box<dyn wgpu::UncapturedErrorHandler>) {
unimplemented!()
}
fn push_error_scope(&self, _filter: wgpu::ErrorFilter) {
unimplemented!()
}
fn pop_error_scope(&self) -> Pin<Box<dyn wgpu::custom::PopErrorScopeFuture>> {
unimplemented!()
}
fn start_capture(&self) {
unimplemented!()
}
fn stop_capture(&self) {
unimplemented!()
}
fn poll(&self, _maintain: wgpu::PollType) -> Result<wgpu::PollStatus, wgpu::PollError> {
unimplemented!()
}
fn get_internal_counters(&self) -> wgpu::InternalCounters {
unimplemented!()
}
fn generate_allocator_report(&self) -> Option<wgpu::AllocatorReport> {
unimplemented!()
}
fn destroy(&self) {
unimplemented!()
}
}
#[derive(Debug)]
struct CustomShaderModule(Counter);
impl ShaderModuleInterface for CustomShaderModule {
fn get_compilation_info(&self) -> Pin<Box<dyn wgpu::custom::ShaderCompilationInfoFuture>> {
unimplemented!()
}
}
#[derive(Debug)]
struct CustomQueue(Counter);
impl QueueInterface for CustomQueue {
fn write_buffer(
&self,
_buffer: &wgpu::custom::DispatchBuffer,
_offset: wgpu::BufferAddress,
_data: &[u8],
) {
unimplemented!()
}
fn create_staging_buffer(
&self,
_size: wgpu::BufferSize,
) -> Option<wgpu::custom::DispatchQueueWriteBuffer> {
unimplemented!()
}
fn validate_write_buffer(
&self,
_buffer: &wgpu::custom::DispatchBuffer,
_offset: wgpu::BufferAddress,
_size: wgpu::BufferSize,
) -> Option<()> {
unimplemented!()
}
fn write_staging_buffer(
&self,
_buffer: &wgpu::custom::DispatchBuffer,
_offset: wgpu::BufferAddress,
_staging_buffer: &wgpu::custom::DispatchQueueWriteBuffer,
) {
unimplemented!()
}
fn write_texture(
&self,
_texture: wgpu::TexelCopyTextureInfo<'_>,
_data: &[u8],
_data_layout: wgpu::TexelCopyBufferLayout,
_size: wgpu::Extent3d,
) {
unimplemented!()
}
fn submit(
&self,
_command_buffers: &mut dyn Iterator<Item = wgpu::custom::DispatchCommandBuffer>,
) -> u64 {
unimplemented!()
}
fn get_timestamp_period(&self) -> f32 {
unimplemented!()
}
fn on_submitted_work_done(&self, _callback: wgpu::custom::BoxSubmittedWorkDoneCallback) {
unimplemented!()
}
#[cfg(target_arch = "wasm32")]
fn copy_external_image_to_texture(
&self,
_source: &wgpu::CopyExternalImageSourceInfo,
_dest: wgpu::CopyExternalImageDestInfo<&wgpu::Texture>,
_size: wgpu::Extent3d,
) {
unimplemented!()
}
}

View File

@ -0,0 +1,45 @@
use std::marker::PhantomData;
use custom::Counter;
use wgpu::{DeviceDescriptor, RequestAdapterOptions};
mod custom;
#[pollster::main]
async fn main() {
let counter = Counter::new();
{
let custom_instance = custom::CustomInstance(counter.clone());
// wrap custom instance into wgpu abstraction
let instance = wgpu::Instance::from_custom(custom_instance);
assert_eq!(counter.count(), 2);
// do work on instance (usually by passing it to other libs)
// here we will simulate a library and ensure that counter is incremented
let adapter = instance
.request_adapter(&RequestAdapterOptions::default())
.await
.unwrap();
assert_eq!(counter.count(), 3);
let (device, _queue) = adapter
.request_device(
&DeviceDescriptor {
label: Some("device"),
..Default::default()
},
None,
)
.await
.unwrap();
assert_eq!(counter.count(), 5);
let _module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("shader"),
source: wgpu::ShaderSource::Dummy(PhantomData),
});
assert_eq!(counter.count(), 6);
}
assert_eq!(counter.count(), 1);
}

View File

@ -82,6 +82,8 @@ noop = ["wgpu-core/noop"]
#! it means that the item is only available when that backend is enabled _and_ the backend
#! is supported on the current platform.
custom = []
#! ### Shading language support
# --------------------------------------------------------------------
#! These features enable support for that input language on all platforms.

View File

@ -45,6 +45,7 @@ fn main() {
naga: { any(feature = "naga-ir", feature = "spirv", feature = "glsl") },
// ⚠️ Keep in sync with target.cfg() definition in wgpu-hal/Cargo.toml and cfg_alias in `wgpu-hal` crate ⚠️
static_dxc: { all(target_os = "windows", feature = "static-dxc", not(target_arch = "aarch64")) },
supports_64bit_atomics: { target_has_atomic = "64" }
supports_64bit_atomics: { target_has_atomic = "64" },
custom: {any(feature = "custom")}
}
}

View File

@ -136,6 +136,14 @@ impl Adapter {
}
}
#[cfg(custom)]
/// Creates Adapter from custom implementation
pub fn from_custom<T: custom::AdapterInterface>(adapter: T) -> Self {
Self {
inner: dispatch::DispatchAdapter::custom(adapter),
}
}
/// Returns whether this adapter may present to the passed surface.
pub fn is_surface_supported(&self, surface: &Surface<'_>) -> bool {
self.inner.is_surface_supported(&surface.inner)

View File

@ -34,6 +34,14 @@ pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
static_assertions::assert_impl_all!(DeviceDescriptor<'_>: Send, Sync);
impl Device {
#[cfg(custom)]
/// Creates Device from custom implementation
pub fn from_custom<T: custom::DeviceInterface>(device: T) -> Self {
Self {
inner: dispatch::DispatchDevice::custom(device),
}
}
/// Check for resource cleanups and mapping callbacks. Will block if [`PollType::Wait`] is passed.
///
/// Return `true` if the queue is empty, or `false` if there are more queue

View File

@ -200,6 +200,14 @@ impl Instance {
}
}
#[cfg(custom)]
/// Creates instance from custom context implementation
pub fn from_custom<T: InstanceInterface>(instance: T) -> Self {
Self {
inner: dispatch::DispatchInstance::Custom(backend::custom::DynContext::new(instance)),
}
}
/// Retrieves all available [`Adapter`]s that match the given [`Backends`].
///
/// # Arguments

View File

@ -90,6 +90,14 @@ impl Drop for QueueWriteBufferView<'_> {
}
impl Queue {
#[cfg(custom)]
/// Creates Queue from custom implementation
pub fn from_custom<T: custom::QueueInterface>(queue: T) -> Self {
Self {
inner: dispatch::DispatchQueue::custom(queue),
}
}
/// Schedule a data write into `buffer` starting at `offset`.
///
/// This method fails if `data` overruns the size of `buffer` starting at `offset`.

View File

@ -57,6 +57,8 @@ impl<'a> RenderBundleEncoder<'a> {
dispatch::DispatchRenderBundleEncoder::Core(b) => b.finish(desc),
#[cfg(webgpu)]
dispatch::DispatchRenderBundleEncoder::WebGPU(b) => b.finish(desc),
#[cfg(custom)]
dispatch::DispatchRenderBundleEncoder::Custom(_) => unimplemented!(),
};
RenderBundle { inner: bundle }

View File

@ -0,0 +1,89 @@
//! Provides wrappers custom backend implementations
#![allow(ambiguous_wide_pointer_comparisons)]
pub use crate::dispatch::*;
use alloc::sync::Arc;
macro_rules! dyn_type {
// cloning of arc forbidden
// but we still use it to provide Eq,Ord,Hash implementations
(pub mut struct $name:ident(dyn $interface:tt)) => {
#[derive(Debug)]
pub(crate) struct $name(Arc<dyn $interface>);
crate::cmp::impl_eq_ord_hash_arc_address!($name => .0);
impl $name {
pub(crate) fn new<T: $interface>(t: T) -> Self {
Self(Arc::new(t))
}
}
impl core::ops::Deref for $name {
type Target = dyn $interface;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl core::ops::DerefMut for $name {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
Arc::get_mut(&mut self.0).expect("")
}
}
};
// cloning of arc is allowed
(pub ref struct $name:ident(dyn $interface:tt)) => {
#[derive(Debug, Clone)]
pub(crate) struct $name(Arc<dyn $interface>);
crate::cmp::impl_eq_ord_hash_arc_address!($name => .0);
impl $name {
pub(crate) fn new<T: $interface>(t: T) -> Self {
Self(Arc::new(t))
}
}
impl core::ops::Deref for $name {
type Target = dyn $interface;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
};
}
dyn_type!(pub ref struct DynContext(dyn InstanceInterface));
dyn_type!(pub ref struct DynAdapter(dyn AdapterInterface));
dyn_type!(pub ref struct DynDevice(dyn DeviceInterface));
dyn_type!(pub ref struct DynQueue(dyn QueueInterface));
dyn_type!(pub ref struct DynShaderModule(dyn ShaderModuleInterface));
dyn_type!(pub ref struct DynBindGroupLayout(dyn BindGroupLayoutInterface));
dyn_type!(pub ref struct DynBindGroup(dyn BindGroupInterface));
dyn_type!(pub ref struct DynTextureView(dyn TextureViewInterface));
dyn_type!(pub ref struct DynSampler(dyn SamplerInterface));
dyn_type!(pub ref struct DynBuffer(dyn BufferInterface));
dyn_type!(pub ref struct DynTexture(dyn TextureInterface));
dyn_type!(pub ref struct DynBlas(dyn BlasInterface));
dyn_type!(pub ref struct DynTlas(dyn TlasInterface));
dyn_type!(pub ref struct DynQuerySet(dyn QuerySetInterface));
dyn_type!(pub ref struct DynPipelineLayout(dyn PipelineLayoutInterface));
dyn_type!(pub ref struct DynRenderPipeline(dyn RenderPipelineInterface));
dyn_type!(pub ref struct DynComputePipeline(dyn ComputePipelineInterface));
dyn_type!(pub ref struct DynPipelineCache(dyn PipelineCacheInterface));
dyn_type!(pub mut struct DynCommandEncoder(dyn CommandEncoderInterface));
dyn_type!(pub mut struct DynComputePass(dyn ComputePassInterface));
dyn_type!(pub mut struct DynRenderPass(dyn RenderPassInterface));
dyn_type!(pub ref struct DynCommandBuffer(dyn CommandBufferInterface));
dyn_type!(pub mut struct DynRenderBundleEncoder(dyn RenderBundleEncoderInterface));
dyn_type!(pub ref struct DynRenderBundle(dyn RenderBundleInterface));
dyn_type!(pub ref struct DynSurface(dyn SurfaceInterface));
dyn_type!(pub ref struct DynSurfaceOutputDetail(dyn SurfaceOutputDetailInterface));
dyn_type!(pub mut struct DynQueueWriteBuffer(dyn QueueWriteBufferInterface));
dyn_type!(pub mut struct DynBufferMappedRange(dyn BufferMappedRangeInterface));

View File

@ -8,3 +8,6 @@ pub mod wgpu_core;
#[cfg(wgpu_core)]
pub(crate) use wgpu_core::ContextWgpuCore;
#[cfg(custom)]
pub mod custom;

View File

@ -45,7 +45,7 @@ macro_rules! impl_send_sync {
};
}
pub(crate) struct ContextWebGpu {
pub struct ContextWebGpu {
/// `None` if browser does not advertise support for WebGPU.
gpu: Option<DefinedNonNullJsValue<webgpu_sys::Gpu>>,
/// Unique identifier for this context.
@ -1266,13 +1266,13 @@ pub struct WebTexture {
}
#[derive(Debug)]
pub(crate) struct WebBlas {
pub struct WebBlas {
/// Unique identifier for this Blas.
ident: crate::cmp::Identifier,
}
#[derive(Debug)]
pub(crate) struct WebTlas {
pub struct WebTlas {
/// Unique identifier for this Blas.
ident: crate::cmp::Identifier,
}
@ -1306,7 +1306,7 @@ pub struct WebComputePipeline {
}
#[derive(Debug)]
pub(crate) struct WebPipelineCache {
pub struct WebPipelineCache {
/// Unique identifier for this PipelineCache.
ident: crate::cmp::Identifier,
}
@ -1363,7 +1363,7 @@ pub struct WebSurface {
}
#[derive(Debug)]
pub(crate) struct WebSurfaceOutputDetail {
pub struct WebSurfaceOutputDetail {
/// Unique identifier for this SurfaceOutputDetail.
ident: crate::cmp::Identifier,
}
@ -1445,37 +1445,6 @@ crate::cmp::impl_eq_ord_hash_proxy!(WebSurfaceOutputDetail => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebQueueWriteBuffer => .ident);
crate::cmp::impl_eq_ord_hash_proxy!(WebBufferMappedRange => .ident);
impl dispatch::InterfaceTypes for ContextWebGpu {
type Instance = ContextWebGpu;
type Adapter = WebAdapter;
type Device = WebDevice;
type Queue = WebQueue;
type ShaderModule = WebShaderModule;
type BindGroupLayout = WebBindGroupLayout;
type BindGroup = WebBindGroup;
type TextureView = WebTextureView;
type Sampler = WebSampler;
type Buffer = WebBuffer;
type Texture = WebTexture;
type Blas = WebBlas;
type Tlas = WebTlas;
type QuerySet = WebQuerySet;
type PipelineLayout = WebPipelineLayout;
type RenderPipeline = WebRenderPipeline;
type ComputePipeline = WebComputePipeline;
type PipelineCache = WebPipelineCache;
type CommandEncoder = WebCommandEncoder;
type ComputePass = WebComputePassEncoder;
type RenderPass = WebRenderPassEncoder;
type CommandBuffer = WebCommandBuffer;
type RenderBundleEncoder = WebRenderBundleEncoder;
type RenderBundle = WebRenderBundle;
type Surface = WebSurface;
type SurfaceOutputDetail = WebSurfaceOutputDetail;
type QueueWriteBuffer = WebQueueWriteBuffer;
type BufferMappedRange = WebBufferMappedRange;
}
impl dispatch::InstanceInterface for ContextWebGpu {
fn new(_desc: &crate::InstanceDescriptor) -> Self
where

View File

@ -17,7 +17,7 @@ use wgt::WasmNotSendSync;
use crate::{
api,
dispatch::{self, BufferMappedRangeInterface, InterfaceTypes},
dispatch::{self, BufferMappedRangeInterface},
BindingResource, BufferBinding, BufferDescriptor, CompilationInfo, CompilationMessage,
CompilationMessageType, ErrorSource, Features, Label, LoadOp, MapMode, Operations,
ShaderSource, SurfaceTargetUnsafe, TextureDescriptor,
@ -742,37 +742,6 @@ crate::cmp::impl_eq_ord_hash_proxy!(CoreSurfaceOutputDetail => .surface_id);
crate::cmp::impl_eq_ord_hash_proxy!(CoreQueueWriteBuffer => .mapping.ptr);
crate::cmp::impl_eq_ord_hash_proxy!(CoreBufferMappedRange => .ptr);
impl InterfaceTypes for ContextWgpuCore {
type Instance = ContextWgpuCore;
type Adapter = CoreAdapter;
type Device = CoreDevice;
type Queue = CoreQueue;
type ShaderModule = CoreShaderModule;
type BindGroupLayout = CoreBindGroupLayout;
type BindGroup = CoreBindGroup;
type TextureView = CoreTextureView;
type Sampler = CoreSampler;
type Buffer = CoreBuffer;
type Texture = CoreTexture;
type Blas = CoreBlas;
type Tlas = CoreTlas;
type QuerySet = CoreQuerySet;
type PipelineLayout = CorePipelineLayout;
type RenderPipeline = CoreRenderPipeline;
type ComputePipeline = CoreComputePipeline;
type PipelineCache = CorePipelineCache;
type CommandEncoder = CoreCommandEncoder;
type ComputePass = CoreComputePass;
type RenderPass = CoreRenderPass;
type CommandBuffer = CoreCommandBuffer;
type RenderBundleEncoder = CoreRenderBundleEncoder;
type RenderBundle = CoreRenderBundle;
type Surface = CoreSurface;
type SurfaceOutputDetail = CoreSurfaceOutputDetail;
type QueueWriteBuffer = CoreQueueWriteBuffer;
type BufferMappedRange = CoreBufferMappedRange;
}
impl dispatch::InstanceInterface for ContextWgpuCore {
fn new(desc: &wgt::InstanceDescriptor) -> Self
where

View File

@ -10,13 +10,19 @@
#![allow(drop_bounds)] // This exists to remind implementors to impl drop.
#![allow(clippy::too_many_arguments)] // It's fine.
#![allow(missing_docs, clippy::missing_safety_doc)] // Interfaces are not documented
use crate::{WasmNotSend, WasmNotSendSync};
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{any::Any, fmt::Debug, future::Future, hash::Hash, ops::Range, pin::Pin};
use crate::backend;
#[cfg(custom)]
use crate::backend::custom::*;
#[cfg(webgpu)]
use crate::backend::webgpu::*;
#[cfg(wgpu_core)]
use crate::backend::wgpu_core::*;
/// Create a single trait with the given supertraits and a blanket impl for all types that implement them.
///
@ -50,43 +56,9 @@ pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>)
// Common traits on all the interface traits
trait_alias!(CommonTraits: Any + Debug + WasmNotSendSync);
// Non-object-safe traits that are added as a bound on InterfaceTypes.
trait_alias!(ComparisonTraits: PartialEq + Eq + PartialOrd + Ord + Hash);
/// Types that represent a "Backend" for the wgpu API.
pub trait InterfaceTypes {
type Instance: InstanceInterface + ComparisonTraits;
type Adapter: AdapterInterface + ComparisonTraits;
type Device: DeviceInterface + ComparisonTraits;
type Queue: QueueInterface + ComparisonTraits;
type ShaderModule: ShaderModuleInterface + ComparisonTraits;
type BindGroupLayout: BindGroupLayoutInterface + ComparisonTraits;
type BindGroup: BindGroupInterface + ComparisonTraits;
type TextureView: TextureViewInterface + ComparisonTraits;
type Sampler: SamplerInterface + ComparisonTraits;
type Buffer: BufferInterface + ComparisonTraits;
type Texture: TextureInterface + ComparisonTraits;
type Blas: BlasInterface + ComparisonTraits;
type Tlas: TlasInterface + ComparisonTraits;
type QuerySet: QuerySetInterface + ComparisonTraits;
type PipelineLayout: PipelineLayoutInterface + ComparisonTraits;
type RenderPipeline: RenderPipelineInterface + ComparisonTraits;
type ComputePipeline: ComputePipelineInterface + ComparisonTraits;
type PipelineCache: PipelineCacheInterface + ComparisonTraits;
type CommandEncoder: CommandEncoderInterface + ComparisonTraits;
type ComputePass: ComputePassInterface + ComparisonTraits;
type RenderPass: RenderPassInterface + ComparisonTraits;
type CommandBuffer: CommandBufferInterface + ComparisonTraits;
type RenderBundleEncoder: RenderBundleEncoderInterface + ComparisonTraits;
type RenderBundle: RenderBundleInterface + ComparisonTraits;
type Surface: SurfaceInterface + ComparisonTraits;
type SurfaceOutputDetail: SurfaceOutputDetailInterface + ComparisonTraits;
type QueueWriteBuffer: QueueWriteBufferInterface + ComparisonTraits;
type BufferMappedRange: BufferMappedRangeInterface + ComparisonTraits;
}
pub trait InstanceInterface: CommonTraits {
fn new(desc: &wgt::InstanceDescriptor) -> Self
fn new(desc: &crate::InstanceDescriptor) -> Self
where
Self: Sized;
@ -138,7 +110,7 @@ pub trait DeviceInterface: CommonTraits {
fn create_shader_module(
&self,
desc: crate::ShaderModuleDescriptor<'_>,
shader_bound_checks: wgt::ShaderRuntimeChecks,
shader_bound_checks: crate::ShaderRuntimeChecks,
) -> DispatchShaderModule;
unsafe fn create_shader_module_spirv(
&self,
@ -196,7 +168,7 @@ pub trait DeviceInterface: CommonTraits {
fn poll(&self, poll_type: crate::PollType) -> Result<crate::PollStatus, crate::PollError>;
fn get_internal_counters(&self) -> crate::InternalCounters;
fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport>;
fn generate_allocator_report(&self) -> Option<crate::AllocatorReport>;
fn destroy(&self);
}
@ -208,8 +180,8 @@ pub trait QueueInterface: CommonTraits {
fn validate_write_buffer(
&self,
buffer: &DispatchBuffer,
offset: wgt::BufferAddress,
size: wgt::BufferSize,
offset: crate::BufferAddress,
size: crate::BufferSize,
) -> Option<()>;
fn write_staging_buffer(
&self,
@ -258,7 +230,7 @@ pub trait BufferInterface: CommonTraits {
#[cfg(webgpu)]
fn get_mapped_range_as_array_buffer(
&self,
sub_range: Range<wgt::BufferAddress>,
sub_range: Range<crate::BufferAddress>,
) -> Option<js_sys::ArrayBuffer>;
fn unmap(&self);
@ -523,7 +495,7 @@ pub trait CommandBufferInterface: CommonTraits {}
pub trait RenderBundleInterface: CommonTraits {}
pub trait SurfaceInterface: CommonTraits {
fn get_capabilities(&self, adapter: &DispatchAdapter) -> wgt::SurfaceCapabilities;
fn get_capabilities(&self, adapter: &DispatchAdapter) -> crate::SurfaceCapabilities;
fn configure(&self, device: &DispatchDevice, config: &crate::SurfaceConfiguration);
fn get_current_texture(
@ -561,25 +533,26 @@ pub trait BufferMappedRangeInterface: CommonTraits {
/// arguments. These are similarly free when there is only one backend.
///
/// In the future, we may want a truly generic backend, which could be extended from this enum.
macro_rules! dispatch_types_inner {
macro_rules! dispatch_types {
(
wgpu_core = $wgpu_core_context:ty;
webgpu = $webgpu_context:ty;
{ref type $name:ident = InterfaceTypes::$subtype:ident: $trait:ident};
ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
) => {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub enum $name {
#[cfg(wgpu_core)]
Core(Arc<<$wgpu_core_context as InterfaceTypes>::$subtype>),
Core(Arc<$core_type>),
#[cfg(webgpu)]
WebGPU(Arc<<$webgpu_context as InterfaceTypes>::$subtype>),
WebGPU(Arc<$webgpu_type>),
#[allow(clippy::allow_attributes, private_interfaces)]
#[cfg(custom)]
Custom($custom_type),
}
impl $name {
#[cfg(wgpu_core)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_core(&self) -> &<$wgpu_core_context as InterfaceTypes>::$subtype {
pub fn as_core(&self) -> &$core_type {
match self {
Self::Core(value) => value,
_ => panic!(concat!(stringify!($name), " is not core")),
@ -589,7 +562,7 @@ macro_rules! dispatch_types_inner {
#[cfg(wgpu_core)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_core_opt(&self) -> Option<&<$wgpu_core_context as InterfaceTypes>::$subtype> {
pub fn as_core_opt(&self) -> Option<&$core_type> {
match self {
Self::Core(value) => Some(value),
_ => None,
@ -599,7 +572,7 @@ macro_rules! dispatch_types_inner {
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu(&self) -> &<$webgpu_context as InterfaceTypes>::$subtype {
pub fn as_webgpu(&self) -> &$webgpu_type {
match self {
Self::WebGPU(value) => value,
_ => panic!(concat!(stringify!($name), " is not webgpu")),
@ -609,32 +582,38 @@ macro_rules! dispatch_types_inner {
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu_opt(&self) -> Option<&<$webgpu_context as InterfaceTypes>::$subtype> {
pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
match self {
Self::WebGPU(value) => Some(value),
_ => None,
}
}
#[cfg(custom)]
#[inline]
pub fn custom<T: $interface>(t: T) -> Self {
Self::Custom($custom_type::new(t))
}
}
#[cfg(wgpu_core)]
impl From<<$wgpu_core_context as InterfaceTypes>::$subtype> for $name {
impl From<$core_type> for $name {
#[inline]
fn from(value: <$wgpu_core_context as InterfaceTypes>::$subtype) -> Self {
fn from(value: $core_type) -> Self {
Self::Core(Arc::new(value))
}
}
#[cfg(webgpu)]
impl From<<$webgpu_context as InterfaceTypes>::$subtype> for $name {
impl From<$webgpu_type> for $name {
#[inline]
fn from(value: <$webgpu_context as InterfaceTypes>::$subtype) -> Self {
fn from(value: $webgpu_type) -> Self {
Self::WebGPU(Arc::new(value))
}
}
impl core::ops::Deref for $name {
type Target = dyn $trait;
type Target = dyn $interface;
#[inline]
fn deref(&self) -> &Self::Target {
@ -643,6 +622,8 @@ macro_rules! dispatch_types_inner {
Self::Core(value) => value.as_ref(),
#[cfg(webgpu)]
Self::WebGPU(value) => value.as_ref(),
#[cfg(custom)]
Self::Custom(value) => value.deref(),
#[cfg(not(any(wgpu_core, webgpu)))]
_ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
}
@ -650,23 +631,24 @@ macro_rules! dispatch_types_inner {
}
};
(
wgpu_core = $wgpu_core_context:ty;
webgpu = $webgpu_context:ty;
{mut type $name:ident = InterfaceTypes::$subtype:ident: $trait:ident};
mut type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
) => {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum $name {
#[cfg(wgpu_core)]
Core(<$wgpu_core_context as InterfaceTypes>::$subtype),
Core($core_type),
#[cfg(webgpu)]
WebGPU(<$webgpu_context as InterfaceTypes>::$subtype),
WebGPU($webgpu_type),
#[allow(clippy::allow_attributes, private_interfaces)]
#[cfg(custom)]
Custom($custom_type),
}
impl $name {
#[cfg(wgpu_core)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_core(&self) -> &<$wgpu_core_context as InterfaceTypes>::$subtype {
pub fn as_core(&self) -> &$core_type {
match self {
Self::Core(value) => value,
_ => panic!(concat!(stringify!($name), " is not core")),
@ -676,7 +658,7 @@ macro_rules! dispatch_types_inner {
#[cfg(wgpu_core)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_core_mut(&mut self) -> &mut <$wgpu_core_context as InterfaceTypes>::$subtype {
pub fn as_core_mut(&mut self) -> &mut $core_type {
match self {
Self::Core(value) => value,
_ => panic!(concat!(stringify!($name), " is not core")),
@ -686,7 +668,7 @@ macro_rules! dispatch_types_inner {
#[cfg(wgpu_core)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_core_opt(&self) -> Option<&<$wgpu_core_context as InterfaceTypes>::$subtype> {
pub fn as_core_opt(&self) -> Option<&$core_type> {
match self {
Self::Core(value) => Some(value),
_ => None,
@ -698,7 +680,7 @@ macro_rules! dispatch_types_inner {
#[allow(clippy::allow_attributes, unused)]
pub fn as_core_mut_opt(
&mut self,
) -> Option<&mut <$wgpu_core_context as InterfaceTypes>::$subtype> {
) -> Option<&mut $core_type> {
match self {
Self::Core(value) => Some(value),
_ => None,
@ -708,7 +690,7 @@ macro_rules! dispatch_types_inner {
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu(&self) -> &<$webgpu_context as InterfaceTypes>::$subtype {
pub fn as_webgpu(&self) -> &$webgpu_type {
match self {
Self::WebGPU(value) => value,
_ => panic!(concat!(stringify!($name), " is not webgpu")),
@ -718,7 +700,7 @@ macro_rules! dispatch_types_inner {
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu_mut(&mut self) -> &mut <$webgpu_context as InterfaceTypes>::$subtype {
pub fn as_webgpu_mut(&mut self) -> &mut $webgpu_type {
match self {
Self::WebGPU(value) => value,
_ => panic!(concat!(stringify!($name), " is not webgpu")),
@ -728,7 +710,7 @@ macro_rules! dispatch_types_inner {
#[cfg(webgpu)]
#[inline]
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu_opt(&self) -> Option<&<$webgpu_context as InterfaceTypes>::$subtype> {
pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
match self {
Self::WebGPU(value) => Some(value),
_ => None,
@ -740,32 +722,38 @@ macro_rules! dispatch_types_inner {
#[allow(clippy::allow_attributes, unused)]
pub fn as_webgpu_mut_opt(
&mut self,
) -> Option<&mut <$webgpu_context as InterfaceTypes>::$subtype> {
) -> Option<&mut $webgpu_type> {
match self {
Self::WebGPU(value) => Some(value),
_ => None,
}
}
#[cfg(custom)]
#[inline]
pub fn custom<T: $interface>(t: T) -> Self {
Self::Custom($custom_type::new(t))
}
}
#[cfg(wgpu_core)]
impl From<<$wgpu_core_context as InterfaceTypes>::$subtype> for $name {
impl From<$core_type> for $name {
#[inline]
fn from(value: <$wgpu_core_context as InterfaceTypes>::$subtype) -> Self {
fn from(value: $core_type) -> Self {
Self::Core(value)
}
}
#[cfg(webgpu)]
impl From<<$webgpu_context as InterfaceTypes>::$subtype> for $name {
impl From<$webgpu_type> for $name {
#[inline]
fn from(value: <$webgpu_context as InterfaceTypes>::$subtype) -> Self {
fn from(value: $webgpu_type) -> Self {
Self::WebGPU(value)
}
}
impl core::ops::Deref for $name {
type Target = dyn $trait;
type Target = dyn $interface;
#[inline]
fn deref(&self) -> &Self::Target {
@ -774,6 +762,8 @@ macro_rules! dispatch_types_inner {
Self::Core(value) => value,
#[cfg(webgpu)]
Self::WebGPU(value) => value,
#[cfg(custom)]
Self::Custom(value) => value.deref(),
#[cfg(not(any(wgpu_core, webgpu)))]
_ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
}
@ -788,6 +778,8 @@ macro_rules! dispatch_types_inner {
Self::Core(value) => value,
#[cfg(webgpu)]
Self::WebGPU(value) => value,
#[cfg(custom)]
Self::Custom(value) => value.deref_mut(),
#[cfg(not(any(wgpu_core, webgpu)))]
_ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
}
@ -796,55 +788,31 @@ macro_rules! dispatch_types_inner {
};
}
macro_rules! dispatch_types {
(
wgpu_core = $wgpu_core_context:ty;
webgpu = $webgpu_context:ty;
{$(
$type:tt;
)*}
) => {
$(
dispatch_types_inner!{
wgpu_core = backend::ContextWgpuCore;
webgpu = backend::ContextWebGpu;
$type;
}
)*
};
}
dispatch_types! {
wgpu_core = backend::ContextWgpuCore;
webgpu = backend::ContextWebGpu;
{
{ref type DispatchInstance = InterfaceTypes::Instance: InstanceInterface};
{ref type DispatchAdapter = InterfaceTypes::Adapter: AdapterInterface};
{ref type DispatchDevice = InterfaceTypes::Device: DeviceInterface};
{ref type DispatchQueue = InterfaceTypes::Queue: QueueInterface};
{ref type DispatchShaderModule = InterfaceTypes::ShaderModule: ShaderModuleInterface};
{ref type DispatchBindGroupLayout = InterfaceTypes::BindGroupLayout: BindGroupLayoutInterface};
{ref type DispatchBindGroup = InterfaceTypes::BindGroup: BindGroupInterface};
{ref type DispatchTextureView = InterfaceTypes::TextureView: TextureViewInterface};
{ref type DispatchSampler = InterfaceTypes::Sampler: SamplerInterface};
{ref type DispatchBuffer = InterfaceTypes::Buffer: BufferInterface};
{ref type DispatchTexture = InterfaceTypes::Texture: TextureInterface};
{ref type DispatchBlas = InterfaceTypes::Blas: BlasInterface};
{ref type DispatchTlas = InterfaceTypes::Tlas: TlasInterface};
{ref type DispatchQuerySet = InterfaceTypes::QuerySet: QuerySetInterface};
{ref type DispatchPipelineLayout = InterfaceTypes::PipelineLayout: PipelineLayoutInterface};
{ref type DispatchRenderPipeline = InterfaceTypes::RenderPipeline: RenderPipelineInterface};
{ref type DispatchComputePipeline = InterfaceTypes::ComputePipeline: ComputePipelineInterface};
{ref type DispatchPipelineCache = InterfaceTypes::PipelineCache: PipelineCacheInterface};
{mut type DispatchCommandEncoder = InterfaceTypes::CommandEncoder: CommandEncoderInterface};
{mut type DispatchComputePass = InterfaceTypes::ComputePass: ComputePassInterface};
{mut type DispatchRenderPass = InterfaceTypes::RenderPass: RenderPassInterface};
{mut type DispatchCommandBuffer = InterfaceTypes::CommandBuffer: CommandBufferInterface};
{mut type DispatchRenderBundleEncoder = InterfaceTypes::RenderBundleEncoder: RenderBundleEncoderInterface};
{ref type DispatchRenderBundle = InterfaceTypes::RenderBundle: RenderBundleInterface};
{ref type DispatchSurface = InterfaceTypes::Surface: SurfaceInterface};
{ref type DispatchSurfaceOutputDetail = InterfaceTypes::SurfaceOutputDetail: SurfaceOutputDetailInterface};
{mut type DispatchQueueWriteBuffer = InterfaceTypes::QueueWriteBuffer: QueueWriteBufferInterface};
{mut type DispatchBufferMappedRange = InterfaceTypes::BufferMappedRange: BufferMappedRangeInterface};
}
}
dispatch_types! {ref type DispatchInstance: InstanceInterface = ContextWgpuCore, ContextWebGpu, DynContext}
dispatch_types! {ref type DispatchAdapter: AdapterInterface = CoreAdapter, WebAdapter, DynAdapter}
dispatch_types! {ref type DispatchDevice: DeviceInterface = CoreDevice, WebDevice, DynDevice}
dispatch_types! {ref type DispatchQueue: QueueInterface = CoreQueue, WebQueue, DynQueue}
dispatch_types! {ref type DispatchShaderModule: ShaderModuleInterface = CoreShaderModule, WebShaderModule, DynShaderModule}
dispatch_types! {ref type DispatchBindGroupLayout: BindGroupLayoutInterface = CoreBindGroupLayout, WebBindGroupLayout, DynBindGroupLayout}
dispatch_types! {ref type DispatchBindGroup: BindGroupInterface = CoreBindGroup, WebBindGroup, DynBindGroup}
dispatch_types! {ref type DispatchTextureView: TextureViewInterface = CoreTextureView, WebTextureView, DynTextureView}
dispatch_types! {ref type DispatchSampler: SamplerInterface = CoreSampler, WebSampler, DynSampler}
dispatch_types! {ref type DispatchBuffer: BufferInterface = CoreBuffer, WebBuffer, DynBuffer}
dispatch_types! {ref type DispatchTexture: TextureInterface = CoreTexture, WebTexture, DynTexture}
dispatch_types! {ref type DispatchBlas: BlasInterface = CoreBlas, WebBlas, DynBlas}
dispatch_types! {ref type DispatchTlas: TlasInterface = CoreTlas, WebTlas, DynTlas}
dispatch_types! {ref type DispatchQuerySet: QuerySetInterface = CoreQuerySet, WebQuerySet, DynQuerySet}
dispatch_types! {ref type DispatchPipelineLayout: PipelineLayoutInterface = CorePipelineLayout, WebPipelineLayout, DynPipelineLayout}
dispatch_types! {ref type DispatchRenderPipeline: RenderPipelineInterface = CoreRenderPipeline, WebRenderPipeline, DynRenderPipeline}
dispatch_types! {ref type DispatchComputePipeline: ComputePipelineInterface = CoreComputePipeline, WebComputePipeline, DynComputePipeline}
dispatch_types! {ref type DispatchPipelineCache: PipelineCacheInterface = CorePipelineCache, WebPipelineCache, DynPipelineCache}
dispatch_types! {mut type DispatchCommandEncoder: CommandEncoderInterface = CoreCommandEncoder, WebCommandEncoder, DynCommandEncoder}
dispatch_types! {mut type DispatchComputePass: ComputePassInterface = CoreComputePass, WebComputePassEncoder, DynComputePass}
dispatch_types! {mut type DispatchRenderPass: RenderPassInterface = CoreRenderPass, WebRenderPassEncoder, DynRenderPass}
dispatch_types! {ref type DispatchCommandBuffer: CommandBufferInterface = CoreCommandBuffer, WebCommandBuffer, DynCommandBuffer}
dispatch_types! {mut type DispatchRenderBundleEncoder: RenderBundleEncoderInterface = CoreRenderBundleEncoder, WebRenderBundleEncoder, DynRenderBundleEncoder}
dispatch_types! {ref type DispatchRenderBundle: RenderBundleInterface = CoreRenderBundle, WebRenderBundle, DynRenderBundle}
dispatch_types! {ref type DispatchSurface: SurfaceInterface = CoreSurface, WebSurface, DynSurface}
dispatch_types! {ref type DispatchSurfaceOutputDetail: SurfaceOutputDetailInterface = CoreSurfaceOutputDetail, WebSurfaceOutputDetail, DynSurfaceOutputDetail}
dispatch_types! {mut type DispatchQueueWriteBuffer: QueueWriteBufferInterface = CoreQueueWriteBuffer, WebQueueWriteBuffer, DynQueueWriteBuffer}
dispatch_types! {mut type DispatchBufferMappedRange: BufferMappedRangeInterface = CoreBufferMappedRange, WebBufferMappedRange, DynBufferMappedRange}

View File

@ -63,12 +63,15 @@ pub mod util;
//
//
#[cfg(custom)]
pub use backend::custom;
pub use api::*;
pub use wgt::{
AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, BackendOptions, Backends,
BindGroupLayoutEntry, BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState,
BufferAddress, BufferBindingType, BufferSize, BufferTransition, BufferUsages, BufferUses,
Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction,
AdapterInfo, AddressMode, AllocatorReport, AstcBlock, AstcChannel, Backend, BackendOptions,
Backends, BindGroupLayoutEntry, BindingType, BlendComponent, BlendFactor, BlendOperation,
BlendState, BufferAddress, BufferBindingType, BufferSize, BufferTransition, BufferUsages,
BufferUses, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction,
CompositeAlphaMode, CopyExternalImageDestInfo, CoreCounters, DepthBiasState, DepthStencilState,
DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, DownlevelLimits,
Dx12BackendOptions, Dx12Compiler, DxcShaderModel, DynamicOffset, Extent3d, Face, Features,