wgpu_hal/lib.rs
1//! A cross-platform unsafe graphics abstraction.
2//!
3//! This crate defines a set of traits abstracting over modern graphics APIs,
4//! with implementations ("backends") for Vulkan, Metal, Direct3D, and GL.
5//!
6//! `wgpu-hal` is a spiritual successor to
7//! [gfx-hal](https://github.com/gfx-rs/gfx), but with reduced scope, and
8//! oriented towards WebGPU implementation goals. It has no overhead for
9//! validation or tracking, and the API translation overhead is kept to the bare
10//! minimum by the design of WebGPU. This API can be used for resource-demanding
11//! applications and engines.
12//!
13//! The `wgpu-hal` crate's main design choices:
14//!
15//! - Our traits are meant to be *portable*: proper use
16//! should get equivalent results regardless of the backend.
17//!
18//! - Our traits' contracts are *unsafe*: implementations perform minimal
19//! validation, if any, and incorrect use will often cause undefined behavior.
20//! This allows us to minimize the overhead we impose over the underlying
21//! graphics system. If you need safety, the [`wgpu-core`] crate provides a
22//! safe API for driving `wgpu-hal`, implementing all necessary validation,
23//! resource state tracking, and so on. (Note that `wgpu-core` is designed for
24//! use via FFI; the [`wgpu`] crate provides more idiomatic Rust bindings for
25//! `wgpu-core`.) Or, you can do your own validation.
26//!
27//! - In the same vein, returned errors *only cover cases the user can't
28//! anticipate*, like running out of memory or losing the device. Any errors
29//! that the user could reasonably anticipate are their responsibility to
30//! avoid. For example, `wgpu-hal` returns no error for mapping a buffer that's
31//! not mappable: as the buffer creator, the user should already know if they
32//! can map it.
33//!
34//! - We use *static dispatch*. The traits are not
35//! generally object-safe. You must select a specific backend type
36//! like [`vulkan::Api`] or [`metal::Api`], and then use that
37//! according to the main traits, or call backend-specific methods.
38//!
39//! - We use *idiomatic Rust parameter passing*,
40//! taking objects by reference, returning them by value, and so on,
41//! unlike `wgpu-core`, which refers to objects by ID.
42//!
43//! - We map buffer contents *persistently*. This means that the buffer can
44//! remain mapped on the CPU while the GPU reads or writes to it. You must
45//! explicitly indicate when data might need to be transferred between CPU and
46//! GPU, if [`Device::map_buffer`] indicates that this is necessary.
47//!
48//! - You must record *explicit barriers* between different usages of a
49//! resource. For example, if a buffer is written to by a compute
50//! shader, and then used as and index buffer to a draw call, you
51//! must use [`CommandEncoder::transition_buffers`] between those two
52//! operations.
53//!
54//! - Pipeline layouts are *explicitly specified* when setting bind groups.
55//! Incompatible layouts disturb groups bound at higher indices.
56//!
57//! - The API *accepts collections as iterators*, to avoid forcing the user to
58//! store data in particular containers. The implementation doesn't guarantee
59//! that any of the iterators are drained, unless stated otherwise by the
60//! function documentation. For this reason, we recommend that iterators don't
61//! do any mutating work.
62//!
63//! Unfortunately, `wgpu-hal`'s safety requirements are not fully documented.
64//! Ideally, all trait methods would have doc comments setting out the
65//! requirements users must meet to ensure correct and portable behavior. If you
66//! are aware of a specific requirement that a backend imposes that is not
67//! ensured by the traits' documented rules, please file an issue. Or, if you are
68//! a capable technical writer, please file a pull request!
69//!
70//! [`wgpu-core`]: https://crates.io/crates/wgpu-core
71//! [`wgpu`]: https://crates.io/crates/wgpu
72//! [`vulkan::Api`]: vulkan/struct.Api.html
73//! [`metal::Api`]: metal/struct.Api.html
74//!
75//! ## Primary backends
76//!
77//! The `wgpu-hal` crate has full-featured backends implemented on the following
78//! platform graphics APIs:
79//!
80//! - Vulkan, available on Linux, Android, and Windows, using the [`ash`] crate's
81//! Vulkan bindings. It's also available on macOS, if you install [MoltenVK].
82//!
83//! - Metal on macOS, using the [`metal`] crate's bindings.
84//!
85//! - Direct3D 12 on Windows, using the [`windows`] crate's bindings.
86//!
87//! [`ash`]: https://crates.io/crates/ash
88//! [MoltenVK]: https://github.com/KhronosGroup/MoltenVK
89//! [`metal`]: https://crates.io/crates/metal
90//! [`windows`]: https://crates.io/crates/windows
91//!
92//! ## Secondary backends
93//!
94//! The `wgpu-hal` crate has a partial implementation based on the following
95//! platform graphics API:
96//!
97//! - The GL backend is available anywhere OpenGL, OpenGL ES, or WebGL are
98//! available. See the [`gles`] module documentation for details.
99//!
100//! [`gles`]: gles/index.html
101//!
102//! You can see what capabilities an adapter is missing by checking the
103//! [`DownlevelCapabilities`][tdc] in [`ExposedAdapter::capabilities`], available
104//! from [`Instance::enumerate_adapters`].
105//!
106//! The API is generally designed to fit the primary backends better than the
107//! secondary backends, so the latter may impose more overhead.
108//!
109//! [tdc]: wgt::DownlevelCapabilities
110//!
111//! ## Traits
112//!
113//! The `wgpu-hal` crate defines a handful of traits that together
114//! represent a cross-platform abstraction for modern GPU APIs.
115//!
116//! - The [`Api`] trait represents a `wgpu-hal` backend. It has no methods of its
117//! own, only a collection of associated types.
118//!
119//! - [`Api::Instance`] implements the [`Instance`] trait. [`Instance::init`]
120//! creates an instance value, which you can use to enumerate the adapters
121//! available on the system. For example, [`vulkan::Api::Instance::init`][Ii]
122//! returns an instance that can enumerate the Vulkan physical devices on your
123//! system.
124//!
125//! - [`Api::Adapter`] implements the [`Adapter`] trait, representing a
126//! particular device from a particular backend. For example, a Vulkan instance
127//! might have a Lavapipe software adapter and a GPU-based adapter.
128//!
129//! - [`Api::Device`] implements the [`Device`] trait, representing an active
130//! link to a device. You get a device value by calling [`Adapter::open`], and
131//! then use it to create buffers, textures, shader modules, and so on.
132//!
133//! - [`Api::Queue`] implements the [`Queue`] trait, which you use to submit
134//! command buffers to a given device.
135//!
136//! - [`Api::CommandEncoder`] implements the [`CommandEncoder`] trait, which you
137//! use to build buffers of commands to submit to a queue. This has all the
138//! methods for drawing and running compute shaders, which is presumably what
139//! you're here for.
140//!
141//! - [`Api::Surface`] implements the [`Surface`] trait, which represents a
142//! swapchain for presenting images on the screen, via interaction with the
143//! system's window manager.
144//!
145//! The [`Api`] trait has various other associated types like [`Api::Buffer`] and
146//! [`Api::Texture`] that represent resources the rest of the interface can
147//! operate on, but these generally do not have their own traits.
148//!
149//! [Ii]: Instance::init
150//!
151//! ## Validation is the calling code's responsibility, not `wgpu-hal`'s
152//!
153//! As much as possible, `wgpu-hal` traits place the burden of validation,
154//! resource tracking, and state tracking on the caller, not on the trait
155//! implementations themselves. Anything which can reasonably be handled in
156//! backend-independent code should be. A `wgpu_hal` backend's sole obligation is
157//! to provide portable behavior, and report conditions that the calling code
158//! can't reasonably anticipate, like device loss or running out of memory.
159//!
160//! The `wgpu` crate collection is intended for use in security-sensitive
161//! applications, like web browsers, where the API is available to untrusted
162//! code. This means that `wgpu-core`'s validation is not simply a service to
163//! developers, to be provided opportunistically when the performance costs are
164//! acceptable and the necessary data is ready at hand. Rather, `wgpu-core`'s
165//! validation must be exhaustive, to ensure that even malicious content cannot
166//! provoke and exploit undefined behavior in the platform's graphics API.
167//!
168//! Because graphics APIs' requirements are complex, the only practical way for
169//! `wgpu` to provide exhaustive validation is to comprehensively track the
170//! lifetime and state of all the resources in the system. Implementing this
171//! separately for each backend is infeasible; effort would be better spent
172//! making the cross-platform validation in `wgpu-core` legible and trustworthy.
173//! Fortunately, the requirements are largely similar across the various
174//! platforms, so cross-platform validation is practical.
175//!
176//! Some backends have specific requirements that aren't practical to foist off
177//! on the `wgpu-hal` user. For example, properly managing macOS Objective-C or
178//! Microsoft COM reference counts is best handled by using appropriate pointer
179//! types within the backend.
180//!
181//! A desire for "defense in depth" may suggest performing additional validation
182//! in `wgpu-hal` when the opportunity arises, but this must be done with
183//! caution. Even experienced contributors infer the expectations their changes
184//! must meet by considering not just requirements made explicit in types, tests,
185//! assertions, and comments, but also those implicit in the surrounding code.
186//! When one sees validation or state-tracking code in `wgpu-hal`, it is tempting
187//! to conclude, "Oh, `wgpu-hal` checks for this, so `wgpu-core` needn't worry
188//! about it - that would be redundant!" The responsibility for exhaustive
189//! validation always rests with `wgpu-core`, regardless of what may or may not
190//! be checked in `wgpu-hal`.
191//!
192//! To this end, any "defense in depth" validation that does appear in `wgpu-hal`
193//! for requirements that `wgpu-core` should have enforced should report failure
194//! via the `unreachable!` macro, because problems detected at this stage always
195//! indicate a bug in `wgpu-core`.
196//!
197//! ## Debugging
198//!
199//! Most of the information on the wiki [Debugging wgpu Applications][wiki-debug]
200//! page still applies to this API, with the exception of API tracing/replay
201//! functionality, which is only available in `wgpu-core`.
202//!
203//! [wiki-debug]: https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications
204
205#![no_std]
206#![cfg_attr(docsrs, feature(doc_cfg))]
207#![allow(
208 // this happens on the GL backend, where it is both thread safe and non-thread safe in the same code.
209 clippy::arc_with_non_send_sync,
210 // We don't use syntax sugar where it's not necessary.
211 clippy::match_like_matches_macro,
212 // Redundant matching is more explicit.
213 clippy::redundant_pattern_matching,
214 // Explicit lifetimes are often easier to reason about.
215 clippy::needless_lifetimes,
216 // No need for defaults in the internal types.
217 clippy::new_without_default,
218 // Matches are good and extendable, no need to make an exception here.
219 clippy::single_match,
220 // Push commands are more regular than macros.
221 clippy::vec_init_then_push,
222 // TODO!
223 clippy::missing_safety_doc,
224 // It gets in the way a lot and does not prevent bugs in practice.
225 clippy::pattern_type_mismatch,
226 // We should investigate these.
227 clippy::large_enum_variant
228)]
229#![warn(
230 clippy::alloc_instead_of_core,
231 clippy::ptr_as_ptr,
232 clippy::std_instead_of_alloc,
233 clippy::std_instead_of_core,
234 trivial_casts,
235 trivial_numeric_casts,
236 unsafe_op_in_unsafe_fn,
237 unused_extern_crates,
238 unused_qualifications
239)]
240
241extern crate alloc;
242extern crate wgpu_types as wgt;
243// Each of these backends needs `std` in some fashion; usually `std::thread` functions.
244#[cfg(any(dx12, gles_with_std, metal, vulkan))]
245#[macro_use]
246extern crate std;
247
248/// DirectX12 API internals.
249#[cfg(dx12)]
250pub mod dx12;
251/// GLES API internals.
252#[cfg(gles)]
253pub mod gles;
254/// Metal API internals.
255#[cfg(metal)]
256pub mod metal;
257/// A dummy API implementation.
258// TODO(https://github.com/gfx-rs/wgpu/issues/7120): this should have a cfg
259pub mod noop;
260/// Vulkan API internals.
261#[cfg(vulkan)]
262pub mod vulkan;
263
264pub mod auxil;
265pub mod api {
266 #[cfg(dx12)]
267 pub use super::dx12::Api as Dx12;
268 #[cfg(gles)]
269 pub use super::gles::Api as Gles;
270 #[cfg(metal)]
271 pub use super::metal::Api as Metal;
272 pub use super::noop::Api as Noop;
273 #[cfg(vulkan)]
274 pub use super::vulkan::Api as Vulkan;
275}
276
277mod dynamic;
278#[cfg(feature = "validation_canary")]
279mod validation_canary;
280
281#[cfg(feature = "validation_canary")]
282pub use validation_canary::{ValidationCanary, VALIDATION_CANARY};
283
284pub(crate) use dynamic::impl_dyn_resource;
285pub use dynamic::{
286 DynAccelerationStructure, DynAcquiredSurfaceTexture, DynAdapter, DynBindGroup,
287 DynBindGroupLayout, DynBuffer, DynCommandBuffer, DynCommandEncoder, DynComputePipeline,
288 DynDevice, DynExposedAdapter, DynFence, DynInstance, DynOpenDevice, DynPipelineCache,
289 DynPipelineLayout, DynQuerySet, DynQueue, DynRenderPipeline, DynResource, DynSampler,
290 DynShaderModule, DynSurface, DynSurfaceTexture, DynTexture, DynTextureView,
291};
292
293#[allow(unused)]
294use alloc::boxed::Box;
295use alloc::{borrow::Cow, string::String, vec::Vec};
296use core::{
297 borrow::Borrow,
298 error::Error,
299 fmt,
300 num::{NonZeroU32, NonZeroU64},
301 ops::{Range, RangeInclusive},
302 ptr::NonNull,
303};
304
305use bitflags::bitflags;
306use raw_window_handle::DisplayHandle;
307use thiserror::Error;
308use wgt::WasmNotSendSync;
309
310cfg_if::cfg_if! {
311 if #[cfg(supports_ptr_atomics)] {
312 use alloc::sync::Arc;
313 } else if #[cfg(feature = "portable-atomic")] {
314 use portable_atomic_util::Arc;
315 }
316}
317
318// - Vertex + Fragment
319// - Compute
320// Task + Mesh + Fragment
321pub const MAX_CONCURRENT_SHADER_STAGES: usize = 3;
322pub const MAX_ANISOTROPY: u8 = 16;
323pub const MAX_BIND_GROUPS: usize = 8;
324pub const MAX_VERTEX_BUFFERS: usize = 16;
325pub const MAX_COLOR_ATTACHMENTS: usize = 8;
326pub const MAX_MIP_LEVELS: u32 = 16;
327/// Size of a single occlusion/timestamp query, when copied into a buffer, in bytes.
328/// cbindgen:ignore
329pub const QUERY_SIZE: wgt::BufferAddress = 8;
330
331pub type Label<'a> = Option<&'a str>;
332pub type MemoryRange = Range<wgt::BufferAddress>;
333pub type FenceValue = u64;
334#[cfg(supports_64bit_atomics)]
335pub type AtomicFenceValue = core::sync::atomic::AtomicU64;
336#[cfg(not(supports_64bit_atomics))]
337pub type AtomicFenceValue = portable_atomic::AtomicU64;
338
339/// A callback to signal that wgpu is no longer using a resource.
340#[cfg(any(gles, vulkan))]
341pub type DropCallback = Box<dyn FnOnce() + Send + Sync + 'static>;
342
343#[cfg(any(gles, vulkan))]
344pub struct DropGuard {
345 callback: Option<DropCallback>,
346}
347
348#[cfg(all(any(gles, vulkan), any(native, Emscripten)))]
349impl DropGuard {
350 fn from_option(callback: Option<DropCallback>) -> Option<Self> {
351 callback.map(Self::new)
352 }
353
354 fn new(callback: DropCallback) -> Self {
355 Self {
356 callback: Some(callback),
357 }
358 }
359}
360
361#[cfg(any(gles, vulkan))]
362impl Drop for DropGuard {
363 fn drop(&mut self) {
364 if let Some(cb) = self.callback.take() {
365 (cb)();
366 }
367 }
368}
369
370#[cfg(any(gles, vulkan))]
371impl fmt::Debug for DropGuard {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 f.debug_struct("DropGuard").finish()
374 }
375}
376
377#[derive(Clone, Debug, PartialEq, Eq, Error)]
378pub enum DeviceError {
379 #[error("Out of memory")]
380 OutOfMemory,
381 #[error("Device is lost")]
382 Lost,
383 #[error("Unexpected error variant (driver implementation is at fault)")]
384 Unexpected,
385}
386
387#[cfg(any(dx12, vulkan))]
388impl From<gpu_allocator::AllocationError> for DeviceError {
389 fn from(result: gpu_allocator::AllocationError) -> Self {
390 match result {
391 gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory,
392 gpu_allocator::AllocationError::FailedToMap(e) => {
393 log::error!("gpu-allocator: Failed to map: {e}");
394 Self::Lost
395 }
396 gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => {
397 log::error!("gpu-allocator: No Compatible Memory Type Found");
398 Self::Lost
399 }
400 gpu_allocator::AllocationError::InvalidAllocationCreateDesc => {
401 log::error!("gpu-allocator: Invalid Allocation Creation Description");
402 Self::Lost
403 }
404 gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => {
405 log::error!("gpu-allocator: Invalid Allocator Creation Description: {e}");
406 Self::Lost
407 }
408
409 gpu_allocator::AllocationError::Internal(e) => {
410 log::error!("gpu-allocator: Internal Error: {e}");
411 Self::Lost
412 }
413 gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10
414 | gpu_allocator::AllocationError::CastableFormatsRequiresEnhancedBarriers
415 | gpu_allocator::AllocationError::CastableFormatsRequiresAtLeastDevice12 => {
416 unreachable!()
417 }
418 }
419 }
420}
421
422// A copy of gpu_allocator::AllocationSizes, allowing to read the configured value for
423// the dx12 backend, we should instead add getters to gpu_allocator::AllocationSizes
424// and remove this type.
425// https://github.com/Traverse-Research/gpu-allocator/issues/295
426#[cfg_attr(not(any(dx12, vulkan)), expect(dead_code))]
427pub(crate) struct AllocationSizes {
428 pub(crate) min_device_memblock_size: u64,
429 pub(crate) max_device_memblock_size: u64,
430 pub(crate) min_host_memblock_size: u64,
431 pub(crate) max_host_memblock_size: u64,
432}
433
434impl AllocationSizes {
435 #[allow(dead_code, reason = "may be unused on some platforms")]
436 pub(crate) fn from_memory_hints(memory_hints: &wgt::MemoryHints) -> Self {
437 // TODO: the allocator's configuration should take hardware capability into
438 // account.
439 const MB: u64 = 1024 * 1024;
440
441 match memory_hints {
442 wgt::MemoryHints::Performance => Self {
443 min_device_memblock_size: 128 * MB,
444 max_device_memblock_size: 256 * MB,
445 min_host_memblock_size: 64 * MB,
446 max_host_memblock_size: 128 * MB,
447 },
448 wgt::MemoryHints::MemoryUsage => Self {
449 min_device_memblock_size: 8 * MB,
450 max_device_memblock_size: 64 * MB,
451 min_host_memblock_size: 4 * MB,
452 max_host_memblock_size: 32 * MB,
453 },
454 wgt::MemoryHints::Manual {
455 suballocated_device_memory_block_size,
456 } => {
457 // TODO: https://github.com/gfx-rs/wgpu/issues/8625
458 // Would it be useful to expose the host size in memory hints
459 // instead of always using half of the device size?
460 let device_size = suballocated_device_memory_block_size;
461 let host_size = device_size.start / 2..device_size.end / 2;
462
463 // gpu_allocator clamps the sizes between 4MiB and 256MiB, but we clamp them ourselves since we use
464 // the sizes when detecting high memory pressure and there is no way to query the values otherwise.
465 Self {
466 min_device_memblock_size: device_size.start.clamp(4 * MB, 256 * MB),
467 max_device_memblock_size: device_size.end.clamp(4 * MB, 256 * MB),
468 min_host_memblock_size: host_size.start.clamp(4 * MB, 256 * MB),
469 max_host_memblock_size: host_size.end.clamp(4 * MB, 256 * MB),
470 }
471 }
472 }
473 }
474}
475
476#[cfg(any(dx12, vulkan))]
477impl From<AllocationSizes> for gpu_allocator::AllocationSizes {
478 fn from(value: AllocationSizes) -> gpu_allocator::AllocationSizes {
479 gpu_allocator::AllocationSizes::new(
480 value.min_device_memblock_size,
481 value.min_host_memblock_size,
482 )
483 .with_max_device_memblock_size(value.max_device_memblock_size)
484 .with_max_host_memblock_size(value.max_host_memblock_size)
485 }
486}
487
488#[allow(dead_code, reason = "may be unused on some platforms")]
489#[cold]
490fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
491 panic!("wgpu-hal invariant was violated (usage error): {txt}")
492}
493
494#[allow(dead_code, reason = "may be unused on some platforms")]
495#[cold]
496fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
497 panic!("wgpu-hal ran into a preventable internal error: {txt}")
498}
499
500#[derive(Clone, Debug, Eq, PartialEq, Error)]
501pub enum ShaderError {
502 #[error("Compilation failed: {0:?}")]
503 Compilation(String),
504 #[error(transparent)]
505 Device(#[from] DeviceError),
506}
507
508#[derive(Clone, Debug, Eq, PartialEq, Error)]
509pub enum PipelineError {
510 #[error("Linkage failed for stage {0:?}: {1}")]
511 Linkage(wgt::ShaderStages, String),
512 #[error("Entry point for stage {0:?} is invalid")]
513 EntryPoint(naga::ShaderStage),
514 #[error(transparent)]
515 Device(#[from] DeviceError),
516 #[error("Pipeline constant error for stage {0:?}: {1}")]
517 PipelineConstants(wgt::ShaderStages, String),
518}
519
520#[derive(Clone, Debug, Eq, PartialEq, Error)]
521pub enum PipelineCacheError {
522 #[error(transparent)]
523 Device(#[from] DeviceError),
524}
525
526#[derive(Clone, Debug, Eq, PartialEq, Error)]
527pub enum SurfaceError {
528 #[error("Surface is lost")]
529 Lost,
530 #[error("Surface is outdated, needs to be re-created")]
531 Outdated,
532 #[error("Timed out waiting for a surface texture")]
533 Timeout,
534 #[error("The window is occluded (e.g. minimized or behind another window). Try again once the window is no longer occluded.")]
535 Occluded,
536 #[error(transparent)]
537 Device(#[from] DeviceError),
538 #[error("Other reason: {0}")]
539 Other(&'static str),
540}
541
542/// Error occurring while trying to create an instance, or create a surface from an instance;
543/// typically relating to the state of the underlying graphics API or hardware.
544#[derive(Clone, Debug, Error)]
545#[error("{message}")]
546pub struct InstanceError {
547 /// These errors are very platform specific, so do not attempt to encode them as an enum.
548 ///
549 /// This message should describe the problem in sufficient detail to be useful for a
550 /// user-to-developer “why won't this work on my machine” bug report, and otherwise follow
551 /// <https://rust-lang.github.io/api-guidelines/interoperability.html#error-types-are-meaningful-and-well-behaved-c-good-err>.
552 message: String,
553
554 /// Underlying error value, if any is available.
555 #[source]
556 source: Option<Arc<dyn Error + Send + Sync + 'static>>,
557}
558
559impl InstanceError {
560 #[allow(dead_code, reason = "may be unused on some platforms")]
561 pub(crate) fn new(message: String) -> Self {
562 Self {
563 message,
564 source: None,
565 }
566 }
567 #[allow(dead_code, reason = "may be unused on some platforms")]
568 pub(crate) fn with_source(message: String, source: impl Error + Send + Sync + 'static) -> Self {
569 cfg_if::cfg_if! {
570 if #[cfg(supports_ptr_atomics)] {
571 let source = Arc::new(source);
572 } else {
573 // TODO(https://github.com/rust-lang/rust/issues/18598): avoid indirection via Box once arbitrary types support unsized coercion
574 let source: Box<dyn Error + Send + Sync + 'static> = Box::new(source);
575 let source = Arc::from(source);
576 }
577 }
578 Self {
579 message,
580 source: Some(source),
581 }
582 }
583}
584
585/// All the types and methods that make up a implementation on top of a backend.
586///
587/// Only the types that have non-dyn trait bounds have methods on them. Most methods
588/// are either on [`CommandEncoder`] or [`Device`].
589///
590/// The api can either be used through generics (through use of this trait and associated
591/// types) or dynamically through using the `Dyn*` traits.
592pub trait Api: Clone + fmt::Debug + Sized + WasmNotSendSync + 'static {
593 const VARIANT: wgt::Backend;
594
595 type Instance: DynInstance + Instance<A = Self>;
596 type Surface: DynSurface + Surface<A = Self>;
597 type Adapter: DynAdapter + Adapter<A = Self>;
598 type Device: DynDevice + Device<A = Self>;
599
600 type Queue: DynQueue + Queue<A = Self>;
601 type CommandEncoder: DynCommandEncoder + CommandEncoder<A = Self>;
602
603 /// This API's command buffer type.
604 ///
605 /// The only thing you can do with `CommandBuffer`s is build them
606 /// with a [`CommandEncoder`] and then pass them to
607 /// [`Queue::submit`] for execution, or destroy them by passing
608 /// them to [`CommandEncoder::reset_all`].
609 ///
610 /// [`CommandEncoder`]: Api::CommandEncoder
611 type CommandBuffer: DynCommandBuffer;
612
613 type Buffer: DynBuffer;
614 type Texture: DynTexture;
615 type SurfaceTexture: DynSurfaceTexture + Borrow<Self::Texture>;
616 type TextureView: DynTextureView;
617 type Sampler: DynSampler;
618 type QuerySet: DynQuerySet;
619
620 /// A value you can block on to wait for something to finish.
621 ///
622 /// A `Fence` holds a monotonically increasing [`FenceValue`]. You can call
623 /// [`Device::wait`] to block until a fence reaches or passes a value you
624 /// choose. [`Queue::submit`] can take a `Fence` and a [`FenceValue`] to
625 /// store in it when the submitted work is complete.
626 ///
627 /// Attempting to set a fence to a value less than its current value has no
628 /// effect.
629 ///
630 /// Waiting on a fence returns as soon as the fence reaches *or passes* the
631 /// requested value. This implies that, in order to reliably determine when
632 /// an operation has completed, operations must finish in order of
633 /// increasing fence values: if a higher-valued operation were to finish
634 /// before a lower-valued operation, then waiting for the fence to reach the
635 /// lower value could return before the lower-valued operation has actually
636 /// finished.
637 ///
638 /// Fences are internally synchronised by the hal, and so should not need to be
639 /// contained in external synchronisation primitives.
640 type Fence: DynFence;
641
642 type BindGroupLayout: DynBindGroupLayout;
643 type BindGroup: DynBindGroup;
644 type PipelineLayout: DynPipelineLayout;
645 type ShaderModule: DynShaderModule;
646 type RenderPipeline: DynRenderPipeline;
647 type ComputePipeline: DynComputePipeline;
648 type PipelineCache: DynPipelineCache;
649
650 type AccelerationStructure: DynAccelerationStructure + 'static;
651}
652
653pub trait Instance: Sized + WasmNotSendSync {
654 type A: Api;
655
656 unsafe fn init(desc: &InstanceDescriptor<'_>) -> Result<Self, InstanceError>;
657 unsafe fn create_surface(
658 &self,
659 display_handle: raw_window_handle::RawDisplayHandle,
660 window_handle: raw_window_handle::RawWindowHandle,
661 ) -> Result<<Self::A as Api>::Surface, InstanceError>;
662 /// `surface_hint` is only used by the GLES backend targeting WebGL2
663 unsafe fn enumerate_adapters(
664 &self,
665 surface_hint: Option<&<Self::A as Api>::Surface>,
666 ) -> Vec<ExposedAdapter<Self::A>>;
667}
668
669pub trait Surface: WasmNotSendSync {
670 type A: Api;
671
672 /// Configure `self` to use `device`.
673 ///
674 /// # Safety
675 ///
676 /// - All GPU work using `self` must have been completed.
677 /// - All [`AcquiredSurfaceTexture`]s must have been destroyed.
678 /// - All [`Api::TextureView`]s derived from the [`AcquiredSurfaceTexture`]s must have been destroyed.
679 /// - The surface `self` must not currently be configured to use any other [`Device`].
680 unsafe fn configure(
681 &self,
682 device: &<Self::A as Api>::Device,
683 config: &SurfaceConfiguration,
684 ) -> Result<(), SurfaceError>;
685
686 /// Unconfigure `self` on `device`.
687 ///
688 /// # Safety
689 ///
690 /// - All GPU work that uses `surface` must have been completed.
691 /// - All [`AcquiredSurfaceTexture`]s must have been destroyed.
692 /// - All [`Api::TextureView`]s derived from the [`AcquiredSurfaceTexture`]s must have been destroyed.
693 /// - The surface `self` must have been configured on `device`.
694 unsafe fn unconfigure(&self, device: &<Self::A as Api>::Device);
695
696 /// Return the next texture to be presented by `self`, for the caller to draw on.
697 ///
698 /// On success, return an [`AcquiredSurfaceTexture`] representing the
699 /// texture into which the caller should draw the image to be displayed on
700 /// `self`.
701 ///
702 /// If `timeout` elapses before `self` has a texture ready to be acquired,
703 /// return `Err(SurfaceError::Timeout)`. If `timeout` is `None`, wait
704 /// indefinitely, with no timeout.
705 ///
706 /// # Using an [`AcquiredSurfaceTexture`]
707 ///
708 /// On success, this function returns an [`AcquiredSurfaceTexture`] whose
709 /// [`texture`] field is a [`SurfaceTexture`] from which the caller can
710 /// [`borrow`] a [`Texture`] to draw on. The [`AcquiredSurfaceTexture`] also
711 /// carries some metadata about that [`SurfaceTexture`].
712 ///
713 /// All calls to [`Queue::submit`] that draw on that [`Texture`] must also
714 /// include the [`SurfaceTexture`] in the `surface_textures` argument.
715 ///
716 /// When you are done drawing on the texture, you can display it on `self`
717 /// by passing the [`SurfaceTexture`] and `self` to [`Queue::present`].
718 ///
719 /// If you do not wish to display the texture, you must pass the
720 /// [`SurfaceTexture`] to [`self.discard_texture`], so that it can be reused
721 /// by future acquisitions.
722 ///
723 /// The fence is internally synchronised by the hal.
724 ///
725 /// # Portability
726 ///
727 /// Some backends can't support a timeout when acquiring a texture. On these
728 /// backends, `timeout` is ignored.
729 ///
730 /// On macOS, this returns `Err(SurfaceError::Timeout)` when the window is
731 /// not visible (minimized, fully occluded, or on another virtual desktop)
732 /// to avoid blocking in `CAMetalLayer.nextDrawable()`.
733 ///
734 /// # Safety
735 ///
736 /// - The surface `self` must currently be configured on some [`Device`].
737 ///
738 /// - The `fence` argument must be the same [`Fence`] passed to all calls to
739 /// [`Queue::submit`] that used [`Texture`]s acquired from this surface.
740 ///
741 /// - You may only have one texture acquired from `self` at a time. When
742 /// `acquire_texture` returns `Ok(ast)`, you must pass the returned
743 /// [`SurfaceTexture`] `ast.texture` to either [`Queue::present`] or
744 /// [`Surface::discard_texture`] before calling `acquire_texture` again.
745 ///
746 /// [`texture`]: AcquiredSurfaceTexture::texture
747 /// [`SurfaceTexture`]: Api::SurfaceTexture
748 /// [`borrow`]: alloc::borrow::Borrow::borrow
749 /// [`Texture`]: Api::Texture
750 /// [`Fence`]: Api::Fence
751 /// [`self.discard_texture`]: Surface::discard_texture
752 unsafe fn acquire_texture(
753 &self,
754 timeout: Option<core::time::Duration>,
755 fence: &<Self::A as Api>::Fence,
756 ) -> Result<AcquiredSurfaceTexture<Self::A>, SurfaceError>;
757
758 /// Relinquish an acquired texture without presenting it.
759 ///
760 /// After this call, the texture underlying [`SurfaceTexture`] may be
761 /// returned by subsequent calls to [`self.acquire_texture`].
762 ///
763 /// # Safety
764 ///
765 /// - The surface `self` must currently be configured on some [`Device`].
766 ///
767 /// - `texture` must be a [`SurfaceTexture`] returned by a call to
768 /// [`self.acquire_texture`] that has not yet been passed to
769 /// [`Queue::present`].
770 ///
771 /// [`SurfaceTexture`]: Api::SurfaceTexture
772 /// [`self.acquire_texture`]: Surface::acquire_texture
773 unsafe fn discard_texture(&self, texture: <Self::A as Api>::SurfaceTexture);
774}
775
776pub trait Adapter: WasmNotSendSync {
777 type A: Api;
778
779 unsafe fn open(
780 &self,
781 features: wgt::Features,
782 limits: &wgt::Limits,
783 memory_hints: &wgt::MemoryHints,
784 ) -> Result<OpenDevice<Self::A>, DeviceError>;
785
786 /// Return the set of supported capabilities for a texture format.
787 unsafe fn texture_format_capabilities(
788 &self,
789 format: wgt::TextureFormat,
790 ) -> TextureFormatCapabilities;
791
792 /// Returns the capabilities of working with a specified surface.
793 ///
794 /// `None` means presentation is not supported for it.
795 unsafe fn surface_capabilities(
796 &self,
797 surface: &<Self::A as Api>::Surface,
798 ) -> Option<SurfaceCapabilities>;
799
800 /// Creates a [`PresentationTimestamp`] using the adapter's WSI.
801 ///
802 /// [`PresentationTimestamp`]: wgt::PresentationTimestamp
803 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp;
804
805 /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
806 /// If a usage is ordered, then if the buffer state doesn't change between draw calls,
807 /// there are no barriers needed for synchronization.
808 fn get_ordered_buffer_usages(&self) -> wgt::BufferUses;
809
810 /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
811 /// If a usage is ordered, then if the buffer state doesn't change between draw calls,
812 /// there are no barriers needed for synchronization.
813 fn get_ordered_texture_usages(&self) -> wgt::TextureUses;
814}
815
816/// A connection to a GPU and a pool of resources to use with it.
817///
818/// A `wgpu-hal` `Device` represents an open connection to a specific graphics
819/// processor, controlled via the backend [`Device::A`]. A `Device` is mostly
820/// used for creating resources. Each `Device` has an associated [`Queue`] used
821/// for command submission.
822///
823/// On Vulkan a `Device` corresponds to a logical device ([`VkDevice`]). Other
824/// backends don't have an exact analog: for example, [`ID3D12Device`]s and
825/// [`MTLDevice`]s are owned by the backends' [`wgpu_hal::Adapter`]
826/// implementations, and shared by all [`wgpu_hal::Device`]s created from that
827/// `Adapter`.
828///
829/// A `Device`'s life cycle is generally:
830///
831/// 1) Obtain a `Device` and its associated [`Queue`] by calling
832/// [`Adapter::open`].
833///
834/// Alternatively, the backend-specific types that implement [`Adapter`] often
835/// have methods for creating a `wgpu-hal` `Device` from a platform-specific
836/// handle. For example, [`vulkan::Adapter::device_from_raw`] can create a
837/// [`vulkan::Device`] from an [`ash::Device`].
838///
839/// 1) Create resources to use on the device by calling methods like
840/// [`Device::create_texture`] or [`Device::create_shader_module`].
841///
842/// 1) Call [`Device::create_command_encoder`] to obtain a [`CommandEncoder`],
843/// which you can use to build [`CommandBuffer`]s holding commands to be
844/// executed on the GPU.
845///
846/// 1) Call [`Queue::submit`] on the `Device`'s associated [`Queue`] to submit
847/// [`CommandBuffer`]s for execution on the GPU. If needed, call
848/// [`Device::wait`] to wait for them to finish execution.
849///
850/// 1) Free resources with methods like [`Device::destroy_texture`] or
851/// [`Device::destroy_shader_module`].
852///
853/// 1) Drop the device.
854///
855/// [`vkDevice`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VkDevice
856/// [`ID3D12Device`]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12device
857/// [`MTLDevice`]: https://developer.apple.com/documentation/metal/mtldevice
858/// [`wgpu_hal::Adapter`]: Adapter
859/// [`wgpu_hal::Device`]: Device
860/// [`vulkan::Adapter::device_from_raw`]: vulkan/struct.Adapter.html#method.device_from_raw
861/// [`vulkan::Device`]: vulkan/struct.Device.html
862/// [`ash::Device`]: https://docs.rs/ash/latest/ash/struct.Device.html
863/// [`CommandBuffer`]: Api::CommandBuffer
864///
865/// # Safety
866///
867/// As with other `wgpu-hal` APIs, [validation] is the caller's
868/// responsibility. Here are the general requirements for all `Device`
869/// methods:
870///
871/// - Any resource passed to a `Device` method must have been created by that
872/// `Device`. For example, a [`Texture`] passed to [`Device::destroy_texture`] must
873/// have been created with the `Device` passed as `self`.
874///
875/// - Resources may not be destroyed if they are used by any submitted command
876/// buffers that have not yet finished execution.
877///
878/// [validation]: index.html#validation-is-the-calling-codes-responsibility-not-wgpu-hals
879/// [`Texture`]: Api::Texture
880pub trait Device: WasmNotSendSync {
881 type A: Api;
882
883 /// Creates a new buffer.
884 ///
885 /// The initial usage is `wgt::BufferUses::empty()`.
886 unsafe fn create_buffer(
887 &self,
888 desc: &BufferDescriptor,
889 ) -> Result<<Self::A as Api>::Buffer, DeviceError>;
890
891 /// Free `buffer` and any GPU resources it owns.
892 ///
893 /// Note that backends are allowed to allocate GPU memory for buffers from
894 /// allocation pools, and this call is permitted to simply return `buffer`'s
895 /// storage to that pool, without making it available to other applications.
896 ///
897 /// # Safety
898 ///
899 /// - The given `buffer` must not currently be mapped.
900 unsafe fn destroy_buffer(&self, buffer: <Self::A as Api>::Buffer);
901
902 /// A hook for when a wgpu-core buffer is created from a raw wgpu-hal buffer.
903 unsafe fn add_raw_buffer(&self, buffer: &<Self::A as Api>::Buffer);
904
905 /// Return a pointer to CPU memory mapping the contents of `buffer`.
906 ///
907 /// Buffer mappings are persistent: the buffer may remain mapped on the CPU
908 /// while the GPU reads or writes to it. (Note that `wgpu_core` does not use
909 /// this feature: when a `wgpu_core::Buffer` is unmapped, the underlying
910 /// `wgpu_hal` buffer is also unmapped.)
911 ///
912 /// If this function returns `Ok(mapping)`, then:
913 ///
914 /// - `mapping.ptr` is the CPU address of the start of the mapped memory.
915 ///
916 /// - If `mapping.is_coherent` is `true`, then CPU writes to the mapped
917 /// memory are immediately visible on the GPU, and vice versa.
918 ///
919 /// # Safety
920 ///
921 /// - The given `buffer` must have been created with the [`MAP_READ`] or
922 /// [`MAP_WRITE`] flags set in [`BufferDescriptor::usage`].
923 ///
924 /// - The given `range` must fall within the size of `buffer`.
925 ///
926 /// - The caller must avoid data races between the CPU and the GPU. A data
927 /// race is any pair of accesses to a particular byte, one of which is a
928 /// write, that are not ordered with respect to each other by some sort of
929 /// synchronization operation.
930 ///
931 /// - If this function returns `Ok(mapping)` and `mapping.is_coherent` is
932 /// `false`, then:
933 ///
934 /// - Every CPU write to a mapped byte followed by a GPU read of that byte
935 /// must have at least one call to [`Device::flush_mapped_ranges`]
936 /// covering that byte that occurs between those two accesses.
937 ///
938 /// - Every GPU write to a mapped byte followed by a CPU read of that byte
939 /// must have at least one call to [`Device::invalidate_mapped_ranges`]
940 /// covering that byte that occurs between those two accesses.
941 ///
942 /// Note that the data race rule above requires that all such access pairs
943 /// be ordered, so it is meaningful to talk about what must occur
944 /// "between" them.
945 ///
946 /// - Zero-sized mappings are not allowed.
947 ///
948 /// - The returned [`BufferMapping::ptr`] must not be used after a call to
949 /// [`Device::unmap_buffer`].
950 ///
951 /// [`MAP_READ`]: wgt::BufferUses::MAP_READ
952 /// [`MAP_WRITE`]: wgt::BufferUses::MAP_WRITE
953 unsafe fn map_buffer(
954 &self,
955 buffer: &<Self::A as Api>::Buffer,
956 range: MemoryRange,
957 ) -> Result<BufferMapping, DeviceError>;
958
959 /// Remove the mapping established by the last call to [`Device::map_buffer`].
960 ///
961 /// # Safety
962 ///
963 /// - The given `buffer` must be currently mapped.
964 unsafe fn unmap_buffer(&self, buffer: &<Self::A as Api>::Buffer);
965
966 /// Indicate that CPU writes to mapped buffer memory should be made visible to the GPU.
967 ///
968 /// # Safety
969 ///
970 /// - The given `buffer` must be currently mapped.
971 ///
972 /// - All ranges produced by `ranges` must fall within `buffer`'s size.
973 unsafe fn flush_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I)
974 where
975 I: Iterator<Item = MemoryRange>;
976
977 /// Indicate that GPU writes to mapped buffer memory should be made visible to the CPU.
978 ///
979 /// # Safety
980 ///
981 /// - The given `buffer` must be currently mapped.
982 ///
983 /// - All ranges produced by `ranges` must fall within `buffer`'s size.
984 unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I)
985 where
986 I: Iterator<Item = MemoryRange>;
987
988 /// Creates a new texture.
989 ///
990 /// The initial usage for all subresources is `wgt::TextureUses::UNINITIALIZED`.
991 unsafe fn create_texture(
992 &self,
993 desc: &TextureDescriptor,
994 ) -> Result<<Self::A as Api>::Texture, DeviceError>;
995 unsafe fn destroy_texture(&self, texture: <Self::A as Api>::Texture);
996
997 /// A hook for when a wgpu-core texture is created from a raw wgpu-hal texture.
998 unsafe fn add_raw_texture(&self, texture: &<Self::A as Api>::Texture);
999
1000 unsafe fn create_texture_view(
1001 &self,
1002 texture: &<Self::A as Api>::Texture,
1003 desc: &TextureViewDescriptor,
1004 ) -> Result<<Self::A as Api>::TextureView, DeviceError>;
1005 unsafe fn destroy_texture_view(&self, view: <Self::A as Api>::TextureView);
1006 unsafe fn create_sampler(
1007 &self,
1008 desc: &SamplerDescriptor,
1009 ) -> Result<<Self::A as Api>::Sampler, DeviceError>;
1010 unsafe fn destroy_sampler(&self, sampler: <Self::A as Api>::Sampler);
1011
1012 /// Create a fresh [`CommandEncoder`].
1013 ///
1014 /// The new `CommandEncoder` is in the "closed" state.
1015 unsafe fn create_command_encoder(
1016 &self,
1017 desc: &CommandEncoderDescriptor<<Self::A as Api>::Queue>,
1018 ) -> Result<<Self::A as Api>::CommandEncoder, DeviceError>;
1019
1020 /// Creates a bind group layout.
1021 unsafe fn create_bind_group_layout(
1022 &self,
1023 desc: &BindGroupLayoutDescriptor,
1024 ) -> Result<<Self::A as Api>::BindGroupLayout, DeviceError>;
1025 unsafe fn destroy_bind_group_layout(&self, bg_layout: <Self::A as Api>::BindGroupLayout);
1026 unsafe fn create_pipeline_layout(
1027 &self,
1028 desc: &PipelineLayoutDescriptor<<Self::A as Api>::BindGroupLayout>,
1029 ) -> Result<<Self::A as Api>::PipelineLayout, DeviceError>;
1030 unsafe fn destroy_pipeline_layout(&self, pipeline_layout: <Self::A as Api>::PipelineLayout);
1031
1032 #[allow(clippy::type_complexity)]
1033 unsafe fn create_bind_group(
1034 &self,
1035 desc: &BindGroupDescriptor<
1036 <Self::A as Api>::BindGroupLayout,
1037 <Self::A as Api>::Buffer,
1038 <Self::A as Api>::Sampler,
1039 <Self::A as Api>::TextureView,
1040 <Self::A as Api>::AccelerationStructure,
1041 >,
1042 ) -> Result<<Self::A as Api>::BindGroup, DeviceError>;
1043 unsafe fn destroy_bind_group(&self, group: <Self::A as Api>::BindGroup);
1044
1045 unsafe fn create_shader_module(
1046 &self,
1047 desc: &ShaderModuleDescriptor,
1048 shader: ShaderInput,
1049 ) -> Result<<Self::A as Api>::ShaderModule, ShaderError>;
1050 unsafe fn destroy_shader_module(&self, module: <Self::A as Api>::ShaderModule);
1051
1052 #[allow(clippy::type_complexity)]
1053 unsafe fn create_render_pipeline(
1054 &self,
1055 desc: &RenderPipelineDescriptor<
1056 <Self::A as Api>::PipelineLayout,
1057 <Self::A as Api>::ShaderModule,
1058 <Self::A as Api>::PipelineCache,
1059 >,
1060 ) -> Result<<Self::A as Api>::RenderPipeline, PipelineError>;
1061 unsafe fn destroy_render_pipeline(&self, pipeline: <Self::A as Api>::RenderPipeline);
1062
1063 #[allow(clippy::type_complexity)]
1064 unsafe fn create_compute_pipeline(
1065 &self,
1066 desc: &ComputePipelineDescriptor<
1067 <Self::A as Api>::PipelineLayout,
1068 <Self::A as Api>::ShaderModule,
1069 <Self::A as Api>::PipelineCache,
1070 >,
1071 ) -> Result<<Self::A as Api>::ComputePipeline, PipelineError>;
1072 unsafe fn destroy_compute_pipeline(&self, pipeline: <Self::A as Api>::ComputePipeline);
1073
1074 unsafe fn create_pipeline_cache(
1075 &self,
1076 desc: &PipelineCacheDescriptor<'_>,
1077 ) -> Result<<Self::A as Api>::PipelineCache, PipelineCacheError>;
1078 fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> {
1079 None
1080 }
1081 unsafe fn destroy_pipeline_cache(&self, cache: <Self::A as Api>::PipelineCache);
1082
1083 unsafe fn create_query_set(
1084 &self,
1085 desc: &wgt::QuerySetDescriptor<Label>,
1086 ) -> Result<<Self::A as Api>::QuerySet, DeviceError>;
1087 unsafe fn destroy_query_set(&self, set: <Self::A as Api>::QuerySet);
1088 unsafe fn create_fence(&self) -> Result<<Self::A as Api>::Fence, DeviceError>;
1089 unsafe fn destroy_fence(&self, fence: <Self::A as Api>::Fence);
1090 unsafe fn get_fence_value(
1091 &self,
1092 fence: &<Self::A as Api>::Fence,
1093 ) -> Result<FenceValue, DeviceError>;
1094
1095 /// Wait for `fence` to reach `value`.
1096 ///
1097 /// Operations like [`Queue::submit`] can accept a [`Fence`] and a
1098 /// [`FenceValue`] to store in it, so you can use this `wait` function
1099 /// to wait for a given queue submission to finish execution.
1100 ///
1101 /// The `value` argument must not exceed the highest value that an actual
1102 /// operation you have already presented to the device is going to store in
1103 /// `fence`. You cannot wait for values yet to be submitted. (This
1104 /// restriction accommodates implementations like the `vulkan` backend's
1105 /// [`FencePool`] that must allocate a distinct synchronization object for
1106 /// each fence value one is able to wait for.)
1107 ///
1108 /// Calling `wait` with a lower [`FenceValue`] than `fence`'s current value
1109 /// returns immediately.
1110 ///
1111 /// If `timeout` is not provided, the function will block indefinitely or until
1112 /// an error is encountered.
1113 ///
1114 /// Returns `Ok(true)` on success and `Ok(false)` on timeout.
1115 ///
1116 /// [`Fence`]: Api::Fence
1117 /// [`FencePool`]: vulkan/enum.Fence.html#variant.FencePool
1118 unsafe fn wait(
1119 &self,
1120 fence: &<Self::A as Api>::Fence,
1121 value: FenceValue,
1122 timeout: Option<core::time::Duration>,
1123 ) -> Result<bool, DeviceError>;
1124
1125 /// Start a graphics debugger capture.
1126 ///
1127 /// # Safety
1128 ///
1129 /// See [`wgpu::Device::start_graphics_debugger_capture`][api] for more details.
1130 ///
1131 /// [api]: ../wgpu/struct.Device.html#method.start_graphics_debugger_capture
1132 unsafe fn start_graphics_debugger_capture(&self) -> bool;
1133
1134 /// Stop a graphics debugger capture.
1135 ///
1136 /// # Safety
1137 ///
1138 /// See [`wgpu::Device::stop_graphics_debugger_capture`][api] for more details.
1139 ///
1140 /// [api]: ../wgpu/struct.Device.html#method.stop_graphics_debugger_capture
1141 unsafe fn stop_graphics_debugger_capture(&self);
1142
1143 #[allow(unused_variables)]
1144 unsafe fn pipeline_cache_get_data(
1145 &self,
1146 cache: &<Self::A as Api>::PipelineCache,
1147 ) -> Option<Vec<u8>> {
1148 None
1149 }
1150
1151 unsafe fn create_acceleration_structure(
1152 &self,
1153 desc: &AccelerationStructureDescriptor,
1154 ) -> Result<<Self::A as Api>::AccelerationStructure, DeviceError>;
1155 unsafe fn get_acceleration_structure_build_sizes(
1156 &self,
1157 desc: &GetAccelerationStructureBuildSizesDescriptor<<Self::A as Api>::Buffer>,
1158 ) -> AccelerationStructureBuildSizes;
1159 unsafe fn get_acceleration_structure_device_address(
1160 &self,
1161 acceleration_structure: &<Self::A as Api>::AccelerationStructure,
1162 ) -> wgt::BufferAddress;
1163 unsafe fn destroy_acceleration_structure(
1164 &self,
1165 acceleration_structure: <Self::A as Api>::AccelerationStructure,
1166 );
1167 fn tlas_instance_to_bytes(&self, instance: TlasInstance) -> Vec<u8>;
1168
1169 fn get_internal_counters(&self) -> wgt::HalCounters;
1170
1171 fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
1172 None
1173 }
1174
1175 fn check_if_oom(&self) -> Result<(), DeviceError>;
1176}
1177
1178pub trait Queue: WasmNotSendSync {
1179 type A: Api;
1180
1181 /// Submit `command_buffers` for execution on GPU.
1182 ///
1183 /// Update `fence` to `value` when the operation is complete. See
1184 /// [`Fence`] for details.
1185 ///
1186 /// All command buffers submitted to a `wgpu_hal` queue are executed in the
1187 /// order they're submitted, with each buffer able to observe the effects of
1188 /// previous buffers' execution. Specifically:
1189 ///
1190 /// - If two calls to `submit` on a single `Queue` occur in a particular
1191 /// order (that is, they happen on the same thread, or on two threads that
1192 /// have synchronized to establish an ordering), then the first
1193 /// submission's commands all complete execution before any of the second
1194 /// submission's commands begin. All results produced by one submission
1195 /// are visible to the next.
1196 ///
1197 /// - Within a submission, command buffers execute in the order in which they
1198 /// appear in `command_buffers`. All results produced by one buffer are
1199 /// visible to the next.
1200 ///
1201 /// If two calls to `submit` on a single `Queue` from different threads are
1202 /// not synchronized to occur in a particular order, they must pass distinct
1203 /// [`Fence`]s. As explained in the [`Fence`] documentation, waiting for
1204 /// operations to complete is only trustworthy when operations finish in
1205 /// order of increasing fence value, but submissions from different threads
1206 /// cannot determine how to order the fence values if the submissions
1207 /// themselves are unordered. If each thread uses a separate [`Fence`], this
1208 /// problem does not arise.
1209 ///
1210 /// # Safety
1211 ///
1212 /// - Each [`CommandBuffer`][cb] in `command_buffers` must have been created
1213 /// from a [`CommandEncoder`][ce] that was constructed from the
1214 /// [`Device`][d] associated with this [`Queue`].
1215 ///
1216 /// - Each [`CommandBuffer`][cb] must remain alive until the submitted
1217 /// commands have finished execution. Since command buffers must not
1218 /// outlive their encoders, this implies that the encoders must remain
1219 /// alive as well.
1220 ///
1221 /// - All resources used by a submitted [`CommandBuffer`][cb]
1222 /// ([`Texture`][t]s, [`BindGroup`][bg]s, [`RenderPipeline`][rp]s, and so
1223 /// on) must remain alive until the command buffer finishes execution.
1224 ///
1225 /// - Every [`SurfaceTexture`][st] that any command in `command_buffers`
1226 /// writes to must appear in the `surface_textures` argument.
1227 ///
1228 /// - No [`SurfaceTexture`][st] may appear in the `surface_textures`
1229 /// argument more than once.
1230 ///
1231 /// - Each [`SurfaceTexture`][st] in `surface_textures` must be configured
1232 /// for use with the [`Device`][d] associated with this [`Queue`],
1233 /// typically by calling [`Surface::configure`].
1234 ///
1235 /// - All calls to this function that include a given [`SurfaceTexture`][st]
1236 /// in `surface_textures` must use the same [`Fence`].
1237 ///
1238 /// - The [`Fence`] passed as `signal_fence.0` must remain alive until
1239 /// all submissions that will signal it have completed.
1240 ///
1241 /// [`Fence`]: Api::Fence
1242 /// [cb]: Api::CommandBuffer
1243 /// [ce]: Api::CommandEncoder
1244 /// [d]: Api::Device
1245 /// [t]: Api::Texture
1246 /// [bg]: Api::BindGroup
1247 /// [rp]: Api::RenderPipeline
1248 /// [st]: Api::SurfaceTexture
1249 unsafe fn submit(
1250 &self,
1251 command_buffers: &[&<Self::A as Api>::CommandBuffer],
1252 surface_textures: &[&<Self::A as Api>::SurfaceTexture],
1253 signal_fence: (&<Self::A as Api>::Fence, FenceValue),
1254 ) -> Result<(), DeviceError>;
1255 /// Present a surface texture to the screen.
1256 ///
1257 /// This consumes the surface texture, returning it to the swapchain.
1258 ///
1259 /// # Safety
1260 ///
1261 /// - `texture` must have been acquired from `surface` via
1262 /// [`Surface::acquire_texture`] and not yet presented or discarded.
1263 /// - `surface` must be configured for use with the [`Device`][d] associated
1264 /// with this [`Queue`].
1265 /// - `texture` must be in the "present" state. Either:
1266 /// - It was passed in [`submit`][s]'s `surface_textures` argument
1267 /// (which transitions it to the present state), or
1268 /// - The caller has otherwise transitioned it (e.g. via a clear +
1269 /// barrier to `PRESENT` for textures that were never rendered to).
1270 /// - Any command buffers that write to `texture` must have been submitted
1271 /// via [`submit`][s] before this call. The submissions do not need to
1272 /// have completed on the GPU; platform-level synchronization handles the
1273 /// ordering between rendering and display.
1274 /// - Must be externally synchronized with all other queue operations
1275 /// ([`submit`][s], [`present`][Queue::present],
1276 /// [`wait_for_idle`][Queue::wait_for_idle]) on the same queue.
1277 ///
1278 /// [d]: Api::Device
1279 /// [s]: Queue::submit
1280 unsafe fn present(
1281 &self,
1282 surface: &<Self::A as Api>::Surface,
1283 texture: <Self::A as Api>::SurfaceTexture,
1284 ) -> Result<(), SurfaceError>;
1285 /// Block until all previously submitted work on this queue has completed,
1286 /// including any pending presentations.
1287 ///
1288 /// # Safety
1289 ///
1290 /// - Must be externally synchronized with all other queue operations
1291 /// ([`submit`][Queue::submit], [`present`][Queue::present],
1292 /// [`wait_for_idle`][Queue::wait_for_idle]) on the same queue.
1293 unsafe fn wait_for_idle(&self) -> Result<(), DeviceError>;
1294 unsafe fn get_timestamp_period(&self) -> f32;
1295}
1296
1297/// Encoder and allocation pool for `CommandBuffer`s.
1298///
1299/// A `CommandEncoder` not only constructs `CommandBuffer`s but also
1300/// acts as the allocation pool that owns the buffers' underlying
1301/// storage. Thus, `CommandBuffer`s must not outlive the
1302/// `CommandEncoder` that created them.
1303///
1304/// The life cycle of a `CommandBuffer` is as follows:
1305///
1306/// - Call [`Device::create_command_encoder`] to create a new
1307/// `CommandEncoder`, in the "closed" state.
1308///
1309/// - Call `begin_encoding` on a closed `CommandEncoder` to begin
1310/// recording commands. This puts the `CommandEncoder` in the
1311/// "recording" state.
1312///
1313/// - Call methods like `copy_buffer_to_buffer`, `begin_render_pass`,
1314/// etc. on a "recording" `CommandEncoder` to add commands to the
1315/// list. (If an error occurs, you must call `discard_encoding`; see
1316/// below.)
1317///
1318/// - Call `end_encoding` on a recording `CommandEncoder` to close the
1319/// encoder and construct a fresh `CommandBuffer` consisting of the
1320/// list of commands recorded up to that point.
1321///
1322/// - Call `discard_encoding` on a recording `CommandEncoder` to drop
1323/// the commands recorded thus far and close the encoder. This is
1324/// the only safe thing to do on a `CommandEncoder` if an error has
1325/// occurred while recording commands.
1326///
1327/// - Call `reset_all` on a closed `CommandEncoder`, passing all the
1328/// live `CommandBuffers` built from it. All the `CommandBuffer`s
1329/// are destroyed, and their resources are freed.
1330///
1331/// # Safety
1332///
1333/// - The `CommandEncoder` must be in the states described above to
1334/// make the given calls.
1335///
1336/// - A `CommandBuffer` that has been submitted for execution on the
1337/// GPU must live until its execution is complete.
1338///
1339/// - A `CommandBuffer` must not outlive the `CommandEncoder` that
1340/// built it.
1341///
1342/// It is the user's responsibility to meet this requirements. This
1343/// allows `CommandEncoder` implementations to keep their state
1344/// tracking to a minimum.
1345pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
1346 type A: Api;
1347
1348 /// Begin encoding a new command buffer.
1349 ///
1350 /// This puts this `CommandEncoder` in the "recording" state.
1351 ///
1352 /// # Safety
1353 ///
1354 /// This `CommandEncoder` must be in the "closed" state.
1355 unsafe fn begin_encoding(&mut self, label: Label) -> Result<(), DeviceError>;
1356
1357 /// Discard the command list under construction.
1358 ///
1359 /// If an error has occurred while recording commands, this
1360 /// is the only safe thing to do with the encoder.
1361 ///
1362 /// This puts this `CommandEncoder` in the "closed" state.
1363 ///
1364 /// # Safety
1365 ///
1366 /// This `CommandEncoder` must be in the "recording" state.
1367 ///
1368 /// Callers must not assume that implementations of this
1369 /// function are idempotent, and thus should not call it
1370 /// multiple times in a row.
1371 unsafe fn discard_encoding(&mut self);
1372
1373 /// Return a fresh [`CommandBuffer`] holding the recorded commands.
1374 ///
1375 /// The returned [`CommandBuffer`] holds all the commands recorded
1376 /// on this `CommandEncoder` since the last call to
1377 /// [`begin_encoding`].
1378 ///
1379 /// This puts this `CommandEncoder` in the "closed" state.
1380 ///
1381 /// # Safety
1382 ///
1383 /// This `CommandEncoder` must be in the "recording" state.
1384 ///
1385 /// The returned [`CommandBuffer`] must not outlive this
1386 /// `CommandEncoder`. Implementations are allowed to build
1387 /// `CommandBuffer`s that depend on storage owned by this
1388 /// `CommandEncoder`.
1389 ///
1390 /// [`CommandBuffer`]: Api::CommandBuffer
1391 /// [`begin_encoding`]: CommandEncoder::begin_encoding
1392 unsafe fn end_encoding(&mut self) -> Result<<Self::A as Api>::CommandBuffer, DeviceError>;
1393
1394 /// Reclaim all resources belonging to this `CommandEncoder`.
1395 ///
1396 /// # Safety
1397 ///
1398 /// This `CommandEncoder` must be in the "closed" state.
1399 ///
1400 /// The `command_buffers` iterator must produce all the live
1401 /// [`CommandBuffer`]s built using this `CommandEncoder` --- that
1402 /// is, every extant `CommandBuffer` returned from `end_encoding`.
1403 ///
1404 /// [`CommandBuffer`]: Api::CommandBuffer
1405 unsafe fn reset_all<I>(&mut self, command_buffers: I)
1406 where
1407 I: Iterator<Item = <Self::A as Api>::CommandBuffer>;
1408
1409 unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
1410 where
1411 T: Iterator<Item = BufferBarrier<'a, <Self::A as Api>::Buffer>>;
1412
1413 unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
1414 where
1415 T: Iterator<Item = TextureBarrier<'a, <Self::A as Api>::Texture>>;
1416
1417 // copy operations
1418
1419 unsafe fn clear_buffer(&mut self, buffer: &<Self::A as Api>::Buffer, range: MemoryRange);
1420
1421 unsafe fn copy_buffer_to_buffer<T>(
1422 &mut self,
1423 src: &<Self::A as Api>::Buffer,
1424 dst: &<Self::A as Api>::Buffer,
1425 regions: T,
1426 ) where
1427 T: Iterator<Item = BufferCopy>;
1428
1429 /// Copy from an external image to an internal texture.
1430 /// Works with a single array layer.
1431 /// Note: `dst` current usage has to be `wgt::TextureUses::COPY_DST`.
1432 /// Note: the copy extent is in physical size (rounded to the block size)
1433 #[cfg(webgl)]
1434 unsafe fn copy_external_image_to_texture<T>(
1435 &mut self,
1436 src: &wgt::CopyExternalImageSourceInfo,
1437 dst: &<Self::A as Api>::Texture,
1438 dst_premultiplication: bool,
1439 regions: T,
1440 ) where
1441 T: Iterator<Item = TextureCopy>;
1442
1443 /// Copy from one texture to another.
1444 /// Works with a single array layer.
1445 /// Note: `dst` current usage has to be `wgt::TextureUses::COPY_DST`.
1446 /// Note: the copy extent is in physical size (rounded to the block size)
1447 unsafe fn copy_texture_to_texture<T>(
1448 &mut self,
1449 src: &<Self::A as Api>::Texture,
1450 src_usage: wgt::TextureUses,
1451 dst: &<Self::A as Api>::Texture,
1452 regions: T,
1453 ) where
1454 T: Iterator<Item = TextureCopy>;
1455
1456 /// Copy from buffer to texture.
1457 /// Works with a single array layer.
1458 /// Note: `dst` current usage has to be `wgt::TextureUses::COPY_DST`.
1459 /// Note: the copy extent is in physical size (rounded to the block size)
1460 unsafe fn copy_buffer_to_texture<T>(
1461 &mut self,
1462 src: &<Self::A as Api>::Buffer,
1463 dst: &<Self::A as Api>::Texture,
1464 regions: T,
1465 ) where
1466 T: Iterator<Item = BufferTextureCopy>;
1467
1468 /// Copy from texture to buffer.
1469 /// Works with a single array layer.
1470 /// Note: the copy extent is in physical size (rounded to the block size)
1471 unsafe fn copy_texture_to_buffer<T>(
1472 &mut self,
1473 src: &<Self::A as Api>::Texture,
1474 src_usage: wgt::TextureUses,
1475 dst: &<Self::A as Api>::Buffer,
1476 regions: T,
1477 ) where
1478 T: Iterator<Item = BufferTextureCopy>;
1479
1480 unsafe fn copy_acceleration_structure_to_acceleration_structure(
1481 &mut self,
1482 src: &<Self::A as Api>::AccelerationStructure,
1483 dst: &<Self::A as Api>::AccelerationStructure,
1484 copy: wgt::AccelerationStructureCopy,
1485 );
1486 // pass common
1487
1488 /// Sets the bind group at `index` to `group`.
1489 ///
1490 /// If this is not the first call to `set_bind_group` within the current
1491 /// render or compute pass:
1492 ///
1493 /// - If `layout` contains `n` bind group layouts, then any previously set
1494 /// bind groups at indices `n` or higher are cleared.
1495 ///
1496 /// - If the first `m` bind group layouts of `layout` are equal to those of
1497 /// the previously passed layout, but no more, then any previously set
1498 /// bind groups at indices `m` or higher are cleared.
1499 ///
1500 /// It follows from the above that passing the same layout as before doesn't
1501 /// clear any bind groups.
1502 ///
1503 /// # Safety
1504 ///
1505 /// - This [`CommandEncoder`] must be within a render or compute pass.
1506 ///
1507 /// - `index` must be the valid index of some bind group layout in `layout`.
1508 /// Call this the "relevant bind group layout".
1509 ///
1510 /// - The layout of `group` must be equal to the relevant bind group layout.
1511 ///
1512 /// - The length of `dynamic_offsets` must match the number of buffer
1513 /// bindings [with dynamic offsets][hdo] in the relevant bind group
1514 /// layout.
1515 ///
1516 /// - If those buffer bindings are ordered by increasing [`binding` number]
1517 /// and paired with elements from `dynamic_offsets`, then each offset must
1518 /// be a valid offset for the binding's corresponding buffer in `group`.
1519 ///
1520 /// [hdo]: wgt::BindingType::Buffer::has_dynamic_offset
1521 /// [`binding` number]: wgt::BindGroupLayoutEntry::binding
1522 unsafe fn set_bind_group(
1523 &mut self,
1524 layout: &<Self::A as Api>::PipelineLayout,
1525 index: u32,
1526 group: &<Self::A as Api>::BindGroup,
1527 dynamic_offsets: &[wgt::DynamicOffset],
1528 );
1529
1530 /// Sets a range in immediate data.
1531 ///
1532 /// IMPORTANT: while the data is passed as words, the offset is in bytes!
1533 ///
1534 /// # Safety
1535 ///
1536 /// - `offset_bytes` must be a multiple of 4.
1537 /// - The range of immediates written must be valid for the pipeline layout at draw time.
1538 unsafe fn set_immediates(
1539 &mut self,
1540 layout: &<Self::A as Api>::PipelineLayout,
1541 offset_bytes: u32,
1542 data: &[u32],
1543 );
1544
1545 unsafe fn insert_debug_marker(&mut self, label: &str);
1546 unsafe fn begin_debug_marker(&mut self, group_label: &str);
1547 unsafe fn end_debug_marker(&mut self);
1548
1549 // queries
1550
1551 /// # Safety:
1552 ///
1553 /// - If `set` is an occlusion query set, it must be the same one as used in the [`RenderPassDescriptor::occlusion_query_set`] parameter.
1554 unsafe fn begin_query(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
1555 /// # Safety:
1556 ///
1557 /// - If `set` is an occlusion query set, it must be the same one as used in the [`RenderPassDescriptor::occlusion_query_set`] parameter.
1558 unsafe fn end_query(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
1559 unsafe fn write_timestamp(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
1560 unsafe fn reset_queries(&mut self, set: &<Self::A as Api>::QuerySet, range: Range<u32>);
1561 unsafe fn copy_query_results(
1562 &mut self,
1563 set: &<Self::A as Api>::QuerySet,
1564 range: Range<u32>,
1565 buffer: &<Self::A as Api>::Buffer,
1566 offset: wgt::BufferAddress,
1567 stride: wgt::BufferSize,
1568 );
1569
1570 // render passes
1571
1572 /// Begin a new render pass, clearing all active bindings.
1573 ///
1574 /// This clears any bindings established by the following calls:
1575 ///
1576 /// - [`set_bind_group`](CommandEncoder::set_bind_group)
1577 /// - [`set_immediates`](CommandEncoder::set_immediates)
1578 /// - [`begin_query`](CommandEncoder::begin_query)
1579 /// - [`set_render_pipeline`](CommandEncoder::set_render_pipeline)
1580 /// - [`set_index_buffer`](CommandEncoder::set_index_buffer)
1581 /// - [`set_vertex_buffer`](CommandEncoder::set_vertex_buffer)
1582 ///
1583 /// # Safety
1584 ///
1585 /// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed
1586 /// by a call to [`end_render_pass`].
1587 ///
1588 /// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed
1589 /// by a call to [`end_compute_pass`].
1590 ///
1591 /// [`begin_render_pass`]: CommandEncoder::begin_render_pass
1592 /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
1593 /// [`end_render_pass`]: CommandEncoder::end_render_pass
1594 /// [`end_compute_pass`]: CommandEncoder::end_compute_pass
1595 unsafe fn begin_render_pass(
1596 &mut self,
1597 desc: &RenderPassDescriptor<<Self::A as Api>::QuerySet, <Self::A as Api>::TextureView>,
1598 ) -> Result<(), DeviceError>;
1599
1600 /// End the current render pass.
1601 ///
1602 /// # Safety
1603 ///
1604 /// - There must have been a prior call to [`begin_render_pass`] on this [`CommandEncoder`]
1605 /// that has not been followed by a call to [`end_render_pass`].
1606 ///
1607 /// [`begin_render_pass`]: CommandEncoder::begin_render_pass
1608 /// [`end_render_pass`]: CommandEncoder::end_render_pass
1609 unsafe fn end_render_pass(&mut self);
1610
1611 unsafe fn set_render_pipeline(&mut self, pipeline: &<Self::A as Api>::RenderPipeline);
1612
1613 unsafe fn set_index_buffer<'a>(
1614 &mut self,
1615 binding: BufferBinding<'a, <Self::A as Api>::Buffer>,
1616 format: wgt::IndexFormat,
1617 );
1618 unsafe fn set_vertex_buffer<'a>(
1619 &mut self,
1620 index: u32,
1621 binding: BufferBinding<'a, <Self::A as Api>::Buffer>,
1622 );
1623 unsafe fn set_viewport(&mut self, rect: &Rect<f32>, depth_range: Range<f32>);
1624 unsafe fn set_scissor_rect(&mut self, rect: &Rect<u32>);
1625 unsafe fn set_stencil_reference(&mut self, value: u32);
1626 unsafe fn set_blend_constants(&mut self, color: &[f32; 4]);
1627
1628 unsafe fn draw(
1629 &mut self,
1630 first_vertex: u32,
1631 vertex_count: u32,
1632 first_instance: u32,
1633 instance_count: u32,
1634 );
1635 unsafe fn draw_indexed(
1636 &mut self,
1637 first_index: u32,
1638 index_count: u32,
1639 base_vertex: i32,
1640 first_instance: u32,
1641 instance_count: u32,
1642 );
1643 unsafe fn draw_indirect(
1644 &mut self,
1645 buffer: &<Self::A as Api>::Buffer,
1646 offset: wgt::BufferAddress,
1647 draw_count: u32,
1648 );
1649 unsafe fn draw_indexed_indirect(
1650 &mut self,
1651 buffer: &<Self::A as Api>::Buffer,
1652 offset: wgt::BufferAddress,
1653 draw_count: u32,
1654 );
1655 unsafe fn draw_indirect_count(
1656 &mut self,
1657 buffer: &<Self::A as Api>::Buffer,
1658 offset: wgt::BufferAddress,
1659 count_buffer: &<Self::A as Api>::Buffer,
1660 count_offset: wgt::BufferAddress,
1661 max_count: u32,
1662 );
1663 unsafe fn draw_indexed_indirect_count(
1664 &mut self,
1665 buffer: &<Self::A as Api>::Buffer,
1666 offset: wgt::BufferAddress,
1667 count_buffer: &<Self::A as Api>::Buffer,
1668 count_offset: wgt::BufferAddress,
1669 max_count: u32,
1670 );
1671 unsafe fn draw_mesh_tasks(
1672 &mut self,
1673 group_count_x: u32,
1674 group_count_y: u32,
1675 group_count_z: u32,
1676 );
1677 unsafe fn draw_mesh_tasks_indirect(
1678 &mut self,
1679 buffer: &<Self::A as Api>::Buffer,
1680 offset: wgt::BufferAddress,
1681 draw_count: u32,
1682 );
1683 unsafe fn draw_mesh_tasks_indirect_count(
1684 &mut self,
1685 buffer: &<Self::A as Api>::Buffer,
1686 offset: wgt::BufferAddress,
1687 count_buffer: &<Self::A as Api>::Buffer,
1688 count_offset: wgt::BufferAddress,
1689 max_count: u32,
1690 );
1691
1692 // compute passes
1693
1694 /// Begin a new compute pass, clearing all active bindings.
1695 ///
1696 /// This clears any bindings established by the following calls:
1697 ///
1698 /// - [`set_bind_group`](CommandEncoder::set_bind_group)
1699 /// - [`set_immediates`](CommandEncoder::set_immediates)
1700 /// - [`begin_query`](CommandEncoder::begin_query)
1701 /// - [`set_compute_pipeline`](CommandEncoder::set_compute_pipeline)
1702 ///
1703 /// # Safety
1704 ///
1705 /// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed
1706 /// by a call to [`end_render_pass`].
1707 ///
1708 /// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed
1709 /// by a call to [`end_compute_pass`].
1710 ///
1711 /// [`begin_render_pass`]: CommandEncoder::begin_render_pass
1712 /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
1713 /// [`end_render_pass`]: CommandEncoder::end_render_pass
1714 /// [`end_compute_pass`]: CommandEncoder::end_compute_pass
1715 unsafe fn begin_compute_pass(
1716 &mut self,
1717 desc: &ComputePassDescriptor<<Self::A as Api>::QuerySet>,
1718 );
1719
1720 /// End the current compute pass.
1721 ///
1722 /// # Safety
1723 ///
1724 /// - There must have been a prior call to [`begin_compute_pass`] on this [`CommandEncoder`]
1725 /// that has not been followed by a call to [`end_compute_pass`].
1726 ///
1727 /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
1728 /// [`end_compute_pass`]: CommandEncoder::end_compute_pass
1729 unsafe fn end_compute_pass(&mut self);
1730
1731 unsafe fn set_compute_pipeline(&mut self, pipeline: &<Self::A as Api>::ComputePipeline);
1732
1733 unsafe fn dispatch_workgroups(&mut self, count: [u32; 3]);
1734 unsafe fn dispatch_workgroups_indirect(
1735 &mut self,
1736 buffer: &<Self::A as Api>::Buffer,
1737 offset: wgt::BufferAddress,
1738 );
1739
1740 /// To get the required sizes for the buffer allocations use `get_acceleration_structure_build_sizes` per descriptor
1741 /// All buffers must be synchronized externally
1742 /// All buffer regions, which are written to may only be passed once per function call,
1743 /// with the exception of updates in the same descriptor.
1744 /// Consequences of this limitation:
1745 /// - scratch buffers need to be unique
1746 /// - a tlas can't be build in the same call with a blas it contains
1747 unsafe fn build_acceleration_structures<'a, T>(
1748 &mut self,
1749 descriptor_count: u32,
1750 descriptors: T,
1751 ) where
1752 Self::A: 'a,
1753 T: IntoIterator<
1754 Item = BuildAccelerationStructureDescriptor<
1755 'a,
1756 <Self::A as Api>::Buffer,
1757 <Self::A as Api>::AccelerationStructure,
1758 >,
1759 >;
1760 unsafe fn place_acceleration_structure_barrier(
1761 &mut self,
1762 barrier: AccelerationStructureBarrier,
1763 );
1764 // modeled off dx12, because this is able to be polyfilled in vulkan as opposed to the other way round
1765 unsafe fn read_acceleration_structure_compact_size(
1766 &mut self,
1767 acceleration_structure: &<Self::A as Api>::AccelerationStructure,
1768 buf: &<Self::A as Api>::Buffer,
1769 );
1770 unsafe fn set_acceleration_structure_dependencies(
1771 command_buffers: &[&<Self::A as Api>::CommandBuffer],
1772 dependencies: &[&<Self::A as Api>::AccelerationStructure],
1773 );
1774}
1775
1776bitflags!(
1777 /// Pipeline layout creation flags.
1778 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1779 pub struct PipelineLayoutFlags: u32 {
1780 /// D3D12: Add support for `first_vertex` and `first_instance` builtins
1781 /// via immediates for direct execution.
1782 const FIRST_VERTEX_INSTANCE = 1 << 0;
1783 /// D3D12: Add support for `num_workgroups` builtins via immediates
1784 /// for direct execution.
1785 const NUM_WORK_GROUPS = 1 << 1;
1786 /// D3D12: Add support for the builtins that the other flags enable for
1787 /// indirect execution.
1788 const INDIRECT_BUILTIN_UPDATE = 1 << 2;
1789 }
1790);
1791
1792bitflags!(
1793 /// Pipeline layout creation flags.
1794 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1795 pub struct BindGroupLayoutFlags: u32 {
1796 /// Allows for bind group binding arrays to be shorter than the array in the BGL.
1797 const PARTIALLY_BOUND = 1 << 0;
1798 }
1799);
1800
1801bitflags!(
1802 /// Texture format capability flags.
1803 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1804 pub struct TextureFormatCapabilities: u32 {
1805 /// Format can be sampled.
1806 const SAMPLED = 1 << 0;
1807 /// Format can be sampled with a linear sampler.
1808 const SAMPLED_LINEAR = 1 << 1;
1809 /// Format can be sampled with a min/max reduction sampler.
1810 const SAMPLED_MINMAX = 1 << 2;
1811
1812 /// Format can be used as storage with read-only access.
1813 const STORAGE_READ_ONLY = 1 << 3;
1814 /// Format can be used as storage with write-only access.
1815 const STORAGE_WRITE_ONLY = 1 << 4;
1816 /// Format can be used as storage with both read and write access.
1817 const STORAGE_READ_WRITE = 1 << 5;
1818 /// Format can be used as storage with atomics.
1819 const STORAGE_ATOMIC = 1 << 6;
1820
1821 /// Format can be used as color and input attachment.
1822 const COLOR_ATTACHMENT = 1 << 7;
1823 /// Format can be used as color (with blending) and input attachment.
1824 const COLOR_ATTACHMENT_BLEND = 1 << 8;
1825 /// Format can be used as depth-stencil and input attachment.
1826 const DEPTH_STENCIL_ATTACHMENT = 1 << 9;
1827
1828 /// Format can be multisampled by x2.
1829 const MULTISAMPLE_X2 = 1 << 10;
1830 /// Format can be multisampled by x4.
1831 const MULTISAMPLE_X4 = 1 << 11;
1832 /// Format can be multisampled by x8.
1833 const MULTISAMPLE_X8 = 1 << 12;
1834 /// Format can be multisampled by x16.
1835 const MULTISAMPLE_X16 = 1 << 13;
1836
1837 /// Format can be used for render pass resolve targets.
1838 const MULTISAMPLE_RESOLVE = 1 << 14;
1839
1840 /// Format can be copied from.
1841 const COPY_SRC = 1 << 15;
1842 /// Format can be copied to.
1843 const COPY_DST = 1 << 16;
1844 }
1845);
1846
1847bitflags!(
1848 /// Texture format capability flags.
1849 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1850 pub struct FormatAspects: u8 {
1851 const COLOR = 1 << 0;
1852 const DEPTH = 1 << 1;
1853 const STENCIL = 1 << 2;
1854 const PLANE_0 = 1 << 3;
1855 const PLANE_1 = 1 << 4;
1856 const PLANE_2 = 1 << 5;
1857
1858 const DEPTH_STENCIL = Self::DEPTH.bits() | Self::STENCIL.bits();
1859 }
1860);
1861
1862impl FormatAspects {
1863 pub fn new(format: wgt::TextureFormat, aspect: wgt::TextureAspect) -> Self {
1864 let aspect_mask = match aspect {
1865 wgt::TextureAspect::All => Self::all(),
1866 wgt::TextureAspect::DepthOnly => Self::DEPTH,
1867 wgt::TextureAspect::StencilOnly => Self::STENCIL,
1868 wgt::TextureAspect::Plane0 => Self::PLANE_0,
1869 wgt::TextureAspect::Plane1 => Self::PLANE_1,
1870 wgt::TextureAspect::Plane2 => Self::PLANE_2,
1871 };
1872 Self::from(format) & aspect_mask
1873 }
1874
1875 /// Returns `true` if only one flag is set
1876 pub fn is_one(&self) -> bool {
1877 self.bits().is_power_of_two()
1878 }
1879
1880 pub fn map(&self) -> wgt::TextureAspect {
1881 match *self {
1882 Self::COLOR => wgt::TextureAspect::All,
1883 Self::DEPTH => wgt::TextureAspect::DepthOnly,
1884 Self::STENCIL => wgt::TextureAspect::StencilOnly,
1885 Self::PLANE_0 => wgt::TextureAspect::Plane0,
1886 Self::PLANE_1 => wgt::TextureAspect::Plane1,
1887 Self::PLANE_2 => wgt::TextureAspect::Plane2,
1888 _ => unreachable!(),
1889 }
1890 }
1891}
1892
1893impl From<wgt::TextureFormat> for FormatAspects {
1894 fn from(format: wgt::TextureFormat) -> Self {
1895 match format {
1896 wgt::TextureFormat::Stencil8 => Self::STENCIL,
1897 wgt::TextureFormat::Depth16Unorm
1898 | wgt::TextureFormat::Depth32Float
1899 | wgt::TextureFormat::Depth24Plus => Self::DEPTH,
1900 wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24PlusStencil8 => {
1901 Self::DEPTH_STENCIL
1902 }
1903 wgt::TextureFormat::NV12 | wgt::TextureFormat::P010 => Self::PLANE_0 | Self::PLANE_1,
1904 _ => Self::COLOR,
1905 }
1906 }
1907}
1908
1909bitflags!(
1910 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1911 pub struct MemoryFlags: u32 {
1912 const TRANSIENT = 1 << 0;
1913 const PREFER_COHERENT = 1 << 1;
1914 }
1915);
1916
1917bitflags!(
1918 /// Attachment load and store operations.
1919 ///
1920 /// There must be at least one flag from the LOAD group and one from the STORE group set.
1921 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1922 pub struct AttachmentOps: u8 {
1923 /// Load the existing contents of the attachment.
1924 const LOAD = 1 << 0;
1925 /// Clear the attachment to a specified value.
1926 const LOAD_CLEAR = 1 << 1;
1927 /// The contents of the attachment are undefined.
1928 const LOAD_DONT_CARE = 1 << 2;
1929 /// Store the contents of the attachment.
1930 const STORE = 1 << 3;
1931 /// The contents of the attachment are undefined after the pass.
1932 const STORE_DISCARD = 1 << 4;
1933 }
1934);
1935
1936#[derive(Debug)]
1937pub struct InstanceDescriptor<'a> {
1938 pub name: &'a str,
1939 pub flags: wgt::InstanceFlags,
1940 pub memory_budget_thresholds: wgt::MemoryBudgetThresholds,
1941 pub backend_options: wgt::BackendOptions,
1942 pub telemetry: Option<Telemetry>,
1943 /// This is a borrow because the surrounding `core::Instance` keeps the owned display handle
1944 /// alive already.
1945 pub display: Option<DisplayHandle<'a>>,
1946}
1947
1948#[derive(Clone, Debug)]
1949pub struct Alignments {
1950 /// The alignment of the start of the buffer used as a GPU copy source.
1951 pub buffer_copy_offset: wgt::BufferSize,
1952
1953 /// The alignment of the row pitch of the texture data stored in a buffer that is
1954 /// used in a GPU copy operation.
1955 pub buffer_copy_pitch: wgt::BufferSize,
1956
1957 /// The finest alignment of bound range checking for uniform buffers.
1958 ///
1959 /// When `wgpu_hal` restricts shader references to the [accessible
1960 /// region][ar] of a [`Uniform`] buffer, the size of the accessible region
1961 /// is the bind group binding's stated [size], rounded up to the next
1962 /// multiple of this value.
1963 ///
1964 /// We don't need an analogous field for storage buffer bindings, because
1965 /// all our backends promise to enforce the size at least to a four-byte
1966 /// alignment, and `wgpu_hal` requires bound range lengths to be a multiple
1967 /// of four anyway.
1968 ///
1969 /// [ar]: struct.BufferBinding.html#accessible-region
1970 /// [`Uniform`]: wgt::BufferBindingType::Uniform
1971 /// [size]: BufferBinding::size
1972 pub uniform_bounds_check_alignment: wgt::BufferSize,
1973
1974 /// The size of the raw TLAS instance
1975 pub raw_tlas_instance_size: u32,
1976
1977 /// What the scratch buffer for building an acceleration structure must be aligned to
1978 pub ray_tracing_scratch_buffer_alignment: u32,
1979}
1980
1981#[derive(Clone, Debug)]
1982pub struct Capabilities {
1983 pub limits: wgt::Limits,
1984 pub alignments: Alignments,
1985 pub downlevel: wgt::DownlevelCapabilities,
1986 /// Supported cooperative matrix configurations.
1987 ///
1988 /// Empty if cooperative matrices are not supported.
1989 pub cooperative_matrix_properties: Vec<wgt::CooperativeMatrixProperties>,
1990}
1991
1992/// An adapter with all the information needed to reason about its capabilities.
1993///
1994/// These are either made by [`Instance::enumerate_adapters`] or by backend specific
1995/// methods on the backend [`Instance`] or [`Adapter`].
1996#[derive(Debug)]
1997pub struct ExposedAdapter<A: Api> {
1998 pub adapter: A::Adapter,
1999 pub info: wgt::AdapterInfo,
2000 pub features: wgt::Features,
2001 pub capabilities: Capabilities,
2002}
2003
2004/// Describes information about what a `Surface`'s presentation capabilities are.
2005/// Fetch this with [Adapter::surface_capabilities].
2006#[derive(Debug, Clone)]
2007pub struct SurfaceCapabilities {
2008 /// List of supported texture formats.
2009 ///
2010 /// Must be at least one.
2011 pub formats: Vec<wgt::TextureFormat>,
2012
2013 /// Range for the number of queued frames.
2014 ///
2015 /// This adjusts either the swapchain frame count to value + 1 - or sets SetMaximumFrameLatency to the value given,
2016 /// or uses a wait-for-present in the acquire method to limit rendering such that it acts like it's a value + 1 swapchain frame set.
2017 ///
2018 /// - `maximum_frame_latency.start` must be at least 1.
2019 /// - `maximum_frame_latency.end` must be larger or equal to `maximum_frame_latency.start`.
2020 pub maximum_frame_latency: RangeInclusive<u32>,
2021
2022 /// Current extent of the surface, if known.
2023 pub current_extent: Option<wgt::Extent3d>,
2024
2025 /// Supported texture usage flags.
2026 ///
2027 /// Must have at least `wgt::TextureUses::COLOR_TARGET`
2028 pub usage: wgt::TextureUses,
2029
2030 /// List of supported V-sync modes.
2031 ///
2032 /// Must be at least one.
2033 pub present_modes: Vec<wgt::PresentMode>,
2034
2035 /// List of supported alpha composition modes.
2036 ///
2037 /// Must be at least one.
2038 pub composite_alpha_modes: Vec<wgt::CompositeAlphaMode>,
2039}
2040
2041#[derive(Debug)]
2042pub struct AcquiredSurfaceTexture<A: Api> {
2043 pub texture: A::SurfaceTexture,
2044 /// The presentation configuration no longer matches
2045 /// the surface properties exactly, but can still be used to present
2046 /// to the surface successfully.
2047 pub suboptimal: bool,
2048}
2049
2050/// An open connection to a device and a queue.
2051///
2052/// This can be created from [`Adapter::open`] or backend
2053/// specific methods on the backend's [`Instance`] or [`Adapter`].
2054#[derive(Debug)]
2055pub struct OpenDevice<A: Api> {
2056 pub device: A::Device,
2057 pub queue: A::Queue,
2058}
2059
2060#[derive(Clone, Debug)]
2061pub struct BufferMapping {
2062 pub ptr: NonNull<u8>,
2063 pub is_coherent: bool,
2064}
2065
2066#[derive(Clone, Debug)]
2067pub struct BufferDescriptor<'a> {
2068 pub label: Label<'a>,
2069 pub size: wgt::BufferAddress,
2070 pub usage: wgt::BufferUses,
2071 pub memory_flags: MemoryFlags,
2072}
2073
2074#[derive(Clone, Debug)]
2075pub struct TextureDescriptor<'a> {
2076 pub label: Label<'a>,
2077 pub size: wgt::Extent3d,
2078 pub mip_level_count: u32,
2079 pub sample_count: u32,
2080 pub dimension: wgt::TextureDimension,
2081 pub format: wgt::TextureFormat,
2082 pub usage: wgt::TextureUses,
2083 pub memory_flags: MemoryFlags,
2084 /// Allows views of this texture to have a different format
2085 /// than the texture does.
2086 pub view_formats: Vec<wgt::TextureFormat>,
2087}
2088
2089impl TextureDescriptor<'_> {
2090 pub fn copy_extent(&self) -> CopyExtent {
2091 CopyExtent::map_extent_to_copy_size(&self.size, self.dimension)
2092 }
2093
2094 pub fn is_cube_compatible(&self) -> bool {
2095 self.dimension == wgt::TextureDimension::D2
2096 && self.size.depth_or_array_layers.is_multiple_of(6)
2097 && self.sample_count == 1
2098 && self.size.width == self.size.height
2099 }
2100
2101 pub fn array_layer_count(&self) -> u32 {
2102 match self.dimension {
2103 wgt::TextureDimension::D1 | wgt::TextureDimension::D3 => 1,
2104 wgt::TextureDimension::D2 => self.size.depth_or_array_layers,
2105 }
2106 }
2107}
2108
2109/// TextureView descriptor.
2110///
2111/// Valid usage:
2112///. - `format` has to be the same as `TextureDescriptor::format`
2113///. - `dimension` has to be compatible with `TextureDescriptor::dimension`
2114///. - `usage` has to be a subset of `TextureDescriptor::usage`
2115///. - `range` has to be a subset of parent texture
2116#[derive(Clone, Debug)]
2117pub struct TextureViewDescriptor<'a> {
2118 pub label: Label<'a>,
2119 pub format: wgt::TextureFormat,
2120 pub dimension: wgt::TextureViewDimension,
2121 pub usage: wgt::TextureUses,
2122 pub range: wgt::ImageSubresourceRange,
2123}
2124
2125#[derive(Clone, Debug)]
2126pub struct SamplerDescriptor<'a> {
2127 pub label: Label<'a>,
2128 pub address_modes: [wgt::AddressMode; 3],
2129 pub mag_filter: wgt::FilterMode,
2130 pub min_filter: wgt::FilterMode,
2131 pub mipmap_filter: wgt::MipmapFilterMode,
2132 pub lod_clamp: Range<f32>,
2133 pub compare: Option<wgt::CompareFunction>,
2134 // Must in the range [1, 16].
2135 //
2136 // Anisotropic filtering must be supported if this is not 1.
2137 pub anisotropy_clamp: u16,
2138 pub border_color: Option<wgt::SamplerBorderColor>,
2139}
2140
2141/// BindGroupLayout descriptor.
2142///
2143/// Valid usage:
2144/// - `entries` are sorted by ascending `wgt::BindGroupLayoutEntry::binding`
2145#[derive(Clone, Debug)]
2146pub struct BindGroupLayoutDescriptor<'a> {
2147 pub label: Label<'a>,
2148 pub flags: BindGroupLayoutFlags,
2149 pub entries: &'a [wgt::BindGroupLayoutEntry],
2150}
2151
2152#[derive(Clone, Debug)]
2153pub struct PipelineLayoutDescriptor<'a, B: DynBindGroupLayout + ?Sized> {
2154 pub label: Label<'a>,
2155 pub flags: PipelineLayoutFlags,
2156 pub bind_group_layouts: &'a [Option<&'a B>],
2157 pub immediate_size: u32,
2158}
2159
2160/// A region of a buffer made visible to shaders via a [`BindGroup`].
2161///
2162/// [`BindGroup`]: Api::BindGroup
2163///
2164/// ## Construction
2165///
2166/// The recommended way to construct a `BufferBinding` is using the `binding`
2167/// method on a wgpu-core `Buffer`, which will validate the binding size
2168/// against the buffer size. A `new_unchecked` constructor is also provided for
2169/// cases where direct construction is necessary.
2170///
2171/// ## Accessible region
2172///
2173/// `wgpu_hal` guarantees that shaders compiled with
2174/// [`ShaderModuleDescriptor::runtime_checks`] set to `true` cannot read or
2175/// write data via this binding outside the *accessible region* of a buffer:
2176///
2177/// - The accessible region starts at [`offset`].
2178///
2179/// - For [`Storage`] bindings, the size of the accessible region is [`size`],
2180/// which must be a multiple of 4.
2181///
2182/// - For [`Uniform`] bindings, the size of the accessible region is [`size`]
2183/// rounded up to the next multiple of
2184/// [`Alignments::uniform_bounds_check_alignment`].
2185///
2186/// Note that this guarantee is stricter than WGSL's requirements for
2187/// [out-of-bounds accesses][woob], as WGSL allows them to return values from
2188/// elsewhere in the buffer. But this guarantee is necessary anyway, to permit
2189/// `wgpu-core` to avoid clearing uninitialized regions of buffers that will
2190/// never be read by the application before they are overwritten. This
2191/// optimization consults bind group buffer binding regions to determine which
2192/// parts of which buffers shaders might observe. This optimization is only
2193/// sound if shader access is bounds-checked.
2194///
2195/// ## Zero-length bindings
2196///
2197/// Some back ends cannot tolerate zero-length regions; for example, see
2198/// [VUID-VkDescriptorBufferInfo-offset-00340][340] and
2199/// [VUID-VkDescriptorBufferInfo-range-00341][341], or the
2200/// documentation for GLES's [glBindBufferRange][bbr]. This documentation
2201/// previously stated that a `BufferBinding` must have `offset` strictly less
2202/// than the size of the buffer, but this restriction was not honored elsewhere
2203/// in the code, so has been removed. However, it remains the case that
2204/// some backends do not support zero-length bindings, so additional
2205/// logic is needed somewhere to handle this properly. See
2206/// [#3170](https://github.com/gfx-rs/wgpu/issues/3170).
2207///
2208/// [`offset`]: BufferBinding::offset
2209/// [`size`]: BufferBinding::size
2210/// [`Storage`]: wgt::BufferBindingType::Storage
2211/// [`Uniform`]: wgt::BufferBindingType::Uniform
2212/// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340
2213/// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341
2214/// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml
2215/// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec
2216#[derive(Debug)]
2217pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
2218 /// The buffer being bound.
2219 ///
2220 /// This is not fully `pub` to prevent direct construction of
2221 /// `BufferBinding`s, while still allowing public read access to the `offset`
2222 /// and `size` properties.
2223 pub(crate) buffer: &'a B,
2224
2225 /// The offset at which the bound region starts.
2226 ///
2227 /// This must be less or equal to the size of the buffer.
2228 pub offset: wgt::BufferAddress,
2229
2230 /// The size of the region bound, in bytes.
2231 ///
2232 /// If `None`, the region extends from `offset` to the end of the
2233 /// buffer. Given the restrictions on `offset`, this means that
2234 /// the size is always greater than zero.
2235 pub size: Option<wgt::BufferSize>,
2236}
2237
2238// We must implement this manually because `B` is not necessarily `Clone`.
2239impl<B: DynBuffer + ?Sized> Clone for BufferBinding<'_, B> {
2240 fn clone(&self) -> Self {
2241 BufferBinding {
2242 buffer: self.buffer,
2243 offset: self.offset,
2244 size: self.size,
2245 }
2246 }
2247}
2248
2249/// Temporary convenience trait to let us call `.get()` on `u64`s in code that
2250/// really wants to be using `NonZeroU64`.
2251/// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove this
2252pub trait ShouldBeNonZeroExt {
2253 fn get(&self) -> u64;
2254}
2255
2256impl ShouldBeNonZeroExt for NonZeroU64 {
2257 fn get(&self) -> u64 {
2258 NonZeroU64::get(*self)
2259 }
2260}
2261
2262impl ShouldBeNonZeroExt for u64 {
2263 fn get(&self) -> u64 {
2264 *self
2265 }
2266}
2267
2268impl ShouldBeNonZeroExt for Option<NonZeroU64> {
2269 fn get(&self) -> u64 {
2270 match *self {
2271 Some(non_zero) => non_zero.get(),
2272 None => 0,
2273 }
2274 }
2275}
2276
2277impl<'a, B: DynBuffer + ?Sized> BufferBinding<'a, B> {
2278 /// Construct a `BufferBinding` with the given contents.
2279 ///
2280 /// When possible, use the `binding` method on a wgpu-core `Buffer` instead
2281 /// of this method. `Buffer::binding` validates the size of the binding
2282 /// against the size of the buffer.
2283 ///
2284 /// It is more difficult to provide a validating constructor here, due to
2285 /// not having direct access to the size of a `DynBuffer`.
2286 ///
2287 /// SAFETY: The caller is responsible for ensuring that a binding of `size`
2288 /// bytes starting at `offset` is contained within the buffer.
2289 ///
2290 /// The `S` type parameter is a temporary convenience to allow callers to
2291 /// pass a zero size. When the zero-size binding issue is resolved, the
2292 /// argument should just match the type of the member.
2293 /// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove the parameter
2294 pub fn new_unchecked<S: Into<Option<NonZeroU64>>>(
2295 buffer: &'a B,
2296 offset: wgt::BufferAddress,
2297 size: S,
2298 ) -> Self {
2299 Self {
2300 buffer,
2301 offset,
2302 size: size.into(),
2303 }
2304 }
2305}
2306
2307#[derive(Debug)]
2308pub struct TextureBinding<'a, T: DynTextureView + ?Sized> {
2309 pub view: &'a T,
2310 pub usage: wgt::TextureUses,
2311}
2312
2313impl<'a, T: DynTextureView + ?Sized> Clone for TextureBinding<'a, T> {
2314 fn clone(&self) -> Self {
2315 TextureBinding {
2316 view: self.view,
2317 usage: self.usage,
2318 }
2319 }
2320}
2321
2322#[derive(Debug)]
2323pub struct ExternalTextureBinding<'a, B: DynBuffer + ?Sized, T: DynTextureView + ?Sized> {
2324 pub planes: [TextureBinding<'a, T>; 3],
2325 pub params: BufferBinding<'a, B>,
2326}
2327
2328impl<'a, B: DynBuffer + ?Sized, T: DynTextureView + ?Sized> Clone
2329 for ExternalTextureBinding<'a, B, T>
2330{
2331 fn clone(&self) -> Self {
2332 ExternalTextureBinding {
2333 planes: self.planes.clone(),
2334 params: self.params.clone(),
2335 }
2336 }
2337}
2338
2339/// cbindgen:ignore
2340#[derive(Clone, Debug)]
2341pub struct BindGroupEntry {
2342 pub binding: u32,
2343 pub resource_index: u32,
2344 pub count: u32,
2345}
2346
2347/// BindGroup descriptor.
2348///
2349/// Valid usage:
2350///. - `entries` has to be sorted by ascending `BindGroupEntry::binding`
2351///. - `entries` has to have the same set of `BindGroupEntry::binding` as `layout`
2352///. - each entry has to be compatible with the `layout`
2353///. - each entry's `BindGroupEntry::resource_index` is within range
2354/// of the corresponding resource array, selected by the relevant
2355/// `BindGroupLayoutEntry`.
2356#[derive(Clone, Debug)]
2357pub struct BindGroupDescriptor<
2358 'a,
2359 Bgl: DynBindGroupLayout + ?Sized,
2360 B: DynBuffer + ?Sized,
2361 S: DynSampler + ?Sized,
2362 T: DynTextureView + ?Sized,
2363 A: DynAccelerationStructure + ?Sized,
2364> {
2365 pub label: Label<'a>,
2366 pub layout: &'a Bgl,
2367 pub buffers: &'a [BufferBinding<'a, B>],
2368 pub samplers: &'a [&'a S],
2369 pub textures: &'a [TextureBinding<'a, T>],
2370 pub entries: &'a [BindGroupEntry],
2371 pub acceleration_structures: &'a [&'a A],
2372 pub external_textures: &'a [ExternalTextureBinding<'a, B, T>],
2373}
2374
2375#[derive(Clone, Debug)]
2376pub struct CommandEncoderDescriptor<'a, Q: DynQueue + ?Sized> {
2377 pub label: Label<'a>,
2378 pub queue: &'a Q,
2379}
2380
2381/// Naga shader module.
2382#[derive(Default)]
2383pub struct NagaShader {
2384 /// Shader module IR.
2385 pub module: Cow<'static, naga::Module>,
2386 /// Analysis information of the module.
2387 pub info: naga::valid::ModuleInfo,
2388 /// Source codes for debug
2389 pub debug_source: Option<DebugSource>,
2390}
2391
2392// Custom implementation avoids the need to generate Debug impl code
2393// for the whole Naga module and info.
2394impl fmt::Debug for NagaShader {
2395 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2396 write!(formatter, "Naga shader")
2397 }
2398}
2399
2400/// Shader input.
2401pub enum ShaderInput<'a> {
2402 Naga(NagaShader),
2403 MetalLib {
2404 file: &'a [u8],
2405 num_workgroups: hashbrown::HashMap<String, (u32, u32, u32)>,
2406 },
2407 Msl {
2408 shader: &'a str,
2409 num_workgroups: hashbrown::HashMap<String, (u32, u32, u32)>,
2410 },
2411 SpirV(&'a [u32]),
2412 Dxil {
2413 shader: &'a [u8],
2414 },
2415 Hlsl {
2416 shader: &'a str,
2417 },
2418 Glsl {
2419 shader: &'a str,
2420 },
2421}
2422
2423pub struct ShaderModuleDescriptor<'a> {
2424 pub label: Label<'a>,
2425
2426 /// # Safety
2427 ///
2428 /// See the documentation for each flag in [`ShaderRuntimeChecks`][src].
2429 ///
2430 /// [src]: wgt::ShaderRuntimeChecks
2431 pub runtime_checks: wgt::ShaderRuntimeChecks,
2432}
2433
2434#[derive(Debug, Clone)]
2435pub struct DebugSource {
2436 pub file_name: Cow<'static, str>,
2437 pub source_code: Cow<'static, str>,
2438}
2439
2440/// Describes a programmable pipeline stage.
2441#[derive(Debug)]
2442pub struct ProgrammableStage<'a, M: DynShaderModule + ?Sized> {
2443 /// The compiled shader module for this stage.
2444 pub module: &'a M,
2445 /// The name of the entry point in the compiled shader. There must be a function with this name
2446 /// in the shader.
2447 pub entry_point: &'a str,
2448 /// Pipeline constants
2449 pub constants: &'a naga::back::PipelineConstants,
2450 /// Whether workgroup scoped memory will be initialized with zero values for this stage.
2451 ///
2452 /// This is required by the WebGPU spec, but may have overhead which can be avoided
2453 /// for cross-platform applications
2454 pub zero_initialize_workgroup_memory: bool,
2455}
2456
2457impl<M: DynShaderModule + ?Sized> Clone for ProgrammableStage<'_, M> {
2458 fn clone(&self) -> Self {
2459 Self {
2460 module: self.module,
2461 entry_point: self.entry_point,
2462 constants: self.constants,
2463 zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
2464 }
2465 }
2466}
2467
2468/// Describes a compute pipeline.
2469#[derive(Clone, Debug)]
2470pub struct ComputePipelineDescriptor<
2471 'a,
2472 Pl: DynPipelineLayout + ?Sized,
2473 M: DynShaderModule + ?Sized,
2474 Pc: DynPipelineCache + ?Sized,
2475> {
2476 pub label: Label<'a>,
2477 /// The layout of bind groups for this pipeline.
2478 pub layout: &'a Pl,
2479 /// The compiled compute stage and its entry point.
2480 pub stage: ProgrammableStage<'a, M>,
2481 /// The cache which will be used and filled when compiling this pipeline
2482 pub cache: Option<&'a Pc>,
2483}
2484
2485pub struct PipelineCacheDescriptor<'a> {
2486 pub label: Label<'a>,
2487 pub data: Option<&'a [u8]>,
2488}
2489
2490/// Describes how the vertex buffer is interpreted.
2491#[derive(Clone, Debug)]
2492pub struct VertexBufferLayout<'a> {
2493 /// The stride, in bytes, between elements of this buffer.
2494 pub array_stride: wgt::BufferAddress,
2495 /// How often this vertex buffer is "stepped" forward.
2496 pub step_mode: wgt::VertexStepMode,
2497 /// The list of attributes which comprise a single vertex.
2498 pub attributes: &'a [wgt::VertexAttribute],
2499}
2500
2501#[derive(Clone, Debug)]
2502pub enum VertexProcessor<'a, M: DynShaderModule + ?Sized> {
2503 Standard {
2504 /// The format of any vertex buffers used with this pipeline.
2505 vertex_buffers: &'a [Option<VertexBufferLayout<'a>>],
2506 /// The vertex stage for this pipeline.
2507 vertex_stage: ProgrammableStage<'a, M>,
2508 },
2509 Mesh {
2510 task_stage: Option<ProgrammableStage<'a, M>>,
2511 mesh_stage: ProgrammableStage<'a, M>,
2512 },
2513}
2514
2515/// Describes a render (graphics) pipeline.
2516#[derive(Clone, Debug)]
2517pub struct RenderPipelineDescriptor<
2518 'a,
2519 Pl: DynPipelineLayout + ?Sized,
2520 M: DynShaderModule + ?Sized,
2521 Pc: DynPipelineCache + ?Sized,
2522> {
2523 pub label: Label<'a>,
2524 /// The layout of bind groups for this pipeline.
2525 pub layout: &'a Pl,
2526 /// The vertex processing state(vertex shader + buffers or task + mesh shaders)
2527 pub vertex_processor: VertexProcessor<'a, M>,
2528 /// The properties of the pipeline at the primitive assembly and rasterization level.
2529 pub primitive: wgt::PrimitiveState,
2530 /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
2531 pub depth_stencil: Option<wgt::DepthStencilState>,
2532 /// The multi-sampling properties of the pipeline.
2533 pub multisample: wgt::MultisampleState,
2534 /// The fragment stage for this pipeline.
2535 pub fragment_stage: Option<ProgrammableStage<'a, M>>,
2536 /// The effect of draw calls on the color aspect of the output target.
2537 pub color_targets: &'a [Option<wgt::ColorTargetState>],
2538 /// If the pipeline will be used with a multiview render pass, this indicates how many array
2539 /// layers the attachments will have.
2540 pub multiview_mask: Option<NonZeroU32>,
2541 /// The cache which will be used and filled when compiling this pipeline
2542 pub cache: Option<&'a Pc>,
2543}
2544
2545#[derive(Debug, Clone)]
2546pub struct SurfaceConfiguration {
2547 /// Maximum number of queued frames. Must be in
2548 /// `SurfaceCapabilities::maximum_frame_latency` range.
2549 pub maximum_frame_latency: u32,
2550 /// Vertical synchronization mode.
2551 pub present_mode: wgt::PresentMode,
2552 /// Alpha composition mode.
2553 pub composite_alpha_mode: wgt::CompositeAlphaMode,
2554 /// Format of the surface textures.
2555 pub format: wgt::TextureFormat,
2556 /// Requested texture extent. Must be in
2557 /// `SurfaceCapabilities::extents` range.
2558 pub extent: wgt::Extent3d,
2559 /// Allowed usage of surface textures,
2560 pub usage: wgt::TextureUses,
2561 /// Allows views of swapchain texture to have a different format
2562 /// than the texture does.
2563 pub view_formats: Vec<wgt::TextureFormat>,
2564}
2565
2566#[derive(Debug, Clone)]
2567pub struct Rect<T> {
2568 pub x: T,
2569 pub y: T,
2570 pub w: T,
2571 pub h: T,
2572}
2573
2574#[derive(Debug, Clone, PartialEq)]
2575pub struct StateTransition<T> {
2576 pub from: T,
2577 pub to: T,
2578}
2579
2580#[derive(Debug, Clone)]
2581pub struct BufferBarrier<'a, B: DynBuffer + ?Sized> {
2582 pub buffer: &'a B,
2583 pub usage: StateTransition<wgt::BufferUses>,
2584}
2585
2586#[derive(Debug, Clone)]
2587pub struct TextureBarrier<'a, T: DynTexture + ?Sized> {
2588 pub texture: &'a T,
2589 pub range: wgt::ImageSubresourceRange,
2590 pub usage: StateTransition<wgt::TextureUses>,
2591}
2592
2593#[derive(Clone, Copy, Debug)]
2594pub struct BufferCopy {
2595 pub src_offset: wgt::BufferAddress,
2596 pub dst_offset: wgt::BufferAddress,
2597 pub size: wgt::BufferSize,
2598}
2599
2600#[derive(Clone, Debug)]
2601pub struct TextureCopyBase {
2602 pub mip_level: u32,
2603 pub array_layer: u32,
2604 /// Origin within a texture.
2605 /// Note: for 1D and 2D textures, Z must be 0.
2606 pub origin: wgt::Origin3d,
2607 pub aspect: FormatAspects,
2608}
2609
2610#[derive(Clone, Copy, Debug)]
2611pub struct CopyExtent {
2612 pub width: u32,
2613 pub height: u32,
2614 pub depth: u32,
2615}
2616
2617impl From<wgt::Extent3d> for CopyExtent {
2618 fn from(value: wgt::Extent3d) -> Self {
2619 let wgt::Extent3d {
2620 width,
2621 height,
2622 depth_or_array_layers,
2623 } = value;
2624 Self {
2625 width,
2626 height,
2627 depth: depth_or_array_layers,
2628 }
2629 }
2630}
2631
2632impl From<CopyExtent> for wgt::Extent3d {
2633 fn from(value: CopyExtent) -> Self {
2634 let CopyExtent {
2635 width,
2636 height,
2637 depth,
2638 } = value;
2639 Self {
2640 width,
2641 height,
2642 depth_or_array_layers: depth,
2643 }
2644 }
2645}
2646
2647#[derive(Clone, Debug)]
2648pub struct TextureCopy {
2649 pub src_base: TextureCopyBase,
2650 pub dst_base: TextureCopyBase,
2651 pub size: CopyExtent,
2652}
2653
2654#[derive(Clone, Debug)]
2655pub struct BufferTextureCopy {
2656 pub buffer_layout: wgt::TexelCopyBufferLayout,
2657 pub texture_base: TextureCopyBase,
2658 pub size: CopyExtent,
2659}
2660
2661#[derive(Clone, Debug)]
2662pub struct Attachment<'a, T: DynTextureView + ?Sized> {
2663 pub view: &'a T,
2664 /// Contains either a single mutating usage as a target,
2665 /// or a valid combination of read-only usages.
2666 pub usage: wgt::TextureUses,
2667}
2668
2669#[derive(Clone, Debug)]
2670pub struct ColorAttachment<'a, T: DynTextureView + ?Sized> {
2671 pub target: Attachment<'a, T>,
2672 pub depth_slice: Option<u32>,
2673 pub resolve_target: Option<Attachment<'a, T>>,
2674 pub ops: AttachmentOps,
2675 pub clear_value: wgt::Color,
2676}
2677
2678#[derive(Clone, Debug)]
2679pub struct DepthStencilAttachment<'a, T: DynTextureView + ?Sized> {
2680 pub target: Attachment<'a, T>,
2681 pub depth_ops: AttachmentOps,
2682 pub stencil_ops: AttachmentOps,
2683 pub clear_value: (f32, u32),
2684}
2685
2686#[derive(Clone, Debug)]
2687pub struct PassTimestampWrites<'a, Q: DynQuerySet + ?Sized> {
2688 pub query_set: &'a Q,
2689 pub beginning_of_pass_write_index: Option<u32>,
2690 pub end_of_pass_write_index: Option<u32>,
2691}
2692
2693#[derive(Clone, Debug)]
2694pub struct RenderPassDescriptor<'a, Q: DynQuerySet + ?Sized, T: DynTextureView + ?Sized> {
2695 pub label: Label<'a>,
2696 pub extent: wgt::Extent3d,
2697 pub sample_count: u32,
2698 pub color_attachments: &'a [Option<ColorAttachment<'a, T>>],
2699 pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, T>>,
2700 pub multiview_mask: Option<NonZeroU32>,
2701 pub timestamp_writes: Option<PassTimestampWrites<'a, Q>>,
2702 pub occlusion_query_set: Option<&'a Q>,
2703}
2704
2705#[derive(Clone, Debug)]
2706pub struct ComputePassDescriptor<'a, Q: DynQuerySet + ?Sized> {
2707 pub label: Label<'a>,
2708 pub timestamp_writes: Option<PassTimestampWrites<'a, Q>>,
2709}
2710
2711#[test]
2712fn test_default_limits() {
2713 let limits = wgt::Limits::default();
2714 assert!(limits.max_bind_groups <= MAX_BIND_GROUPS as u32);
2715}
2716
2717#[derive(Clone, Debug)]
2718pub struct AccelerationStructureDescriptor<'a> {
2719 pub label: Label<'a>,
2720 pub size: wgt::BufferAddress,
2721 pub format: AccelerationStructureFormat,
2722 pub allow_compaction: bool,
2723}
2724
2725#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2726pub enum AccelerationStructureFormat {
2727 TopLevel,
2728 BottomLevel,
2729}
2730
2731#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2732pub enum AccelerationStructureBuildMode {
2733 Build,
2734 Update,
2735}
2736
2737/// Information of the required size for a corresponding entries struct (+ flags)
2738#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
2739pub struct AccelerationStructureBuildSizes {
2740 pub acceleration_structure_size: wgt::BufferAddress,
2741 pub update_scratch_size: wgt::BufferAddress,
2742 pub build_scratch_size: wgt::BufferAddress,
2743}
2744
2745/// Updates use source_acceleration_structure if present, else the update will be performed in place.
2746/// For updates, only the data is allowed to change (not the meta data or sizes).
2747#[derive(Clone, Debug)]
2748pub struct BuildAccelerationStructureDescriptor<
2749 'a,
2750 B: DynBuffer + ?Sized,
2751 A: DynAccelerationStructure + ?Sized,
2752> {
2753 pub entries: &'a AccelerationStructureEntries<'a, B>,
2754 pub mode: AccelerationStructureBuildMode,
2755 pub flags: AccelerationStructureBuildFlags,
2756 pub source_acceleration_structure: Option<&'a A>,
2757 pub destination_acceleration_structure: &'a A,
2758 pub scratch_buffer: &'a B,
2759 pub scratch_buffer_offset: wgt::BufferAddress,
2760}
2761
2762/// - All buffers, buffer addresses and offsets will be ignored.
2763/// - The build mode will be ignored.
2764/// - Reducing the amount of Instances, Triangle groups or AABB groups (or the number of Triangles/AABBs in corresponding groups),
2765/// may result in reduced size requirements.
2766/// - Any other change may result in a bigger or smaller size requirement.
2767#[derive(Clone, Debug)]
2768pub struct GetAccelerationStructureBuildSizesDescriptor<'a, B: DynBuffer + ?Sized> {
2769 pub entries: &'a AccelerationStructureEntries<'a, B>,
2770 pub flags: AccelerationStructureBuildFlags,
2771}
2772
2773/// Entries for a single descriptor
2774/// * `Instances` - Multiple instances for a top level acceleration structure
2775/// * `Triangles` - Multiple triangle meshes for a bottom level acceleration structure
2776/// * `AABBs` - List of list of axis aligned bounding boxes for a bottom level acceleration structure
2777#[derive(Debug)]
2778pub enum AccelerationStructureEntries<'a, B: DynBuffer + ?Sized> {
2779 Instances(AccelerationStructureInstances<'a, B>),
2780 Triangles(Vec<AccelerationStructureTriangles<'a, B>>),
2781 AABBs(Vec<AccelerationStructureAABBs<'a, B>>),
2782}
2783
2784/// * `first_vertex` - offset in the vertex buffer (as number of vertices)
2785/// * `indices` - optional index buffer with attributes
2786/// * `transform` - optional transform
2787#[derive(Clone, Debug)]
2788pub struct AccelerationStructureTriangles<'a, B: DynBuffer + ?Sized> {
2789 pub vertex_buffer: Option<&'a B>,
2790 pub vertex_format: wgt::VertexFormat,
2791 pub first_vertex: u32,
2792 pub vertex_count: u32,
2793 pub vertex_stride: wgt::BufferAddress,
2794 pub indices: Option<AccelerationStructureTriangleIndices<'a, B>>,
2795 pub transform: Option<AccelerationStructureTriangleTransform<'a, B>>,
2796 pub flags: AccelerationStructureGeometryFlags,
2797}
2798
2799/// * `offset` - offset in bytes
2800#[derive(Clone, Debug)]
2801pub struct AccelerationStructureAABBs<'a, B: DynBuffer + ?Sized> {
2802 pub buffer: Option<&'a B>,
2803 pub offset: u32,
2804 pub count: u32,
2805 pub stride: wgt::BufferAddress,
2806 pub flags: AccelerationStructureGeometryFlags,
2807}
2808
2809pub struct AccelerationStructureCopy {
2810 pub copy_flags: wgt::AccelerationStructureCopy,
2811 pub type_flags: wgt::AccelerationStructureType,
2812}
2813
2814/// * `offset` - offset in bytes
2815#[derive(Clone, Debug)]
2816pub struct AccelerationStructureInstances<'a, B: DynBuffer + ?Sized> {
2817 pub buffer: Option<&'a B>,
2818 pub offset: u32,
2819 pub count: u32,
2820}
2821
2822/// * `offset` - offset in bytes
2823#[derive(Clone, Debug)]
2824pub struct AccelerationStructureTriangleIndices<'a, B: DynBuffer + ?Sized> {
2825 pub format: wgt::IndexFormat,
2826 pub buffer: Option<&'a B>,
2827 pub offset: u32,
2828 pub count: u32,
2829}
2830
2831/// * `offset` - offset in bytes
2832#[derive(Clone, Debug)]
2833pub struct AccelerationStructureTriangleTransform<'a, B: DynBuffer + ?Sized> {
2834 pub buffer: &'a B,
2835 pub offset: u32,
2836}
2837
2838pub use wgt::AccelerationStructureFlags as AccelerationStructureBuildFlags;
2839pub use wgt::AccelerationStructureGeometryFlags;
2840
2841bitflags::bitflags! {
2842 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
2843 pub struct AccelerationStructureUses: u8 {
2844 // For blas used as input for tlas
2845 const BUILD_INPUT = 1 << 0;
2846 // Target for acceleration structure build
2847 const BUILD_OUTPUT = 1 << 1;
2848 // Tlas used in a shader
2849 const SHADER_INPUT = 1 << 2;
2850 // Blas used to query compacted size
2851 const QUERY_INPUT = 1 << 3;
2852 // BLAS used as a src for a copy operation
2853 const COPY_SRC = 1 << 4;
2854 // BLAS used as a dst for a copy operation
2855 const COPY_DST = 1 << 5;
2856 }
2857}
2858
2859#[derive(Debug, Clone)]
2860pub struct AccelerationStructureBarrier {
2861 pub usage: StateTransition<AccelerationStructureUses>,
2862}
2863
2864#[derive(Debug, Copy, Clone)]
2865pub struct TlasInstance {
2866 pub transform: [f32; 12],
2867 pub custom_data: u32,
2868 pub mask: u8,
2869 pub blas_address: u64,
2870}
2871
2872#[cfg(dx12)]
2873pub enum D3D12ExposeAdapterResult {
2874 CreateDeviceError(dx12::CreateDeviceError),
2875 UnknownFeatureLevel(i32),
2876 ResourceBindingTier2Requirement,
2877 ShaderModel6Requirement,
2878 Success(dx12::FeatureLevel, dx12::ShaderModel),
2879}
2880
2881/// Pluggable telemetry, mainly to be used by Firefox.
2882#[derive(Debug, Clone, Copy)]
2883pub struct Telemetry {
2884 #[cfg(dx12)]
2885 pub d3d12_expose_adapter: fn(
2886 desc: &windows::Win32::Graphics::Dxgi::DXGI_ADAPTER_DESC2,
2887 driver_version: Result<[u16; 4], windows_core::HRESULT>,
2888 result: D3D12ExposeAdapterResult,
2889 ),
2890}