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