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    #[must_use]
229    pub fn create_render_bundle_encoder<'a>(
230        &self,
231        desc: &RenderBundleEncoderDescriptor<'_>,
232    ) -> RenderBundleEncoder<'a> {
233        let encoder = self.inner.create_render_bundle_encoder(desc);
234        RenderBundleEncoder {
235            inner: encoder,
236            _p: PhantomData,
237        }
238    }
239
240    /// Creates a new [`BindGroup`].
241    #[must_use]
242    pub fn create_bind_group(&self, desc: &BindGroupDescriptor<'_>) -> BindGroup {
243        let group = self.inner.create_bind_group(desc);
244        BindGroup { inner: group }
245    }
246
247    /// Creates a [`BindGroupLayout`].
248    #[must_use]
249    pub fn create_bind_group_layout(
250        &self,
251        desc: &BindGroupLayoutDescriptor<'_>,
252    ) -> BindGroupLayout {
253        let layout = self.inner.create_bind_group_layout(desc);
254        BindGroupLayout { inner: layout }
255    }
256
257    /// Creates a [`PipelineLayout`].
258    #[must_use]
259    pub fn create_pipeline_layout(&self, desc: &PipelineLayoutDescriptor<'_>) -> PipelineLayout {
260        let layout = self.inner.create_pipeline_layout(desc);
261        PipelineLayout { inner: layout }
262    }
263
264    /// Creates a [`RenderPipeline`].
265    #[must_use]
266    pub fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor<'_>) -> RenderPipeline {
267        let pipeline = self.inner.create_render_pipeline(desc);
268        RenderPipeline { inner: pipeline }
269    }
270
271    /// Creates a mesh shader based [`RenderPipeline`].
272    #[must_use]
273    pub fn create_mesh_pipeline(&self, desc: &MeshPipelineDescriptor<'_>) -> RenderPipeline {
274        let pipeline = self.inner.create_mesh_pipeline(desc);
275        RenderPipeline { inner: pipeline }
276    }
277
278    /// Creates a [`ComputePipeline`].
279    #[must_use]
280    pub fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor<'_>) -> ComputePipeline {
281        let pipeline = self.inner.create_compute_pipeline(desc);
282        ComputePipeline { inner: pipeline }
283    }
284
285    /// Creates a [`Buffer`].
286    #[must_use]
287    pub fn create_buffer(&self, desc: &BufferDescriptor<'_>) -> Buffer {
288        let map_context = MapContext::new(desc.mapped_at_creation.then_some(0..desc.size));
289
290        let buffer = self.inner.create_buffer(desc);
291
292        Buffer {
293            inner: buffer,
294            map_context: Arc::new(Mutex::new(map_context)),
295        }
296    }
297
298    /// Creates a new [`Texture`].
299    ///
300    /// `desc` specifies the general format of the texture.
301    #[must_use]
302    pub fn create_texture(&self, desc: &TextureDescriptor<'_>) -> Texture {
303        let texture = self.inner.create_texture(desc);
304
305        Texture { inner: texture }
306    }
307
308    /// Creates a [`Texture`] from a wgpu-hal Texture.
309    ///
310    /// # Types
311    ///
312    /// The type of `A::Texture` depends on the backend:
313    ///
314    #[doc = crate::macros::hal_type_vulkan!("Texture")]
315    #[doc = crate::macros::hal_type_metal!("Texture")]
316    #[doc = crate::macros::hal_type_dx12!("Texture")]
317    #[doc = crate::macros::hal_type_gles!("Texture")]
318    ///
319    /// On [`Backend::BrowserWebGpu`], use `Device::create_texture_from_webgpu_handle()` instead.
320    ///
321    /// # `initial_state`
322    ///
323    /// If the resource has already been initialized, `initial_state` should be
324    /// set to the [`wgt::TextureUses`] state of the wrapped resource.  It will
325    /// be used as the source state (`oldLayout` / `StateBefore`) of the first
326    /// barrier emitted on the texture.
327    ///
328    /// If the resource has not been initialized (or if the existing contents
329    /// may be discarded), `initial_state` may be set to
330    /// `TextureUses::UNINITIALIZED`.
331    ///
332    /// # Safety
333    ///
334    /// - `hal_texture` must be created from this device internal handle
335    /// - `hal_texture` must be created respecting `desc`
336    /// - `hal_texture` must be initialized
337    /// - `initial_state`, if it is not `TextureUses::UNINITIALIZED`, must
338    ///   match the actual driver-side layout/state of the wrapped resource at
339    ///   the moment of wrap.
340    #[cfg(wgpu_core)]
341    #[must_use]
342    pub unsafe fn create_texture_from_hal<A: hal::Api>(
343        &self,
344        hal_texture: A::Texture,
345        desc: &TextureDescriptor<'_>,
346        initial_state: wgt::TextureUses,
347    ) -> Texture {
348        let texture = unsafe {
349            let core_device = self.inner.as_core();
350            core_device.context.create_texture_from_hal::<A>(
351                hal_texture,
352                core_device,
353                desc,
354                initial_state,
355            )
356        };
357        Texture {
358            inner: texture.into(),
359        }
360    }
361
362    /// Wraps a foreign [`webgpu::GpuTexture`] (e.g. a canvas `getCurrentTexture()` result)
363    /// as a [`Texture`] without any copy.
364    ///
365    /// The wrapped texture is *external*: dropping the returned `Texture` (or
366    /// calling [`Texture::destroy`] on it) does **not** call `GpuTexture.destroy()`
367    /// on the underlying handle - its lifetime is the caller's responsibility.
368    ///
369    /// If `drop_callback` is `Some`, it fires when wgpu releases its last
370    /// reference to the wrapped handle. wgpu never calls `GpuTexture.destroy()`
371    /// itself on a wrapped texture; to hand the handle's lifetime to wgpu,
372    /// supply a callback that calls `GpuTexture.destroy()`. The callback can
373    /// also be used to free a pool slot or notify dependent code that wgpu is
374    /// done with the handle. Pass `None` if the caller manages the handle's
375    /// lifetime entirely on their own.
376    ///
377    /// This is the WebGPU counterpart of [`Self::create_texture_from_hal`].
378    /// A `Some` `drop_callback` plays the same role as `wgpu_hal::DropCallback`
379    /// does on the Vulkan backend. The `None` case differs: here the texture is
380    /// always external and wgpu never destroys it, whereas on Vulkan a `None`
381    /// callback means wgpu takes ownership of the image and destroys it.
382    ///
383    /// The caller must guarantee:
384    ///
385    /// 1. `texture` was produced by the same underlying `GpuDevice` that this `Device` wraps.
386    /// 2. `desc.format`, `desc.size`, `desc.usage`, `desc.dimension`,
387    ///    `desc.mip_level_count`, and `desc.sample_count` match the actual
388    ///    `GPUTexture`'s reflected values. wgpu stores these verbatim and
389    ///    returns them from [`Texture::size`], [`Texture::format`], etc.
390    ///    without re-checking the handle; a mismatch yields silently incorrect
391    ///    metadata and, downstream, `GPUValidationError`s rather than memory
392    ///    unsafety (the browser bounds every access).
393    /// 3. The underlying `GpuTexture` must remain alive for as long as wgpu
394    ///    may use it (e.g. until any submitted command buffer that references
395    ///    it has finished executing). If `drop_callback` is `Some`, it is
396    ///    sufficient to keep the handle alive until the callback fires.
397    #[cfg(webgpu)]
398    #[must_use]
399    pub fn create_texture_from_webgpu_handle(
400        &self,
401        texture: webgpu::GpuTexture,
402        desc: &TextureDescriptor<'_>,
403        drop_callback: Option<webgpu::DropCallback>,
404    ) -> Texture {
405        let inner = self
406            .inner
407            .as_webgpu()
408            .wrap_external_texture(texture, desc, drop_callback);
409        Texture { inner }
410    }
411
412    /// Returns the underlying [`webgpu::GpuDevice`] handle if this `Device`
413    /// is on the WebGPU backend, otherwise `None`.
414    #[cfg(webgpu)]
415    pub fn as_webgpu(&self) -> Option<&webgpu::GpuDevice> {
416        self.inner.as_webgpu_opt().map(|wd| &wd.inner)
417    }
418
419    /// Creates a new [`ExternalTexture`].
420    #[must_use]
421    pub fn create_external_texture(
422        &self,
423        desc: &ExternalTextureDescriptor<'_>,
424        planes: &[&TextureView],
425    ) -> ExternalTexture {
426        let external_texture = self.inner.create_external_texture(desc, planes);
427
428        ExternalTexture {
429            inner: external_texture,
430        }
431    }
432
433    /// Creates a [`Buffer`] from a wgpu-hal Buffer.
434    ///
435    /// # Types
436    ///
437    /// The type of `A::Buffer` depends on the backend:
438    ///
439    #[doc = crate::macros::hal_type_vulkan!("Buffer")]
440    #[doc = crate::macros::hal_type_metal!("Buffer")]
441    #[doc = crate::macros::hal_type_dx12!("Buffer")]
442    #[doc = crate::macros::hal_type_gles!("Buffer")]
443    ///
444    /// # Safety
445    ///
446    /// - `hal_buffer` must be created from this device internal handle
447    /// - `hal_buffer` must be created respecting `desc`
448    /// - `hal_buffer` must be initialized
449    /// - `hal_buffer` must not have zero size
450    #[cfg(wgpu_core)]
451    #[must_use]
452    pub unsafe fn create_buffer_from_hal<A: hal::Api>(
453        &self,
454        hal_buffer: A::Buffer,
455        desc: &BufferDescriptor<'_>,
456    ) -> Buffer {
457        let map_context = MapContext::new(desc.mapped_at_creation.then_some(0..desc.size));
458
459        let buffer = unsafe {
460            let core_device = self.inner.as_core();
461            core_device
462                .context
463                .create_buffer_from_hal::<A>(hal_buffer, core_device, desc)
464        };
465
466        Buffer {
467            inner: buffer.into(),
468            map_context: Arc::new(Mutex::new(map_context)),
469        }
470    }
471
472    /// Creates a new [`Sampler`].
473    ///
474    /// `desc` specifies the behavior of the sampler.
475    #[must_use]
476    pub fn create_sampler(&self, desc: &SamplerDescriptor<'_>) -> Sampler {
477        let sampler = self.inner.create_sampler(desc);
478        Sampler { inner: sampler }
479    }
480
481    /// Creates a new [`QuerySet`].
482    #[must_use]
483    pub fn create_query_set(&self, desc: &QuerySetDescriptor<'_>) -> QuerySet {
484        let query_set = self.inner.create_query_set(desc);
485        QuerySet { inner: query_set }
486    }
487
488    /// Set a callback which will be called for all errors that are not handled in error scopes.
489    pub fn on_uncaptured_error(&self, handler: Arc<dyn UncapturedErrorHandler>) {
490        self.inner.on_uncaptured_error(handler)
491    }
492
493    /// Push an error scope on this device's thread-local error scope
494    /// stack. All operations on this device, or on resources created
495    /// from this device, will have their errors captured by this scope
496    /// until the scope is popped.
497    ///
498    /// Scopes must be popped in reverse order to their creation. If
499    /// a guard is dropped without being `pop()`ped, the scope will be
500    /// popped, and the captured errors will be dropped.
501    ///
502    /// Multiple error scopes may be active at one time, forming a stack.
503    /// Each error will be reported to the inner-most scope that matches
504    /// its filter.
505    ///
506    /// With the `std` feature enabled, this stack is **thread-local**.
507    /// Without, this is **global** to all threads.
508    ///
509    /// ```rust
510    /// # async move {
511    /// # let device: wgpu::Device = unreachable!();
512    /// let error_scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
513    ///
514    /// // ...
515    /// // do work that may produce validation errors
516    /// // ...
517    ///
518    /// // pop the error scope and get a future for the result
519    /// let error_future = error_scope.pop();
520    ///
521    /// // await the future to get the error, if any
522    /// let error = error_future.await;
523    /// # };
524    /// ```
525    pub fn push_error_scope(&self, filter: ErrorFilter) -> ErrorScopeGuard {
526        let index = self.inner.push_error_scope(filter);
527        ErrorScopeGuard {
528            device: self.inner.clone(),
529            index,
530            popped: false,
531            _phantom: PhantomData,
532        }
533    }
534
535    /// Starts a capture in the attached graphics debugger.
536    ///
537    /// This behaves differently depending on which graphics debugger is attached:
538    ///
539    /// - Renderdoc: Calls [`StartFrameCapture(device, NULL)`][rd].
540    /// - Xcode: Creates a capture with [`MTLCaptureManager`][xcode].
541    /// - None: No action is taken.
542    ///
543    /// # Safety
544    ///
545    /// - There should not be any other captures currently active.
546    /// - All other safety rules are defined by the graphics debugger, see the
547    ///   documentation for the specific debugger.
548    /// - In general, graphics debuggers can easily cause crashes, so this isn't
549    ///   ever guaranteed to be sound.
550    ///
551    /// # Tips
552    ///
553    /// - Debuggers need to capture both the recording of the commands and the
554    ///   submission of the commands to the GPU. Try to wrap all of your
555    ///   gpu work in a capture.
556    /// - If you encounter issues, try waiting for the GPU to finish all work
557    ///   before stopping the capture.
558    ///
559    /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv417StartFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle
560    /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager
561    #[doc(alias = "start_renderdoc_capture")]
562    #[doc(alias = "start_xcode_capture")]
563    pub unsafe fn start_graphics_debugger_capture(&self) {
564        unsafe { self.inner.start_graphics_debugger_capture() }
565    }
566
567    /// Stops the current capture in the attached graphics debugger.
568    ///
569    /// This behaves differently depending on which graphics debugger is attached:
570    ///
571    /// - Renderdoc: Calls [`EndFrameCapture(device, NULL)`][rd].
572    /// - Xcode: Stops the capture with [`MTLCaptureManager`][xcode].
573    /// - None: No action is taken.
574    ///
575    /// # Safety
576    ///
577    /// - There should be a capture currently active.
578    /// - All other safety rules are defined by the graphics debugger, see the
579    ///   documentation for the specific debugger.
580    /// - In general, graphics debuggers can easily cause crashes, so this isn't
581    ///   ever guaranteed to be sound.
582    ///
583    /// # Tips
584    ///
585    /// - If you encounter issues, try to submit all work to the GPU, and waiting
586    ///   for that work to finish before stopping the capture.
587    ///
588    /// [rd]: https://renderdoc.org/docs/in_application_api.html#_CPPv415EndFrameCapture23RENDERDOC_DevicePointer22RENDERDOC_WindowHandle
589    /// [xcode]: https://developer.apple.com/documentation/metal/mtlcapturemanager
590    #[doc(alias = "stop_renderdoc_capture")]
591    #[doc(alias = "stop_xcode_capture")]
592    pub unsafe fn stop_graphics_debugger_capture(&self) {
593        unsafe { self.inner.stop_graphics_debugger_capture() }
594    }
595
596    /// Query internal counters from the native backend for debugging purposes.
597    ///
598    /// Some backends may not set all counters, or may not set any counter at all.
599    /// The `counters` cargo feature must be enabled for any counter to be set.
600    ///
601    /// If a counter is not set, its contains its default value (zero).
602    #[must_use]
603    pub fn get_internal_counters(&self) -> wgt::InternalCounters {
604        self.inner.get_internal_counters()
605    }
606
607    /// Generate an GPU memory allocation report if the underlying backend supports it.
608    ///
609    /// Backends that do not support producing these reports return `None`. A backend may
610    /// Support it and still return `None` if it is not using performing sub-allocation,
611    /// for example as a workaround for driver issues.
612    #[must_use]
613    pub fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
614        self.inner.generate_allocator_report()
615    }
616
617    /// Get the [`wgpu_hal`] device from this `Device`.
618    ///
619    /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
620    /// and pass that struct to the to the `A` type parameter.
621    ///
622    /// Returns a guard that dereferences to the type of the hal backend
623    /// which implements [`A::Device`].
624    ///
625    /// # Types
626    ///
627    /// The returned type depends on the backend:
628    ///
629    #[doc = crate::macros::hal_type_vulkan!("Device")]
630    #[doc = crate::macros::hal_type_metal!("Device")]
631    #[doc = crate::macros::hal_type_dx12!("Device")]
632    #[doc = crate::macros::hal_type_gles!("Device")]
633    ///
634    /// # Errors
635    ///
636    /// This method will return None if:
637    /// - The device is not from the backend specified by `A`.
638    /// - The device is from the `webgpu` or `custom` backend.
639    ///
640    /// On the `webgpu` backend, use `as_webgpu` instead.
641    ///
642    /// # Safety
643    ///
644    /// - The returned resource must not be destroyed unless the guard
645    ///   is the last reference to it and it is not in use by the GPU.
646    ///   The guard and handle may be dropped at any time however.
647    /// - All the safety requirements of wgpu-hal must be upheld.
648    ///
649    /// [`A::Device`]: hal::Api::Device
650    #[cfg(wgpu_core)]
651    pub unsafe fn as_hal<A: hal::Api>(
652        &self,
653    ) -> Option<impl Deref<Target = A::Device> + WasmNotSendSync> {
654        let device = self.inner.as_core_opt()?;
655        unsafe { device.context.device_as_hal::<A>(device) }
656    }
657
658    /// Destroy this device.
659    pub fn destroy(&self) {
660        self.inner.destroy()
661    }
662
663    /// Set a DeviceLostCallback on this device.
664    pub fn set_device_lost_callback(
665        &self,
666        callback: impl Fn(DeviceLostReason, String) + Send + 'static,
667    ) {
668        self.inner.set_device_lost_callback(Box::new(callback))
669    }
670
671    /// Create a [`PipelineCache`] with initial data
672    ///
673    /// This can be passed to [`Device::create_compute_pipeline`]
674    /// and [`Device::create_render_pipeline`] to either accelerate these
675    /// or add the cache results from those.
676    ///
677    /// # Safety
678    ///
679    /// If the `data` field of `desc` is set, it must have previously been returned from a call
680    /// to [`PipelineCache::get_data`][^saving]. This `data` will only be used if it came
681    /// from an adapter with the same [`util::pipeline_cache_key`].
682    /// This *is* compatible across wgpu versions, as any data format change will
683    /// be accounted for.
684    ///
685    /// It is *not* supported to bring caches from previous direct uses of backend APIs
686    /// into this method.
687    ///
688    /// # Errors
689    ///
690    /// Returns an error value if:
691    ///  * the [`PIPELINE_CACHE`](wgt::Features::PIPELINE_CACHE) feature is not enabled
692    ///  * this device is invalid; or
693    ///  * the device is out of memory
694    ///
695    /// This method also returns an error value if:
696    ///  * The `fallback` field on `desc` is false; and
697    ///  * the `data` provided would not be used[^data_not_used]
698    ///
699    /// If an error value is used in subsequent calls, default caching will be used.
700    ///
701    /// [^saving]: We do recognise that saving this data to disk means this condition
702    /// is impossible to fully prove. Consider the risks for your own application in this case.
703    ///
704    /// [^data_not_used]: This data may be not used if: the data was produced by a prior
705    /// version of wgpu; or was created for an incompatible adapter, or there was a GPU driver
706    /// update. In some cases, the data might not be used and a real value is returned,
707    /// this is left to the discretion of GPU drivers.
708    #[must_use]
709    pub unsafe fn create_pipeline_cache(
710        &self,
711        desc: &PipelineCacheDescriptor<'_>,
712    ) -> PipelineCache {
713        let cache = unsafe { self.inner.create_pipeline_cache(desc) };
714        PipelineCache { inner: cache }
715    }
716}
717
718/// [`Features::EXPERIMENTAL_RAY_QUERY`] must be enabled on the device in order to call these functions.
719impl Device {
720    /// Create a bottom level acceleration structure, used inside a top level acceleration structure for ray tracing.
721    /// - `desc`: The descriptor of the acceleration structure.
722    /// - `sizes`: Size descriptor limiting what can be built into the acceleration structure.
723    ///
724    /// # Validation
725    /// If any of the following is not satisfied a validation error is generated
726    ///
727    /// The device ***must*** have [`Features::EXPERIMENTAL_RAY_QUERY`] enabled.
728    /// if `sizes` is [`BlasGeometrySizeDescriptors::Triangles`] then the following must be satisfied
729    /// - For every geometry descriptor (for the purposes this is called `geo_desc`) of `sizes.descriptors` the following must be satisfied:
730    ///     - `geo_desc.vertex_format` must be within allowed formats (allowed formats for a given feature set
731    ///       may be queried with [`Features::allowed_vertex_formats_for_blas`]).
732    ///     - Both or neither of `geo_desc.index_format` and `geo_desc.index_count` must be provided.
733    ///
734    /// [`Features::EXPERIMENTAL_RAY_QUERY`]: wgt::Features::EXPERIMENTAL_RAY_QUERY
735    /// [`Features::allowed_vertex_formats_for_blas`]: wgt::Features::allowed_vertex_formats_for_blas
736    #[must_use]
737    pub fn create_blas(
738        &self,
739        desc: &CreateBlasDescriptor<'_>,
740        sizes: BlasGeometrySizeDescriptors,
741    ) -> Blas {
742        let (handle, blas) = self.inner.create_blas(desc, sizes);
743
744        Blas {
745            inner: blas,
746            handle,
747        }
748    }
749
750    /// Create a top level acceleration structure, used for ray tracing.
751    /// - `desc`: The descriptor of the acceleration structure.
752    ///
753    /// # Validation
754    /// If any of the following is not satisfied a validation error is generated
755    ///
756    /// The device ***must*** have [`Features::EXPERIMENTAL_RAY_QUERY`] enabled.
757    ///
758    /// [`Features::EXPERIMENTAL_RAY_QUERY`]: wgt::Features::EXPERIMENTAL_RAY_QUERY
759    #[must_use]
760    pub fn create_tlas(&self, desc: &CreateTlasDescriptor<'_>) -> Tlas {
761        let tlas = self.inner.create_tlas(desc);
762
763        Tlas {
764            inner: tlas,
765            instances: vec![None; desc.max_instances as usize],
766            lowest_unmodified: 0,
767        }
768    }
769}
770
771/// Requesting a device from an [`Adapter`] failed.
772#[derive(Clone, Debug)]
773pub struct RequestDeviceError {
774    pub(crate) inner: RequestDeviceErrorKind,
775}
776
777impl RequestDeviceError {
778    /// Construct an error from a custom backend message. This is mainly useful for custom backends.
779    #[cfg(custom)]
780    pub fn from_message(message: String) -> Self {
781        RequestDeviceError {
782            inner: RequestDeviceErrorKind::Custom(message),
783        }
784    }
785}
786
787#[derive(Clone, Debug)]
788pub(crate) enum RequestDeviceErrorKind {
789    /// Error from [`wgpu_core`].
790    // must match dependency cfg
791    #[cfg(wgpu_core)]
792    Core(wgc::instance::RequestDeviceError),
793
794    /// Error from web API that was called by `wgpu` to request a device.
795    ///
796    /// (This is currently never used by the webgl backend, but it could be.)
797    #[cfg(webgpu)]
798    WebGpu(String),
799
800    /// Error from a custom backend.
801    #[cfg(custom)]
802    Custom(String),
803}
804
805static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
806
807impl fmt::Display for RequestDeviceError {
808    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
809        match &self.inner {
810            #[cfg(wgpu_core)]
811            RequestDeviceErrorKind::Core(error) => error.fmt(_f),
812            #[cfg(webgpu)]
813            RequestDeviceErrorKind::WebGpu(error) => {
814                write!(_f, "{error}")
815            }
816            #[cfg(custom)]
817            RequestDeviceErrorKind::Custom(msg) => write!(_f, "{msg}"),
818            #[cfg(not(any(webgpu, wgpu_core)))]
819            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
820        }
821    }
822}
823
824impl error::Error for RequestDeviceError {
825    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
826        match &self.inner {
827            #[cfg(wgpu_core)]
828            RequestDeviceErrorKind::Core(error) => error.source(),
829            #[cfg(webgpu)]
830            RequestDeviceErrorKind::WebGpu(_) => None,
831            #[cfg(custom)]
832            RequestDeviceErrorKind::Custom(_) => None,
833            #[cfg(not(any(webgpu, wgpu_core)))]
834            _ => unimplemented!("unknown `RequestDeviceErrorKind`"),
835        }
836    }
837}
838
839#[cfg(wgpu_core)]
840impl From<wgc::instance::RequestDeviceError> for RequestDeviceError {
841    fn from(error: wgc::instance::RequestDeviceError) -> Self {
842        Self {
843            inner: RequestDeviceErrorKind::Core(error),
844        }
845    }
846}
847
848/// Guard for an error scope pushed with [`Device::push_error_scope()`].
849///
850/// Call [`pop()`] to pop the scope and get a future for the result. If
851/// the guard is dropped without being popped explicitly, the scope will still be popped,
852/// and the captured errors will be dropped.
853///
854/// This guard is neither `Send` nor `Sync`, as error scopes are handled
855/// on a per-thread basis when the `std` feature is enabled.
856///
857/// [`pop()`]: ErrorScopeGuard::pop
858#[must_use = "Error scopes must be explicitly popped to retrieve errors they catch"]
859pub struct ErrorScopeGuard {
860    device: dispatch::DispatchDevice,
861    index: u32,
862    popped: bool,
863    // Ensure the guard is !Send and !Sync
864    _phantom: PhantomData<*mut ()>,
865}
866
867static_assertions::assert_not_impl_any!(ErrorScopeGuard: Send, Sync);
868
869impl ErrorScopeGuard {
870    /// Pops the error scope.
871    ///
872    /// Returns a future which resolves to the error captured by this scope, if any.
873    /// The pop takes effect immediately; the future does not need to be awaited before doing work that is outside of this error scope.
874    pub fn pop(mut self) -> impl Future<Output = Option<Error>> + WasmNotSend {
875        self.popped = true;
876        self.device.pop_error_scope(self.index)
877    }
878}
879
880impl Drop for ErrorScopeGuard {
881    fn drop(&mut self) {
882        if !self.popped {
883            drop(self.device.pop_error_scope(self.index));
884        }
885    }
886}
887
888impl fmt::Debug for ErrorScopeGuard {
889    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
890        let ErrorScopeGuard {
891            device,
892            index,
893            popped,
894            _phantom: _,
895        } = self;
896        f.debug_struct("ErrorScopeGuard")
897            .field("device", device)
898            .field("index", index)
899            .field("popped", popped)
900            .finish()
901    }
902}