wgpu/
dispatch.rs

1//! Infrastructure for dispatching calls to the appropriate "backend". The "backends" are:
2//!
3//! - `wgpu_core`: An implementation of the the wgpu api on top of various native graphics APIs.
4//! - `webgpu`: An implementation of the wgpu api which calls WebGPU directly.
5//!
6//! The interface traits are all object safe and listed in the `InterfaceTypes` trait.
7//!
8//! The method for dispatching should optimize well if only one backend is compiled in,
9//! as-if there was no dispatching at all.
10
11#![allow(drop_bounds)] // This exists to remind implementors to impl drop.
12#![allow(clippy::too_many_arguments)] // It's fine.
13#![allow(missing_docs, clippy::missing_safety_doc)] // Interfaces are not documented
14
15use crate::{Blas, Tlas, WasmNotSend, WasmNotSendSync};
16
17use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
18use core::{any::Any, fmt::Debug, future::Future, hash::Hash, ops::Range, pin::Pin};
19
20#[cfg(custom)]
21use crate::backend::custom::*;
22#[cfg(webgpu)]
23use crate::backend::webgpu::*;
24#[cfg(wgpu_core)]
25use crate::backend::wgpu_core::*;
26
27/// Create a single trait with the given supertraits and a blanket impl for all types that implement them.
28///
29/// This is useful for creating a trait alias as a shorthand.
30macro_rules! trait_alias {
31    ($name:ident: $($bound:tt)+) => {
32        pub trait $name: $($bound)+ {}
33        impl<T: $($bound)+> $name for T {}
34    };
35}
36
37// Various return futures in the API.
38trait_alias!(RequestAdapterFuture: Future<Output = Result<DispatchAdapter, wgt::RequestAdapterError>> + WasmNotSend + 'static);
39trait_alias!(RequestDeviceFuture: Future<Output = Result<(DispatchDevice, DispatchQueue), crate::RequestDeviceError>> + WasmNotSend + 'static);
40trait_alias!(PopErrorScopeFuture: Future<Output = Option<crate::Error>> + WasmNotSend + 'static);
41trait_alias!(ShaderCompilationInfoFuture: Future<Output = crate::CompilationInfo> + WasmNotSend + 'static);
42
43// We can't use trait aliases here, as you can't convert from a dyn Trait to dyn Supertrait _yet_.
44#[cfg(send_sync)]
45pub type BoxDeviceLostCallback = Box<dyn FnOnce(crate::DeviceLostReason, String) + Send + 'static>;
46#[cfg(not(send_sync))]
47pub type BoxDeviceLostCallback = Box<dyn FnOnce(crate::DeviceLostReason, String) + 'static>;
48#[cfg(send_sync)]
49pub type BoxSubmittedWorkDoneCallback = Box<dyn FnOnce() + Send + 'static>;
50#[cfg(not(send_sync))]
51pub type BoxSubmittedWorkDoneCallback = Box<dyn FnOnce() + 'static>;
52#[cfg(send_sync)]
53pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>) + Send + 'static>;
54#[cfg(not(send_sync))]
55pub type BufferMapCallback = Box<dyn FnOnce(Result<(), crate::BufferAsyncError>) + 'static>;
56
57#[cfg(send_sync)]
58pub type BlasCompactCallback = Box<dyn FnOnce(Result<(), crate::BlasAsyncError>) + Send + 'static>;
59#[cfg(not(send_sync))]
60pub type BlasCompactCallback = Box<dyn FnOnce(Result<(), crate::BlasAsyncError>) + 'static>;
61
62// remove when rust 1.86
63#[cfg_attr(not(custom), expect(dead_code))]
64pub trait AsAny {
65    fn as_any(&self) -> &dyn Any;
66}
67
68impl<T: 'static> AsAny for T {
69    fn as_any(&self) -> &dyn Any {
70        self
71    }
72}
73
74// Common traits on all the interface traits
75trait_alias!(CommonTraits: AsAny + Any + Debug + WasmNotSendSync);
76
77pub trait InstanceInterface: CommonTraits {
78    fn new(desc: &crate::InstanceDescriptor) -> Self
79    where
80        Self: Sized;
81
82    unsafe fn create_surface(
83        &self,
84        target: crate::SurfaceTargetUnsafe,
85    ) -> Result<DispatchSurface, crate::CreateSurfaceError>;
86
87    fn request_adapter(
88        &self,
89        options: &crate::RequestAdapterOptions<'_, '_>,
90    ) -> Pin<Box<dyn RequestAdapterFuture>>;
91
92    fn poll_all_devices(&self, force_wait: bool) -> bool;
93
94    #[cfg(feature = "wgsl")]
95    fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures;
96}
97
98pub trait AdapterInterface: CommonTraits {
99    fn request_device(
100        &self,
101        desc: &crate::DeviceDescriptor<'_>,
102    ) -> Pin<Box<dyn RequestDeviceFuture>>;
103
104    fn is_surface_supported(&self, surface: &DispatchSurface) -> bool;
105
106    fn features(&self) -> crate::Features;
107
108    fn limits(&self) -> crate::Limits;
109
110    fn downlevel_capabilities(&self) -> crate::DownlevelCapabilities;
111
112    fn get_info(&self) -> crate::AdapterInfo;
113
114    fn get_texture_format_features(
115        &self,
116        format: crate::TextureFormat,
117    ) -> crate::TextureFormatFeatures;
118
119    fn get_presentation_timestamp(&self) -> crate::PresentationTimestamp;
120}
121
122pub trait DeviceInterface: CommonTraits {
123    fn features(&self) -> crate::Features;
124    fn limits(&self) -> crate::Limits;
125
126    fn create_shader_module(
127        &self,
128        desc: crate::ShaderModuleDescriptor<'_>,
129        shader_bound_checks: crate::ShaderRuntimeChecks,
130    ) -> DispatchShaderModule;
131
132    unsafe fn create_shader_module_passthrough(
133        &self,
134        desc: &crate::ShaderModuleDescriptorPassthrough<'_>,
135    ) -> DispatchShaderModule;
136
137    fn create_bind_group_layout(
138        &self,
139        desc: &crate::BindGroupLayoutDescriptor<'_>,
140    ) -> DispatchBindGroupLayout;
141    fn create_bind_group(&self, desc: &crate::BindGroupDescriptor<'_>) -> DispatchBindGroup;
142    fn create_pipeline_layout(
143        &self,
144        desc: &crate::PipelineLayoutDescriptor<'_>,
145    ) -> DispatchPipelineLayout;
146    fn create_render_pipeline(
147        &self,
148        desc: &crate::RenderPipelineDescriptor<'_>,
149    ) -> DispatchRenderPipeline;
150    fn create_mesh_pipeline(
151        &self,
152        desc: &crate::MeshPipelineDescriptor<'_>,
153    ) -> DispatchRenderPipeline;
154    fn create_compute_pipeline(
155        &self,
156        desc: &crate::ComputePipelineDescriptor<'_>,
157    ) -> DispatchComputePipeline;
158    unsafe fn create_pipeline_cache(
159        &self,
160        desc: &crate::PipelineCacheDescriptor<'_>,
161    ) -> DispatchPipelineCache;
162    fn create_buffer(&self, desc: &crate::BufferDescriptor<'_>) -> DispatchBuffer;
163    fn create_texture(&self, desc: &crate::TextureDescriptor<'_>) -> DispatchTexture;
164    fn create_external_texture(
165        &self,
166        desc: &crate::ExternalTextureDescriptor<'_>,
167        planes: &[&crate::TextureView],
168    ) -> DispatchExternalTexture;
169    fn create_blas(
170        &self,
171        desc: &crate::CreateBlasDescriptor<'_>,
172        sizes: crate::BlasGeometrySizeDescriptors,
173    ) -> (Option<u64>, DispatchBlas);
174    fn create_tlas(&self, desc: &crate::CreateTlasDescriptor<'_>) -> DispatchTlas;
175    fn create_sampler(&self, desc: &crate::SamplerDescriptor<'_>) -> DispatchSampler;
176    fn create_query_set(&self, desc: &crate::QuerySetDescriptor<'_>) -> DispatchQuerySet;
177    fn create_command_encoder(
178        &self,
179        desc: &crate::CommandEncoderDescriptor<'_>,
180    ) -> DispatchCommandEncoder;
181    fn create_render_bundle_encoder(
182        &self,
183        desc: &crate::RenderBundleEncoderDescriptor<'_>,
184    ) -> DispatchRenderBundleEncoder;
185
186    fn set_device_lost_callback(&self, device_lost_callback: BoxDeviceLostCallback);
187
188    fn on_uncaptured_error(&self, handler: Arc<dyn crate::UncapturedErrorHandler>);
189    fn push_error_scope(&self, filter: crate::ErrorFilter);
190    fn pop_error_scope(&self) -> Pin<Box<dyn PopErrorScopeFuture>>;
191
192    unsafe fn start_graphics_debugger_capture(&self);
193    unsafe fn stop_graphics_debugger_capture(&self);
194
195    fn poll(&self, poll_type: wgt::PollType<u64>) -> Result<crate::PollStatus, crate::PollError>;
196
197    fn get_internal_counters(&self) -> crate::InternalCounters;
198    fn generate_allocator_report(&self) -> Option<crate::AllocatorReport>;
199
200    fn destroy(&self);
201}
202
203pub trait QueueInterface: CommonTraits {
204    fn write_buffer(&self, buffer: &DispatchBuffer, offset: crate::BufferAddress, data: &[u8]);
205
206    fn create_staging_buffer(&self, size: crate::BufferSize) -> Option<DispatchQueueWriteBuffer>;
207    fn validate_write_buffer(
208        &self,
209        buffer: &DispatchBuffer,
210        offset: crate::BufferAddress,
211        size: crate::BufferSize,
212    ) -> Option<()>;
213    fn write_staging_buffer(
214        &self,
215        buffer: &DispatchBuffer,
216        offset: crate::BufferAddress,
217        staging_buffer: &DispatchQueueWriteBuffer,
218    );
219
220    fn write_texture(
221        &self,
222        texture: crate::TexelCopyTextureInfo<'_>,
223        data: &[u8],
224        data_layout: crate::TexelCopyBufferLayout,
225        size: crate::Extent3d,
226    );
227    #[cfg(web)]
228    fn copy_external_image_to_texture(
229        &self,
230        source: &crate::CopyExternalImageSourceInfo,
231        dest: crate::CopyExternalImageDestInfo<&crate::api::Texture>,
232        size: crate::Extent3d,
233    );
234
235    /// Submit must always drain the iterator, even in the case of error.
236    fn submit(&self, command_buffers: &mut dyn Iterator<Item = DispatchCommandBuffer>) -> u64;
237
238    fn get_timestamp_period(&self) -> f32;
239    fn on_submitted_work_done(&self, callback: BoxSubmittedWorkDoneCallback);
240
241    fn compact_blas(&self, blas: &DispatchBlas) -> (Option<u64>, DispatchBlas);
242}
243
244pub trait ShaderModuleInterface: CommonTraits {
245    fn get_compilation_info(&self) -> Pin<Box<dyn ShaderCompilationInfoFuture>>;
246}
247pub trait BindGroupLayoutInterface: CommonTraits {}
248pub trait BindGroupInterface: CommonTraits {}
249pub trait TextureViewInterface: CommonTraits {}
250pub trait SamplerInterface: CommonTraits {}
251pub trait BufferInterface: CommonTraits {
252    fn map_async(
253        &self,
254        mode: crate::MapMode,
255        range: Range<crate::BufferAddress>,
256        callback: BufferMapCallback,
257    );
258    fn get_mapped_range(&self, sub_range: Range<crate::BufferAddress>)
259        -> DispatchBufferMappedRange;
260
261    fn unmap(&self);
262
263    fn destroy(&self);
264}
265pub trait TextureInterface: CommonTraits {
266    fn create_view(&self, desc: &crate::TextureViewDescriptor<'_>) -> DispatchTextureView;
267
268    fn destroy(&self);
269}
270pub trait ExternalTextureInterface: CommonTraits {
271    fn destroy(&self);
272}
273pub trait BlasInterface: CommonTraits {
274    fn prepare_compact_async(&self, callback: BlasCompactCallback);
275    fn ready_for_compaction(&self) -> bool;
276}
277pub trait TlasInterface: CommonTraits {}
278pub trait QuerySetInterface: CommonTraits {}
279pub trait PipelineLayoutInterface: CommonTraits {}
280pub trait RenderPipelineInterface: CommonTraits {
281    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
282}
283pub trait ComputePipelineInterface: CommonTraits {
284    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
285}
286pub trait PipelineCacheInterface: CommonTraits {
287    fn get_data(&self) -> Option<Vec<u8>>;
288}
289pub trait CommandEncoderInterface: CommonTraits {
290    fn copy_buffer_to_buffer(
291        &self,
292        source: &DispatchBuffer,
293        source_offset: crate::BufferAddress,
294        destination: &DispatchBuffer,
295        destination_offset: crate::BufferAddress,
296        copy_size: Option<crate::BufferAddress>,
297    );
298    fn copy_buffer_to_texture(
299        &self,
300        source: crate::TexelCopyBufferInfo<'_>,
301        destination: crate::TexelCopyTextureInfo<'_>,
302        copy_size: crate::Extent3d,
303    );
304    fn copy_texture_to_buffer(
305        &self,
306        source: crate::TexelCopyTextureInfo<'_>,
307        destination: crate::TexelCopyBufferInfo<'_>,
308        copy_size: crate::Extent3d,
309    );
310    fn copy_texture_to_texture(
311        &self,
312        source: crate::TexelCopyTextureInfo<'_>,
313        destination: crate::TexelCopyTextureInfo<'_>,
314        copy_size: crate::Extent3d,
315    );
316
317    fn begin_compute_pass(&self, desc: &crate::ComputePassDescriptor<'_>) -> DispatchComputePass;
318    fn begin_render_pass(&self, desc: &crate::RenderPassDescriptor<'_>) -> DispatchRenderPass;
319    fn finish(&mut self) -> DispatchCommandBuffer;
320
321    fn clear_texture(
322        &self,
323        texture: &DispatchTexture,
324        subresource_range: &crate::ImageSubresourceRange,
325    );
326    fn clear_buffer(
327        &self,
328        buffer: &DispatchBuffer,
329        offset: crate::BufferAddress,
330        size: Option<crate::BufferAddress>,
331    );
332
333    fn insert_debug_marker(&self, label: &str);
334    fn push_debug_group(&self, label: &str);
335    fn pop_debug_group(&self);
336
337    fn write_timestamp(&self, query_set: &DispatchQuerySet, query_index: u32);
338    fn resolve_query_set(
339        &self,
340        query_set: &DispatchQuerySet,
341        first_query: u32,
342        query_count: u32,
343        destination: &DispatchBuffer,
344        destination_offset: crate::BufferAddress,
345    );
346    fn mark_acceleration_structures_built<'a>(
347        &self,
348        blas: &mut dyn Iterator<Item = &'a Blas>,
349        tlas: &mut dyn Iterator<Item = &'a Tlas>,
350    );
351
352    fn build_acceleration_structures<'a>(
353        &self,
354        blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
355        tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
356    );
357
358    fn transition_resources<'a>(
359        &mut self,
360        buffer_transitions: &mut dyn Iterator<Item = wgt::BufferTransition<&'a DispatchBuffer>>,
361        texture_transitions: &mut dyn Iterator<Item = wgt::TextureTransition<&'a DispatchTexture>>,
362    );
363}
364pub trait ComputePassInterface: CommonTraits {
365    fn set_pipeline(&mut self, pipeline: &DispatchComputePipeline);
366    fn set_bind_group(
367        &mut self,
368        index: u32,
369        bind_group: Option<&DispatchBindGroup>,
370        offsets: &[crate::DynamicOffset],
371    );
372    fn set_push_constants(&mut self, offset: u32, data: &[u8]);
373
374    fn insert_debug_marker(&mut self, label: &str);
375    fn push_debug_group(&mut self, group_label: &str);
376    fn pop_debug_group(&mut self);
377
378    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
379    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
380    fn end_pipeline_statistics_query(&mut self);
381
382    fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32);
383    fn dispatch_workgroups_indirect(
384        &mut self,
385        indirect_buffer: &DispatchBuffer,
386        indirect_offset: crate::BufferAddress,
387    );
388    fn end(&mut self);
389}
390pub trait RenderPassInterface: CommonTraits {
391    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
392    fn set_bind_group(
393        &mut self,
394        index: u32,
395        bind_group: Option<&DispatchBindGroup>,
396        offsets: &[crate::DynamicOffset],
397    );
398    fn set_index_buffer(
399        &mut self,
400        buffer: &DispatchBuffer,
401        index_format: crate::IndexFormat,
402        offset: crate::BufferAddress,
403        size: Option<crate::BufferSize>,
404    );
405    fn set_vertex_buffer(
406        &mut self,
407        slot: u32,
408        buffer: &DispatchBuffer,
409        offset: crate::BufferAddress,
410        size: Option<crate::BufferSize>,
411    );
412    fn set_push_constants(&mut self, stages: crate::ShaderStages, offset: u32, data: &[u8]);
413    fn set_blend_constant(&mut self, color: crate::Color);
414    fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
415    fn set_viewport(
416        &mut self,
417        x: f32,
418        y: f32,
419        width: f32,
420        height: f32,
421        min_depth: f32,
422        max_depth: f32,
423    );
424    fn set_stencil_reference(&mut self, reference: u32);
425
426    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
427    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
428    fn draw_mesh_tasks(&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32);
429    fn draw_indirect(
430        &mut self,
431        indirect_buffer: &DispatchBuffer,
432        indirect_offset: crate::BufferAddress,
433    );
434    fn draw_indexed_indirect(
435        &mut self,
436        indirect_buffer: &DispatchBuffer,
437        indirect_offset: crate::BufferAddress,
438    );
439    fn draw_mesh_tasks_indirect(
440        &mut self,
441        indirect_buffer: &DispatchBuffer,
442        indirect_offset: crate::BufferAddress,
443    );
444
445    fn multi_draw_indirect(
446        &mut self,
447        indirect_buffer: &DispatchBuffer,
448        indirect_offset: crate::BufferAddress,
449        count: u32,
450    );
451    fn multi_draw_indexed_indirect(
452        &mut self,
453        indirect_buffer: &DispatchBuffer,
454        indirect_offset: crate::BufferAddress,
455        count: u32,
456    );
457    fn multi_draw_indirect_count(
458        &mut self,
459        indirect_buffer: &DispatchBuffer,
460        indirect_offset: crate::BufferAddress,
461        count_buffer: &DispatchBuffer,
462        count_buffer_offset: crate::BufferAddress,
463        max_count: u32,
464    );
465    fn multi_draw_mesh_tasks_indirect(
466        &mut self,
467        indirect_buffer: &DispatchBuffer,
468        indirect_offset: crate::BufferAddress,
469        count: u32,
470    );
471    fn multi_draw_indexed_indirect_count(
472        &mut self,
473        indirect_buffer: &DispatchBuffer,
474        indirect_offset: crate::BufferAddress,
475        count_buffer: &DispatchBuffer,
476        count_buffer_offset: crate::BufferAddress,
477        max_count: u32,
478    );
479    fn multi_draw_mesh_tasks_indirect_count(
480        &mut self,
481        indirect_buffer: &DispatchBuffer,
482        indirect_offset: crate::BufferAddress,
483        count_buffer: &DispatchBuffer,
484        count_buffer_offset: crate::BufferAddress,
485        max_count: u32,
486    );
487
488    fn insert_debug_marker(&mut self, label: &str);
489    fn push_debug_group(&mut self, group_label: &str);
490    fn pop_debug_group(&mut self);
491
492    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
493    fn begin_occlusion_query(&mut self, query_index: u32);
494    fn end_occlusion_query(&mut self);
495    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
496    fn end_pipeline_statistics_query(&mut self);
497
498    fn execute_bundles(&mut self, render_bundles: &mut dyn Iterator<Item = &DispatchRenderBundle>);
499
500    fn end(&mut self);
501}
502
503pub trait RenderBundleEncoderInterface: CommonTraits {
504    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
505    fn set_bind_group(
506        &mut self,
507        index: u32,
508        bind_group: Option<&DispatchBindGroup>,
509        offsets: &[crate::DynamicOffset],
510    );
511    fn set_index_buffer(
512        &mut self,
513        buffer: &DispatchBuffer,
514        index_format: crate::IndexFormat,
515        offset: crate::BufferAddress,
516        size: Option<crate::BufferSize>,
517    );
518    fn set_vertex_buffer(
519        &mut self,
520        slot: u32,
521        buffer: &DispatchBuffer,
522        offset: crate::BufferAddress,
523        size: Option<crate::BufferSize>,
524    );
525    fn set_push_constants(&mut self, stages: crate::ShaderStages, offset: u32, data: &[u8]);
526
527    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
528    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
529    fn draw_indirect(
530        &mut self,
531        indirect_buffer: &DispatchBuffer,
532        indirect_offset: crate::BufferAddress,
533    );
534    fn draw_indexed_indirect(
535        &mut self,
536        indirect_buffer: &DispatchBuffer,
537        indirect_offset: crate::BufferAddress,
538    );
539
540    fn finish(self, desc: &crate::RenderBundleDescriptor<'_>) -> DispatchRenderBundle
541    where
542        Self: Sized;
543}
544
545pub trait CommandBufferInterface: CommonTraits {}
546pub trait RenderBundleInterface: CommonTraits {}
547
548pub trait SurfaceInterface: CommonTraits {
549    fn get_capabilities(&self, adapter: &DispatchAdapter) -> crate::SurfaceCapabilities;
550
551    fn configure(&self, device: &DispatchDevice, config: &crate::SurfaceConfiguration);
552    fn get_current_texture(
553        &self,
554    ) -> (
555        Option<DispatchTexture>,
556        crate::SurfaceStatus,
557        DispatchSurfaceOutputDetail,
558    );
559}
560
561pub trait SurfaceOutputDetailInterface: CommonTraits {
562    fn present(&self);
563    fn texture_discard(&self);
564}
565
566pub trait QueueWriteBufferInterface: CommonTraits {
567    fn slice(&self) -> &[u8];
568
569    fn slice_mut(&mut self) -> &mut [u8];
570}
571
572pub trait BufferMappedRangeInterface: CommonTraits {
573    fn slice(&self) -> &[u8];
574    fn slice_mut(&mut self) -> &mut [u8];
575
576    #[cfg(webgpu)]
577    fn as_uint8array(&self) -> &js_sys::Uint8Array;
578}
579
580/// Generates Dispatch types for each of the interfaces. Each type is a wrapper around the
581/// wgpu_core and webgpu types, and derefs to the appropriate interface trait-object.
582///
583/// When there is only one backend, devirtualization fires and all dispatches should turn into
584/// direct calls. If there are multiple, some dispatching will occur.
585///
586/// This also provides `as_*` methods so that the backend implementations can dereference other
587/// arguments. These are similarly free when there is only one backend.
588///
589/// In the future, we may want a truly generic backend, which could be extended from this enum.
590macro_rules! dispatch_types {
591    (
592        ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
593    ) => {
594        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
595        pub enum $name {
596            #[cfg(wgpu_core)]
597            Core(Arc<$core_type>),
598            #[cfg(webgpu)]
599            WebGPU($webgpu_type),
600            #[allow(clippy::allow_attributes, private_interfaces)]
601            #[cfg(custom)]
602            Custom($custom_type),
603        }
604
605        impl $name {
606            #[cfg(wgpu_core)]
607            #[inline]
608            #[allow(clippy::allow_attributes, unused)]
609            pub fn as_core(&self) -> &$core_type {
610                match self {
611                    Self::Core(value) => value,
612                    _ => panic!(concat!(stringify!($name), " is not core")),
613                }
614            }
615
616            #[cfg(wgpu_core)]
617            #[inline]
618            #[allow(clippy::allow_attributes, unused)]
619            pub fn as_core_opt(&self) -> Option<&$core_type> {
620                match self {
621                    Self::Core(value) => Some(value),
622                    _ => None,
623                }
624            }
625
626            #[cfg(custom)]
627            #[inline]
628            #[allow(clippy::allow_attributes, unused)]
629            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
630                match self {
631                    Self::Custom(value) => value.downcast(),
632                    _ => None,
633                }
634            }
635
636            #[cfg(webgpu)]
637            #[inline]
638            #[allow(clippy::allow_attributes, unused)]
639            pub fn as_webgpu(&self) -> &$webgpu_type {
640                match self {
641                    Self::WebGPU(value) => value,
642                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
643                }
644            }
645
646            #[cfg(webgpu)]
647            #[inline]
648            #[allow(clippy::allow_attributes, unused)]
649            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
650                match self {
651                    Self::WebGPU(value) => Some(value),
652                    _ => None,
653                }
654            }
655
656            #[cfg(custom)]
657            #[inline]
658            pub fn custom<T: $interface>(t: T) -> Self {
659                Self::Custom($custom_type::new(t))
660            }
661        }
662
663        #[cfg(wgpu_core)]
664        impl From<$core_type> for $name {
665            #[inline]
666            fn from(value: $core_type) -> Self {
667                Self::Core(Arc::new(value))
668            }
669        }
670
671        #[cfg(webgpu)]
672        impl From<$webgpu_type> for $name {
673            #[inline]
674            fn from(value: $webgpu_type) -> Self {
675                Self::WebGPU(value)
676            }
677        }
678
679        impl core::ops::Deref for $name {
680            type Target = dyn $interface;
681
682            #[inline]
683            fn deref(&self) -> &Self::Target {
684                match self {
685                    #[cfg(wgpu_core)]
686                    Self::Core(value) => value.as_ref(),
687                    #[cfg(webgpu)]
688                    Self::WebGPU(value) => value,
689                    #[cfg(custom)]
690                    Self::Custom(value) => value.deref(),
691                    #[cfg(not(any(wgpu_core, webgpu)))]
692                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
693                }
694            }
695        }
696    };
697    (
698        mut type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
699    ) => {
700        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
701        pub enum $name {
702            #[cfg(wgpu_core)]
703            Core($core_type),
704            #[cfg(webgpu)]
705            WebGPU($webgpu_type),
706            #[allow(clippy::allow_attributes, private_interfaces)]
707            #[cfg(custom)]
708            Custom($custom_type),
709        }
710
711        impl $name {
712            #[cfg(wgpu_core)]
713            #[inline]
714            #[allow(clippy::allow_attributes, unused)]
715            pub fn as_core(&self) -> &$core_type {
716                match self {
717                    Self::Core(value) => value,
718                    _ => panic!(concat!(stringify!($name), " is not core")),
719                }
720            }
721
722            #[cfg(wgpu_core)]
723            #[inline]
724            #[allow(clippy::allow_attributes, unused)]
725            pub fn as_core_mut(&mut self) -> &mut $core_type {
726                match self {
727                    Self::Core(value) => value,
728                    _ => panic!(concat!(stringify!($name), " is not core")),
729                }
730            }
731
732            #[cfg(wgpu_core)]
733            #[inline]
734            #[allow(clippy::allow_attributes, unused)]
735            pub fn as_core_opt(&self) -> Option<&$core_type> {
736                match self {
737                    Self::Core(value) => Some(value),
738                    _ => None,
739                }
740            }
741
742            #[cfg(wgpu_core)]
743            #[inline]
744            #[allow(clippy::allow_attributes, unused)]
745            pub fn as_core_mut_opt(
746                &mut self,
747            ) -> Option<&mut $core_type> {
748                match self {
749                    Self::Core(value) => Some(value),
750                    _ => None,
751                }
752            }
753
754            #[cfg(custom)]
755            #[inline]
756            #[allow(clippy::allow_attributes, unused)]
757            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
758                match self {
759                    Self::Custom(value) => value.downcast(),
760                    _ => None,
761                }
762            }
763
764            #[cfg(webgpu)]
765            #[inline]
766            #[allow(clippy::allow_attributes, unused)]
767            pub fn as_webgpu(&self) -> &$webgpu_type {
768                match self {
769                    Self::WebGPU(value) => value,
770                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
771                }
772            }
773
774            #[cfg(webgpu)]
775            #[inline]
776            #[allow(clippy::allow_attributes, unused)]
777            pub fn as_webgpu_mut(&mut self) -> &mut $webgpu_type {
778                match self {
779                    Self::WebGPU(value) => value,
780                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
781                }
782            }
783
784            #[cfg(webgpu)]
785            #[inline]
786            #[allow(clippy::allow_attributes, unused)]
787            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
788                match self {
789                    Self::WebGPU(value) => Some(value),
790                    _ => None,
791                }
792            }
793
794            #[cfg(webgpu)]
795            #[inline]
796            #[allow(clippy::allow_attributes, unused)]
797            pub fn as_webgpu_mut_opt(
798                &mut self,
799            ) -> Option<&mut $webgpu_type> {
800                match self {
801                    Self::WebGPU(value) => Some(value),
802                    _ => None,
803                }
804            }
805
806            #[cfg(custom)]
807            #[inline]
808            pub fn custom<T: $interface>(t: T) -> Self {
809                Self::Custom($custom_type::new(t))
810            }
811        }
812
813        #[cfg(wgpu_core)]
814        impl From<$core_type> for $name {
815            #[inline]
816            fn from(value: $core_type) -> Self {
817                Self::Core(value)
818            }
819        }
820
821        #[cfg(webgpu)]
822        impl From<$webgpu_type> for $name {
823            #[inline]
824            fn from(value: $webgpu_type) -> Self {
825                Self::WebGPU(value)
826            }
827        }
828
829        impl core::ops::Deref for $name {
830            type Target = dyn $interface;
831
832            #[inline]
833            fn deref(&self) -> &Self::Target {
834                match self {
835                    #[cfg(wgpu_core)]
836                    Self::Core(value) => value,
837                    #[cfg(webgpu)]
838                    Self::WebGPU(value) => value,
839                    #[cfg(custom)]
840                    Self::Custom(value) => value.deref(),
841                    #[cfg(not(any(wgpu_core, webgpu)))]
842                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
843                }
844            }
845        }
846
847        impl core::ops::DerefMut for $name {
848            #[inline]
849            fn deref_mut(&mut self) -> &mut Self::Target {
850                match self {
851                    #[cfg(wgpu_core)]
852                    Self::Core(value) => value,
853                    #[cfg(webgpu)]
854                    Self::WebGPU(value) => value,
855                    #[cfg(custom)]
856                    Self::Custom(value) => value.deref_mut(),
857                    #[cfg(not(any(wgpu_core, webgpu)))]
858                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
859                }
860            }
861        }
862    };
863}
864
865dispatch_types! {ref type DispatchInstance: InstanceInterface = ContextWgpuCore, ContextWebGpu, DynContext}
866dispatch_types! {ref type DispatchAdapter: AdapterInterface = CoreAdapter, WebAdapter, DynAdapter}
867dispatch_types! {ref type DispatchDevice: DeviceInterface = CoreDevice, WebDevice, DynDevice}
868dispatch_types! {ref type DispatchQueue: QueueInterface = CoreQueue, WebQueue, DynQueue}
869dispatch_types! {ref type DispatchShaderModule: ShaderModuleInterface = CoreShaderModule, WebShaderModule, DynShaderModule}
870dispatch_types! {ref type DispatchBindGroupLayout: BindGroupLayoutInterface = CoreBindGroupLayout, WebBindGroupLayout, DynBindGroupLayout}
871dispatch_types! {ref type DispatchBindGroup: BindGroupInterface = CoreBindGroup, WebBindGroup, DynBindGroup}
872dispatch_types! {ref type DispatchTextureView: TextureViewInterface = CoreTextureView, WebTextureView, DynTextureView}
873dispatch_types! {ref type DispatchSampler: SamplerInterface = CoreSampler, WebSampler, DynSampler}
874dispatch_types! {ref type DispatchBuffer: BufferInterface = CoreBuffer, WebBuffer, DynBuffer}
875dispatch_types! {ref type DispatchTexture: TextureInterface = CoreTexture, WebTexture, DynTexture}
876dispatch_types! {ref type DispatchExternalTexture: ExternalTextureInterface = CoreExternalTexture, WebExternalTexture, DynExternalTexture}
877dispatch_types! {ref type DispatchBlas: BlasInterface = CoreBlas, WebBlas, DynBlas}
878dispatch_types! {ref type DispatchTlas: TlasInterface = CoreTlas, WebTlas, DynTlas}
879dispatch_types! {ref type DispatchQuerySet: QuerySetInterface = CoreQuerySet, WebQuerySet, DynQuerySet}
880dispatch_types! {ref type DispatchPipelineLayout: PipelineLayoutInterface = CorePipelineLayout, WebPipelineLayout, DynPipelineLayout}
881dispatch_types! {ref type DispatchRenderPipeline: RenderPipelineInterface = CoreRenderPipeline, WebRenderPipeline, DynRenderPipeline}
882dispatch_types! {ref type DispatchComputePipeline: ComputePipelineInterface = CoreComputePipeline, WebComputePipeline, DynComputePipeline}
883dispatch_types! {ref type DispatchPipelineCache: PipelineCacheInterface = CorePipelineCache, WebPipelineCache, DynPipelineCache}
884dispatch_types! {mut type DispatchCommandEncoder: CommandEncoderInterface = CoreCommandEncoder, WebCommandEncoder, DynCommandEncoder}
885dispatch_types! {mut type DispatchComputePass: ComputePassInterface = CoreComputePass, WebComputePassEncoder, DynComputePass}
886dispatch_types! {mut type DispatchRenderPass: RenderPassInterface = CoreRenderPass, WebRenderPassEncoder, DynRenderPass}
887dispatch_types! {mut type DispatchCommandBuffer: CommandBufferInterface = CoreCommandBuffer, WebCommandBuffer, DynCommandBuffer}
888dispatch_types! {mut type DispatchRenderBundleEncoder: RenderBundleEncoderInterface = CoreRenderBundleEncoder, WebRenderBundleEncoder, DynRenderBundleEncoder}
889dispatch_types! {ref type DispatchRenderBundle: RenderBundleInterface = CoreRenderBundle, WebRenderBundle, DynRenderBundle}
890dispatch_types! {ref type DispatchSurface: SurfaceInterface = CoreSurface, WebSurface, DynSurface}
891dispatch_types! {ref type DispatchSurfaceOutputDetail: SurfaceOutputDetailInterface = CoreSurfaceOutputDetail, WebSurfaceOutputDetail, DynSurfaceOutputDetail}
892dispatch_types! {mut type DispatchQueueWriteBuffer: QueueWriteBufferInterface = CoreQueueWriteBuffer, WebQueueWriteBuffer, DynQueueWriteBuffer}
893dispatch_types! {mut type DispatchBufferMappedRange: BufferMappedRangeInterface = CoreBufferMappedRange, WebBufferMappedRange, DynBufferMappedRange}