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