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