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    fn push_error_scope(&self, filter: crate::ErrorFilter);
197    fn pop_error_scope(&self) -> Pin<Box<dyn PopErrorScopeFuture>>;
198
199    unsafe fn start_graphics_debugger_capture(&self);
200    unsafe fn stop_graphics_debugger_capture(&self);
201
202    fn poll(&self, poll_type: wgt::PollType<u64>) -> Result<crate::PollStatus, crate::PollError>;
203
204    fn get_internal_counters(&self) -> crate::InternalCounters;
205    fn generate_allocator_report(&self) -> Option<crate::AllocatorReport>;
206
207    fn destroy(&self);
208}
209
210pub trait QueueInterface: CommonTraits {
211    fn write_buffer(&self, buffer: &DispatchBuffer, offset: crate::BufferAddress, data: &[u8]);
212
213    fn create_staging_buffer(&self, size: crate::BufferSize) -> Option<DispatchQueueWriteBuffer>;
214    fn validate_write_buffer(
215        &self,
216        buffer: &DispatchBuffer,
217        offset: crate::BufferAddress,
218        size: crate::BufferSize,
219    ) -> Option<()>;
220    fn write_staging_buffer(
221        &self,
222        buffer: &DispatchBuffer,
223        offset: crate::BufferAddress,
224        staging_buffer: &DispatchQueueWriteBuffer,
225    );
226
227    fn write_texture(
228        &self,
229        texture: crate::TexelCopyTextureInfo<'_>,
230        data: &[u8],
231        data_layout: crate::TexelCopyBufferLayout,
232        size: crate::Extent3d,
233    );
234    #[cfg(web)]
235    fn copy_external_image_to_texture(
236        &self,
237        source: &crate::CopyExternalImageSourceInfo,
238        dest: crate::CopyExternalImageDestInfo<&crate::api::Texture>,
239        size: crate::Extent3d,
240    );
241
242    /// Submit must always drain the iterator, even in the case of error.
243    fn submit(&self, command_buffers: &mut dyn Iterator<Item = DispatchCommandBuffer>) -> u64;
244
245    fn get_timestamp_period(&self) -> f32;
246    fn on_submitted_work_done(&self, callback: BoxSubmittedWorkDoneCallback);
247
248    fn compact_blas(&self, blas: &DispatchBlas) -> (Option<u64>, DispatchBlas);
249}
250
251pub trait ShaderModuleInterface: CommonTraits {
252    fn get_compilation_info(&self) -> Pin<Box<dyn ShaderCompilationInfoFuture>>;
253}
254pub trait BindGroupLayoutInterface: CommonTraits {}
255pub trait BindGroupInterface: CommonTraits {}
256pub trait TextureViewInterface: CommonTraits {}
257pub trait SamplerInterface: CommonTraits {}
258pub trait BufferInterface: CommonTraits {
259    fn map_async(
260        &self,
261        mode: crate::MapMode,
262        range: Range<crate::BufferAddress>,
263        callback: BufferMapCallback,
264    );
265    fn get_mapped_range(&self, sub_range: Range<crate::BufferAddress>)
266        -> DispatchBufferMappedRange;
267
268    fn unmap(&self);
269
270    fn destroy(&self);
271}
272pub trait TextureInterface: CommonTraits {
273    fn create_view(&self, desc: &crate::TextureViewDescriptor<'_>) -> DispatchTextureView;
274
275    fn destroy(&self);
276}
277pub trait ExternalTextureInterface: CommonTraits {
278    fn destroy(&self);
279}
280pub trait BlasInterface: CommonTraits {
281    fn prepare_compact_async(&self, callback: BlasCompactCallback);
282    fn ready_for_compaction(&self) -> bool;
283}
284pub trait TlasInterface: CommonTraits {}
285pub trait QuerySetInterface: CommonTraits {}
286pub trait PipelineLayoutInterface: CommonTraits {}
287pub trait RenderPipelineInterface: CommonTraits {
288    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
289}
290pub trait ComputePipelineInterface: CommonTraits {
291    fn get_bind_group_layout(&self, index: u32) -> DispatchBindGroupLayout;
292}
293pub trait PipelineCacheInterface: CommonTraits {
294    fn get_data(&self) -> Option<Vec<u8>>;
295}
296pub trait CommandEncoderInterface: CommonTraits {
297    fn copy_buffer_to_buffer(
298        &self,
299        source: &DispatchBuffer,
300        source_offset: crate::BufferAddress,
301        destination: &DispatchBuffer,
302        destination_offset: crate::BufferAddress,
303        copy_size: Option<crate::BufferAddress>,
304    );
305    fn copy_buffer_to_texture(
306        &self,
307        source: crate::TexelCopyBufferInfo<'_>,
308        destination: crate::TexelCopyTextureInfo<'_>,
309        copy_size: crate::Extent3d,
310    );
311    fn copy_texture_to_buffer(
312        &self,
313        source: crate::TexelCopyTextureInfo<'_>,
314        destination: crate::TexelCopyBufferInfo<'_>,
315        copy_size: crate::Extent3d,
316    );
317    fn copy_texture_to_texture(
318        &self,
319        source: crate::TexelCopyTextureInfo<'_>,
320        destination: crate::TexelCopyTextureInfo<'_>,
321        copy_size: crate::Extent3d,
322    );
323
324    fn begin_compute_pass(&self, desc: &crate::ComputePassDescriptor<'_>) -> DispatchComputePass;
325    fn begin_render_pass(&self, desc: &crate::RenderPassDescriptor<'_>) -> DispatchRenderPass;
326    fn finish(&mut self) -> DispatchCommandBuffer;
327
328    fn clear_texture(
329        &self,
330        texture: &DispatchTexture,
331        subresource_range: &crate::ImageSubresourceRange,
332    );
333    fn clear_buffer(
334        &self,
335        buffer: &DispatchBuffer,
336        offset: crate::BufferAddress,
337        size: Option<crate::BufferAddress>,
338    );
339
340    fn insert_debug_marker(&self, label: &str);
341    fn push_debug_group(&self, label: &str);
342    fn pop_debug_group(&self);
343
344    fn write_timestamp(&self, query_set: &DispatchQuerySet, query_index: u32);
345    fn resolve_query_set(
346        &self,
347        query_set: &DispatchQuerySet,
348        first_query: u32,
349        query_count: u32,
350        destination: &DispatchBuffer,
351        destination_offset: crate::BufferAddress,
352    );
353    fn mark_acceleration_structures_built<'a>(
354        &self,
355        blas: &mut dyn Iterator<Item = &'a Blas>,
356        tlas: &mut dyn Iterator<Item = &'a Tlas>,
357    );
358
359    fn build_acceleration_structures<'a>(
360        &self,
361        blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
362        tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
363    );
364
365    fn transition_resources<'a>(
366        &mut self,
367        buffer_transitions: &mut dyn Iterator<Item = wgt::BufferTransition<&'a DispatchBuffer>>,
368        texture_transitions: &mut dyn Iterator<Item = wgt::TextureTransition<&'a DispatchTexture>>,
369    );
370}
371pub trait ComputePassInterface: CommonTraits {
372    fn set_pipeline(&mut self, pipeline: &DispatchComputePipeline);
373    fn set_bind_group(
374        &mut self,
375        index: u32,
376        bind_group: Option<&DispatchBindGroup>,
377        offsets: &[crate::DynamicOffset],
378    );
379    fn set_push_constants(&mut self, offset: u32, data: &[u8]);
380
381    fn insert_debug_marker(&mut self, label: &str);
382    fn push_debug_group(&mut self, group_label: &str);
383    fn pop_debug_group(&mut self);
384
385    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
386    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
387    fn end_pipeline_statistics_query(&mut self);
388
389    fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32);
390    fn dispatch_workgroups_indirect(
391        &mut self,
392        indirect_buffer: &DispatchBuffer,
393        indirect_offset: crate::BufferAddress,
394    );
395    fn end(&mut self);
396}
397pub trait RenderPassInterface: CommonTraits {
398    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
399    fn set_bind_group(
400        &mut self,
401        index: u32,
402        bind_group: Option<&DispatchBindGroup>,
403        offsets: &[crate::DynamicOffset],
404    );
405    fn set_index_buffer(
406        &mut self,
407        buffer: &DispatchBuffer,
408        index_format: crate::IndexFormat,
409        offset: crate::BufferAddress,
410        size: Option<crate::BufferSize>,
411    );
412    fn set_vertex_buffer(
413        &mut self,
414        slot: u32,
415        buffer: &DispatchBuffer,
416        offset: crate::BufferAddress,
417        size: Option<crate::BufferSize>,
418    );
419    fn set_push_constants(&mut self, stages: crate::ShaderStages, offset: u32, data: &[u8]);
420    fn set_blend_constant(&mut self, color: crate::Color);
421    fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
422    fn set_viewport(
423        &mut self,
424        x: f32,
425        y: f32,
426        width: f32,
427        height: f32,
428        min_depth: f32,
429        max_depth: f32,
430    );
431    fn set_stencil_reference(&mut self, reference: u32);
432
433    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
434    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
435    fn draw_mesh_tasks(&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32);
436    fn draw_indirect(
437        &mut self,
438        indirect_buffer: &DispatchBuffer,
439        indirect_offset: crate::BufferAddress,
440    );
441    fn draw_indexed_indirect(
442        &mut self,
443        indirect_buffer: &DispatchBuffer,
444        indirect_offset: crate::BufferAddress,
445    );
446    fn draw_mesh_tasks_indirect(
447        &mut self,
448        indirect_buffer: &DispatchBuffer,
449        indirect_offset: crate::BufferAddress,
450    );
451
452    fn multi_draw_indirect(
453        &mut self,
454        indirect_buffer: &DispatchBuffer,
455        indirect_offset: crate::BufferAddress,
456        count: u32,
457    );
458    fn multi_draw_indexed_indirect(
459        &mut self,
460        indirect_buffer: &DispatchBuffer,
461        indirect_offset: crate::BufferAddress,
462        count: u32,
463    );
464    fn multi_draw_indirect_count(
465        &mut self,
466        indirect_buffer: &DispatchBuffer,
467        indirect_offset: crate::BufferAddress,
468        count_buffer: &DispatchBuffer,
469        count_buffer_offset: crate::BufferAddress,
470        max_count: u32,
471    );
472    fn multi_draw_mesh_tasks_indirect(
473        &mut self,
474        indirect_buffer: &DispatchBuffer,
475        indirect_offset: crate::BufferAddress,
476        count: u32,
477    );
478    fn multi_draw_indexed_indirect_count(
479        &mut self,
480        indirect_buffer: &DispatchBuffer,
481        indirect_offset: crate::BufferAddress,
482        count_buffer: &DispatchBuffer,
483        count_buffer_offset: crate::BufferAddress,
484        max_count: u32,
485    );
486    fn multi_draw_mesh_tasks_indirect_count(
487        &mut self,
488        indirect_buffer: &DispatchBuffer,
489        indirect_offset: crate::BufferAddress,
490        count_buffer: &DispatchBuffer,
491        count_buffer_offset: crate::BufferAddress,
492        max_count: u32,
493    );
494
495    fn insert_debug_marker(&mut self, label: &str);
496    fn push_debug_group(&mut self, group_label: &str);
497    fn pop_debug_group(&mut self);
498
499    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
500    fn begin_occlusion_query(&mut self, query_index: u32);
501    fn end_occlusion_query(&mut self);
502    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
503    fn end_pipeline_statistics_query(&mut self);
504
505    fn execute_bundles(&mut self, render_bundles: &mut dyn Iterator<Item = &DispatchRenderBundle>);
506
507    fn end(&mut self);
508}
509
510pub trait RenderBundleEncoderInterface: CommonTraits {
511    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
512    fn set_bind_group(
513        &mut self,
514        index: u32,
515        bind_group: Option<&DispatchBindGroup>,
516        offsets: &[crate::DynamicOffset],
517    );
518    fn set_index_buffer(
519        &mut self,
520        buffer: &DispatchBuffer,
521        index_format: crate::IndexFormat,
522        offset: crate::BufferAddress,
523        size: Option<crate::BufferSize>,
524    );
525    fn set_vertex_buffer(
526        &mut self,
527        slot: u32,
528        buffer: &DispatchBuffer,
529        offset: crate::BufferAddress,
530        size: Option<crate::BufferSize>,
531    );
532    fn set_push_constants(&mut self, stages: crate::ShaderStages, offset: u32, data: &[u8]);
533
534    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
535    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
536    fn draw_indirect(
537        &mut self,
538        indirect_buffer: &DispatchBuffer,
539        indirect_offset: crate::BufferAddress,
540    );
541    fn draw_indexed_indirect(
542        &mut self,
543        indirect_buffer: &DispatchBuffer,
544        indirect_offset: crate::BufferAddress,
545    );
546
547    fn finish(self, desc: &crate::RenderBundleDescriptor<'_>) -> DispatchRenderBundle
548    where
549        Self: Sized;
550}
551
552pub trait CommandBufferInterface: CommonTraits {}
553pub trait RenderBundleInterface: CommonTraits {}
554
555pub trait SurfaceInterface: CommonTraits {
556    fn get_capabilities(&self, adapter: &DispatchAdapter) -> crate::SurfaceCapabilities;
557
558    fn configure(&self, device: &DispatchDevice, config: &crate::SurfaceConfiguration);
559    fn get_current_texture(
560        &self,
561    ) -> (
562        Option<DispatchTexture>,
563        crate::SurfaceStatus,
564        DispatchSurfaceOutputDetail,
565    );
566}
567
568pub trait SurfaceOutputDetailInterface: CommonTraits {
569    fn present(&self);
570    fn texture_discard(&self);
571}
572
573pub trait QueueWriteBufferInterface: CommonTraits {
574    fn slice(&self) -> &[u8];
575
576    fn slice_mut(&mut self) -> &mut [u8];
577}
578
579pub trait BufferMappedRangeInterface: CommonTraits {
580    fn slice(&self) -> &[u8];
581    fn slice_mut(&mut self) -> &mut [u8];
582
583    #[cfg(webgpu)]
584    fn as_uint8array(&self) -> &js_sys::Uint8Array;
585}
586
587/// Generates a dispatch type for some `wgpu` API type.
588///
589/// Invocations of this macro take one of the following forms:
590///
591/// ```ignore
592/// dispatch_types! {mut type D: I = Core, Web, Dyn }
593/// dispatch_types! {ref type D: I = Core, Web, Dyn }
594/// ```
595///
596/// This defines `D` as a type that dereferences to a `dyn I` trait object. Most uses of
597/// `D` in the rest of this crate just call the methods from the `dyn I` object, not from
598/// `D` itself.
599///
600/// Internally, `D` is an enum with up to three variants holding values of type `Core`,
601/// `Web`, and `Dyn`, all of which must implement `I`. `Core`, `Web` and `Dyn` are the
602/// types from the `wgpu_core`, `webgpu`, and `custom` submodules of `wgpu::backend` that
603/// correspond to `D`. The macro generates `Deref` and `DerefMut` implementations that
604/// match on this enum and produce a `dyn I` reference for each variant.
605///
606/// The macro's `mut type` form defines `D` as the unique owner of the backend type, with
607/// a `DerefMut` implementation, and `as_*_mut` methods that return `&mut` references.
608/// This `D` does not implement `Clone`.
609///
610/// The macro's `ref type` form defines `D` to hold an `Arc` pointing to the backend type,
611/// permitting `Clone` and `Deref`, but losing exclusive, mutable access.
612///
613/// For example:
614///
615/// ```ignore
616/// dispatch_types! {ref type DispatchBuffer: BufferInterface =
617///                  CoreBuffer, WebBuffer, DynBuffer}
618/// ```
619///
620/// This defines `DispatchBuffer` as a type that dereferences to `&dyn BufferInterface`,
621/// which has methods like `map_async` and `destroy`. The enum would be:
622///
623/// ```ignore
624/// pub enum DispatchBuffer {
625///     #[cfg(wgpu_core)]
626///     Core(Arc<CoreBuffer>),
627///     #[cfg(webgpu)]
628///     WebGPU(WebBuffer),
629///     #[cfg(custom)]
630///     Custom(DynBuffer),
631/// }
632/// ```
633///
634/// This macro also defines `as_*` methods so that the backend implementations can
635/// dereference other arguments.
636///
637/// ## Devirtualization
638///
639/// The dispatch types generated by this macro are carefully designed to allow the
640/// compiler to completely devirtualize calls in most circumstances.
641///
642/// Note that every variant of the enum generated by this macro is under a `#[cfg]`.
643/// Naturally, the `match` expressions in the `Deref` and `DerefMut` implementations have
644/// matching `#[cfg]` attributes on each match arm.
645///
646/// In practice, when `wgpu`'s `"custom"` feature is not enabled, there is usually only
647/// one variant in the `enum`, making it effectively a newtype around the sole variant's
648/// data: it has no discriminant to branch on, and the `match` expressions are removed
649/// entirely by the compiler.
650///
651/// In this case, when we invoke a method from the interface trait `I` on a dispatch type,
652/// the `Deref` and `DerefMut` implementations' `match` statements build a `&dyn I` for
653/// the data, on which we immediately invoke a method. The vtable is a constant, allowing
654/// the Rust compiler to turn the `dyn` method call into an ordinary method call. This
655/// creates opportunities for inlining.
656///
657/// Similarly, the `as_*` methods are free when there is only one backend.
658macro_rules! dispatch_types {
659    (
660        ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
661    ) => {
662        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
663        pub enum $name {
664            #[cfg(wgpu_core)]
665            Core(Arc<$core_type>),
666            #[cfg(webgpu)]
667            WebGPU($webgpu_type),
668            #[allow(clippy::allow_attributes, private_interfaces)]
669            #[cfg(custom)]
670            Custom($custom_type),
671        }
672
673        impl $name {
674            #[cfg(wgpu_core)]
675            #[inline]
676            #[allow(clippy::allow_attributes, unused)]
677            pub fn as_core(&self) -> &$core_type {
678                match self {
679                    Self::Core(value) => value,
680                    _ => panic!(concat!(stringify!($name), " is not core")),
681                }
682            }
683
684            #[cfg(wgpu_core)]
685            #[inline]
686            #[allow(clippy::allow_attributes, unused)]
687            pub fn as_core_opt(&self) -> Option<&$core_type> {
688                match self {
689                    Self::Core(value) => Some(value),
690                    _ => None,
691                }
692            }
693
694            #[cfg(custom)]
695            #[inline]
696            #[allow(clippy::allow_attributes, unused)]
697            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
698                match self {
699                    Self::Custom(value) => value.downcast(),
700                    _ => None,
701                }
702            }
703
704            #[cfg(webgpu)]
705            #[inline]
706            #[allow(clippy::allow_attributes, unused)]
707            pub fn as_webgpu(&self) -> &$webgpu_type {
708                match self {
709                    Self::WebGPU(value) => value,
710                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
711                }
712            }
713
714            #[cfg(webgpu)]
715            #[inline]
716            #[allow(clippy::allow_attributes, unused)]
717            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
718                match self {
719                    Self::WebGPU(value) => Some(value),
720                    _ => None,
721                }
722            }
723
724            #[cfg(custom)]
725            #[inline]
726            pub fn custom<T: $interface>(t: T) -> Self {
727                Self::Custom($custom_type::new(t))
728            }
729        }
730
731        #[cfg(wgpu_core)]
732        impl From<$core_type> for $name {
733            #[inline]
734            fn from(value: $core_type) -> Self {
735                Self::Core(Arc::new(value))
736            }
737        }
738
739        #[cfg(webgpu)]
740        impl From<$webgpu_type> for $name {
741            #[inline]
742            fn from(value: $webgpu_type) -> Self {
743                Self::WebGPU(value)
744            }
745        }
746
747        impl core::ops::Deref for $name {
748            type Target = dyn $interface;
749
750            #[inline]
751            fn deref(&self) -> &Self::Target {
752                match self {
753                    #[cfg(wgpu_core)]
754                    Self::Core(value) => value.as_ref(),
755                    #[cfg(webgpu)]
756                    Self::WebGPU(value) => value,
757                    #[cfg(custom)]
758                    Self::Custom(value) => value.deref(),
759                    #[cfg(not(any(wgpu_core, webgpu)))]
760                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
761                }
762            }
763        }
764    };
765    (
766        mut type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
767    ) => {
768        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
769        pub enum $name {
770            #[cfg(wgpu_core)]
771            Core($core_type),
772            #[cfg(webgpu)]
773            WebGPU($webgpu_type),
774            #[allow(clippy::allow_attributes, private_interfaces)]
775            #[cfg(custom)]
776            Custom($custom_type),
777        }
778
779        impl $name {
780            #[cfg(wgpu_core)]
781            #[inline]
782            #[allow(clippy::allow_attributes, unused)]
783            pub fn as_core(&self) -> &$core_type {
784                match self {
785                    Self::Core(value) => value,
786                    _ => panic!(concat!(stringify!($name), " is not core")),
787                }
788            }
789
790            #[cfg(wgpu_core)]
791            #[inline]
792            #[allow(clippy::allow_attributes, unused)]
793            pub fn as_core_mut(&mut self) -> &mut $core_type {
794                match self {
795                    Self::Core(value) => value,
796                    _ => panic!(concat!(stringify!($name), " is not core")),
797                }
798            }
799
800            #[cfg(wgpu_core)]
801            #[inline]
802            #[allow(clippy::allow_attributes, unused)]
803            pub fn as_core_opt(&self) -> Option<&$core_type> {
804                match self {
805                    Self::Core(value) => Some(value),
806                    _ => None,
807                }
808            }
809
810            #[cfg(wgpu_core)]
811            #[inline]
812            #[allow(clippy::allow_attributes, unused)]
813            pub fn as_core_mut_opt(
814                &mut self,
815            ) -> Option<&mut $core_type> {
816                match self {
817                    Self::Core(value) => Some(value),
818                    _ => None,
819                }
820            }
821
822            #[cfg(custom)]
823            #[inline]
824            #[allow(clippy::allow_attributes, unused)]
825            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
826                match self {
827                    Self::Custom(value) => value.downcast(),
828                    _ => None,
829                }
830            }
831
832            #[cfg(webgpu)]
833            #[inline]
834            #[allow(clippy::allow_attributes, unused)]
835            pub fn as_webgpu(&self) -> &$webgpu_type {
836                match self {
837                    Self::WebGPU(value) => value,
838                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
839                }
840            }
841
842            #[cfg(webgpu)]
843            #[inline]
844            #[allow(clippy::allow_attributes, unused)]
845            pub fn as_webgpu_mut(&mut self) -> &mut $webgpu_type {
846                match self {
847                    Self::WebGPU(value) => value,
848                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
849                }
850            }
851
852            #[cfg(webgpu)]
853            #[inline]
854            #[allow(clippy::allow_attributes, unused)]
855            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
856                match self {
857                    Self::WebGPU(value) => Some(value),
858                    _ => None,
859                }
860            }
861
862            #[cfg(webgpu)]
863            #[inline]
864            #[allow(clippy::allow_attributes, unused)]
865            pub fn as_webgpu_mut_opt(
866                &mut self,
867            ) -> Option<&mut $webgpu_type> {
868                match self {
869                    Self::WebGPU(value) => Some(value),
870                    _ => None,
871                }
872            }
873
874            #[cfg(custom)]
875            #[inline]
876            pub fn custom<T: $interface>(t: T) -> Self {
877                Self::Custom($custom_type::new(t))
878            }
879        }
880
881        #[cfg(wgpu_core)]
882        impl From<$core_type> for $name {
883            #[inline]
884            fn from(value: $core_type) -> Self {
885                Self::Core(value)
886            }
887        }
888
889        #[cfg(webgpu)]
890        impl From<$webgpu_type> for $name {
891            #[inline]
892            fn from(value: $webgpu_type) -> Self {
893                Self::WebGPU(value)
894            }
895        }
896
897        impl core::ops::Deref for $name {
898            type Target = dyn $interface;
899
900            #[inline]
901            fn deref(&self) -> &Self::Target {
902                match self {
903                    #[cfg(wgpu_core)]
904                    Self::Core(value) => value,
905                    #[cfg(webgpu)]
906                    Self::WebGPU(value) => value,
907                    #[cfg(custom)]
908                    Self::Custom(value) => value.deref(),
909                    #[cfg(not(any(wgpu_core, webgpu)))]
910                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
911                }
912            }
913        }
914
915        impl core::ops::DerefMut for $name {
916            #[inline]
917            fn deref_mut(&mut self) -> &mut Self::Target {
918                match self {
919                    #[cfg(wgpu_core)]
920                    Self::Core(value) => value,
921                    #[cfg(webgpu)]
922                    Self::WebGPU(value) => value,
923                    #[cfg(custom)]
924                    Self::Custom(value) => value.deref_mut(),
925                    #[cfg(not(any(wgpu_core, webgpu)))]
926                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
927                }
928            }
929        }
930    };
931}
932
933dispatch_types! {ref type DispatchInstance: InstanceInterface = ContextWgpuCore, ContextWebGpu, DynContext}
934dispatch_types! {ref type DispatchAdapter: AdapterInterface = CoreAdapter, WebAdapter, DynAdapter}
935dispatch_types! {ref type DispatchDevice: DeviceInterface = CoreDevice, WebDevice, DynDevice}
936dispatch_types! {ref type DispatchQueue: QueueInterface = CoreQueue, WebQueue, DynQueue}
937dispatch_types! {ref type DispatchShaderModule: ShaderModuleInterface = CoreShaderModule, WebShaderModule, DynShaderModule}
938dispatch_types! {ref type DispatchBindGroupLayout: BindGroupLayoutInterface = CoreBindGroupLayout, WebBindGroupLayout, DynBindGroupLayout}
939dispatch_types! {ref type DispatchBindGroup: BindGroupInterface = CoreBindGroup, WebBindGroup, DynBindGroup}
940dispatch_types! {ref type DispatchTextureView: TextureViewInterface = CoreTextureView, WebTextureView, DynTextureView}
941dispatch_types! {ref type DispatchSampler: SamplerInterface = CoreSampler, WebSampler, DynSampler}
942dispatch_types! {ref type DispatchBuffer: BufferInterface = CoreBuffer, WebBuffer, DynBuffer}
943dispatch_types! {ref type DispatchTexture: TextureInterface = CoreTexture, WebTexture, DynTexture}
944dispatch_types! {ref type DispatchExternalTexture: ExternalTextureInterface = CoreExternalTexture, WebExternalTexture, DynExternalTexture}
945dispatch_types! {ref type DispatchBlas: BlasInterface = CoreBlas, WebBlas, DynBlas}
946dispatch_types! {ref type DispatchTlas: TlasInterface = CoreTlas, WebTlas, DynTlas}
947dispatch_types! {ref type DispatchQuerySet: QuerySetInterface = CoreQuerySet, WebQuerySet, DynQuerySet}
948dispatch_types! {ref type DispatchPipelineLayout: PipelineLayoutInterface = CorePipelineLayout, WebPipelineLayout, DynPipelineLayout}
949dispatch_types! {ref type DispatchRenderPipeline: RenderPipelineInterface = CoreRenderPipeline, WebRenderPipeline, DynRenderPipeline}
950dispatch_types! {ref type DispatchComputePipeline: ComputePipelineInterface = CoreComputePipeline, WebComputePipeline, DynComputePipeline}
951dispatch_types! {ref type DispatchPipelineCache: PipelineCacheInterface = CorePipelineCache, WebPipelineCache, DynPipelineCache}
952dispatch_types! {mut type DispatchCommandEncoder: CommandEncoderInterface = CoreCommandEncoder, WebCommandEncoder, DynCommandEncoder}
953dispatch_types! {mut type DispatchComputePass: ComputePassInterface = CoreComputePass, WebComputePassEncoder, DynComputePass}
954dispatch_types! {mut type DispatchRenderPass: RenderPassInterface = CoreRenderPass, WebRenderPassEncoder, DynRenderPass}
955dispatch_types! {mut type DispatchCommandBuffer: CommandBufferInterface = CoreCommandBuffer, WebCommandBuffer, DynCommandBuffer}
956dispatch_types! {mut type DispatchRenderBundleEncoder: RenderBundleEncoderInterface = CoreRenderBundleEncoder, WebRenderBundleEncoder, DynRenderBundleEncoder}
957dispatch_types! {ref type DispatchRenderBundle: RenderBundleInterface = CoreRenderBundle, WebRenderBundle, DynRenderBundle}
958dispatch_types! {ref type DispatchSurface: SurfaceInterface = CoreSurface, WebSurface, DynSurface}
959dispatch_types! {ref type DispatchSurfaceOutputDetail: SurfaceOutputDetailInterface = CoreSurfaceOutputDetail, WebSurfaceOutputDetail, DynSurfaceOutputDetail}
960dispatch_types! {mut type DispatchQueueWriteBuffer: QueueWriteBufferInterface = CoreQueueWriteBuffer, WebQueueWriteBuffer, DynQueueWriteBuffer}
961dispatch_types! {mut type DispatchBufferMappedRange: BufferMappedRangeInterface = CoreBufferMappedRange, WebBufferMappedRange, DynBufferMappedRange}