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