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