From cf26dcdeb399f481357f83dc6021cb9970753524 Mon Sep 17 00:00:00 2001 From: sagudev <16504129+sagudev@users.noreply.github.com> Date: Fri, 10 Jan 2025 07:20:13 +0100 Subject: [PATCH] showcase how to impl own context Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- Cargo.lock | 22 +++ Cargo.toml | 2 +- wgpu-custom/Cargo.toml | 17 ++ wgpu-custom/src/custom.rs | 332 +++++++++++++++++++++++++++++++++++++ wgpu-custom/src/main.rs | 45 +++++ wgpu/src/api/adapter.rs | 8 + wgpu/src/api/device.rs | 8 + wgpu/src/api/instance.rs | 4 +- wgpu/src/api/queue.rs | 8 + wgpu/src/backend/custom.rs | 21 +-- wgpu/src/dispatch.rs | 41 +++-- wgpu/src/lib.rs | 15 +- 12 files changed, 487 insertions(+), 36 deletions(-) create mode 100644 wgpu-custom/Cargo.toml create mode 100644 wgpu-custom/src/custom.rs create mode 100644 wgpu-custom/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 49e05174678..55f133b008c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2639,6 +2639,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 = "pp-rs" @@ -4043,6 +4057,14 @@ dependencies = [ "wgpu-types", ] +[[package]] +name = "wgpu-custom" +version = "23.0.1" +dependencies = [ + "pollster", + "wgpu", +] + [[package]] name = "wgpu-examples" version = "23.0.1" diff --git a/Cargo.toml b/Cargo.toml index c16b1b000d4..448f38a0570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ members = [ "wgpu-info", "wgpu-macros", "wgpu-types", - "wgpu", + "wgpu", "wgpu-custom", ] exclude = [] default-members = [ diff --git a/wgpu-custom/Cargo.toml b/wgpu-custom/Cargo.toml new file mode 100644 index 00000000000..3aea8c657aa --- /dev/null +++ b/wgpu-custom/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wgpu-custom" +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 +pollster = { workspace = true, features = ["macro"] } + +[lints] +workspace = true diff --git a/wgpu-custom/src/custom.rs b/wgpu-custom/src/custom.rs new file mode 100644 index 00000000000..1826e21b36d --- /dev/null +++ b/wgpu-custom/src/custom.rs @@ -0,0 +1,332 @@ +#![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 { + unimplemented!() + } + + fn request_adapter( + &self, + _options: &wgpu::RequestAdapterOptions<'_, '_>, + ) -> std::pin::Pin> { + Box::pin(std::future::ready(Some(DispatchAdapter::custom( + CustomAdapter(self.0.clone()), + )))) + } + + fn poll_all_devices(&self, _force_wait: bool) -> bool { + unimplemented!() + } +} + +#[derive(Debug)] +struct CustomAdapter(Counter); + +impl AdapterInterface for CustomAdapter { + fn request_device( + &self, + desc: &wgpu::DeviceDescriptor<'_>, + _trace_dir: Option<&std::path::Path>, + ) -> Pin> { + 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, 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) { + unimplemented!() + } + + fn push_error_scope(&self, _filter: wgpu::ErrorFilter) { + unimplemented!() + } + + fn pop_error_scope(&self) -> Pin> { + unimplemented!() + } + + fn start_capture(&self) { + unimplemented!() + } + + fn stop_capture(&self) { + unimplemented!() + } + + fn poll(&self, _maintain: wgpu::Maintain) -> wgpu::MaintainResult { + unimplemented!() + } + + fn get_internal_counters(&self) -> wgpu::InternalCounters { + unimplemented!() + } + + fn generate_allocator_report(&self) -> Option { + unimplemented!() + } + + fn destroy(&self) { + unimplemented!() + } +} + +#[derive(Debug)] +struct CustomShaderModule(Counter); + +impl ShaderModuleInterface for CustomShaderModule { + fn get_compilation_info(&self) -> Pin> { + unimplemented!() + } +} + +#[derive(Debug)] +struct CustomQueue(Counter); + +impl QueueInterface for CustomQueue { + fn write_buffer( + &self, + _buffer: &wgpu::custom::DispatchBuffer, + _offset: wgpu::BufferAddress, + _data: &[u8], + ) { + todo!() + } + + fn create_staging_buffer( + &self, + _size: wgpu::BufferSize, + ) -> Option { + todo!() + } + + fn validate_write_buffer( + &self, + _buffer: &wgpu::custom::DispatchBuffer, + _offset: wgpu::BufferAddress, + _size: wgpu::BufferSize, + ) -> Option<()> { + todo!() + } + + fn write_staging_buffer( + &self, + _buffer: &wgpu::custom::DispatchBuffer, + _offset: wgpu::BufferAddress, + _staging_buffer: &wgpu::custom::DispatchQueueWriteBuffer, + ) { + todo!() + } + + fn write_texture( + &self, + _texture: wgpu::TexelCopyTextureInfo<'_>, + _data: &[u8], + _data_layout: wgpu::TexelCopyBufferLayout, + _size: wgpu::Extent3d, + ) { + todo!() + } + + fn submit( + &self, + _command_buffers: &mut dyn Iterator, + ) -> u64 { + todo!() + } + + fn get_timestamp_period(&self) -> f32 { + todo!() + } + + fn on_submitted_work_done(&self, _callback: wgpu::custom::BoxSubmittedWorkDoneCallback) { + todo!() + } +} diff --git a/wgpu-custom/src/main.rs b/wgpu-custom/src/main.rs new file mode 100644 index 00000000000..ed6c0b4fbed --- /dev/null +++ b/wgpu-custom/src/main.rs @@ -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); +} diff --git a/wgpu/src/api/adapter.rs b/wgpu/src/api/adapter.rs index 0b38c531034..85d1944a734 100644 --- a/wgpu/src/api/adapter.rs +++ b/wgpu/src/api/adapter.rs @@ -136,6 +136,14 @@ impl Adapter { } } + //#[cfg(custom)] + /// Creates Adapter from custom implementation + pub fn from_custom(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) diff --git a/wgpu/src/api/device.rs b/wgpu/src/api/device.rs index f923ab4ee58..ff0f064781b 100644 --- a/wgpu/src/api/device.rs +++ b/wgpu/src/api/device.rs @@ -33,6 +33,14 @@ pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor>; static_assertions::assert_impl_all!(DeviceDescriptor<'_>: Send, Sync); impl Device { + //#[cfg(custom)] + /// Creates Device from custom implementation + pub fn from_custom(device: T) -> Self { + Self { + inner: dispatch::DispatchDevice::custom(device), + } + } + /// Check for resource cleanups and mapping callbacks. Will block if [`Maintain::Wait`] is passed. /// /// Return `true` if the queue is empty, or `false` if there are more queue diff --git a/wgpu/src/api/instance.rs b/wgpu/src/api/instance.rs index bec024d91dc..386204f2b7a 100644 --- a/wgpu/src/api/instance.rs +++ b/wgpu/src/api/instance.rs @@ -202,8 +202,8 @@ impl Instance { } //#[cfg(custom)] - /// Creates Instance from custom context implementation - pub fn from_custom_instance(instance: T) -> Self { + /// Creates instance from custom context implementation + pub fn from_custom(instance: T) -> Self { Self { inner: dispatch::DispatchInstance::Custom(backend::custom::DynContext::new(instance)), } diff --git a/wgpu/src/api/queue.rs b/wgpu/src/api/queue.rs index ed1feeec9ce..ca2daa0cea3 100644 --- a/wgpu/src/api/queue.rs +++ b/wgpu/src/api/queue.rs @@ -82,6 +82,14 @@ impl Drop for QueueWriteBufferView<'_> { } impl Queue { + //#[cfg(custom)] + /// Creates Queue from custom implementation + pub fn from_custom(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`. diff --git a/wgpu/src/backend/custom.rs b/wgpu/src/backend/custom.rs index 929c18961e8..2ac54290a43 100644 --- a/wgpu/src/backend/custom.rs +++ b/wgpu/src/backend/custom.rs @@ -1,15 +1,8 @@ +//! Provides wrappers custom backend implementations + #![allow(ambiguous_wide_pointer_comparisons)] -use crate::dispatch::{ - AdapterInterface, BindGroupInterface, BindGroupLayoutInterface, BlasInterface, BufferInterface, - BufferMappedRangeInterface, CommandBufferInterface, CommandEncoderInterface, - ComputePassInterface, ComputePipelineInterface, DeviceInterface, InstanceInterface, - PipelineCacheInterface, PipelineLayoutInterface, QuerySetInterface, QueueInterface, - QueueWriteBufferInterface, RenderBundleEncoderInterface, RenderBundleInterface, - RenderPassInterface, RenderPipelineInterface, SamplerInterface, ShaderModuleInterface, - SurfaceInterface, SurfaceOutputDetailInterface, TextureInterface, TextureViewInterface, - TlasInterface, -}; +pub use crate::dispatch::*; use std::sync::Arc; @@ -17,11 +10,11 @@ macro_rules! dyn_type { // cloning of arc forbidden (pub mut struct $name:ident(dyn $interface:tt)) => { #[derive(Debug)] - pub struct $name(Arc); + pub(crate) struct $name(Arc); crate::cmp::impl_eq_ord_hash_arc_address!($name => .0); impl $name { - pub fn new(t: T) -> Self { + pub(crate) fn new(t: T) -> Self { Self(Arc::new(t)) } } @@ -45,11 +38,11 @@ macro_rules! dyn_type { // cloning of arc is allowed (pub ref struct $name:ident(dyn $interface:tt)) => { #[derive(Debug, Clone)] - pub struct $name(Arc); + pub(crate) struct $name(Arc); crate::cmp::impl_eq_ord_hash_arc_address!($name => .0); impl $name { - pub fn new(t: T) -> Self { + pub(crate) fn new(t: T) -> Self { Self(Arc::new(t)) } } diff --git a/wgpu/src/dispatch.rs b/wgpu/src/dispatch.rs index cbf4232a5a5..2fe45022b93 100644 --- a/wgpu/src/dispatch.rs +++ b/wgpu/src/dispatch.rs @@ -10,6 +10,7 @@ #![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}; @@ -51,7 +52,7 @@ pub type BufferMapCallback = Box) trait_alias!(CommonTraits: Any + Debug + WasmNotSendSync); pub trait InstanceInterface: CommonTraits { - fn new(desc: &wgt::InstanceDescriptor) -> Self + fn new(desc: &crate::InstanceDescriptor) -> Self where Self: Sized; @@ -100,7 +101,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, @@ -158,7 +159,7 @@ pub trait DeviceInterface: CommonTraits { fn poll(&self, maintain: crate::Maintain) -> crate::MaintainResult; fn get_internal_counters(&self) -> crate::InternalCounters; - fn generate_allocator_report(&self) -> Option; + fn generate_allocator_report(&self) -> Option; fn destroy(&self); } @@ -170,8 +171,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, @@ -190,8 +191,8 @@ pub trait QueueInterface: CommonTraits { #[cfg(any(webgpu, webgl))] fn copy_external_image_to_texture( &self, - source: &wgt::CopyExternalImageSourceInfo, - dest: wgt::CopyExternalImageDestInfo<&crate::api::Texture>, + source: &crate::CopyExternalImageSourceInfo, + dest: crate::CopyExternalImageDestInfo<&crate::api::Texture>, size: crate::Extent3d, ); @@ -220,7 +221,7 @@ pub trait BufferInterface: CommonTraits { #[cfg(webgpu)] fn get_mapped_range_as_array_buffer( &self, - sub_range: Range, + sub_range: Range, ) -> Option; fn unmap(&self); @@ -483,7 +484,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( @@ -523,7 +524,7 @@ pub trait BufferMappedRangeInterface: CommonTraits { /// In the future, we may want a truly generic backend, which could be extended from this enum. macro_rules! dispatch_types_inner { ( - {ref type $name:ident = $subtype:ident: $trait:ident}; + {ref type $name:ident = $subtype:ident: $interface:ident}; ) => { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] pub enum $name { @@ -531,6 +532,7 @@ macro_rules! dispatch_types_inner { Core(Arc), #[cfg(webgpu)] WebGPU(Arc), + #[allow(private_interfaces)] //#[cfg(custom)] Custom(backend::custom::interface_types::$subtype), } @@ -575,6 +577,12 @@ macro_rules! dispatch_types_inner { _ => None, } } + + //#[cfg(custom)] + #[inline] + pub fn custom(t: T) -> Self { + Self::Custom(backend::custom::interface_types::$subtype::new(t)) + } } #[cfg(wgpu_core)] @@ -594,7 +602,7 @@ macro_rules! dispatch_types_inner { } impl std::ops::Deref for $name { - type Target = dyn $trait; + type Target = dyn $interface; #[inline] fn deref(&self) -> &Self::Target { @@ -610,7 +618,7 @@ macro_rules! dispatch_types_inner { } }; ( - {mut type $name:ident = $subtype:ident: $trait:ident}; + {mut type $name:ident = $subtype:ident: $interface:ident}; ) => { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum $name { @@ -618,6 +626,7 @@ macro_rules! dispatch_types_inner { Core(backend::wgpu_core::interface_types::$subtype), #[cfg(webgpu)] WebGPU(backend::webgpu::interface_types::$subtype), + #[allow(private_interfaces)] //#[cfg(custom)] Custom(backend::custom::interface_types::$subtype), } @@ -706,6 +715,12 @@ macro_rules! dispatch_types_inner { _ => None, } } + + //#[cfg(custom)] + #[inline] + pub fn custom(t: T) -> Self { + Self::Custom(backend::custom::interface_types::$subtype::new(t)) + } } #[cfg(wgpu_core)] @@ -725,7 +740,7 @@ macro_rules! dispatch_types_inner { } impl std::ops::Deref for $name { - type Target = dyn $trait; + type Target = dyn $interface; #[inline] fn deref(&self) -> &Self::Target { diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 56813441ed0..38bc0f06629 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -44,14 +44,17 @@ pub mod util; // // +//#[cfg(custom)] +pub use backend::custom; + pub use api::*; pub use wgt::{ - AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, Backends, BindGroupLayoutEntry, - BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, - BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, - CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CoreCounters, DepthBiasState, - DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, - Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, + AdapterInfo, AddressMode, AllocatorReport, AstcBlock, AstcChannel, Backend, Backends, + BindGroupLayoutEntry, BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, + BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, + ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, CoreCounters, + DepthBiasState, DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, + DownlevelFlags, Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, Gles3MinorVersion, HalCounters, ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, InternalCounters, Limits, MaintainResult, MemoryHints, MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference,