wgpu/api/
device.rs

1use alloc::{boxed::Box, string::String, sync::Arc, vec};
2#[cfg(wgpu_core)]
3use core::ops::Deref;
4use core::{error, fmt, future::Future};
5
6use crate::api::blas::{Blas, BlasGeometrySizeDescriptors, CreateBlasDescriptor};
7use crate::api::tlas::{CreateTlasDescriptor, Tlas};
8use crate::util::Mutex;
9use crate::*;
10
11/// Open connection to a graphics and/or compute device.
12///
13/// Responsible for the creation of most rendering and compute resources.
14/// These are then used in commands, which are submitted to a [`Queue`].
15///
16/// A device may be requested from an adapter with [`Adapter::request_device`].
17///
18/// Corresponds to [WebGPU `GPUDevice`](https://gpuweb.github.io/gpuweb/#gpu-device).
19#[derive(Debug, Clone)]
20pub struct Device {
21    pub(crate) inner: dispatch::DispatchDevice,
22}
23#[cfg(send_sync)]
24static_assertions::assert_impl_all!(Device: Send, Sync);
25
26crate::cmp::impl_eq_ord_hash_proxy!(Device => .inner);
27
28/// Describes a [`Device`].
29///
30/// For use with [`Adapter::request_device`].
31///
32/// Corresponds to [WebGPU `GPUDeviceDescriptor`](
33/// https://gpuweb.github.io/gpuweb/#dictdef-gpudevicedescriptor).
34pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
35static_assertions::assert_impl_all!(DeviceDescriptor<'_>: Send, Sync);
36
37impl Device {
38    #[cfg(custom)]
39    /// Returns custom implementation of Device (if custom backend and is internally T)
40    pub fn as_custom<T: custom::DeviceInterface>(&self) -> Option<&T> {
41        self.inner.as_custom()
42    }
43
44    #[cfg(custom)]
45    /// Creates Device from custom implementation
46    pub fn from_custom<T: custom::DeviceInterface>(device: T) -> Self {
47        Self {
48            inner: dispatch::DispatchDevice::custom(device),
49        }
50    }
51
52    /// Constructs a stub device for testing using [`Backend::Noop`].
53    ///
54    /// This is a convenience function which avoids the configuration, `async`, and fallibility
55    /// aspects of constructing a device through `Instance`.
56    #[cfg(feature = "noop")]
57    pub fn noop(desc: &DeviceDescriptor<'_>) -> (Device, Queue) {
58        use core::future::Future as _;
59        use core::pin::pin;
60        use core::task;
61        let ctx = &mut task::Context::from_waker(waker::noop_waker_ref());
62
63        let instance = Instance::new(&InstanceDescriptor {
64            backends: Backends::NOOP,
65            backend_options: BackendOptions {
66                noop: NoopBackendOptions { enable: true },
67                ..Default::default()
68            },
69            ..Default::default()
70        });
71
72        // Both of these futures are trivial and should complete instantaneously,
73        // so we do not need an executor and can just poll them once.
74        let task::Poll::Ready(Ok(adapter)) =
75            pin!(instance.request_adapter(&RequestAdapterOptions::default())).poll(ctx)
76        else {
77            unreachable!()
78        };
79        let task::Poll::Ready(Ok(device_and_queue)) = pin!(adapter.request_device(desc)).poll(ctx)
80        else {
81            unreachable!()
82        };
83        device_and_queue
84    }
85
86    /// Check for resource cleanups and mapping callbacks. Will block if [`PollType::Wait`] is passed.
87    ///
88    /// Return `true` if the queue is empty, or `false` if there are more queue
89    /// submissions still in flight. (Note that, unless access to the [`Queue`] is
90    /// coordinated somehow, this information could be out of date by the time
91    /// the caller receives it. `Queue`s can be shared between threads, so
92    /// other threads could submit new work at any time.)
93    ///
94    /// When running on WebGPU, this is a no-op. `Device`s are automatically polled.
95    pub fn poll(&self, poll_type: PollType) -> Result<crate::PollStatus, crate::PollError> {
96        self.inner.poll(poll_type.map_index(|s| s.index))
97    }
98
99    /// The features which can be used on this device.
100    ///
101    /// No additional features can be used, even if the underlying adapter can support them.
102    #[must_use]
103    pub fn features(&self) -> Features {
104        self.inner.features()
105    }
106
107    /// The limits which can be used on this device.
108    ///
109    /// No better limits can be used, even if the underlying adapter can support them.
110    #[must_use]
111    pub fn limits(&self) -> Limits {
112        self.inner.limits()
113    }
114
115    /// Creates a shader module.
116    ///
117    /// <div class="warning">
118    // NOTE: Keep this in sync with `naga::front::wgsl::parse_str`!
119    // NOTE: Keep this in sync with `wgpu_core::Global::device_create_shader_module`!
120    ///
121    /// This function may consume a lot of stack space. Compiler-enforced limits for parsing
122    /// recursion exist; if shader compilation runs into them, it will return an error gracefully.
123    /// However, on some build profiles and platforms, the default stack size for a thread may be
124    /// exceeded before this limit is reached during parsing. Callers should ensure that there is
125    /// enough stack space for this, particularly if calls to this method are exposed to user
126    /// input.
127    ///
128    /// </div>
129    #[must_use]
130    pub fn create_shader_module(&self, desc: ShaderModuleDescriptor<'_>) -> ShaderModule {
131        let module = self
132            .inner
133            .create_shader_module(desc, wgt::ShaderRuntimeChecks::checked());
134        ShaderModule { inner: module }
135    }
136
137    /// Deprecated: Use [`create_shader_module_trusted`][csmt] instead.
138    ///
139    /// # Safety
140    ///
141    /// See [`create_shader_module_trusted`][csmt].
142    ///
143    /// [csmt]: Self::create_shader_module_trusted
144    #[deprecated(
145        since = "24.0.0",
146        note = "Use `Device::create_shader_module_trusted(desc, wgpu::ShaderRuntimeChecks::unchecked())` instead."
147    )]
148    #[must_use]
149    pub unsafe fn create_shader_module_unchecked(
150        &self,
151        desc: ShaderModuleDescriptor<'_>,
152    ) -> ShaderModule {
153        unsafe { self.create_shader_module_trusted(desc, crate::ShaderRuntimeChecks::unchecked()) }
154    }
155
156    /// Creates a shader module with flags to dictate runtime checks.
157    ///
158    /// When running on WebGPU, this will merely call [`create_shader_module`][csm].
159    ///
160    /// # Safety
161    ///
162    /// In contrast with [`create_shader_module`][csm] this function
163    /// creates a shader module with user-customizable runtime checks which allows shaders to
164    /// perform operations which can lead to undefined behavior like indexing out of bounds,
165    /// thus it's the caller responsibility to pass a shader which doesn't perform any of this
166    /// operations.
167    ///
168    /// See the documentation for [`ShaderRuntimeChecks`][src] for more information about specific checks.
169    ///
170    /// [csm]: Self::create_shader_module
171    /// [src]: crate::ShaderRuntimeChecks
172    #[must_use]
173    pub unsafe fn create_shader_module_trusted(
174        &self,
175        desc: ShaderModuleDescriptor<'_>,
176        runtime_checks: crate::ShaderRuntimeChecks,
177    ) -> ShaderModule {
178        let module = self.inner.create_shader_module(desc, runtime_checks);
179        ShaderModule { inner: module }
180    }
181
182    /// Creates a shader module which will bypass wgpu's shader tooling and validation and be used directly by the backend.
183    ///
184    /// # Safety
185    ///
186    /// This function passes data to the backend as-is and can potentially result in a
187    /// driver crash or bogus behaviour. No attempt is made to ensure that data is valid.
188    #[must_use]
189    pub unsafe fn create_shader_module_passthrough(
190        &self,
191        desc: ShaderModuleDescriptorPassthrough<'_>,
192    ) -> ShaderModule {
193        let module = unsafe { self.inner.create_shader_module_passthrough(&desc) };
194        ShaderModule { inner: module }
195    }
196
197    /// Creates an empty [`CommandEncoder`].
198    #[must_use]
199    pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor<'_>) -> CommandEncoder {
200        let encoder = self.inner.create_command_encoder(desc);
201        CommandEncoder { inner: encoder }
202    }
203
204    /// Creates an empty [`RenderBundleEncoder`].
205    #[must_use]
206    pub fn create_render_bundle_encoder<'a>(
207        &self,
208        desc: &RenderBundleEncoderDescriptor<'_>,
209    ) -> RenderBundleEncoder<'a> {
210        let encoder = self.inner.create_render_bundle_encoder(desc);
211        RenderBundleEncoder {
212            inner: encoder,
213            _p: core::marker::PhantomData,
214        }
215    }
216
217    /// Creates a new [`BindGroup`].
218    #[must_use]
219    pub fn create_bind_group(&self, desc: &BindGroupDescriptor<'_>) -> BindGroup {
220        let group = self.inner.create_bind_group(desc);
221        BindGroup { inner: group }
222    }
223
224    /// Creates a [`BindGroupLayout`].
225    #[must_use]
226    pub fn create_bind_group_layout(
227        &self,
228        desc: &BindGroupLayoutDescriptor<'_>,
229    ) -> BindGroupLayout {
230        let layout = self.inner.create_bind_group_layout(desc);
231        BindGroupLayout { inner: layout }
232    }
233
234    /// Creates a [`PipelineLayout`].
235    #[must_use]
236    pub fn create_pipeline_layout(&self, desc: &PipelineLayoutDescriptor<'_>) -> PipelineLayout {
237        let layout = self.inner.create_pipeline_layout(desc);
238        PipelineLayout { inner: layout }
239    }
240
241    /// Creates a [`RenderPipeline`].
242    #[must_use]
243    pub fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor<'_>) -> RenderPipeline {
244        let pipeline = self.inner.create_render_pipeline(desc);
245        RenderPipeline { inner: pipeline }
246    }
247
248    /// Creates a mesh shader based [`RenderPipeline`].
249    #[must_use]
250    pub fn create_mesh_pipeline(&self, desc: &MeshPipelineDescriptor<'_>) -> RenderPipeline {
251        let pipeline = self.inner.create_mesh_pipeline(desc);
252        RenderPipeline { inner: pipeline }
253    }
254
255    /// Creates a [`ComputePipeline`].
256    #[must_use]
257    pub fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor<'_>) -> ComputePipeline {
258        let pipeline = self.inner.create_compute_pipeline(desc);
259        ComputePipeline { inner: pipeline }
260    }
261
262    /// Creates a [`Buffer`].
263    #[must_use]
264    pub fn create_buffer(&self, desc: &BufferDescriptor<'_>) -> Buffer {
265        let mut map_context = MapContext::new();
266        if desc.mapped_at_creation {
267            map_context.initial_range = 0..desc.size;
268        }
269
270        let buffer = self.inner.create_buffer(desc);
271
272        Buffer {
273            inner: buffer,
274            map_context: Arc::new(Mutex::new(map_context)),
275            size: desc.size,
276            usage: desc.usage,
277        }
278    }
279
280    /// Creates a new [`Texture`].
281    ///
282    /// `desc` specifies the general format of the texture.
283    #[must_use]
284    pub fn create_texture(&self, desc: &TextureDescriptor<'_>) -> Texture {
285        let texture = self.inner.create_texture(desc);
286
287        Texture {
288            inner: texture,
289            descriptor: TextureDescriptor {
290                label: None,
291                view_formats: &[],
292                ..desc.clone()
293            },
294        }
295    }
296
297    /// Creates a [`Texture`] from a wgpu-hal Texture.
298    ///
299    /// # Types
300    ///
301    /// The type of `A::Texture` depends on the backend:
302    ///
303    #[doc = crate::hal_type_vulkan!("Texture")]
304    #[doc = crate::hal_type_metal!("Texture")]
305    #[doc = crate::hal_type_dx12!("Texture")]
306    #[doc = crate::hal_type_gles!("Texture")]
307    ///
308    /// # Safety
309    ///
310    /// - `hal_texture` must be created from this device internal handle
311    /// - `hal_texture` must be created respecting `desc`
312    /// - `hal_texture` must be initialized
313    #[cfg(wgpu_core)]
314    #[must_use]
315    pub unsafe fn create_texture_from_hal<A: hal::Api>(
316        &self,
317        hal_texture: A::Texture,
318        desc: &TextureDescriptor<'_>,
319    ) -> Texture {
320        let texture = unsafe {
321            let core_device = self.inner.as_core();
322            core_device
323                .context
324                .create_texture_from_hal::<A>(hal_texture, core_device, desc)
325        };
326        Texture {
327            inner: texture.into(),
328            descriptor: TextureDescriptor {
329                label: None,
330                view_formats: &[],
331                ..desc.clone()
332            },
333        }
334    }
335
336    /// Creates a new [`ExternalTexture`].
337    #[must_use]
338    pub fn create_external_texture(
339        &self,
340        desc: &ExternalTextureDescriptor<'_>,
341        planes: &[&TextureView],
342    ) -> ExternalTexture {
343        let external_texture = self.inner.create_external_texture(desc, planes);
344
345        ExternalTexture {
346            inner: external_texture,
347        }
348    }
349
350    /// Creates a [`Buffer`] from a wgpu-hal Buffer.
351    ///
352    /// # Types
353    ///
354    /// The type of `A::Buffer` depends on the backend:
355    ///
356    #[doc = crate::hal_type_vulkan!("Buffer")]
357    #[doc = crate::hal_type_metal!("Buffer")]
358    #[doc = crate::hal_type_dx12!("Buffer")]
359    #[doc = crate::hal_type_gles!("Buffer")]
360    ///
361    /// # Safety
362    ///
363    /// - `hal_buffer` must be created from this device internal handle
364    /// - `hal_buffer` must be created respecting `desc`
365    /// - `hal_buffer` must be initialized
366    /// - `hal_buffer` must not have zero size
367    #[cfg(wgpu_core)]
368    #[must_use]
369    pub unsafe fn create_buffer_from_hal<A: hal::Api>(
370        &self,
371        hal_buffer: A::Buffer,
372        desc: &BufferDescriptor<'_>,
373    ) -> Buffer {
374        let mut map_context = MapContext::new();
375        if desc.mapped_at_creation {
376            map_context.initial_range = 0..desc.size;
377        }
378
379        let buffer = unsafe {
380            let core_device = self.inner.as_core();
381            core_device
382                .context
383                .create_buffer_from_hal::<A>(hal_buffer, core_device, desc)
384        };
385
386        Buffer {
387            inner: buffer.into(),
388            map_context: Arc::new(Mutex::new(map_context)),
389            size: desc.size,
390            usage: desc.usage,
391        }
392    }
393
394    /// Creates a new [`Sampler`].
395    ///
396    /// `desc` specifies the behavior of the sampler.
397    #[must_use]
398    pub fn create_sampler(&self, desc: &SamplerDescriptor<'_>) -> Sampler {
399        let sampler = self.inner.create_sampler(desc);
400        Sampler { inner: sampler }
401    }
402
403    /// Creates a new [`QuerySet`].
404    #[must_use]
405    pub fn create_query_set(&self, desc: &QuerySetDescriptor<'_>) -> QuerySet {
406        let query_set = self.inner.create_query_set(desc);
407        QuerySet { inner: query_set }
408    }
409
410    /// Set a callback for errors that are not handled in error scopes.
411    pub fn on_uncaptured_error(&self, handler: Box<dyn UncapturedErrorHandler>) {
412        self.inner.on_uncaptured_error(handler)
413    }
414
415    /// Push an error scope.
416    pub fn push_error_scope(&self, filter: ErrorFilter) {
417        self.inner.push_error_scope(filter)
418    }
419
420    /// Pop an error scope.
421    pub fn pop_error_scope(&self) -> impl Future<Output = Option<Error>> + WasmNotSend {
422        self.inner.pop_error_scope()
423    }
424
425    /// Starts a capture in the attached graphics debugger.
426    ///
427    /// This behaves differently depending on which graphics debugger is attached:
428    ///
429    /// - Renderdoc: Calls [`StartFrameCapture(device, NULL)`][rd].
430    /// - Xcode: Creates a capture with [`MTLCaptureManager`][xcode].
431    /// - None: No action is taken.
432    ///
433    /// # Safety
434    ///
435    /// - There should not be any other captures currently active.
436    /// - All other safety rules are defined by the graphics debugger, see the
437    ///   documentation for the specific debugger.
438    /// - In general, graphics debuggers can easily cause crashes, so this isn't
439    ///   ever guaranteed to be sound.
440    ///
441    /// # Tips
442    ///
443    /// - Debuggers need to capture both the recording of the commands and the
444    ///   submission of the commands to the GPU. Try to wrap all of your
445    ///   gpu work in a capture.
446    /// - If you encounter issues, try waiting for the GPU to finish all work
447    ///   before stopping the capture.
448    ///
449    /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv417StartFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle
450    /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager
451    #[doc(alias = "start_renderdoc_capture")]
452    #[doc(alias = "start_xcode_capture")]
453    pub unsafe fn start_graphics_debugger_capture(&self) {
454        unsafe { self.inner.start_graphics_debugger_capture() }
455    }
456
457    /// Stops the current capture in the attached graphics debugger.
458    ///
459    /// This behaves differently depending on which graphics debugger is attached:
460    ///
461    /// - Renderdoc: Calls [`EndFrameCapture(device, NULL)`][rd].
462    /// - Xcode: Stops the capture with [`MTLCaptureManager`][xcode].
463    /// - None: No action is taken.
464    ///
465    /// # Safety
466    ///
467    /// - There should be a capture currently active.
468    /// - All other safety rules are defined by the graphics debugger, see the
469    ///   documentation for the specific debugger.
470    /// - In general, graphics debuggers can easily cause crashes, so this isn't
471    ///   ever guaranteed to be sound.
472    ///
473    /// # Tips
474    ///
475    /// - If you encounter issues, try to submit all work to the GPU, and waiting
476    ///   for that work to finish before stopping the capture.
477    ///
478    /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv415EndFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle
479    /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager
480    #[doc(alias = "stop_renderdoc_capture")]
481    #[doc(alias = "stop_xcode_capture")]
482    pub unsafe fn stop_graphics_debugger_capture(&self) {
483        unsafe { self.inner.stop_graphics_debugger_capture() }
484    }
485
486    /// Query internal counters from the native backend for debugging purposes.
487    ///
488    /// Some backends may not set all counters, or may not set any counter at all.
489    /// The `counters` cargo feature must be enabled for any counter to be set.
490    ///
491    /// If a counter is not set, its contains its default value (zero).
492    #[must_use]
493    pub fn get_internal_counters(&self) -> wgt::InternalCounters {
494        self.inner.get_internal_counters()
495    }
496
497    /// Generate an GPU memory allocation report if the underlying backend supports it.
498    ///
499    /// Backends that do not support producing these reports return `None`. A backend may
500    /// Support it and still return `None` if it is not using performing sub-allocation,
501    /// for example as a workaround for driver issues.
502    #[must_use]
503    pub fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
504        self.inner.generate_allocator_report()
505    }
506
507    /// Get the [`wgpu_hal`] device from this `Device`.
508    ///
509    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
510    /// and pass that struct to the to the `A` type parameter.
511    ///
512    /// Returns a guard that dereferences to the type of the hal backend
513    /// which implements [`A::Device`].
514    ///
515    /// # Types
516    ///
517    /// The returned type depends on the backend:
518    ///
519    #[doc = crate::hal_type_vulkan!("Device")]
520    #[doc = crate::hal_type_metal!("Device")]
521    #[doc = crate::hal_type_dx12!("Device")]
522    #[doc = crate::hal_type_gles!("Device")]
523    ///
524    /// # Errors
525    ///
526    /// This method will return None if:
527    /// - The device is not from the backend specified by `A`.
528    /// - The device is from the `webgpu` or `custom` backend.
529    ///
530    /// # Safety
531    ///
532    /// - The returned resource must not be destroyed unless the guard
533    ///   is the last reference to it and it is not in use by the GPU.
534    ///   The guard and handle may be dropped at any time however.
535    /// - All the safety requirements of wgpu-hal must be upheld.
536    ///
537    /// [`A::Device`]: hal::Api::Device
538    #[cfg(wgpu_core)]
539    pub unsafe fn as_hal<A: hal::Api>(
540        &self,
541    ) -> Option<impl Deref<Target = A::Device> + WasmNotSendSync> {
542        let device = self.inner.as_core_opt()?;
543        unsafe { device.context.device_as_hal::<A>(device) }
544    }
545
546    /// Destroy this device.
547    pub fn destroy(&self) {
548        self.inner.destroy()
549    }
550
551    /// Set a DeviceLostCallback on this device.
552    pub fn set_device_lost_callback(
553        &self,
554        callback: impl Fn(DeviceLostReason, String) + Send + 'static,
555    ) {
556        self.inner.set_device_lost_callback(Box::new(callback))
557    }
558
559    /// Create a [`PipelineCache`] with initial data
560    ///
561    /// This can be passed to [`Device::create_compute_pipeline`]
562    /// and [`Device::create_render_pipeline`] to either accelerate these
563    /// or add the cache results from those.
564    ///
565    /// # Safety
566    ///
567    /// If the `data` field of `desc` is set, it must have previously been returned from a call
568    /// to [`PipelineCache::get_data`][^saving]. This `data` will only be used if it came
569    /// from an adapter with the same [`util::pipeline_cache_key`].
570    /// This *is* compatible across wgpu versions, as any data format change will
571    /// be accounted for.
572    ///
573    /// It is *not* supported to bring caches from previous direct uses of backend APIs
574    /// into this method.
575    ///
576    /// # Errors
577    ///
578    /// Returns an error value if:
579    ///  * the [`PIPELINE_CACHE`](wgt::Features::PIPELINE_CACHE) feature is not enabled
580    ///  * this device is invalid; or
581    ///  * the device is out of memory
582    ///
583    /// This method also returns an error value if:
584    ///  * The `fallback` field on `desc` is false; and
585    ///  * the `data` provided would not be used[^data_not_used]
586    ///
587    /// If an error value is used in subsequent calls, default caching will be used.
588    ///
589    /// [^saving]: We do recognise that saving this data to disk means this condition
590    /// is impossible to fully prove. Consider the risks for your own application in this case.
591    ///
592    /// [^data_not_used]: This data may be not used if: the data was produced by a prior
593    /// version of wgpu; or was created for an incompatible adapter, or there was a GPU driver
594    /// update. In some cases, the data might not be used and a real value is returned,
595    /// this is left to the discretion of GPU drivers.
596    #[must_use]
597    pub unsafe fn create_pipeline_cache(
598        &self,
599        desc: &PipelineCacheDescriptor<'_>,
600    ) -> PipelineCache {
601        let cache = unsafe { self.inner.create_pipeline_cache(desc) };
602        PipelineCache { inner: cache }
603    }
604}
605
606/// [`Features::EXPERIMENTAL_RAY_QUERY`] must be enabled on the device in order to call these functions.
607impl Device {
608    /// Create a bottom level acceleration structure, used inside a top level acceleration structure for ray tracing.
609    /// - `desc`: The descriptor of the acceleration structure.
610    /// - `sizes`: Size descriptor limiting what can be built into the acceleration structure.
611    ///
612    /// # Validation
613    /// If any of the following is not satisfied a validation error is generated
614    ///
615    /// The device ***must*** have [`Features::EXPERIMENTAL_RAY_QUERY`] enabled.
616    /// if `sizes` is [`BlasGeometrySizeDescriptors::Triangles`] then the following must be satisfied
617    /// - For every geometry descriptor (for the purposes this is called `geo_desc`) of `sizes.descriptors` the following must be satisfied:
618    ///     - `geo_desc.vertex_format` must be within allowed formats (allowed formats for a given feature set
619    ///       may be queried with [`Features::allowed_vertex_formats_for_blas`]).
620    ///     - Both or neither of `geo_desc.index_format` and `geo_desc.index_count` must be provided.
621    ///
622    /// [`Features::EXPERIMENTAL_RAY_QUERY`]: wgt::Features::EXPERIMENTAL_RAY_QUERY
623    /// [`Features::allowed_vertex_formats_for_blas`]: wgt::Features::allowed_vertex_formats_for_blas
624    #[must_use]
625    pub fn create_blas(
626        &self,
627        desc: &CreateBlasDescriptor<'_>,
628        sizes: BlasGeometrySizeDescriptors,
629    ) -> Blas {
630        let (handle, blas) = self.inner.create_blas(desc, sizes);
631
632        Blas {
633            inner: blas,
634            handle,
635        }
636    }
637
638    /// Create a top level acceleration structure, used for ray tracing.
639    /// - `desc`: The descriptor of the acceleration structure.
640    ///
641    /// # Validation
642    /// If any of the following is not satisfied a validation error is generated
643    ///
644    /// The device ***must*** have [`Features::EXPERIMENTAL_RAY_QUERY`] enabled.
645    ///
646    /// [`Features::EXPERIMENTAL_RAY_QUERY`]: wgt::Features::EXPERIMENTAL_RAY_QUERY
647    #[must_use]
648    pub fn create_tlas(&self, desc: &CreateTlasDescriptor<'_>) -> Tlas {
649        let tlas = self.inner.create_tlas(desc);
650
651        Tlas {
652            inner: tlas,
653            instances: vec![None; desc.max_instances as usize],
654            lowest_unmodified: 0,
655        }
656    }
657}
658
659/// Requesting a device from an [`Adapter`] failed.
660#[derive(Clone, Debug)]
661pub struct RequestDeviceError {
662    pub(crate) inner: RequestDeviceErrorKind,
663}
664#[derive(Clone, Debug)]
665pub(crate) enum RequestDeviceErrorKind {
666    /// Error from [`wgpu_core`].
667    // must match dependency cfg
668    #[cfg(wgpu_core)]
669    Core(wgc::instance::RequestDeviceError),
670
671    /// Error from web API that was called by `wgpu` to request a device.
672    ///
673    /// (This is currently never used by the webgl backend, but it could be.)
674    #[cfg(webgpu)]
675    WebGpu(String),
676}
677
678static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
679
680impl fmt::Display for RequestDeviceError {
681    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
682        match &self.inner {
683            #[cfg(wgpu_core)]
684            RequestDeviceErrorKind::Core(error) => error.fmt(_f),
685            #[cfg(webgpu)]
686            RequestDeviceErrorKind::WebGpu(error) => {
687                write!(_f, "{error}")
688            }
689            #[cfg(not(any(webgpu, wgpu_core)))]
690            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
691        }
692    }
693}
694
695impl error::Error for RequestDeviceError {
696    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
697        match &self.inner {
698            #[cfg(wgpu_core)]
699            RequestDeviceErrorKind::Core(error) => error.source(),
700            #[cfg(webgpu)]
701            RequestDeviceErrorKind::WebGpu(_) => None,
702            #[cfg(not(any(webgpu, wgpu_core)))]
703            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
704        }
705    }
706}
707
708#[cfg(wgpu_core)]
709impl From<wgc::instance::RequestDeviceError> for RequestDeviceError {
710    fn from(error: wgc::instance::RequestDeviceError) -> Self {
711        Self {
712            inner: RequestDeviceErrorKind::Core(error),
713        }
714    }
715}
716
717/// Type for the callback of uncaptured error handler
718pub trait UncapturedErrorHandler: Fn(Error) + Send + 'static {}
719impl<T> UncapturedErrorHandler for T where T: Fn(Error) + Send + 'static {}
720
721/// Kinds of [`Error`]s a [`Device::push_error_scope()`] may be configured to catch.
722#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
723pub enum ErrorFilter {
724    /// Catch only out-of-memory errors.
725    OutOfMemory,
726    /// Catch only validation errors.
727    Validation,
728    /// Catch only internal errors.
729    Internal,
730}
731static_assertions::assert_impl_all!(ErrorFilter: Send, Sync);
732
733/// Lower level source of the error.
734///
735/// `Send + Sync` varies depending on configuration.
736#[cfg(send_sync)]
737#[cfg_attr(docsrs, doc(cfg(all())))]
738pub type ErrorSource = Box<dyn error::Error + Send + Sync + 'static>;
739/// Lower level source of the error.
740///
741/// `Send + Sync` varies depending on configuration.
742#[cfg(not(send_sync))]
743#[cfg_attr(docsrs, doc(cfg(all())))]
744pub type ErrorSource = Box<dyn error::Error + 'static>;
745
746/// Errors resulting from usage of GPU APIs.
747///
748/// By default, errors translate into panics. Depending on the backend and circumstances,
749/// errors may occur synchronously or asynchronously. When errors need to be handled, use
750/// [`Device::push_error_scope()`] or [`Device::on_uncaptured_error()`].
751#[derive(Debug)]
752pub enum Error {
753    /// Out of memory.
754    OutOfMemory {
755        /// Lower level source of the error.
756        source: ErrorSource,
757    },
758    /// Validation error, signifying a bug in code or data provided to `wgpu`.
759    Validation {
760        /// Lower level source of the error.
761        source: ErrorSource,
762        /// Description of the validation error.
763        description: String,
764    },
765    /// Internal error. Used for signalling any failures not explicitly expected by WebGPU.
766    ///
767    /// These could be due to internal implementation or system limits being reached.
768    Internal {
769        /// Lower level source of the error.
770        source: ErrorSource,
771        /// Description of the internal GPU error.
772        description: String,
773    },
774}
775#[cfg(send_sync)]
776static_assertions::assert_impl_all!(Error: Send, Sync);
777
778impl error::Error for Error {
779    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
780        match self {
781            Error::OutOfMemory { source } => Some(source.as_ref()),
782            Error::Validation { source, .. } => Some(source.as_ref()),
783            Error::Internal { source, .. } => Some(source.as_ref()),
784        }
785    }
786}
787
788impl fmt::Display for Error {
789    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790        match self {
791            Error::OutOfMemory { .. } => f.write_str("Out of Memory"),
792            Error::Validation { description, .. } => f.write_str(description),
793            Error::Internal { description, .. } => f.write_str(description),
794        }
795    }
796}
797
798// Copied from [`futures::task::noop_waker`].
799// Needed until MSRV is 1.85 with `task::Waker::noop()` available
800#[cfg(feature = "noop")]
801mod waker {
802    use core::ptr::null;
803    use core::task::{RawWaker, RawWakerVTable, Waker};
804
805    unsafe fn noop_clone(_data: *const ()) -> RawWaker {
806        noop_raw_waker()
807    }
808
809    unsafe fn noop(_data: *const ()) {}
810
811    const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
812
813    const fn noop_raw_waker() -> RawWaker {
814        RawWaker::new(null(), &NOOP_WAKER_VTABLE)
815    }
816
817    /// Get a static reference to a [`Waker`] which
818    /// does nothing when `wake()` is called on it.
819    #[inline]
820    pub fn noop_waker_ref() -> &'static Waker {
821        struct SyncRawWaker(RawWaker);
822        unsafe impl Sync for SyncRawWaker {}
823
824        static NOOP_WAKER_INSTANCE: SyncRawWaker = SyncRawWaker(noop_raw_waker());
825
826        // SAFETY: `Waker` is #[repr(transparent)] over its `RawWaker`.
827        unsafe { &*(&NOOP_WAKER_INSTANCE.0 as *const RawWaker as *const Waker) }
828    }
829}