//! A cross-platform unsafe graphics abstraction. //! //! This crate defines a set of traits abstracting over modern graphics APIs, //! with implementations ("backends") for Vulkan, Metal, Direct3D, and GL. //! //! `wgpu-hal` is a spiritual successor to //! [gfx-hal](https://github.com/gfx-rs/gfx), but with reduced scope, and //! oriented towards WebGPU implementation goals. It has no overhead for //! validation or tracking, and the API translation overhead is kept to the bare //! minimum by the design of WebGPU. This API can be used for resource-demanding //! applications and engines. //! //! The `wgpu-hal` crate's main design choices: //! //! - Our traits are meant to be *portable*: proper use //! should get equivalent results regardless of the backend. //! //! - Our traits' contracts are *unsafe*: implementations perform minimal //! validation, if any, and incorrect use will often cause undefined behavior. //! This allows us to minimize the overhead we impose over the underlying //! graphics system. If you need safety, the [`wgpu-core`] crate provides a //! safe API for driving `wgpu-hal`, implementing all necessary validation, //! resource state tracking, and so on. (Note that `wgpu-core` is designed for //! use via FFI; the [`wgpu`] crate provides more idiomatic Rust bindings for //! `wgpu-core`.) Or, you can do your own validation. //! //! - In the same vein, returned errors *only cover cases the user can't //! anticipate*, like running out of memory or losing the device. Any errors //! that the user could reasonably anticipate are their responsibility to //! avoid. For example, `wgpu-hal` returns no error for mapping a buffer that's //! not mappable: as the buffer creator, the user should already know if they //! can map it. //! //! - We use *static dispatch*. The traits are not //! generally object-safe. You must select a specific backend type //! like [`vulkan::Api`] or [`metal::Api`], and then use that //! according to the main traits, or call backend-specific methods. //! //! - We use *idiomatic Rust parameter passing*, //! taking objects by reference, returning them by value, and so on, //! unlike `wgpu-core`, which refers to objects by ID. //! //! - We map buffer contents *persistently*. This means that the buffer can //! remain mapped on the CPU while the GPU reads or writes to it. You must //! explicitly indicate when data might need to be transferred between CPU and //! GPU, if [`Device::map_buffer`] indicates that this is necessary. //! //! - You must record *explicit barriers* between different usages of a //! resource. For example, if a buffer is written to by a compute //! shader, and then used as and index buffer to a draw call, you //! must use [`CommandEncoder::transition_buffers`] between those two //! operations. //! //! - Pipeline layouts are *explicitly specified* when setting bind groups. //! Incompatible layouts disturb groups bound at higher indices. //! //! - The API *accepts collections as iterators*, to avoid forcing the user to //! store data in particular containers. The implementation doesn't guarantee //! that any of the iterators are drained, unless stated otherwise by the //! function documentation. For this reason, we recommend that iterators don't //! do any mutating work. //! //! Unfortunately, `wgpu-hal`'s safety requirements are not fully documented. //! Ideally, all trait methods would have doc comments setting out the //! requirements users must meet to ensure correct and portable behavior. If you //! are aware of a specific requirement that a backend imposes that is not //! ensured by the traits' documented rules, please file an issue. Or, if you are //! a capable technical writer, please file a pull request! //! //! [`wgpu-core`]: https://crates.io/crates/wgpu-core //! [`wgpu`]: https://crates.io/crates/wgpu //! [`vulkan::Api`]: vulkan/struct.Api.html //! [`metal::Api`]: metal/struct.Api.html //! //! ## Primary backends //! //! The `wgpu-hal` crate has full-featured backends implemented on the following //! platform graphics APIs: //! //! - Vulkan, available on Linux, Android, and Windows, using the [`ash`] crate's //! Vulkan bindings. It's also available on macOS, if you install [MoltenVK]. //! //! - Metal on macOS, using the [`metal`] crate's bindings. //! //! - Direct3D 12 on Windows, using the [`windows`] crate's bindings. //! //! [`ash`]: https://crates.io/crates/ash //! [MoltenVK]: https://github.com/KhronosGroup/MoltenVK //! [`metal`]: https://crates.io/crates/metal //! [`windows`]: https://crates.io/crates/windows //! //! ## Secondary backends //! //! The `wgpu-hal` crate has a partial implementation based on the following //! platform graphics API: //! //! - The GL backend is available anywhere OpenGL, OpenGL ES, or WebGL are //! available. See the [`gles`] module documentation for details. //! //! [`gles`]: gles/index.html //! //! You can see what capabilities an adapter is missing by checking the //! [`DownlevelCapabilities`][tdc] in [`ExposedAdapter::capabilities`], available //! from [`Instance::enumerate_adapters`]. //! //! The API is generally designed to fit the primary backends better than the //! secondary backends, so the latter may impose more overhead. //! //! [tdc]: wgt::DownlevelCapabilities //! //! ## Traits //! //! The `wgpu-hal` crate defines a handful of traits that together //! represent a cross-platform abstraction for modern GPU APIs. //! //! - The [`Api`] trait represents a `wgpu-hal` backend. It has no methods of its //! own, only a collection of associated types. //! //! - [`Api::Instance`] implements the [`Instance`] trait. [`Instance::init`] //! creates an instance value, which you can use to enumerate the adapters //! available on the system. For example, [`vulkan::Api::Instance::init`][Ii] //! returns an instance that can enumerate the Vulkan physical devices on your //! system. //! //! - [`Api::Adapter`] implements the [`Adapter`] trait, representing a //! particular device from a particular backend. For example, a Vulkan instance //! might have a Lavapipe software adapter and a GPU-based adapter. //! //! - [`Api::Device`] implements the [`Device`] trait, representing an active //! link to a device. You get a device value by calling [`Adapter::open`], and //! then use it to create buffers, textures, shader modules, and so on. //! //! - [`Api::Queue`] implements the [`Queue`] trait, which you use to submit //! command buffers to a given device. //! //! - [`Api::CommandEncoder`] implements the [`CommandEncoder`] trait, which you //! use to build buffers of commands to submit to a queue. This has all the //! methods for drawing and running compute shaders, which is presumably what //! you're here for. //! //! - [`Api::Surface`] implements the [`Surface`] trait, which represents a //! swapchain for presenting images on the screen, via interaction with the //! system's window manager. //! //! The [`Api`] trait has various other associated types like [`Api::Buffer`] and //! [`Api::Texture`] that represent resources the rest of the interface can //! operate on, but these generally do not have their own traits. //! //! [Ii]: Instance::init //! //! ## Validation is the calling code's responsibility, not `wgpu-hal`'s //! //! As much as possible, `wgpu-hal` traits place the burden of validation, //! resource tracking, and state tracking on the caller, not on the trait //! implementations themselves. Anything which can reasonably be handled in //! backend-independent code should be. A `wgpu_hal` backend's sole obligation is //! to provide portable behavior, and report conditions that the calling code //! can't reasonably anticipate, like device loss or running out of memory. //! //! The `wgpu` crate collection is intended for use in security-sensitive //! applications, like web browsers, where the API is available to untrusted //! code. This means that `wgpu-core`'s validation is not simply a service to //! developers, to be provided opportunistically when the performance costs are //! acceptable and the necessary data is ready at hand. Rather, `wgpu-core`'s //! validation must be exhaustive, to ensure that even malicious content cannot //! provoke and exploit undefined behavior in the platform's graphics API. //! //! Because graphics APIs' requirements are complex, the only practical way for //! `wgpu` to provide exhaustive validation is to comprehensively track the //! lifetime and state of all the resources in the system. Implementing this //! separately for each backend is infeasible; effort would be better spent //! making the cross-platform validation in `wgpu-core` legible and trustworthy. //! Fortunately, the requirements are largely similar across the various //! platforms, so cross-platform validation is practical. //! //! Some backends have specific requirements that aren't practical to foist off //! on the `wgpu-hal` user. For example, properly managing macOS Objective-C or //! Microsoft COM reference counts is best handled by using appropriate pointer //! types within the backend. //! //! A desire for "defense in depth" may suggest performing additional validation //! in `wgpu-hal` when the opportunity arises, but this must be done with //! caution. Even experienced contributors infer the expectations their changes //! must meet by considering not just requirements made explicit in types, tests, //! assertions, and comments, but also those implicit in the surrounding code. //! When one sees validation or state-tracking code in `wgpu-hal`, it is tempting //! to conclude, "Oh, `wgpu-hal` checks for this, so `wgpu-core` needn't worry //! about it - that would be redundant!" The responsibility for exhaustive //! validation always rests with `wgpu-core`, regardless of what may or may not //! be checked in `wgpu-hal`. //! //! To this end, any "defense in depth" validation that does appear in `wgpu-hal` //! for requirements that `wgpu-core` should have enforced should report failure //! via the `unreachable!` macro, because problems detected at this stage always //! indicate a bug in `wgpu-core`. //! //! ## Debugging //! //! Most of the information on the wiki [Debugging wgpu Applications][wiki-debug] //! page still applies to this API, with the exception of API tracing/replay //! functionality, which is only available in `wgpu-core`. //! //! [wiki-debug]: https://github.com/gfx-rs/wgpu/wiki/Debugging-wgpu-Applications
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![allow( // this happens on the GL backend, where it is both thread safe and non-thread safe in the same code.
clippy::arc_with_non_send_sync, // We don't use syntax sugar where it's not necessary.
clippy::match_like_matches_macro, // Redundant matching is more explicit.
clippy::redundant_pattern_matching, // Explicit lifetimes are often easier to reason about.
clippy::needless_lifetimes, // No need for defaults in the internal types.
clippy::new_without_default, // Matches are good and extendable, no need to make an exception here.
clippy::single_match, // Push commands are more regular than macros.
clippy::vec_init_then_push, // We unsafe impl `Send` for a reason.
clippy::non_send_fields_in_send_ty, // TODO!
clippy::missing_safety_doc, // It gets in the way a lot and does not prevent bugs in practice.
clippy::pattern_type_mismatch,
)] #![warn(
clippy::ptr_as_ptr,
trivial_casts,
trivial_numeric_casts,
unsafe_op_in_unsafe_fn,
unused_extern_crates,
unused_qualifications
)]
/// DirectX12 API internals. #[cfg(dx12)] pubmod dx12; /// A dummy API implementation. pubmod empty; /// GLES API internals. #[cfg(gles)] pubmod gles; /// Metal API internals. #[cfg(metal)] pubmod metal; /// Vulkan API internals. #[cfg(vulkan)] pubmod vulkan;
pubmod auxil; pubmod api { #[cfg(dx12)] pubusesuper::dx12::Api as Dx12; pubusesuper::empty::Api as Empty; #[cfg(gles)] pubusesuper::gles::Api as Gles; #[cfg(metal)] pubusesuper::metal::Api as Metal; #[cfg(vulkan)] pubusesuper::vulkan::Api as Vulkan;
}
/// A callback to signal that wgpu is no longer using a resource. #[cfg(any(gles, vulkan))] pubtype DropCallback = Box<dyn FnOnce() + Send + Sync + 'static>;
#[derive(Clone, Debug, PartialEq, Eq, Error)] pubenum DeviceError { #[error("Out of memory")]
OutOfMemory, #[error("Device is lost")]
Lost, #[error("Creation of a resource failed for a reason other than running out of memory.")]
ResourceCreationFailed, #[error("Unexpected error variant (driver implementation is at fault)")]
Unexpected,
}
#[allow(dead_code)] // may be unused on some platforms #[cold] fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal invariant was violated (usage error): {txt}")
}
#[allow(dead_code)] // may be unused on some platforms #[cold] fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal ran into a preventable internal error: {txt}")
}
#[derive(Clone, Debug, Eq, PartialEq, Error)] pubenum SurfaceError { #[error("Surface is lost")]
Lost, #[error("Surface is outdated, needs to be re-created")]
Outdated, #[error(transparent)]
Device(#[from] DeviceError), #[error("Other reason: {0}")]
Other(&'static str),
}
/// Error occurring while trying to create an instance, or create a surface from an instance; /// typically relating to the state of the underlying graphics API or hardware. #[derive(Clone, Debug, Error)] #[error("{message}")] pubstruct InstanceError { /// These errors are very platform specific, so do not attempt to encode them as an enum. /// /// This message should describe the problem in sufficient detail to be useful for a /// user-to-developer “why won't this work on my machine” bug report, and otherwise follow /// <https://rust-lang.github.io/api-guidelines/interoperability.html#error-types-are-meaningful-and-well-behaved-c-good-err>.
message: String,
/// Underlying error value, if any is available. #[source]
source: Option<Arc<dyn std::error::Error + Send + Sync + 'static>>,
}
impl InstanceError { #[allow(dead_code)] // may be unused on some platforms pub(crate) fn new(message: String) -> Self { Self {
message,
source: None,
}
} #[allow(dead_code)] // may be unused on some platforms pub(crate) fn with_source(
message: String,
source: impl std::error::Error + Send + Sync + 'static,
) -> Self { Self {
message,
source: Some(Arc::new(source)),
}
}
}
pubtrait Api: Clone + fmt::Debug + Sized { type Instance: DynInstance + Instance<A = Self>; type Surface: DynSurface + Surface<A = Self>; type Adapter: DynAdapter + Adapter<A = Self>; type Device: DynDevice + Device<A = Self>;
type Queue: DynQueue + Queue<A = Self>; type CommandEncoder: DynCommandEncoder + CommandEncoder<A = Self>;
/// This API's command buffer type. /// /// The only thing you can do with `CommandBuffer`s is build them /// with a [`CommandEncoder`] and then pass them to /// [`Queue::submit`] for execution, or destroy them by passing /// them to [`CommandEncoder::reset_all`]. /// /// [`CommandEncoder`]: Api::CommandEncoder type CommandBuffer: DynCommandBuffer;
type Buffer: DynBuffer; type Texture: DynTexture; type SurfaceTexture: DynSurfaceTexture + Borrow<Self::Texture>; type TextureView: DynTextureView; type Sampler: DynSampler; type QuerySet: DynQuerySet;
/// A value you can block on to wait for something to finish. /// /// A `Fence` holds a monotonically increasing [`FenceValue`]. You can call /// [`Device::wait`] to block until a fence reaches or passes a value you /// choose. [`Queue::submit`] can take a `Fence` and a [`FenceValue`] to /// store in it when the submitted work is complete. /// /// Attempting to set a fence to a value less than its current value has no /// effect. /// /// Waiting on a fence returns as soon as the fence reaches *or passes* the /// requested value. This implies that, in order to reliably determine when /// an operation has completed, operations must finish in order of /// increasing fence values: if a higher-valued operation were to finish /// before a lower-valued operation, then waiting for the fence to reach the /// lower value could return before the lower-valued operation has actually /// finished. type Fence: DynFence;
type BindGroupLayout: DynBindGroupLayout; type BindGroup: DynBindGroup; type PipelineLayout: DynPipelineLayout; type ShaderModule: DynShaderModule; type RenderPipeline: DynRenderPipeline; type ComputePipeline: DynComputePipeline; type PipelineCache: DynPipelineCache;
type AccelerationStructure: DynAccelerationStructure + 'static;
}
pubtrait Instance: Sized + WasmNotSendSync { type A: Api;
unsafefn init(desc: &InstanceDescriptor) -> Result<Self, InstanceError>; unsafefn create_surface(
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Result<<Self::A as Api>::Surface, InstanceError>; /// `surface_hint` is only used by the GLES backend targeting WebGL2 unsafefn enumerate_adapters(
&self,
surface_hint: Option<&<Self::A as Api>::Surface>,
) -> Vec<ExposedAdapter<Self::A>>;
}
pubtrait Surface: WasmNotSendSync { type A: Api;
/// Configure `self` to use `device`. /// /// # Safety /// /// - All GPU work using `self` must have been completed. /// - All [`AcquiredSurfaceTexture`]s must have been destroyed. /// - All [`Api::TextureView`]s derived from the [`AcquiredSurfaceTexture`]s must have been destroyed. /// - The surface `self` must not currently be configured to use any other [`Device`]. unsafefn configure(
&self,
device: &<Self::A as Api>::Device,
config: &SurfaceConfiguration,
) -> Result<(), SurfaceError>;
/// Unconfigure `self` on `device`. /// /// # Safety /// /// - All GPU work that uses `surface` must have been completed. /// - All [`AcquiredSurfaceTexture`]s must have been destroyed. /// - All [`Api::TextureView`]s derived from the [`AcquiredSurfaceTexture`]s must have been destroyed. /// - The surface `self` must have been configured on `device`. unsafefn unconfigure(&self, device: &<Self::A as Api>::Device);
/// Return the next texture to be presented by `self`, for the caller to draw on. /// /// On success, return an [`AcquiredSurfaceTexture`] representing the /// texture into which the caller should draw the image to be displayed on /// `self`. /// /// If `timeout` elapses before `self` has a texture ready to be acquired, /// return `Ok(None)`. If `timeout` is `None`, wait indefinitely, with no /// timeout. /// /// # Using an [`AcquiredSurfaceTexture`] /// /// On success, this function returns an [`AcquiredSurfaceTexture`] whose /// [`texture`] field is a [`SurfaceTexture`] from which the caller can /// [`borrow`] a [`Texture`] to draw on. The [`AcquiredSurfaceTexture`] also /// carries some metadata about that [`SurfaceTexture`]. /// /// All calls to [`Queue::submit`] that draw on that [`Texture`] must also /// include the [`SurfaceTexture`] in the `surface_textures` argument. /// /// When you are done drawing on the texture, you can display it on `self` /// by passing the [`SurfaceTexture`] and `self` to [`Queue::present`]. /// /// If you do not wish to display the texture, you must pass the /// [`SurfaceTexture`] to [`self.discard_texture`], so that it can be reused /// by future acquisitions. /// /// # Portability /// /// Some backends can't support a timeout when acquiring a texture. On these /// backends, `timeout` is ignored. /// /// # Safety /// /// - The surface `self` must currently be configured on some [`Device`]. /// /// - The `fence` argument must be the same [`Fence`] passed to all calls to /// [`Queue::submit`] that used [`Texture`]s acquired from this surface. /// /// - You may only have one texture acquired from `self` at a time. When /// `acquire_texture` returns `Ok(Some(ast))`, you must pass the returned /// [`SurfaceTexture`] `ast.texture` to either [`Queue::present`] or /// [`Surface::discard_texture`] before calling `acquire_texture` again. /// /// [`texture`]: AcquiredSurfaceTexture::texture /// [`SurfaceTexture`]: Api::SurfaceTexture /// [`borrow`]: std::borrow::Borrow::borrow /// [`Texture`]: Api::Texture /// [`Fence`]: Api::Fence /// [`self.discard_texture`]: Surface::discard_texture unsafefn acquire_texture(
&self,
timeout: Option<std::time::Duration>,
fence: &<Self::A as Api>::Fence,
) -> Result<Option<AcquiredSurfaceTexture<Self::A>>, SurfaceError>;
/// Relinquish an acquired texture without presenting it. /// /// After this call, the texture underlying [`SurfaceTexture`] may be /// returned by subsequent calls to [`self.acquire_texture`]. /// /// # Safety /// /// - The surface `self` must currently be configured on some [`Device`]. /// /// - `texture` must be a [`SurfaceTexture`] returned by a call to /// [`self.acquire_texture`] that has not yet been passed to /// [`Queue::present`]. /// /// [`SurfaceTexture`]: Api::SurfaceTexture /// [`self.acquire_texture`]: Surface::acquire_texture unsafefn discard_texture(&self, texture: <Self::A as Api>::SurfaceTexture);
}
/// Return the set of supported capabilities for a texture format. unsafefn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> TextureFormatCapabilities;
/// Returns the capabilities of working with a specified surface. /// /// `None` means presentation is not supported for it. unsafefn surface_capabilities(
&self,
surface: &<Self::A as Api>::Surface,
) -> Option<SurfaceCapabilities>;
/// Creates a [`PresentationTimestamp`] using the adapter's WSI. /// /// [`PresentationTimestamp`]: wgt::PresentationTimestamp unsafefn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp;
}
/// A connection to a GPU and a pool of resources to use with it. /// /// A `wgpu-hal` `Device` represents an open connection to a specific graphics /// processor, controlled via the backend [`Device::A`]. A `Device` is mostly /// used for creating resources. Each `Device` has an associated [`Queue`] used /// for command submission. /// /// On Vulkan a `Device` corresponds to a logical device ([`VkDevice`]). Other /// backends don't have an exact analog: for example, [`ID3D12Device`]s and /// [`MTLDevice`]s are owned by the backends' [`wgpu_hal::Adapter`] /// implementations, and shared by all [`wgpu_hal::Device`]s created from that /// `Adapter`. /// /// A `Device`'s life cycle is generally: /// /// 1) Obtain a `Device` and its associated [`Queue`] by calling /// [`Adapter::open`]. /// /// Alternatively, the backend-specific types that implement [`Adapter`] often /// have methods for creating a `wgpu-hal` `Device` from a platform-specific /// handle. For example, [`vulkan::Adapter::device_from_raw`] can create a /// [`vulkan::Device`] from an [`ash::Device`]. /// /// 1) Create resources to use on the device by calling methods like /// [`Device::create_texture`] or [`Device::create_shader_module`]. /// /// 1) Call [`Device::create_command_encoder`] to obtain a [`CommandEncoder`], /// which you can use to build [`CommandBuffer`]s holding commands to be /// executed on the GPU. /// /// 1) Call [`Queue::submit`] on the `Device`'s associated [`Queue`] to submit /// [`CommandBuffer`]s for execution on the GPU. If needed, call /// [`Device::wait`] to wait for them to finish execution. /// /// 1) Free resources with methods like [`Device::destroy_texture`] or /// [`Device::destroy_shader_module`]. /// /// 1) Drop the device. /// /// [`vkDevice`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VkDevice /// [`ID3D12Device`]: https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12device /// [`MTLDevice`]: https://developer.apple.com/documentation/metal/mtldevice /// [`wgpu_hal::Adapter`]: Adapter /// [`wgpu_hal::Device`]: Device /// [`vulkan::Adapter::device_from_raw`]: vulkan/struct.Adapter.html#method.device_from_raw /// [`vulkan::Device`]: vulkan/struct.Device.html /// [`ash::Device`]: https://docs.rs/ash/latest/ash/struct.Device.html /// [`CommandBuffer`]: Api::CommandBuffer /// /// # Safety /// /// As with other `wgpu-hal` APIs, [validation] is the caller's /// responsibility. Here are the general requirements for all `Device` /// methods: /// /// - Any resource passed to a `Device` method must have been created by that /// `Device`. For example, a [`Texture`] passed to [`Device::destroy_texture`] must /// have been created with the `Device` passed as `self`. /// /// - Resources may not be destroyed if they are used by any submitted command /// buffers that have not yet finished execution. /// /// [validation]: index.html#validation-is-the-calling-codes-responsibility-not-wgpu-hals /// [`Texture`]: Api::Texture pubtrait Device: WasmNotSendSync { type A: Api;
/// Creates a new buffer. /// /// The initial usage is `BufferUses::empty()`. unsafefn create_buffer(
&self,
desc: &BufferDescriptor,
) -> Result<<Self::A as Api>::Buffer, DeviceError>;
/// Free `buffer` and any GPU resources it owns. /// /// Note that backends are allowed to allocate GPU memory for buffers from /// allocation pools, and this call is permitted to simply return `buffer`'s /// storage to that pool, without making it available to other applications. /// /// # Safety /// /// - The given `buffer` must not currently be mapped. unsafefn destroy_buffer(&self, buffer: <Self::A as Api>::Buffer);
/// A hook for when a wgpu-core buffer is created from a raw wgpu-hal buffer. unsafefn add_raw_buffer(&self, buffer: &<Self::A as Api>::Buffer);
/// Return a pointer to CPU memory mapping the contents of `buffer`. /// /// Buffer mappings are persistent: the buffer may remain mapped on the CPU /// while the GPU reads or writes to it. (Note that `wgpu_core` does not use /// this feature: when a `wgpu_core::Buffer` is unmapped, the underlying /// `wgpu_hal` buffer is also unmapped.) /// /// If this function returns `Ok(mapping)`, then: /// /// - `mapping.ptr` is the CPU address of the start of the mapped memory. /// /// - If `mapping.is_coherent` is `true`, then CPU writes to the mapped /// memory are immediately visible on the GPU, and vice versa. /// /// # Safety /// /// - The given `buffer` must have been created with the [`MAP_READ`] or /// [`MAP_WRITE`] flags set in [`BufferDescriptor::usage`]. /// /// - The given `range` must fall within the size of `buffer`. /// /// - The caller must avoid data races between the CPU and the GPU. A data /// race is any pair of accesses to a particular byte, one of which is a /// write, that are not ordered with respect to each other by some sort of /// synchronization operation. /// /// - If this function returns `Ok(mapping)` and `mapping.is_coherent` is /// `false`, then: /// /// - Every CPU write to a mapped byte followed by a GPU read of that byte /// must have at least one call to [`Device::flush_mapped_ranges`] /// covering that byte that occurs between those two accesses. /// /// - Every GPU write to a mapped byte followed by a CPU read of that byte /// must have at least one call to [`Device::invalidate_mapped_ranges`] /// covering that byte that occurs between those two accesses. /// /// Note that the data race rule above requires that all such access pairs /// be ordered, so it is meaningful to talk about what must occur /// "between" them. /// /// - Zero-sized mappings are not allowed. /// /// - The returned [`BufferMapping::ptr`] must not be used after a call to /// [`Device::unmap_buffer`]. /// /// [`MAP_READ`]: BufferUses::MAP_READ /// [`MAP_WRITE`]: BufferUses::MAP_WRITE unsafefn map_buffer(
&self,
buffer: &<Self::A as Api>::Buffer,
range: MemoryRange,
) -> Result<BufferMapping, DeviceError>;
/// Remove the mapping established by the last call to [`Device::map_buffer`]. /// /// # Safety /// /// - The given `buffer` must be currently mapped. unsafefn unmap_buffer(&self, buffer: &<Self::A as Api>::Buffer);
/// Indicate that CPU writes to mapped buffer memory should be made visible to the GPU. /// /// # Safety /// /// - The given `buffer` must be currently mapped. /// /// - All ranges produced by `ranges` must fall within `buffer`'s size. unsafefn flush_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I) where
I: Iterator<Item = MemoryRange>;
/// Indicate that GPU writes to mapped buffer memory should be made visible to the CPU. /// /// # Safety /// /// - The given `buffer` must be currently mapped. /// /// - All ranges produced by `ranges` must fall within `buffer`'s size. unsafefn invalidate_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I) where
I: Iterator<Item = MemoryRange>;
/// Creates a new texture. /// /// The initial usage for all subresources is `TextureUses::UNINITIALIZED`. unsafefn create_texture(
&self,
desc: &TextureDescriptor,
) -> Result<<Self::A as Api>::Texture, DeviceError>; unsafefn destroy_texture(&self, texture: <Self::A as Api>::Texture);
/// A hook for when a wgpu-core texture is created from a raw wgpu-hal texture. unsafefn add_raw_texture(&self, texture: &<Self::A as Api>::Texture);
unsafefn create_texture_view(
&self,
texture: &<Self::A as Api>::Texture,
desc: &TextureViewDescriptor,
) -> Result<<Self::A as Api>::TextureView, DeviceError>; unsafefn destroy_texture_view(&self, view: <Self::A as Api>::TextureView); unsafefn create_sampler(
&self,
desc: &SamplerDescriptor,
) -> Result<<Self::A as Api>::Sampler, DeviceError>; unsafefn destroy_sampler(&self, sampler: <Self::A as Api>::Sampler);
/// Create a fresh [`CommandEncoder`]. /// /// The new `CommandEncoder` is in the "closed" state. unsafefn create_command_encoder(
&self,
desc: &CommandEncoderDescriptor<<Self::A as Api>::Queue>,
) -> Result<<Self::A as Api>::CommandEncoder, DeviceError>;
/// Creates a bind group layout. unsafefn create_bind_group_layout(
&self,
desc: &BindGroupLayoutDescriptor,
) -> Result<<Self::A as Api>::BindGroupLayout, DeviceError>; unsafefn destroy_bind_group_layout(&self, bg_layout: <Self::A as Api>::BindGroupLayout); unsafefn create_pipeline_layout(
&self,
desc: &PipelineLayoutDescriptor<<Self::A as Api>::BindGroupLayout>,
) -> Result<<Self::A as Api>::PipelineLayout, DeviceError>; unsafefn destroy_pipeline_layout(&self, pipeline_layout: <Self::A as Api>::PipelineLayout);
#[allow(clippy::type_complexity)] unsafefn create_bind_group(
&self,
desc: &BindGroupDescriptor<
<Self::A as Api>::BindGroupLayout,
<Self::A as Api>::Buffer,
<Self::A as Api>::Sampler,
<Self::A as Api>::TextureView,
<Self::A as Api>::AccelerationStructure,
>,
) -> Result<<Self::A as Api>::BindGroup, DeviceError>; unsafefn destroy_bind_group(&self, group: <Self::A as Api>::BindGroup);
unsafefn create_shader_module(
&self,
desc: &ShaderModuleDescriptor,
shader: ShaderInput,
) -> Result<<Self::A as Api>::ShaderModule, ShaderError>; unsafefn destroy_shader_module(&self, module: <Self::A as Api>::ShaderModule);
#[allow(clippy::type_complexity)] unsafefn create_render_pipeline(
&self,
desc: &RenderPipelineDescriptor<
<Self::A as Api>::PipelineLayout,
<Self::A as Api>::ShaderModule,
<Self::A as Api>::PipelineCache,
>,
) -> Result<<Self::A as Api>::RenderPipeline, PipelineError>; unsafefn destroy_render_pipeline(&self, pipeline: <Self::A as Api>::RenderPipeline);
#[allow(clippy::type_complexity)] unsafefn create_compute_pipeline(
&self,
desc: &ComputePipelineDescriptor<
<Self::A as Api>::PipelineLayout,
<Self::A as Api>::ShaderModule,
<Self::A as Api>::PipelineCache,
>,
) -> Result<<Self::A as Api>::ComputePipeline, PipelineError>; unsafefn destroy_compute_pipeline(&self, pipeline: <Self::A as Api>::ComputePipeline);
unsafefn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<Label>,
) -> Result<<Self::A as Api>::QuerySet, DeviceError>; unsafefn destroy_query_set(&self, set: <Self::A as Api>::QuerySet); unsafefn create_fence(&self) -> Result<<Self::A as Api>::Fence, DeviceError>; unsafefn destroy_fence(&self, fence: <Self::A as Api>::Fence); unsafefn get_fence_value(
&self,
fence: &<Self::A as Api>::Fence,
) -> Result<FenceValue, DeviceError>;
/// Wait for `fence` to reach `value`. /// /// Operations like [`Queue::submit`] can accept a [`Fence`] and a /// [`FenceValue`] to store in it, so you can use this `wait` function /// to wait for a given queue submission to finish execution. /// /// The `value` argument must be a value that some actual operation you have /// already presented to the device is going to store in `fence`. You cannot /// wait for values yet to be submitted. (This restriction accommodates /// implementations like the `vulkan` backend's [`FencePool`] that must /// allocate a distinct synchronization object for each fence value one is /// able to wait for.) /// /// Calling `wait` with a lower [`FenceValue`] than `fence`'s current value /// returns immediately. /// /// [`Fence`]: Api::Fence /// [`FencePool`]: vulkan/enum.Fence.html#variant.FencePool unsafefn wait(
&self,
fence: &<Self::A as Api>::Fence,
value: FenceValue,
timeout_ms: u32,
) -> Result<bool, DeviceError>;
/// Submit `command_buffers` for execution on GPU. /// /// Update `fence` to `value` when the operation is complete. See /// [`Fence`] for details. /// /// A `wgpu_hal` queue is "single threaded": all command buffers are /// executed in the order they're submitted, with each buffer able to see /// previous buffers' results. Specifically: /// /// - If two calls to `submit` on a single `Queue` occur in a particular /// order (that is, they happen on the same thread, or on two threads that /// have synchronized to establish an ordering), then the first /// submission's commands all complete execution before any of the second /// submission's commands begin. All results produced by one submission /// are visible to the next. /// /// - Within a submission, command buffers execute in the order in which they /// appear in `command_buffers`. All results produced by one buffer are /// visible to the next. /// /// If two calls to `submit` on a single `Queue` from different threads are /// not synchronized to occur in a particular order, they must pass distinct /// [`Fence`]s. As explained in the [`Fence`] documentation, waiting for /// operations to complete is only trustworthy when operations finish in /// order of increasing fence value, but submissions from different threads /// cannot determine how to order the fence values if the submissions /// themselves are unordered. If each thread uses a separate [`Fence`], this /// problem does not arise. /// /// # Safety /// /// - Each [`CommandBuffer`][cb] in `command_buffers` must have been created /// from a [`CommandEncoder`][ce] that was constructed from the /// [`Device`][d] associated with this [`Queue`]. /// /// - Each [`CommandBuffer`][cb] must remain alive until the submitted /// commands have finished execution. Since command buffers must not /// outlive their encoders, this implies that the encoders must remain /// alive as well. /// /// - All resources used by a submitted [`CommandBuffer`][cb] /// ([`Texture`][t]s, [`BindGroup`][bg]s, [`RenderPipeline`][rp]s, and so /// on) must remain alive until the command buffer finishes execution. /// /// - Every [`SurfaceTexture`][st] that any command in `command_buffers` /// writes to must appear in the `surface_textures` argument. /// /// - No [`SurfaceTexture`][st] may appear in the `surface_textures` /// argument more than once. /// /// - Each [`SurfaceTexture`][st] in `surface_textures` must be configured /// for use with the [`Device`][d] associated with this [`Queue`], /// typically by calling [`Surface::configure`]. /// /// - All calls to this function that include a given [`SurfaceTexture`][st] /// in `surface_textures` must use the same [`Fence`]. /// /// - The [`Fence`] passed as `signal_fence.0` must remain alive until /// all submissions that will signal it have completed. /// /// [`Fence`]: Api::Fence /// [cb]: Api::CommandBuffer /// [ce]: Api::CommandEncoder /// [d]: Api::Device /// [t]: Api::Texture /// [bg]: Api::BindGroup /// [rp]: Api::RenderPipeline /// [st]: Api::SurfaceTexture unsafefn submit(
&self,
command_buffers: &[&<Self::A as Api>::CommandBuffer],
surface_textures: &[&<Self::A as Api>::SurfaceTexture],
signal_fence: (&mut <Self::A as Api>::Fence, FenceValue),
) -> Result<(), DeviceError>; unsafefn present(
&self,
surface: &<Self::A as Api>::Surface,
texture: <Self::A as Api>::SurfaceTexture,
) -> Result<(), SurfaceError>; unsafefn get_timestamp_period(&self) -> f32;
}
/// Encoder and allocation pool for `CommandBuffer`s. /// /// A `CommandEncoder` not only constructs `CommandBuffer`s but also /// acts as the allocation pool that owns the buffers' underlying /// storage. Thus, `CommandBuffer`s must not outlive the /// `CommandEncoder` that created them. /// /// The life cycle of a `CommandBuffer` is as follows: /// /// - Call [`Device::create_command_encoder`] to create a new /// `CommandEncoder`, in the "closed" state. /// /// - Call `begin_encoding` on a closed `CommandEncoder` to begin /// recording commands. This puts the `CommandEncoder` in the /// "recording" state. /// /// - Call methods like `copy_buffer_to_buffer`, `begin_render_pass`, /// etc. on a "recording" `CommandEncoder` to add commands to the /// list. (If an error occurs, you must call `discard_encoding`; see /// below.) /// /// - Call `end_encoding` on a recording `CommandEncoder` to close the /// encoder and construct a fresh `CommandBuffer` consisting of the /// list of commands recorded up to that point. /// /// - Call `discard_encoding` on a recording `CommandEncoder` to drop /// the commands recorded thus far and close the encoder. This is /// the only safe thing to do on a `CommandEncoder` if an error has /// occurred while recording commands. /// /// - Call `reset_all` on a closed `CommandEncoder`, passing all the /// live `CommandBuffers` built from it. All the `CommandBuffer`s /// are destroyed, and their resources are freed. /// /// # Safety /// /// - The `CommandEncoder` must be in the states described above to /// make the given calls. /// /// - A `CommandBuffer` that has been submitted for execution on the /// GPU must live until its execution is complete. /// /// - A `CommandBuffer` must not outlive the `CommandEncoder` that /// built it. /// /// It is the user's responsibility to meet this requirements. This /// allows `CommandEncoder` implementations to keep their state /// tracking to a minimum. pubtrait CommandEncoder: WasmNotSendSync + fmt::Debug { type A: Api;
/// Begin encoding a new command buffer. /// /// This puts this `CommandEncoder` in the "recording" state. /// /// # Safety /// /// This `CommandEncoder` must be in the "closed" state. unsafefn begin_encoding(&mutself, label: Label) -> Result<(), DeviceError>;
/// Discard the command list under construction. /// /// If an error has occurred while recording commands, this /// is the only safe thing to do with the encoder. /// /// This puts this `CommandEncoder` in the "closed" state. /// /// # Safety /// /// This `CommandEncoder` must be in the "recording" state. /// /// Callers must not assume that implementations of this /// function are idempotent, and thus should not call it /// multiple times in a row. unsafefn discard_encoding(&mutself);
/// Return a fresh [`CommandBuffer`] holding the recorded commands. /// /// The returned [`CommandBuffer`] holds all the commands recorded /// on this `CommandEncoder` since the last call to /// [`begin_encoding`]. /// /// This puts this `CommandEncoder` in the "closed" state. /// /// # Safety /// /// This `CommandEncoder` must be in the "recording" state. /// /// The returned [`CommandBuffer`] must not outlive this /// `CommandEncoder`. Implementations are allowed to build /// `CommandBuffer`s that depend on storage owned by this /// `CommandEncoder`. /// /// [`CommandBuffer`]: Api::CommandBuffer /// [`begin_encoding`]: CommandEncoder::begin_encoding unsafefn end_encoding(&mutself) -> Result<<Self::A as Api>::CommandBuffer, DeviceError>;
/// Reclaim all resources belonging to this `CommandEncoder`. /// /// # Safety /// /// This `CommandEncoder` must be in the "closed" state. /// /// The `command_buffers` iterator must produce all the live /// [`CommandBuffer`]s built using this `CommandEncoder` --- that /// is, every extant `CommandBuffer` returned from `end_encoding`. /// /// [`CommandBuffer`]: Api::CommandBuffer unsafefn reset_all<I>(&mutself, command_buffers: I) where
I: Iterator<Item = <Self::A as Api>::CommandBuffer>;
unsafefn transition_buffers<'a, T>(&mut self, barriers: T) where
T: Iterator<Item = BufferBarrier<'a, <Self::A as Api>::Buffer>>;
unsafefn transition_textures<'a, T>(&mut self, barriers: T) where
T: Iterator<Item = TextureBarrier<'a, <Self::A as Api>::Texture>>;
// copy operations
unsafefn clear_buffer(&mutself, buffer: &<Self::A as Api>::Buffer, range: MemoryRange);
unsafefn copy_buffer_to_buffer<T>(
&mutself,
src: &<Self::A as Api>::Buffer,
dst: &<Self::A as Api>::Buffer,
regions: T,
) where
T: Iterator<Item = BufferCopy>;
/// Copy from an external image to an internal texture. /// Works with a single array layer. /// Note: `dst` current usage has to be `TextureUses::COPY_DST`. /// Note: the copy extent is in physical size (rounded to the block size) #[cfg(webgl)] unsafefn copy_external_image_to_texture<T>(
&mutself,
src: &wgt::CopyExternalImageSourceInfo,
dst: &<Self::A as Api>::Texture,
dst_premultiplication: bool,
regions: T,
) where
T: Iterator<Item = TextureCopy>;
/// Copy from one texture to another. /// Works with a single array layer. /// Note: `dst` current usage has to be `TextureUses::COPY_DST`. /// Note: the copy extent is in physical size (rounded to the block size) unsafefn copy_texture_to_texture<T>(
&mutself,
src: &<Self::A as Api>::Texture,
src_usage: TextureUses,
dst: &<Self::A as Api>::Texture,
regions: T,
) where
T: Iterator<Item = TextureCopy>;
/// Copy from buffer to texture. /// Works with a single array layer. /// Note: `dst` current usage has to be `TextureUses::COPY_DST`. /// Note: the copy extent is in physical size (rounded to the block size) unsafefn copy_buffer_to_texture<T>(
&mutself,
src: &<Self::A as Api>::Buffer,
dst: &<Self::A as Api>::Texture,
regions: T,
) where
T: Iterator<Item = BufferTextureCopy>;
/// Copy from texture to buffer. /// Works with a single array layer. /// Note: the copy extent is in physical size (rounded to the block size) unsafefn copy_texture_to_buffer<T>(
&mutself,
src: &<Self::A as Api>::Texture,
src_usage: TextureUses,
dst: &<Self::A as Api>::Buffer,
regions: T,
) where
T: Iterator<Item = BufferTextureCopy>;
// pass common
/// Sets the bind group at `index` to `group`. /// /// If this is not the first call to `set_bind_group` within the current /// render or compute pass: /// /// - If `layout` contains `n` bind group layouts, then any previously set /// bind groups at indices `n` or higher are cleared. /// /// - If the first `m` bind group layouts of `layout` are equal to those of /// the previously passed layout, but no more, then any previously set /// bind groups at indices `m` or higher are cleared. /// /// It follows from the above that passing the same layout as before doesn't /// clear any bind groups. /// /// # Safety /// /// - This [`CommandEncoder`] must be within a render or compute pass. /// /// - `index` must be the valid index of some bind group layout in `layout`. /// Call this the "relevant bind group layout". /// /// - The layout of `group` must be equal to the relevant bind group layout. /// /// - The length of `dynamic_offsets` must match the number of buffer /// bindings [with dynamic offsets][hdo] in the relevant bind group /// layout. /// /// - If those buffer bindings are ordered by increasing [`binding` number] /// and paired with elements from `dynamic_offsets`, then each offset must /// be a valid offset for the binding's corresponding buffer in `group`. /// /// [hdo]: wgt::BindingType::Buffer::has_dynamic_offset /// [`binding` number]: wgt::BindGroupLayoutEntry::binding unsafefn set_bind_group(
&mutself,
layout: &<Self::A as Api>::PipelineLayout,
index: u32,
group: &<Self::A as Api>::BindGroup,
dynamic_offsets: &[wgt::DynamicOffset],
);
/// Sets a range in push constant data. /// /// IMPORTANT: while the data is passed as words, the offset is in bytes! /// /// # Safety /// /// - `offset_bytes` must be a multiple of 4. /// - The range of push constants written must be valid for the pipeline layout at draw time. unsafefn set_push_constants(
&mutself,
layout: &<Self::A as Api>::PipelineLayout,
stages: wgt::ShaderStages,
offset_bytes: u32,
data: &[u32],
);
/// # Safety: /// /// - If `set` is an occlusion query set, it must be the same one as used in the [`RenderPassDescriptor::occlusion_query_set`] parameter. unsafefn begin_query(&mutself, set: &<Self::A as Api>::QuerySet, index: u32); /// # Safety: /// /// - If `set` is an occlusion query set, it must be the same one as used in the [`RenderPassDescriptor::occlusion_query_set`] parameter. unsafefn end_query(&mutself, set: &<Self::A as Api>::QuerySet, index: u32); unsafefn write_timestamp(&mutself, set: &<Self::A as Api>::QuerySet, index: u32); unsafefn reset_queries(&mutself, set: &<Self::A as Api>::QuerySet, range: Range<u32>); unsafefn copy_query_results(
&mutself,
set: &<Self::A as Api>::QuerySet,
range: Range<u32>,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
stride: wgt::BufferSize,
);
// render passes
/// Begin a new render pass, clearing all active bindings. /// /// This clears any bindings established by the following calls: /// /// - [`set_bind_group`](CommandEncoder::set_bind_group) /// - [`set_push_constants`](CommandEncoder::set_push_constants) /// - [`begin_query`](CommandEncoder::begin_query) /// - [`set_render_pipeline`](CommandEncoder::set_render_pipeline) /// - [`set_index_buffer`](CommandEncoder::set_index_buffer) /// - [`set_vertex_buffer`](CommandEncoder::set_vertex_buffer) /// /// # Safety /// /// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed /// by a call to [`end_render_pass`]. /// /// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed /// by a call to [`end_compute_pass`]. /// /// [`begin_render_pass`]: CommandEncoder::begin_render_pass /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass /// [`end_render_pass`]: CommandEncoder::end_render_pass /// [`end_compute_pass`]: CommandEncoder::end_compute_pass unsafefn begin_render_pass(
&mutself,
desc: &RenderPassDescriptor<<Self::A as Api>::QuerySet, <Self::A as Api>::TextureView>,
);
/// End the current render pass. /// /// # Safety /// /// - There must have been a prior call to [`begin_render_pass`] on this [`CommandEncoder`] /// that has not been followed by a call to [`end_render_pass`]. /// /// [`begin_render_pass`]: CommandEncoder::begin_render_pass /// [`end_render_pass`]: CommandEncoder::end_render_pass unsafefn end_render_pass(&mutself);
/// Begin a new compute pass, clearing all active bindings. /// /// This clears any bindings established by the following calls: /// /// - [`set_bind_group`](CommandEncoder::set_bind_group) /// - [`set_push_constants`](CommandEncoder::set_push_constants) /// - [`begin_query`](CommandEncoder::begin_query) /// - [`set_compute_pipeline`](CommandEncoder::set_compute_pipeline) /// /// # Safety /// /// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed /// by a call to [`end_render_pass`]. /// /// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed /// by a call to [`end_compute_pass`]. /// /// [`begin_render_pass`]: CommandEncoder::begin_render_pass /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass /// [`end_render_pass`]: CommandEncoder::end_render_pass /// [`end_compute_pass`]: CommandEncoder::end_compute_pass unsafefn begin_compute_pass(
&mutself,
desc: &ComputePassDescriptor<<Self::A as Api>::QuerySet>,
);
/// End the current compute pass. /// /// # Safety /// /// - There must have been a prior call to [`begin_compute_pass`] on this [`CommandEncoder`] /// that has not been followed by a call to [`end_compute_pass`]. /// /// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass /// [`end_compute_pass`]: CommandEncoder::end_compute_pass unsafefn end_compute_pass(&mutself);
unsafefn set_compute_pipeline(&mutself, pipeline: &<Self::A as Api>::ComputePipeline);
/// To get the required sizes for the buffer allocations use `get_acceleration_structure_build_sizes` per descriptor /// All buffers must be synchronized externally /// All buffer regions, which are written to may only be passed once per function call, /// with the exception of updates in the same descriptor. /// Consequences of this limitation: /// - scratch buffers need to be unique /// - a tlas can't be build in the same call with a blas it contains unsafefn build_acceleration_structures<'a, T>(
&mutself,
descriptor_count: u32,
descriptors: T,
) where Self::A: 'a,
T: IntoIterator<
Item = BuildAccelerationStructureDescriptor< 'a,
<Self::A as Api>::Buffer,
<Self::A as Api>::AccelerationStructure,
>,
>;
bitflags!( /// Pipeline layout creation flags. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubstruct PipelineLayoutFlags: u32 { /// D3D12: Add support for `first_vertex` and `first_instance` builtins /// via push constants for direct execution. const FIRST_VERTEX_INSTANCE = 1 << 0; /// D3D12: Add support for `num_workgroups` builtins via push constants /// for direct execution. const NUM_WORK_GROUPS = 1 << 1; /// D3D12: Add support for the builtins that the other flags enable for /// indirect execution. const INDIRECT_BUILTIN_UPDATE = 1 << 2;
}
);
bitflags!( /// Pipeline layout creation flags. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubstruct BindGroupLayoutFlags: u32 { /// Allows for bind group binding arrays to be shorter than the array in the BGL. const PARTIALLY_BOUND = 1 << 0;
}
);
bitflags!( /// Texture format capability flags. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubstruct TextureFormatCapabilities: u32 { /// Format can be sampled. const SAMPLED = 1 << 0; /// Format can be sampled with a linear sampler. const SAMPLED_LINEAR = 1 << 1; /// Format can be sampled with a min/max reduction sampler. const SAMPLED_MINMAX = 1 << 2;
/// Format can be used as storage with read-only access. const STORAGE_READ_ONLY = 1 << 3; /// Format can be used as storage with write-only access. const STORAGE_WRITE_ONLY = 1 << 4; /// Format can be used as storage with both read and write access. const STORAGE_READ_WRITE = 1 << 5; /// Format can be used as storage with atomics. const STORAGE_ATOMIC = 1 << 6;
/// Format can be used as color and input attachment. const COLOR_ATTACHMENT = 1 << 7; /// Format can be used as color (with blending) and input attachment. const COLOR_ATTACHMENT_BLEND = 1 << 8; /// Format can be used as depth-stencil and input attachment. const DEPTH_STENCIL_ATTACHMENT = 1 << 9;
/// Format can be multisampled by x2. const MULTISAMPLE_X2 = 1 << 10; /// Format can be multisampled by x4. const MULTISAMPLE_X4 = 1 << 11; /// Format can be multisampled by x8. const MULTISAMPLE_X8 = 1 << 12; /// Format can be multisampled by x16. const MULTISAMPLE_X16 = 1 << 13;
/// Format can be used for render pass resolve targets. const MULTISAMPLE_RESOLVE = 1 << 14;
/// Format can be copied from. const COPY_SRC = 1 << 15; /// Format can be copied to. const COPY_DST = 1 << 16;
}
);
bitflags::bitflags! { /// Similar to `wgt::BufferUsages` but for internal use. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubstruct BufferUses: u16 { /// The argument to a read-only mapping. const MAP_READ = 1 << 0; /// The argument to a write-only mapping. const MAP_WRITE = 1 << 1; /// The source of a hardware copy. const COPY_SRC = 1 << 2; /// The destination of a hardware copy. const COPY_DST = 1 << 3; /// The index buffer used for drawing. const INDEX = 1 << 4; /// A vertex buffer used for drawing. const VERTEX = 1 << 5; /// A uniform buffer bound in a bind group. const UNIFORM = 1 << 6; /// A read-only storage buffer used in a bind group. const STORAGE_READ_ONLY = 1 << 7; /// A read-write buffer used in a bind group. const STORAGE_READ_WRITE = 1 << 8; /// The indirect or count buffer in a indirect draw or dispatch. const INDIRECT = 1 << 9; /// A buffer used to store query results. const QUERY_RESOLVE = 1 << 10; const ACCELERATION_STRUCTURE_SCRATCH = 1 << 11; const BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 12; const TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 13; /// The combination of states that a buffer may be in _at the same time_. const INCLUSIVE = Self::MAP_READ.bits() | Self::COPY_SRC.bits() | Self::INDEX.bits() | Self::VERTEX.bits() | Self::UNIFORM.bits() | Self::STORAGE_READ_ONLY.bits() | Self::INDIRECT.bits() | Self::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits() | Self::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits(); /// The combination of states that a buffer must exclusively be in. const EXCLUSIVE = Self::MAP_WRITE.bits() | Self::COPY_DST.bits() | Self::STORAGE_READ_WRITE.bits() | Self::ACCELERATION_STRUCTURE_SCRATCH.bits(); /// The combination of all usages that the are guaranteed to be be ordered by the hardware. /// If a usage is ordered, then if the buffer state doesn't change between draw calls, there /// are no barriers needed for synchronization. const ORDERED = Self::INCLUSIVE.bits() | Self::MAP_WRITE.bits();
}
}
bitflags::bitflags! { /// Similar to `wgt::TextureUsages` but for internal use. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubstruct TextureUses: u16 { /// The texture is in unknown state. const UNINITIALIZED = 1 << 0; /// Ready to present image to the surface. const PRESENT = 1 << 1; /// The source of a hardware copy. const COPY_SRC = 1 << 2; /// The destination of a hardware copy. const COPY_DST = 1 << 3; /// Read-only sampled or fetched resource. const RESOURCE = 1 << 4; /// The color target of a renderpass. const COLOR_TARGET = 1 << 5; /// Read-only depth stencil usage. const DEPTH_STENCIL_READ = 1 << 6; /// Read-write depth stencil usage const DEPTH_STENCIL_WRITE = 1 << 7; /// Read-only storage texture usage. Corresponds to a UAV in d3d, so is exclusive, despite being read only. const STORAGE_READ_ONLY = 1 << 8; /// Write-only storage texture usage. const STORAGE_WRITE_ONLY = 1 << 9; /// Read-write storage texture usage. const STORAGE_READ_WRITE = 1 << 10; /// Image atomic enabled storage const STORAGE_ATOMIC = 1 << 11; /// The combination of states that a texture may be in _at the same time_. const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits(); /// The combination of states that a texture must exclusively be in. const EXCLUSIVE = Self::COPY_DST.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ_ONLY.bits() | Self::STORAGE_WRITE_ONLY.bits() | Self::STORAGE_READ_WRITE.bits() | Self::STORAGE_ATOMIC.bits() | Self::PRESENT.bits(); /// The combination of all usages that the are guaranteed to be be ordered by the hardware. /// If a usage is ordered, then if the texture state doesn't change between draw calls, there /// are no barriers needed for synchronization. const ORDERED = Self::INCLUSIVE.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ_ONLY.bits();
/// Flag used by the wgpu-core texture tracker to say a texture is in different states for every sub-resource const COMPLEX = 1 << 12; /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource. /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized. const UNKNOWN = 1 << 13;
}
}
#[derive(Clone, Debug)] pubstruct Alignments { /// The alignment of the start of the buffer used as a GPU copy source. pub buffer_copy_offset: wgt::BufferSize,
/// The alignment of the row pitch of the texture data stored in a buffer that is /// used in a GPU copy operation. pub buffer_copy_pitch: wgt::BufferSize,
/// The finest alignment of bound range checking for uniform buffers. /// /// When `wgpu_hal` restricts shader references to the [accessible /// region][ar] of a [`Uniform`] buffer, the size of the accessible region /// is the bind group binding's stated [size], rounded up to the next /// multiple of this value. /// /// We don't need an analogous field for storage buffer bindings, because /// all our backends promise to enforce the size at least to a four-byte /// alignment, and `wgpu_hal` requires bound range lengths to be a multiple /// of four anyway. /// /// [ar]: struct.BufferBinding.html#accessible-region /// [`Uniform`]: wgt::BufferBindingType::Uniform /// [size]: BufferBinding::size pub uniform_bounds_check_alignment: wgt::BufferSize,
/// The size of the raw TLAS instance pub raw_tlas_instance_size: usize,
/// What the scratch buffer for building an acceleration structure must be aligned to pub ray_tracing_scratch_buffer_alignment: u32,
}
/// Describes information about what a `Surface`'s presentation capabilities are. /// Fetch this with [Adapter::surface_capabilities]. #[derive(Debug, Clone)] pubstruct SurfaceCapabilities { /// List of supported texture formats. /// /// Must be at least one. pub formats: Vec<wgt::TextureFormat>,
/// Range for the number of queued frames. /// /// This adjusts either the swapchain frame count to value + 1 - or sets SetMaximumFrameLatency to the value given, /// 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. /// /// - `maximum_frame_latency.start` must be at least 1. /// - `maximum_frame_latency.end` must be larger or equal to `maximum_frame_latency.start`. pub maximum_frame_latency: RangeInclusive<u32>,
/// Current extent of the surface, if known. pub current_extent: Option<wgt::Extent3d>,
/// Supported texture usage flags. /// /// Must have at least `TextureUses::COLOR_TARGET` pub usage: TextureUses,
/// List of supported V-sync modes. /// /// Must be at least one. pub present_modes: Vec<wgt::PresentMode>,
/// List of supported alpha composition modes. /// /// Must be at least one. pub composite_alpha_modes: Vec<wgt::CompositeAlphaMode>,
}
#[derive(Debug)] pubstruct AcquiredSurfaceTexture<A: Api> { pub texture: A::SurfaceTexture, /// The presentation configuration no longer matches /// the surface properties exactly, but can still be used to present /// to the surface successfully. pub suboptimal: bool,
}
/// TextureView descriptor. /// /// Valid usage: ///. - `format` has to be the same as `TextureDescriptor::format` ///. - `dimension` has to be compatible with `TextureDescriptor::dimension` ///. - `usage` has to be a subset of `TextureDescriptor::usage` ///. - `range` has to be a subset of parent texture #[derive(Clone, Debug)] pubstruct TextureViewDescriptor<'a> { pub label: Label<'a>, pub format: wgt::TextureFormat, pub dimension: wgt::TextureViewDimension, pub usage: TextureUses, pub range: wgt::ImageSubresourceRange,
}
#[derive(Clone, Debug)] pubstruct SamplerDescriptor<'a> { pub label: Label<'a>, pub address_modes: [wgt::AddressMode; 3], pub mag_filter: wgt::FilterMode, pub min_filter: wgt::FilterMode, pub mipmap_filter: wgt::FilterMode, pub lod_clamp: Range<f32>, pub compare: Option<wgt::CompareFunction>, // Must in the range [1, 16]. // // Anisotropic filtering must be supported if this is not 1. pub anisotropy_clamp: u16, pub border_color: Option<wgt::SamplerBorderColor>,
}
/// A region of a buffer made visible to shaders via a [`BindGroup`]. /// /// [`BindGroup`]: Api::BindGroup /// /// ## Accessible region /// /// `wgpu_hal` guarantees that shaders compiled with /// [`ShaderModuleDescriptor::runtime_checks`] set to `true` cannot read or /// write data via this binding outside the *accessible region* of [`buffer`]: /// /// - The accessible region starts at [`offset`]. /// /// - For [`Storage`] bindings, the size of the accessible region is [`size`], /// which must be a multiple of 4. /// /// - For [`Uniform`] bindings, the size of the accessible region is [`size`] /// rounded up to the next multiple of /// [`Alignments::uniform_bounds_check_alignment`]. /// /// Note that this guarantee is stricter than WGSL's requirements for /// [out-of-bounds accesses][woob], as WGSL allows them to return values from /// elsewhere in the buffer. But this guarantee is necessary anyway, to permit /// `wgpu-core` to avoid clearing uninitialized regions of buffers that will /// never be read by the application before they are overwritten. This /// optimization consults bind group buffer binding regions to determine which /// parts of which buffers shaders might observe. This optimization is only /// sound if shader access is bounds-checked. /// /// [`buffer`]: BufferBinding::buffer /// [`offset`]: BufferBinding::offset /// [`size`]: BufferBinding::size /// [`Storage`]: wgt::BufferBindingType::Storage /// [`Uniform`]: wgt::BufferBindingType::Uniform /// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec #[derive(Debug)] pubstruct BufferBinding<'a, B: DynBuffer + ?Sized> { /// The buffer being bound. pub buffer: &'a B,
/// The size of the region bound, in bytes. /// /// If `None`, the region extends from `offset` to the end of the /// buffer. Given the restrictions on `offset`, this means that /// the size is always greater than zero. pub size: Option<wgt::BufferSize>,
}
/// BindGroup descriptor. /// /// Valid usage: ///. - `entries` has to be sorted by ascending `BindGroupEntry::binding` ///. - `entries` has to have the same set of `BindGroupEntry::binding` as `layout` ///. - each entry has to be compatible with the `layout` ///. - each entry's `BindGroupEntry::resource_index` is within range /// of the corresponding resource array, selected by the relevant /// `BindGroupLayoutEntry`. #[derive(Clone, Debug)] pubstruct BindGroupDescriptor< 'a,
Bgl: DynBindGroupLayout + ?Sized,
B: DynBuffer + ?Sized,
S: DynSampler + ?Sized,
T: DynTextureView + ?Sized,
A: DynAccelerationStructure + ?Sized,
> { pub label: Label<'a>, pub layout: &'a Bgl, pub buffers: &'a [BufferBinding<'a, B>], pub samplers: &'a [&'a S], pub textures: &'a [TextureBinding<'a, T>], pub entries: &'a [BindGroupEntry], pub acceleration_structures: &'a [&'a A],
}
/// # Safety /// /// See the documentation for each flag in [`ShaderRuntimeChecks`][src]. /// /// [src]: wgt::ShaderRuntimeChecks pub runtime_checks: wgt::ShaderRuntimeChecks,
}
/// Describes a programmable pipeline stage. #[derive(Debug)] pubstruct ProgrammableStage<'a, M: DynShaderModule + ?Sized> { /// The compiled shader module for this stage. pub module: &'a M, /// The name of the entry point in the compiled shader. There must be a function with this name /// in the shader. pub entry_point: &'a str, /// Pipeline constants pub constants: &'a naga::back::PipelineConstants, /// Whether workgroup scoped memory will be initialized with zero values for this stage. /// /// This is required by the WebGPU spec, but may have overhead which can be avoided /// for cross-platform applications pub zero_initialize_workgroup_memory: bool,
}
/// Describes a compute pipeline. #[derive(Clone, Debug)] pubstruct ComputePipelineDescriptor< 'a,
Pl: DynPipelineLayout + ?Sized,
M: DynShaderModule + ?Sized,
Pc: DynPipelineCache + ?Sized,
> { pub label: Label<'a>, /// The layout of bind groups for this pipeline. pub layout: &'a Pl, /// The compiled compute stage and its entry point. pub stage: ProgrammableStage<'a, M>, /// The cache which will be used and filled when compiling this pipeline pub cache: Option<&'a Pc>,
}
/// Describes how the vertex buffer is interpreted. #[derive(Clone, Debug)] pubstruct VertexBufferLayout<'a> { /// The stride, in bytes, between elements of this buffer. pub array_stride: wgt::BufferAddress, /// How often this vertex buffer is "stepped" forward. pub step_mode: wgt::VertexStepMode, /// The list of attributes which comprise a single vertex. pub attributes: &'a [wgt::VertexAttribute],
}
/// Describes a render (graphics) pipeline. #[derive(Clone, Debug)] pubstruct RenderPipelineDescriptor< 'a,
Pl: DynPipelineLayout + ?Sized,
M: DynShaderModule + ?Sized,
Pc: DynPipelineCache + ?Sized,
> { pub label: Label<'a>, /// The layout of bind groups for this pipeline. pub layout: &'a Pl, /// The format of any vertex buffers used with this pipeline. pub vertex_buffers: &'a [VertexBufferLayout<'a>], /// The vertex stage for this pipeline. pub vertex_stage: ProgrammableStage<'a, M>, /// The properties of the pipeline at the primitive assembly and rasterization level. pub primitive: wgt::PrimitiveState, /// The effect of draw calls on the depth and stencil aspects of the output target, if any. pub depth_stencil: Option<wgt::DepthStencilState>, /// The multi-sampling properties of the pipeline. pub multisample: wgt::MultisampleState, /// The fragment stage for this pipeline. pub fragment_stage: Option<ProgrammableStage<'a, M>>, /// The effect of draw calls on the color aspect of the output target. pub color_targets: &'a [Option<wgt::ColorTargetState>], /// If the pipeline will be used with a multiview render pass, this indicates how many array /// layers the attachments will have. pub multiview: Option<NonZeroU32>, /// The cache which will be used and filled when compiling this pipeline pub cache: Option<&'a Pc>,
}
#[derive(Debug, Clone)] pubstruct SurfaceConfiguration { /// Maximum number of queued frames. Must be in /// `SurfaceCapabilities::maximum_frame_latency` range. pub maximum_frame_latency: u32, /// Vertical synchronization mode. pub present_mode: wgt::PresentMode, /// Alpha composition mode. pub composite_alpha_mode: wgt::CompositeAlphaMode, /// Format of the surface textures. pub format: wgt::TextureFormat, /// Requested texture extent. Must be in /// `SurfaceCapabilities::extents` range. pub extent: wgt::Extent3d, /// Allowed usage of surface textures, pub usage: TextureUses, /// Allows views of swapchain texture to have a different format /// than the texture does. pub view_formats: Vec<wgt::TextureFormat>,
}
#[derive(Clone, Debug)] pubstruct TextureCopyBase { pub mip_level: u32, pub array_layer: u32, /// Origin within a texture. /// Note: for 1D and 2D textures, Z must be 0. pub origin: wgt::Origin3d, pub aspect: FormatAspects,
}
#[derive(Clone, Debug)] pubstruct Attachment<'a, T: DynTextureView + ?Sized> { pub view: &'a T, /// Contains either a single mutating usage as a target, /// or a valid combination of read-only usages. pub usage: TextureUses,
}
/// Stores the text of any validation errors that have occurred since /// the last call to `get_and_reset`. /// /// Each value is a validation error and a message associated with it, /// or `None` if the error has no message from the api. /// /// This is used for internal wgpu testing only and _must not_ be used /// as a way to check for errors. /// /// This works as a static because `cargo nextest` runs all of our /// tests in separate processes, so each test gets its own canary. /// /// This prevents the issue of one validation error terminating the /// entire process. pubstatic VALIDATION_CANARY: ValidationCanary = ValidationCanary {
inner: Mutex::new(Vec::new()),
};
/// Flag for internal testing. pubstruct ValidationCanary {
inner: Mutex<Vec<String>>,
}
impl ValidationCanary { #[allow(dead_code)] // in some configurations this function is dead fn add(&self, msg: String) { self.inner.lock().push(msg);
}
/// Returns any API validation errors that have occurred in this process /// since the last call to this function. pubfn get_and_reset(&self) -> Vec<String> { self.inner.lock().drain(..).collect()
}
}
#[test] fn test_default_limits() { let limits = wgt::Limits::default();
assert!(limits.max_bind_groups <= MAX_BIND_GROUPS as u32);
}
/// Information of the required size for a corresponding entries struct (+ flags) #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pubstruct AccelerationStructureBuildSizes { pub acceleration_structure_size: wgt::BufferAddress, pub update_scratch_size: wgt::BufferAddress, pub build_scratch_size: wgt::BufferAddress,
}
/// Updates use source_acceleration_structure if present, else the update will be performed in place. /// For updates, only the data is allowed to change (not the meta data or sizes). #[derive(Clone, Debug)] pubstruct BuildAccelerationStructureDescriptor< 'a,
B: DynBuffer + ?Sized,
A: DynAccelerationStructure + ?Sized,
> { pub entries: &'a AccelerationStructureEntries<'a, B>, pub mode: AccelerationStructureBuildMode, pub flags: AccelerationStructureBuildFlags, pub source_acceleration_structure: Option<&'a A>, pub destination_acceleration_structure: &'a A, pub scratch_buffer: &'a B, pub scratch_buffer_offset: wgt::BufferAddress,
}
/// - All buffers, buffer addresses and offsets will be ignored. /// - The build mode will be ignored. /// - Reducing the amount of Instances, Triangle groups or AABB groups (or the number of Triangles/AABBs in corresponding groups), /// may result in reduced size requirements. /// - Any other change may result in a bigger or smaller size requirement. #[derive(Clone, Debug)] pubstruct GetAccelerationStructureBuildSizesDescriptor<'a, B: DynBuffer + ?Sized> { pub entries: &'a AccelerationStructureEntries<'a, B>, pub flags: AccelerationStructureBuildFlags,
}
/// Entries for a single descriptor /// * `Instances` - Multiple instances for a top level acceleration structure /// * `Triangles` - Multiple triangle meshes for a bottom level acceleration structure /// * `AABBs` - List of list of axis aligned bounding boxes for a bottom level acceleration structure #[derive(Debug)] pubenum AccelerationStructureEntries<'a, B: DynBuffer + ?Sized> {
Instances(AccelerationStructureInstances<'a, B>),
Triangles(Vec<AccelerationStructureTriangles<'a, B>>),
AABBs(Vec<AccelerationStructureAABBs<'a, B>>),
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.