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    #[cfg(wgpu_core)]
129    fn cooperative_matrix_properties(&self) -> Vec<crate::wgt::CooperativeMatrixProperties>;
130}
131
132pub trait DeviceInterface: CommonTraits {
133    fn features(&self) -> crate::Features;
134    fn limits(&self) -> crate::Limits;
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 {
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    fn end(&mut self);
400}
401pub trait RenderPassInterface: CommonTraits {
402    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
403    fn set_bind_group(
404        &mut self,
405        index: u32,
406        bind_group: Option<&DispatchBindGroup>,
407        offsets: &[crate::DynamicOffset],
408    );
409    fn set_index_buffer(
410        &mut self,
411        buffer: &DispatchBuffer,
412        index_format: crate::IndexFormat,
413        offset: crate::BufferAddress,
414        size: Option<crate::BufferSize>,
415    );
416    fn set_vertex_buffer(
417        &mut self,
418        slot: u32,
419        buffer: &DispatchBuffer,
420        offset: crate::BufferAddress,
421        size: Option<crate::BufferSize>,
422    );
423    fn set_immediates(&mut self, offset: u32, data: &[u8]);
424    fn set_blend_constant(&mut self, color: crate::Color);
425    fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
426    fn set_viewport(
427        &mut self,
428        x: f32,
429        y: f32,
430        width: f32,
431        height: f32,
432        min_depth: f32,
433        max_depth: f32,
434    );
435    fn set_stencil_reference(&mut self, reference: u32);
436
437    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
438    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
439    fn draw_mesh_tasks(&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32);
440    fn draw_indirect(
441        &mut self,
442        indirect_buffer: &DispatchBuffer,
443        indirect_offset: crate::BufferAddress,
444    );
445    fn draw_indexed_indirect(
446        &mut self,
447        indirect_buffer: &DispatchBuffer,
448        indirect_offset: crate::BufferAddress,
449    );
450    fn draw_mesh_tasks_indirect(
451        &mut self,
452        indirect_buffer: &DispatchBuffer,
453        indirect_offset: crate::BufferAddress,
454    );
455
456    fn multi_draw_indirect(
457        &mut self,
458        indirect_buffer: &DispatchBuffer,
459        indirect_offset: crate::BufferAddress,
460        count: u32,
461    );
462    fn multi_draw_indexed_indirect(
463        &mut self,
464        indirect_buffer: &DispatchBuffer,
465        indirect_offset: crate::BufferAddress,
466        count: u32,
467    );
468    fn multi_draw_indirect_count(
469        &mut self,
470        indirect_buffer: &DispatchBuffer,
471        indirect_offset: crate::BufferAddress,
472        count_buffer: &DispatchBuffer,
473        count_buffer_offset: crate::BufferAddress,
474        max_count: u32,
475    );
476    fn multi_draw_mesh_tasks_indirect(
477        &mut self,
478        indirect_buffer: &DispatchBuffer,
479        indirect_offset: crate::BufferAddress,
480        count: u32,
481    );
482    fn multi_draw_indexed_indirect_count(
483        &mut self,
484        indirect_buffer: &DispatchBuffer,
485        indirect_offset: crate::BufferAddress,
486        count_buffer: &DispatchBuffer,
487        count_buffer_offset: crate::BufferAddress,
488        max_count: u32,
489    );
490    fn multi_draw_mesh_tasks_indirect_count(
491        &mut self,
492        indirect_buffer: &DispatchBuffer,
493        indirect_offset: crate::BufferAddress,
494        count_buffer: &DispatchBuffer,
495        count_buffer_offset: crate::BufferAddress,
496        max_count: u32,
497    );
498
499    fn insert_debug_marker(&mut self, label: &str);
500    fn push_debug_group(&mut self, group_label: &str);
501    fn pop_debug_group(&mut self);
502
503    fn write_timestamp(&mut self, query_set: &DispatchQuerySet, query_index: u32);
504    fn begin_occlusion_query(&mut self, query_index: u32);
505    fn end_occlusion_query(&mut self);
506    fn begin_pipeline_statistics_query(&mut self, query_set: &DispatchQuerySet, query_index: u32);
507    fn end_pipeline_statistics_query(&mut self);
508
509    fn execute_bundles(&mut self, render_bundles: &mut dyn Iterator<Item = &DispatchRenderBundle>);
510
511    fn end(&mut self);
512}
513
514pub trait RenderBundleEncoderInterface: CommonTraits {
515    fn set_pipeline(&mut self, pipeline: &DispatchRenderPipeline);
516    fn set_bind_group(
517        &mut self,
518        index: u32,
519        bind_group: Option<&DispatchBindGroup>,
520        offsets: &[crate::DynamicOffset],
521    );
522    fn set_index_buffer(
523        &mut self,
524        buffer: &DispatchBuffer,
525        index_format: crate::IndexFormat,
526        offset: crate::BufferAddress,
527        size: Option<crate::BufferSize>,
528    );
529    fn set_vertex_buffer(
530        &mut self,
531        slot: u32,
532        buffer: &DispatchBuffer,
533        offset: crate::BufferAddress,
534        size: Option<crate::BufferSize>,
535    );
536    fn set_immediates(&mut self, offset: u32, data: &[u8]);
537
538    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
539    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
540    fn draw_indirect(
541        &mut self,
542        indirect_buffer: &DispatchBuffer,
543        indirect_offset: crate::BufferAddress,
544    );
545    fn draw_indexed_indirect(
546        &mut self,
547        indirect_buffer: &DispatchBuffer,
548        indirect_offset: crate::BufferAddress,
549    );
550
551    fn finish(self, desc: &crate::RenderBundleDescriptor<'_>) -> DispatchRenderBundle
552    where
553        Self: Sized;
554}
555
556pub trait CommandBufferInterface: CommonTraits {}
557pub trait RenderBundleInterface: CommonTraits {}
558
559pub trait SurfaceInterface: CommonTraits {
560    fn get_capabilities(&self, adapter: &DispatchAdapter) -> crate::SurfaceCapabilities;
561
562    fn configure(&self, device: &DispatchDevice, config: &crate::SurfaceConfiguration);
563    fn get_current_texture(
564        &self,
565    ) -> (
566        Option<DispatchTexture>,
567        crate::SurfaceStatus,
568        DispatchSurfaceOutputDetail,
569    );
570}
571
572pub trait SurfaceOutputDetailInterface: CommonTraits {
573    fn present(&self);
574    fn texture_discard(&self);
575}
576
577pub trait QueueWriteBufferInterface: CommonTraits {
578    fn slice(&self) -> &[u8];
579
580    fn slice_mut(&mut self) -> &mut [u8];
581}
582
583pub trait BufferMappedRangeInterface: CommonTraits {
584    fn slice(&self) -> &[u8];
585    fn slice_mut(&mut self) -> &mut [u8];
586
587    #[cfg(webgpu)]
588    fn as_uint8array(&self) -> &js_sys::Uint8Array;
589}
590
591/// Generates a dispatch type for some `wgpu` API type.
592///
593/// Invocations of this macro take one of the following forms:
594///
595/// ```ignore
596/// dispatch_types! {mut type D: I = Core, Web, Dyn }
597/// dispatch_types! {ref type D: I = Core, Web, Dyn }
598/// ```
599///
600/// This defines `D` as a type that dereferences to a `dyn I` trait object. Most uses of
601/// `D` in the rest of this crate just call the methods from the `dyn I` object, not from
602/// `D` itself.
603///
604/// Internally, `D` is an enum with up to three variants holding values of type `Core`,
605/// `Web`, and `Dyn`, all of which must implement `I`. `Core`, `Web` and `Dyn` are the
606/// types from the `wgpu_core`, `webgpu`, and `custom` submodules of `wgpu::backend` that
607/// correspond to `D`. The macro generates `Deref` and `DerefMut` implementations that
608/// match on this enum and produce a `dyn I` reference for each variant.
609///
610/// The macro's `mut type` form defines `D` as the unique owner of the backend type, with
611/// a `DerefMut` implementation, and `as_*_mut` methods that return `&mut` references.
612/// This `D` does not implement `Clone`.
613///
614/// The macro's `ref type` form defines `D` to hold an `Arc` pointing to the backend type,
615/// permitting `Clone` and `Deref`, but losing exclusive, mutable access.
616///
617/// For example:
618///
619/// ```ignore
620/// dispatch_types! {ref type DispatchBuffer: BufferInterface =
621///                  CoreBuffer, WebBuffer, DynBuffer}
622/// ```
623///
624/// This defines `DispatchBuffer` as a type that dereferences to `&dyn BufferInterface`,
625/// which has methods like `map_async` and `destroy`. The enum would be:
626///
627/// ```ignore
628/// pub enum DispatchBuffer {
629///     #[cfg(wgpu_core)]
630///     Core(Arc<CoreBuffer>),
631///     #[cfg(webgpu)]
632///     WebGPU(WebBuffer),
633///     #[cfg(custom)]
634///     Custom(DynBuffer),
635/// }
636/// ```
637///
638/// This macro also defines `as_*` methods so that the backend implementations can
639/// dereference other arguments.
640///
641/// ## Devirtualization
642///
643/// The dispatch types generated by this macro are carefully designed to allow the
644/// compiler to completely devirtualize calls in most circumstances.
645///
646/// Note that every variant of the enum generated by this macro is under a `#[cfg]`.
647/// Naturally, the `match` expressions in the `Deref` and `DerefMut` implementations have
648/// matching `#[cfg]` attributes on each match arm.
649///
650/// In practice, when `wgpu`'s `"custom"` feature is not enabled, there is usually only
651/// one variant in the `enum`, making it effectively a newtype around the sole variant's
652/// data: it has no discriminant to branch on, and the `match` expressions are removed
653/// entirely by the compiler.
654///
655/// In this case, when we invoke a method from the interface trait `I` on a dispatch type,
656/// the `Deref` and `DerefMut` implementations' `match` statements build a `&dyn I` for
657/// the data, on which we immediately invoke a method. The vtable is a constant, allowing
658/// the Rust compiler to turn the `dyn` method call into an ordinary method call. This
659/// creates opportunities for inlining.
660///
661/// Similarly, the `as_*` methods are free when there is only one backend.
662macro_rules! dispatch_types {
663    (
664        ref type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
665    ) => {
666        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
667        pub enum $name {
668            #[cfg(wgpu_core)]
669            Core(Arc<$core_type>),
670            #[cfg(webgpu)]
671            WebGPU($webgpu_type),
672            #[allow(clippy::allow_attributes, private_interfaces)]
673            #[cfg(custom)]
674            Custom($custom_type),
675        }
676
677        impl $name {
678            #[cfg(wgpu_core)]
679            #[inline]
680            #[allow(clippy::allow_attributes, unused)]
681            pub fn as_core(&self) -> &$core_type {
682                match self {
683                    Self::Core(value) => value,
684                    _ => panic!(concat!(stringify!($name), " is not core")),
685                }
686            }
687
688            #[cfg(wgpu_core)]
689            #[inline]
690            #[allow(clippy::allow_attributes, unused)]
691            pub fn as_core_opt(&self) -> Option<&$core_type> {
692                match self {
693                    Self::Core(value) => Some(value),
694                    _ => None,
695                }
696            }
697
698            #[cfg(custom)]
699            #[inline]
700            #[allow(clippy::allow_attributes, unused)]
701            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
702                match self {
703                    Self::Custom(value) => value.downcast(),
704                    _ => None,
705                }
706            }
707
708            #[cfg(webgpu)]
709            #[inline]
710            #[allow(clippy::allow_attributes, unused)]
711            pub fn as_webgpu(&self) -> &$webgpu_type {
712                match self {
713                    Self::WebGPU(value) => value,
714                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
715                }
716            }
717
718            #[cfg(webgpu)]
719            #[inline]
720            #[allow(clippy::allow_attributes, unused)]
721            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
722                match self {
723                    Self::WebGPU(value) => Some(value),
724                    _ => None,
725                }
726            }
727
728            #[cfg(custom)]
729            #[inline]
730            pub fn custom<T: $interface>(t: T) -> Self {
731                Self::Custom($custom_type::new(t))
732            }
733        }
734
735        #[cfg(wgpu_core)]
736        impl From<$core_type> for $name {
737            #[inline]
738            fn from(value: $core_type) -> Self {
739                Self::Core(Arc::new(value))
740            }
741        }
742
743        #[cfg(webgpu)]
744        impl From<$webgpu_type> for $name {
745            #[inline]
746            fn from(value: $webgpu_type) -> Self {
747                Self::WebGPU(value)
748            }
749        }
750
751        impl core::ops::Deref for $name {
752            type Target = dyn $interface;
753
754            #[inline]
755            fn deref(&self) -> &Self::Target {
756                match self {
757                    #[cfg(wgpu_core)]
758                    Self::Core(value) => value.as_ref(),
759                    #[cfg(webgpu)]
760                    Self::WebGPU(value) => value,
761                    #[cfg(custom)]
762                    Self::Custom(value) => value.deref(),
763                    #[cfg(not(any(wgpu_core, webgpu)))]
764                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
765                }
766            }
767        }
768    };
769    (
770        mut type $name:ident: $interface:ident = $core_type:ident,$webgpu_type:ident,$custom_type:ident
771    ) => {
772        #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
773        pub enum $name {
774            #[cfg(wgpu_core)]
775            Core($core_type),
776            #[cfg(webgpu)]
777            WebGPU($webgpu_type),
778            #[allow(clippy::allow_attributes, private_interfaces)]
779            #[cfg(custom)]
780            Custom($custom_type),
781        }
782
783        impl $name {
784            #[cfg(wgpu_core)]
785            #[inline]
786            #[allow(clippy::allow_attributes, unused)]
787            pub fn as_core(&self) -> &$core_type {
788                match self {
789                    Self::Core(value) => value,
790                    _ => panic!(concat!(stringify!($name), " is not core")),
791                }
792            }
793
794            #[cfg(wgpu_core)]
795            #[inline]
796            #[allow(clippy::allow_attributes, unused)]
797            pub fn as_core_mut(&mut self) -> &mut $core_type {
798                match self {
799                    Self::Core(value) => value,
800                    _ => panic!(concat!(stringify!($name), " is not core")),
801                }
802            }
803
804            #[cfg(wgpu_core)]
805            #[inline]
806            #[allow(clippy::allow_attributes, unused)]
807            pub fn as_core_opt(&self) -> Option<&$core_type> {
808                match self {
809                    Self::Core(value) => Some(value),
810                    _ => None,
811                }
812            }
813
814            #[cfg(wgpu_core)]
815            #[inline]
816            #[allow(clippy::allow_attributes, unused)]
817            pub fn as_core_mut_opt(
818                &mut self,
819            ) -> Option<&mut $core_type> {
820                match self {
821                    Self::Core(value) => Some(value),
822                    _ => None,
823                }
824            }
825
826            #[cfg(custom)]
827            #[inline]
828            #[allow(clippy::allow_attributes, unused)]
829            pub fn as_custom<T: $interface>(&self) -> Option<&T> {
830                match self {
831                    Self::Custom(value) => value.downcast(),
832                    _ => None,
833                }
834            }
835
836            #[cfg(webgpu)]
837            #[inline]
838            #[allow(clippy::allow_attributes, unused)]
839            pub fn as_webgpu(&self) -> &$webgpu_type {
840                match self {
841                    Self::WebGPU(value) => value,
842                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
843                }
844            }
845
846            #[cfg(webgpu)]
847            #[inline]
848            #[allow(clippy::allow_attributes, unused)]
849            pub fn as_webgpu_mut(&mut self) -> &mut $webgpu_type {
850                match self {
851                    Self::WebGPU(value) => value,
852                    _ => panic!(concat!(stringify!($name), " is not webgpu")),
853                }
854            }
855
856            #[cfg(webgpu)]
857            #[inline]
858            #[allow(clippy::allow_attributes, unused)]
859            pub fn as_webgpu_opt(&self) -> Option<&$webgpu_type> {
860                match self {
861                    Self::WebGPU(value) => Some(value),
862                    _ => None,
863                }
864            }
865
866            #[cfg(webgpu)]
867            #[inline]
868            #[allow(clippy::allow_attributes, unused)]
869            pub fn as_webgpu_mut_opt(
870                &mut self,
871            ) -> Option<&mut $webgpu_type> {
872                match self {
873                    Self::WebGPU(value) => Some(value),
874                    _ => None,
875                }
876            }
877
878            #[cfg(custom)]
879            #[inline]
880            pub fn custom<T: $interface>(t: T) -> Self {
881                Self::Custom($custom_type::new(t))
882            }
883        }
884
885        #[cfg(wgpu_core)]
886        impl From<$core_type> for $name {
887            #[inline]
888            fn from(value: $core_type) -> Self {
889                Self::Core(value)
890            }
891        }
892
893        #[cfg(webgpu)]
894        impl From<$webgpu_type> for $name {
895            #[inline]
896            fn from(value: $webgpu_type) -> Self {
897                Self::WebGPU(value)
898            }
899        }
900
901        impl core::ops::Deref for $name {
902            type Target = dyn $interface;
903
904            #[inline]
905            fn deref(&self) -> &Self::Target {
906                match self {
907                    #[cfg(wgpu_core)]
908                    Self::Core(value) => value,
909                    #[cfg(webgpu)]
910                    Self::WebGPU(value) => value,
911                    #[cfg(custom)]
912                    Self::Custom(value) => value.deref(),
913                    #[cfg(not(any(wgpu_core, webgpu)))]
914                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
915                }
916            }
917        }
918
919        impl core::ops::DerefMut for $name {
920            #[inline]
921            fn deref_mut(&mut self) -> &mut Self::Target {
922                match self {
923                    #[cfg(wgpu_core)]
924                    Self::Core(value) => value,
925                    #[cfg(webgpu)]
926                    Self::WebGPU(value) => value,
927                    #[cfg(custom)]
928                    Self::Custom(value) => value.deref_mut(),
929                    #[cfg(not(any(wgpu_core, webgpu)))]
930                    _ => panic!("No context available. You need to enable one of wgpu's backend feature build flags."),
931                }
932            }
933        }
934    };
935}
936
937dispatch_types! {ref type DispatchInstance: InstanceInterface = ContextWgpuCore, ContextWebGpu, DynContext}
938dispatch_types! {ref type DispatchAdapter: AdapterInterface = CoreAdapter, WebAdapter, DynAdapter}
939dispatch_types! {ref type DispatchDevice: DeviceInterface = CoreDevice, WebDevice, DynDevice}
940dispatch_types! {ref type DispatchQueue: QueueInterface = CoreQueue, WebQueue, DynQueue}
941dispatch_types! {ref type DispatchShaderModule: ShaderModuleInterface = CoreShaderModule, WebShaderModule, DynShaderModule}
942dispatch_types! {ref type DispatchBindGroupLayout: BindGroupLayoutInterface = CoreBindGroupLayout, WebBindGroupLayout, DynBindGroupLayout}
943dispatch_types! {ref type DispatchBindGroup: BindGroupInterface = CoreBindGroup, WebBindGroup, DynBindGroup}
944dispatch_types! {ref type DispatchTextureView: TextureViewInterface = CoreTextureView, WebTextureView, DynTextureView}
945dispatch_types! {ref type DispatchSampler: SamplerInterface = CoreSampler, WebSampler, DynSampler}
946dispatch_types! {ref type DispatchBuffer: BufferInterface = CoreBuffer, WebBuffer, DynBuffer}
947dispatch_types! {ref type DispatchTexture: TextureInterface = CoreTexture, WebTexture, DynTexture}
948dispatch_types! {ref type DispatchExternalTexture: ExternalTextureInterface = CoreExternalTexture, WebExternalTexture, DynExternalTexture}
949dispatch_types! {ref type DispatchBlas: BlasInterface = CoreBlas, WebBlas, DynBlas}
950dispatch_types! {ref type DispatchTlas: TlasInterface = CoreTlas, WebTlas, DynTlas}
951dispatch_types! {ref type DispatchQuerySet: QuerySetInterface = CoreQuerySet, WebQuerySet, DynQuerySet}
952dispatch_types! {ref type DispatchPipelineLayout: PipelineLayoutInterface = CorePipelineLayout, WebPipelineLayout, DynPipelineLayout}
953dispatch_types! {ref type DispatchRenderPipeline: RenderPipelineInterface = CoreRenderPipeline, WebRenderPipeline, DynRenderPipeline}
954dispatch_types! {ref type DispatchComputePipeline: ComputePipelineInterface = CoreComputePipeline, WebComputePipeline, DynComputePipeline}
955dispatch_types! {ref type DispatchPipelineCache: PipelineCacheInterface = CorePipelineCache, WebPipelineCache, DynPipelineCache}
956dispatch_types! {mut type DispatchCommandEncoder: CommandEncoderInterface = CoreCommandEncoder, WebCommandEncoder, DynCommandEncoder}
957dispatch_types! {mut type DispatchComputePass: ComputePassInterface = CoreComputePass, WebComputePassEncoder, DynComputePass}
958dispatch_types! {mut type DispatchRenderPass: RenderPassInterface = CoreRenderPass, WebRenderPassEncoder, DynRenderPass}
959dispatch_types! {mut type DispatchCommandBuffer: CommandBufferInterface = CoreCommandBuffer, WebCommandBuffer, DynCommandBuffer}
960dispatch_types! {mut type DispatchRenderBundleEncoder: RenderBundleEncoderInterface = CoreRenderBundleEncoder, WebRenderBundleEncoder, DynRenderBundleEncoder}
961dispatch_types! {ref type DispatchRenderBundle: RenderBundleInterface = CoreRenderBundle, WebRenderBundle, DynRenderBundle}
962dispatch_types! {ref type DispatchSurface: SurfaceInterface = CoreSurface, WebSurface, DynSurface}
963dispatch_types! {ref type DispatchSurfaceOutputDetail: SurfaceOutputDetailInterface = CoreSurfaceOutputDetail, WebSurfaceOutputDetail, DynSurfaceOutputDetail}
964dispatch_types! {mut type DispatchQueueWriteBuffer: QueueWriteBufferInterface = CoreQueueWriteBuffer, WebQueueWriteBuffer, DynQueueWriteBuffer}
965dispatch_types! {mut type DispatchBufferMappedRange: BufferMappedRangeInterface = CoreBufferMappedRange, WebBufferMappedRange, DynBufferMappedRange}