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}