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    fn cooperative_matrix_properties(&self) -> Vec<crate::wgt::CooperativeMatrixProperties>;
129}
130
131pub trait DeviceInterface: CommonTraits {
132    fn features(&self) -> crate::Features;
133    fn limits(&self) -> crate::Limits;
134    fn adapter_info(&self) -> crate::AdapterInfo;
135
136    fn create_shader_module(
137        &self,
138        desc: crate::ShaderModuleDescriptor<'_>,
139        shader_bound_checks: crate::ShaderRuntimeChecks,
140    ) -> DispatchShaderModule;
141
142    unsafe fn create_shader_module_passthrough(
143        &self,
144        desc: &crate::ShaderModuleDescriptorPassthrough<'_>,
145    ) -> DispatchShaderModule;
146
147    fn create_bind_group_layout(
148        &self,
149        desc: &crate::BindGroupLayoutDescriptor<'_>,
150    ) -> DispatchBindGroupLayout;
151    fn create_bind_group(&self, desc: &crate::BindGroupDescriptor<'_>) -> DispatchBindGroup;
152    fn create_pipeline_layout(
153        &self,
154        desc: &crate::PipelineLayoutDescriptor<'_>,
155    ) -> DispatchPipelineLayout;
156    fn create_render_pipeline(
157        &self,
158        desc: &crate::RenderPipelineDescriptor<'_>,
159    ) -> DispatchRenderPipeline;
160    fn create_mesh_pipeline(
161        &self,
162        desc: &crate::MeshPipelineDescriptor<'_>,
163    ) -> DispatchRenderPipeline;
164    fn create_compute_pipeline(
165        &self,
166        desc: &crate::ComputePipelineDescriptor<'_>,
167    ) -> DispatchComputePipeline;
168    unsafe fn create_pipeline_cache(
169        &self,
170        desc: &crate::PipelineCacheDescriptor<'_>,
171    ) -> DispatchPipelineCache;
172    fn create_buffer(&self, desc: &crate::BufferDescriptor<'_>) -> DispatchBuffer;
173    fn create_texture(&self, desc: &crate::TextureDescriptor<'_>) -> DispatchTexture;
174    fn create_external_texture(
175        &self,
176        desc: &crate::ExternalTextureDescriptor<'_>,
177        planes: &[&crate::TextureView],
178    ) -> DispatchExternalTexture;
179    fn create_blas(
180        &self,
181        desc: &crate::CreateBlasDescriptor<'_>,
182        sizes: crate::BlasGeometrySizeDescriptors,
183    ) -> (Option<u64>, DispatchBlas);
184    fn create_tlas(&self, desc: &crate::CreateTlasDescriptor<'_>) -> DispatchTlas;
185    fn create_sampler(&self, desc: &crate::SamplerDescriptor<'_>) -> DispatchSampler;
186    fn create_query_set(&self, desc: &crate::QuerySetDescriptor<'_>) -> DispatchQuerySet;
187    fn create_command_encoder(
188        &self,
189        desc: &crate::CommandEncoderDescriptor<'_>,
190    ) -> DispatchCommandEncoder;
191    fn create_render_bundle_encoder(
192        &self,
193        desc: &crate::RenderBundleEncoderDescriptor<'_>,
194    ) -> DispatchRenderBundleEncoder;
195
196    fn set_device_lost_callback(&self, device_lost_callback: BoxDeviceLostCallback);
197
198    fn on_uncaptured_error(&self, handler: Arc<dyn crate::UncapturedErrorHandler>);
199    // Returns index on the stack of the pushed error scope.
200    fn push_error_scope(&self, filter: crate::ErrorFilter) -> u32;
201    fn pop_error_scope(&self, index: u32) -> Pin<Box<dyn PopErrorScopeFuture>>;
202
203    unsafe fn start_graphics_debugger_capture(&self);
204    unsafe fn stop_graphics_debugger_capture(&self);
205
206    fn poll(&self, poll_type: wgt::PollType<u64>) -> Result<crate::PollStatus, crate::PollError>;
207
208    fn get_internal_counters(&self) -> crate::InternalCounters;
209    fn generate_allocator_report(&self) -> Option<crate::AllocatorReport>;
210
211    fn destroy(&self);
212}
213
214pub trait QueueInterface: CommonTraits {
215    fn write_buffer(&self, buffer: &DispatchBuffer, offset: crate::BufferAddress, data: &[u8]);
216
217    fn create_staging_buffer(&self, size: crate::BufferSize) -> Option<DispatchQueueWriteBuffer>;
218    fn validate_write_buffer(
219        &self,
220        buffer: &DispatchBuffer,
221        offset: crate::BufferAddress,
222        size: crate::BufferSize,
223    ) -> Option<()>;
224    fn write_staging_buffer(
225        &self,
226        buffer: &DispatchBuffer,
227        offset: crate::BufferAddress,
228        staging_buffer: &DispatchQueueWriteBuffer,
229    );
230
231    fn write_texture(
232        &self,
233        texture: crate::TexelCopyTextureInfo<'_>,
234        data: &[u8],
235        data_layout: crate::TexelCopyBufferLayout,
236        size: crate::Extent3d,
237    );
238    #[cfg(web)]
239    fn copy_external_image_to_texture(
240        &self,
241        source: &crate::CopyExternalImageSourceInfo,
242        dest: crate::CopyExternalImageDestInfo<&crate::api::Texture>,
243        size: crate::Extent3d,
244    );
245
246    /// Submit must always drain the iterator, even in the case of error.
247    fn submit(&self, command_buffers: &mut dyn Iterator<Item = DispatchCommandBuffer>) -> u64;
248
249    fn get_timestamp_period(&self) -> f32;
250    fn on_submitted_work_done(&self, callback: BoxSubmittedWorkDoneCallback);
251
252    fn compact_blas(&self, blas: &DispatchBlas) -> (Option<u64>, DispatchBlas);
253}
254
255pub trait ShaderModuleInterface: CommonTraits {
256    fn get_compilation_info(&self) -> Pin<Box<dyn ShaderCompilationInfoFuture>>;
257}
258pub trait BindGroupLayoutInterface: CommonTraits {}
259pub trait BindGroupInterface: CommonTraits {}
260pub trait TextureViewInterface: CommonTraits {}
261pub trait SamplerInterface: CommonTraits {}
262pub trait BufferInterface: CommonTraits {
263    fn map_async(
264        &self,
265        mode: crate::MapMode,
266        range: Range<crate::BufferAddress>,
267        callback: BufferMapCallback,
268    );
269    fn get_mapped_range(&self, sub_range: Range<crate::BufferAddress>)
270        -> DispatchBufferMappedRange;
271
272    fn unmap(&self);
273
274    fn destroy(&self);
275}
276pub trait TextureInterface: CommonTraits {
277    fn create_view(&self, desc: &crate::TextureViewDescriptor<'_>) -> DispatchTextureView;
278
279    fn destroy(&self);
280}
281pub trait ExternalTextureInterface: CommonTraits {
282    fn destroy(&self);
283}
284pub trait BlasInterface: CommonTraits {
285    fn prepare_compact_async(&self, callback: BlasCompactCallback);
286    fn ready_for_compaction(&self) -> bool;
287}
288pub trait TlasInterface: CommonTraits {}
289pub trait QuerySetInterface: CommonTraits {}
290pub trait PipelineLayoutInterface: CommonTraits {}
291pub trait RenderPipelineInterface: CommonTraits {
292    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
293}
294pub trait ComputePipelineInterface: CommonTraits {
295    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
296}
297pub trait PipelineCacheInterface: CommonTraits {
298    fn get_data(&self) -> Option<Vec<u8>>;
299}
300pub trait CommandEncoderInterface: CommonTraits {
301    fn copy_buffer_to_buffer(
302        &self,
303        source: &DispatchBuffer,
304        source_offset: crate::BufferAddress,
305        destination: &DispatchBuffer,
306        destination_offset: crate::BufferAddress,
307        copy_size: Option<crate::BufferAddress>,
308    );
309    fn copy_buffer_to_texture(
310        &self,
311        source: crate::TexelCopyBufferInfo<'_>,
312        destination: crate::TexelCopyTextureInfo<'_>,
313        copy_size: crate::Extent3d,
314    );
315    fn copy_texture_to_buffer(
316        &self,
317        source: crate::TexelCopyTextureInfo<'_>,
318        destination: crate::TexelCopyBufferInfo<'_>,
319        copy_size: crate::Extent3d,
320    );
321    fn copy_texture_to_texture(
322        &self,
323        source: crate::TexelCopyTextureInfo<'_>,
324        destination: crate::TexelCopyTextureInfo<'_>,
325        copy_size: crate::Extent3d,
326    );
327
328    fn begin_compute_pass(&self, desc: &crate::ComputePassDescriptor<'_>) -> DispatchComputePass;
329    fn begin_render_pass(&self, desc: &crate::RenderPassDescriptor<'_>) -> DispatchRenderPass;
330    fn finish(&mut self) -> DispatchCommandBuffer;
331
332    fn clear_texture(
333        &self,
334        texture: &DispatchTexture,
335        subresource_range: &crate::ImageSubresourceRange,
336    );
337    fn clear_buffer(
338        &self,
339        buffer: &DispatchBuffer,
340        offset: crate::BufferAddress,
341        size: Option<crate::BufferAddress>,
342    );
343
344    fn insert_debug_marker(&self, label: &str);
345    fn push_debug_group(&self, label: &str);
346    fn pop_debug_group(&self);
347
348    fn write_timestamp(&self, query_set: &DispatchQuerySet, query_index: u32);
349    fn resolve_query_set(
350        &self,
351        query_set: &DispatchQuerySet,
352        first_query: u32,
353        query_count: u32,
354        destination: &DispatchBuffer,
355        destination_offset: crate::BufferAddress,
356    );
357    fn mark_acceleration_structures_built<'a>(
358        &self,
359        blas: &mut dyn Iterator<Item = &'a Blas>,
360        tlas: &mut dyn Iterator<Item = &'a Tlas>,
361    );
362
363    fn build_acceleration_structures<'a>(
364        &self,
365        blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
366        tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
367    );
368
369    fn transition_resources<'a>(
370        &mut self,
371        buffer_transitions: &mut dyn Iterator<Item = wgt::BufferTransition<&'a DispatchBuffer>>,
372        texture_transitions: &mut dyn Iterator<Item = wgt::TextureTransition<&'a DispatchTexture>>,
373    );
374}
375pub trait ComputePassInterface: CommonTraits + Drop {
376    fn set_pipeline(&mut self, pipeline: &DispatchComputePipeline);
377    fn set_bind_group(
378        &mut self,
379        index: u32,
380        bind_group: Option<&DispatchBindGroup>,
381        offsets: &[crate::DynamicOffset],
382    );
383    fn set_immediates(&mut self, offset: u32, data: &[u8]);
384
385    fn insert_debug_marker(&mut self, label: &str);
386    fn push_debug_group(&mut self, group_label: &str);
387    fn pop_debug_group(&mut self);
388
389    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
390    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
391    fn end_pipeline_statistics_query(&mut self);
392
393    fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32);
394    fn dispatch_workgroups_indirect(
395        &mut self,
396        indirect_buffer: &DispatchBuffer,
397        indirect_offset: crate::BufferAddress,
398    );
399}
400pub trait RenderPassInterface: CommonTraits + Drop {
401    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
402    fn set_bind_group(
403        &mut self,
404        index: u32,
405        bind_group: Option<&DispatchBindGroup>,
406        offsets: &[crate::DynamicOffset],
407    );
408    fn set_index_buffer(
409        &mut self,
410        buffer: &DispatchBuffer,
411        index_format: crate::IndexFormat,
412        offset: crate::BufferAddress,
413        size: Option<crate::BufferSize>,
414    );
415    fn set_vertex_buffer(
416        &mut self,
417        slot: u32,
418        buffer: &DispatchBuffer,
419        offset: crate::BufferAddress,
420        size: Option<crate::BufferSize>,
421    );
422    fn set_immediates(&mut self, offset: u32, data: &[u8]);
423    fn set_blend_constant(&mut self, color: crate::Color);
424    fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
425    fn set_viewport(
426        &mut self,
427        x: f32,
428        y: f32,
429        width: f32,
430        height: f32,
431        min_depth: f32,
432        max_depth: f32,
433    );
434    fn set_stencil_reference(&mut self, reference: u32);
435
436    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
437    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
438    fn draw_mesh_tasks(&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32);
439    fn draw_indirect(
440        &mut self,
441        indirect_buffer: &DispatchBuffer,
442        indirect_offset: crate::BufferAddress,
443    );
444    fn draw_indexed_indirect(
445        &mut self,
446        indirect_buffer: &DispatchBuffer,
447        indirect_offset: crate::BufferAddress,
448    );
449    fn draw_mesh_tasks_indirect(
450        &mut self,
451        indirect_buffer: &DispatchBuffer,
452        indirect_offset: crate::BufferAddress,
453    );
454
455    fn multi_draw_indirect(
456        &mut self,
457        indirect_buffer: &DispatchBuffer,
458        indirect_offset: crate::BufferAddress,
459        count: u32,
460    );
461    fn multi_draw_indexed_indirect(
462        &mut self,
463        indirect_buffer: &DispatchBuffer,
464        indirect_offset: crate::BufferAddress,
465        count: u32,
466    );
467    fn multi_draw_indirect_count(
468        &mut self,
469        indirect_buffer: &DispatchBuffer,
470        indirect_offset: crate::BufferAddress,
471        count_buffer: &DispatchBuffer,
472        count_buffer_offset: crate::BufferAddress,
473        max_count: u32,
474    );
475    fn multi_draw_mesh_tasks_indirect(
476        &mut self,
477        indirect_buffer: &DispatchBuffer,
478        indirect_offset: crate::BufferAddress,
479        count: u32,
480    );
481    fn multi_draw_indexed_indirect_count(
482        &mut self,
483        indirect_buffer: &DispatchBuffer,
484        indirect_offset: crate::BufferAddress,
485        count_buffer: &DispatchBuffer,
486        count_buffer_offset: crate::BufferAddress,
487        max_count: u32,
488    );
489    fn multi_draw_mesh_tasks_indirect_count(
490        &mut self,
491        indirect_buffer: &DispatchBuffer,
492        indirect_offset: crate::BufferAddress,
493        count_buffer: &DispatchBuffer,
494        count_buffer_offset: crate::BufferAddress,
495        max_count: u32,
496    );
497
498    fn insert_debug_marker(&mut self, label: &str);
499    fn push_debug_group(&mut self, group_label: &str);
500    fn pop_debug_group(&mut self);
501
502    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
503    fn begin_occlusion_query(&mut self, query_index: u32);
504    fn end_occlusion_query(&mut self);
505    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
506    fn end_pipeline_statistics_query(&mut self);
507
508    fn execute_bundles(&mut self, render_bundles: &mut dyn Iterator<Item = &DispatchRenderBundle>);
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, 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}