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