wgpu_types/lib.rs
1//! This library describes the API surface of WebGPU that is agnostic of the backend.
2//! This API is used for targeting both Web and Native.
3
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![allow(
6 // We don't use syntax sugar where it's not necessary.
7 clippy::match_like_matches_macro,
8)]
9#![warn(clippy::ptr_as_ptr, missing_docs, unsafe_op_in_unsafe_fn)]
10#![no_std]
11
12#[cfg(feature = "std")]
13extern crate std;
14
15extern crate alloc;
16
17use alloc::borrow::Cow;
18use alloc::{string::String, vec, vec::Vec};
19use core::{
20 cmp::Ordering,
21 fmt,
22 hash::{Hash, Hasher},
23 mem,
24 num::NonZeroU32,
25 ops::Range,
26 time::Duration,
27};
28
29use bytemuck::{Pod, Zeroable};
30
31#[cfg(any(feature = "serde", test))]
32use {
33 alloc::format,
34 serde::{Deserialize, Serialize},
35};
36
37pub mod assertions;
38mod cast_utils;
39mod counters;
40mod env;
41pub mod error;
42mod features;
43pub mod instance;
44pub mod math;
45mod tokens;
46mod transfers;
47
48pub use counters::*;
49pub use features::*;
50pub use instance::*;
51pub use tokens::*;
52pub use transfers::*;
53
54/// Integral type used for [`Buffer`] offsets and sizes.
55///
56/// [`Buffer`]: ../wgpu/struct.Buffer.html
57pub type BufferAddress = u64;
58
59/// Integral type used for [`BufferSlice`] sizes.
60///
61/// Note that while this type is non-zero, a [`Buffer`] *per se* can have a size of zero,
62/// but no slice or mapping can be created from it.
63///
64/// [`Buffer`]: ../wgpu/struct.Buffer.html
65/// [`BufferSlice`]: ../wgpu/struct.BufferSlice.html
66pub type BufferSize = core::num::NonZeroU64;
67
68/// Integral type used for binding locations in shaders.
69///
70/// Used in [`VertexAttribute`]s and errors.
71///
72/// [`VertexAttribute`]: ../wgpu/struct.VertexAttribute.html
73pub type ShaderLocation = u32;
74
75/// Integral type used for
76/// [dynamic bind group offsets](../wgpu/struct.RenderPass.html#method.set_bind_group).
77pub type DynamicOffset = u32;
78
79/// Buffer-texture copies must have [`bytes_per_row`] aligned to this number.
80///
81/// This doesn't apply to [`Queue::write_texture`][Qwt], only to [`copy_buffer_to_texture()`]
82/// and [`copy_texture_to_buffer()`].
83///
84/// [`bytes_per_row`]: TexelCopyBufferLayout::bytes_per_row
85/// [`copy_buffer_to_texture()`]: ../wgpu/struct.Queue.html#method.copy_buffer_to_texture
86/// [`copy_texture_to_buffer()`]: ../wgpu/struct.Queue.html#method.copy_texture_to_buffer
87/// [Qwt]: ../wgpu/struct.Queue.html#method.write_texture
88pub const COPY_BYTES_PER_ROW_ALIGNMENT: u32 = 256;
89
90/// An [offset into the query resolve buffer] has to be aligned to this.
91///
92/// [offset into the query resolve buffer]: ../wgpu/struct.CommandEncoder.html#method.resolve_query_set
93pub const QUERY_RESOLVE_BUFFER_ALIGNMENT: BufferAddress = 256;
94
95/// Buffer to buffer copy as well as buffer clear offsets and sizes must be aligned to this number.
96pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
97
98/// Minimum alignment of buffer mappings.
99///
100/// The range passed to [`map_async()`] or [`get_mapped_range()`] must be at least this aligned.
101///
102/// [`map_async()`]: ../wgpu/struct.Buffer.html#method.map_async
103/// [`get_mapped_range()`]: ../wgpu/struct.Buffer.html#method.get_mapped_range
104pub const MAP_ALIGNMENT: BufferAddress = 8;
105
106/// [Vertex buffer offsets] and [strides] have to be a multiple of this number.
107///
108/// [Vertex buffer offsets]: ../wgpu/util/trait.RenderEncoder.html#tymethod.set_vertex_buffer
109/// [strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
110pub const VERTEX_ALIGNMENT: BufferAddress = 4;
111
112/// [Vertex buffer strides] have to be a multiple of this number.
113///
114/// [Vertex buffer strides]: ../wgpu/struct.VertexBufferLayout.html#structfield.array_stride
115#[deprecated(note = "Use `VERTEX_ALIGNMENT` instead", since = "27.0.0")]
116pub const VERTEX_STRIDE_ALIGNMENT: BufferAddress = 4;
117
118/// Ranges of [writes to push constant storage] must be at least this aligned.
119///
120/// [writes to push constant storage]: ../wgpu/struct.RenderPass.html#method.set_push_constants
121pub const PUSH_CONSTANT_ALIGNMENT: u32 = 4;
122
123/// Maximum queries in a [`QuerySetDescriptor`].
124pub const QUERY_SET_MAX_QUERIES: u32 = 4096;
125
126/// Size in bytes of a single piece of [query] data.
127///
128/// [query]: ../wgpu/struct.QuerySet.html
129pub const QUERY_SIZE: u32 = 8;
130
131/// Backends supported by wgpu.
132///
133/// See also [`Backends`].
134#[repr(u8)]
135#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137pub enum Backend {
138 /// Dummy backend, which may be used for testing.
139 ///
140 /// It performs no rendering or computation, but allows creation of stub GPU resource types,
141 /// so that code which manages GPU resources can be tested without an available GPU.
142 /// Specifically, the following operations are implemented:
143 ///
144 /// * Enumerating adapters will always return one noop adapter, which can be used to create
145 /// devices.
146 /// * Buffers may be created, written, mapped, and copied to other buffers.
147 /// * Command encoders may be created, but only buffer operations are useful.
148 ///
149 /// Other resources can be created but are nonfunctional; notably,
150 ///
151 /// * Render passes and compute passes are not executed.
152 /// * Textures may be created, but do not store any texels.
153 /// * There are no compatible surfaces.
154 ///
155 /// An adapter using the noop backend can only be obtained if [`NoopBackendOptions`]
156 /// enables it, in addition to the ordinary requirement of [`Backends::NOOP`] being set.
157 /// This ensures that applications not desiring a non-functional backend will not receive it.
158 Noop = 0,
159 /// Vulkan API (Windows, Linux, Android, MacOS via `vulkan-portability`/MoltenVK)
160 Vulkan = 1,
161 /// Metal API (Apple platforms)
162 Metal = 2,
163 /// Direct3D-12 (Windows)
164 Dx12 = 3,
165 /// OpenGL 3.3+ (Windows), OpenGL ES 3.0+ (Linux, Android, MacOS via Angle), and WebGL2
166 Gl = 4,
167 /// WebGPU in the browser
168 BrowserWebGpu = 5,
169}
170
171impl Backend {
172 /// Array of all [`Backend`] values, corresponding to [`Backends::all()`].
173 pub const ALL: [Backend; Backends::all().bits().count_ones() as usize] = [
174 Self::Noop,
175 Self::Vulkan,
176 Self::Metal,
177 Self::Dx12,
178 Self::Gl,
179 Self::BrowserWebGpu,
180 ];
181
182 /// Returns the string name of the backend.
183 #[must_use]
184 pub const fn to_str(self) -> &'static str {
185 match self {
186 Backend::Noop => "noop",
187 Backend::Vulkan => "vulkan",
188 Backend::Metal => "metal",
189 Backend::Dx12 => "dx12",
190 Backend::Gl => "gl",
191 Backend::BrowserWebGpu => "webgpu",
192 }
193 }
194}
195
196impl core::fmt::Display for Backend {
197 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198 f.write_str(self.to_str())
199 }
200}
201
202/// Power Preference when choosing a physical adapter.
203///
204/// Corresponds to [WebGPU `GPUPowerPreference`](
205/// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference).
206#[repr(C)]
207#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
210pub enum PowerPreference {
211 #[default]
212 /// Power usage is not considered when choosing an adapter.
213 None = 0,
214 /// Adapter that uses the least possible power. This is often an integrated GPU.
215 LowPower = 1,
216 /// Adapter that has the highest performance. This is often a discrete GPU.
217 HighPerformance = 2,
218}
219
220impl PowerPreference {
221 /// Get a power preference from the environment variable `WGPU_POWER_PREF`.
222 pub fn from_env() -> Option<Self> {
223 let env = crate::env::var("WGPU_POWER_PREF")?;
224 match env.to_lowercase().as_str() {
225 "low" => Some(Self::LowPower),
226 "high" => Some(Self::HighPerformance),
227 "none" => Some(Self::None),
228 _ => None,
229 }
230 }
231}
232
233bitflags::bitflags! {
234 /// Represents the backends that wgpu will use.
235 #[repr(transparent)]
236 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
237 #[cfg_attr(feature = "serde", serde(transparent))]
238 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
239 pub struct Backends: u32 {
240 /// [`Backend::Noop`].
241 const NOOP = 1 << Backend::Noop as u32;
242
243 /// [`Backend::Vulkan`].
244 /// Supported on Windows, Linux/Android, and macOS/iOS via Vulkan Portability (with the Vulkan feature enabled)
245 const VULKAN = 1 << Backend::Vulkan as u32;
246
247 /// [`Backend::Gl`].
248 /// Supported on Linux/Android, the web through webassembly via WebGL, and Windows and
249 /// macOS/iOS via ANGLE
250 const GL = 1 << Backend::Gl as u32;
251
252 /// [`Backend::Metal`].
253 /// Supported on macOS and iOS.
254 const METAL = 1 << Backend::Metal as u32;
255
256 /// [`Backend::Dx12`].
257 /// Supported on Windows 10 and later
258 const DX12 = 1 << Backend::Dx12 as u32;
259
260 /// [`Backend::BrowserWebGpu`].
261 /// Supported when targeting the web through WebAssembly with the `webgpu` feature enabled.
262 ///
263 /// The WebGPU backend is special in several ways:
264 /// It is not not implemented by `wgpu_core` and instead by the higher level `wgpu` crate.
265 /// Whether WebGPU is targeted is decided upon the creation of the `wgpu::Instance`,
266 /// *not* upon adapter creation. See `wgpu::Instance::new`.
267 const BROWSER_WEBGPU = 1 << Backend::BrowserWebGpu as u32;
268
269 /// All the apis that wgpu offers first tier of support for.
270 ///
271 /// * [`Backends::VULKAN`]
272 /// * [`Backends::METAL`]
273 /// * [`Backends::DX12`]
274 /// * [`Backends::BROWSER_WEBGPU`]
275 const PRIMARY = Self::VULKAN.bits()
276 | Self::METAL.bits()
277 | Self::DX12.bits()
278 | Self::BROWSER_WEBGPU.bits();
279
280 /// All the apis that wgpu offers second tier of support for. These may
281 /// be unsupported/still experimental.
282 ///
283 /// * [`Backends::GL`]
284 const SECONDARY = Self::GL.bits();
285 }
286}
287
288impl Default for Backends {
289 fn default() -> Self {
290 Self::all()
291 }
292}
293
294impl From<Backend> for Backends {
295 fn from(backend: Backend) -> Self {
296 Self::from_bits(1 << backend as u32).unwrap()
297 }
298}
299
300impl Backends {
301 /// Gets a set of backends from the environment variable `WGPU_BACKEND`.
302 ///
303 /// See [`Self::from_comma_list()`] for the format of the string.
304 pub fn from_env() -> Option<Self> {
305 let env = crate::env::var("WGPU_BACKEND")?;
306 Some(Self::from_comma_list(&env))
307 }
308
309 /// Takes the given options, modifies them based on the `WGPU_BACKEND` environment variable, and returns the result.
310 pub fn with_env(&self) -> Self {
311 if let Some(env) = Self::from_env() {
312 env
313 } else {
314 *self
315 }
316 }
317
318 /// Generates a set of backends from a comma separated list of case-insensitive backend names.
319 ///
320 /// Whitespace is stripped, so both 'gl, dx12' and 'gl,dx12' are valid.
321 ///
322 /// Always returns WEBGPU on wasm over webgpu.
323 ///
324 /// Names:
325 /// - vulkan = "vulkan" or "vk"
326 /// - dx12 = "dx12" or "d3d12"
327 /// - metal = "metal" or "mtl"
328 /// - gles = "opengl" or "gles" or "gl"
329 /// - webgpu = "webgpu"
330 pub fn from_comma_list(string: &str) -> Self {
331 let mut backends = Self::empty();
332 for backend in string.to_lowercase().split(',') {
333 backends |= match backend.trim() {
334 "vulkan" | "vk" => Self::VULKAN,
335 "dx12" | "d3d12" => Self::DX12,
336 "metal" | "mtl" => Self::METAL,
337 "opengl" | "gles" | "gl" => Self::GL,
338 "webgpu" => Self::BROWSER_WEBGPU,
339 "noop" => Self::NOOP,
340 b => {
341 log::warn!("unknown backend string '{b}'");
342 continue;
343 }
344 }
345 }
346
347 if backends.is_empty() {
348 log::warn!("no valid backend strings found!");
349 }
350
351 backends
352 }
353}
354
355/// Options for requesting adapter.
356///
357/// Corresponds to [WebGPU `GPURequestAdapterOptions`](
358/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
359#[repr(C)]
360#[derive(Clone, Debug, PartialEq, Eq, Hash)]
361#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
362pub struct RequestAdapterOptions<S> {
363 /// Power preference for the adapter.
364 pub power_preference: PowerPreference,
365 /// Indicates that only a fallback adapter can be returned. This is generally a "software"
366 /// implementation on the system.
367 pub force_fallback_adapter: bool,
368 /// Surface that is required to be presentable with the requested adapter. This does not
369 /// create the surface, only guarantees that the adapter can present to said surface.
370 /// For WebGL, this is strictly required, as an adapter can not be created without a surface.
371 pub compatible_surface: Option<S>,
372}
373
374impl<S> Default for RequestAdapterOptions<S> {
375 fn default() -> Self {
376 Self {
377 power_preference: PowerPreference::default(),
378 force_fallback_adapter: false,
379 compatible_surface: None,
380 }
381 }
382}
383
384/// Error when [`Instance::request_adapter()`] fails.
385///
386/// This type is not part of the WebGPU standard, where `requestAdapter()` would simply return null.
387///
388/// [`Instance::request_adapter()`]: ../wgpu/struct.Instance.html#method.request_adapter
389#[derive(Clone, Debug, PartialEq)]
390#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
391#[non_exhaustive]
392pub enum RequestAdapterError {
393 /// No adapter available via the instance’s backends matched the request’s adapter criteria.
394 NotFound {
395 // These fields must be set by wgpu-core and wgpu, but are not intended to be stable API,
396 // only data for the production of the error message.
397 #[doc(hidden)]
398 active_backends: Backends,
399 #[doc(hidden)]
400 requested_backends: Backends,
401 #[doc(hidden)]
402 supported_backends: Backends,
403 #[doc(hidden)]
404 no_fallback_backends: Backends,
405 #[doc(hidden)]
406 no_adapter_backends: Backends,
407 #[doc(hidden)]
408 incompatible_surface_backends: Backends,
409 },
410
411 /// Attempted to obtain adapter specified by environment variable, but the environment variable
412 /// was not set.
413 EnvNotSet,
414}
415
416impl core::error::Error for RequestAdapterError {}
417impl fmt::Display for RequestAdapterError {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 match self {
420 RequestAdapterError::NotFound {
421 active_backends,
422 requested_backends,
423 supported_backends,
424 no_fallback_backends,
425 no_adapter_backends,
426 incompatible_surface_backends,
427 } => {
428 write!(f, "No suitable graphics adapter found; ")?;
429 let mut first = true;
430 for backend in Backend::ALL {
431 let bit = Backends::from(backend);
432 let comma = if mem::take(&mut first) { "" } else { ", " };
433 let explanation = if !requested_backends.contains(bit) {
434 // We prefer reporting this, because it makes the error most stable with
435 // respect to what is directly controllable by the caller, as opposed to
436 // compilation options or the run-time environment.
437 "not requested"
438 } else if !supported_backends.contains(bit) {
439 "support not compiled in"
440 } else if no_adapter_backends.contains(bit) {
441 "found no adapters"
442 } else if incompatible_surface_backends.contains(bit) {
443 "not compatible with provided surface"
444 } else if no_fallback_backends.contains(bit) {
445 "had no fallback adapters"
446 } else if !active_backends.contains(bit) {
447 // Backend requested but not active in this instance
448 if backend == Backend::Noop {
449 "not explicitly enabled"
450 } else {
451 "drivers/libraries could not be loaded"
452 }
453 } else {
454 // This path should be unreachable, but don't crash.
455 "[unknown reason]"
456 };
457 write!(f, "{comma}{backend} {explanation}")?;
458 }
459 }
460 RequestAdapterError::EnvNotSet => f.write_str("WGPU_ADAPTER_NAME not set")?,
461 }
462 Ok(())
463 }
464}
465
466/// Invoke a macro for each of the limits.
467///
468/// The supplied macro should take two arguments. The first is a limit name, as
469/// an identifier, typically used to access a member of `struct Limits`. The
470/// second is `Ordering::Less` if valid values are less than the limit (the
471/// common case), or `Ordering::Greater` if valid values are more than the limit
472/// (for limits like alignments, which are minima instead of maxima).
473macro_rules! with_limits {
474 ($macro_name:ident) => {
475 $macro_name!(max_texture_dimension_1d, Ordering::Less);
476 $macro_name!(max_texture_dimension_1d, Ordering::Less);
477 $macro_name!(max_texture_dimension_2d, Ordering::Less);
478 $macro_name!(max_texture_dimension_3d, Ordering::Less);
479 $macro_name!(max_texture_array_layers, Ordering::Less);
480 $macro_name!(max_bind_groups, Ordering::Less);
481 $macro_name!(max_bindings_per_bind_group, Ordering::Less);
482 $macro_name!(
483 max_dynamic_uniform_buffers_per_pipeline_layout,
484 Ordering::Less
485 );
486 $macro_name!(
487 max_dynamic_storage_buffers_per_pipeline_layout,
488 Ordering::Less
489 );
490 $macro_name!(max_sampled_textures_per_shader_stage, Ordering::Less);
491 $macro_name!(max_samplers_per_shader_stage, Ordering::Less);
492 $macro_name!(max_storage_buffers_per_shader_stage, Ordering::Less);
493 $macro_name!(max_storage_textures_per_shader_stage, Ordering::Less);
494 $macro_name!(max_uniform_buffers_per_shader_stage, Ordering::Less);
495 $macro_name!(max_binding_array_elements_per_shader_stage, Ordering::Less);
496 $macro_name!(max_uniform_buffer_binding_size, Ordering::Less);
497 $macro_name!(max_storage_buffer_binding_size, Ordering::Less);
498 $macro_name!(max_vertex_buffers, Ordering::Less);
499 $macro_name!(max_buffer_size, Ordering::Less);
500 $macro_name!(max_vertex_attributes, Ordering::Less);
501 $macro_name!(max_vertex_buffer_array_stride, Ordering::Less);
502 $macro_name!(min_uniform_buffer_offset_alignment, Ordering::Greater);
503 $macro_name!(min_storage_buffer_offset_alignment, Ordering::Greater);
504 $macro_name!(max_inter_stage_shader_components, Ordering::Less);
505 $macro_name!(max_color_attachments, Ordering::Less);
506 $macro_name!(max_color_attachment_bytes_per_sample, Ordering::Less);
507 $macro_name!(max_compute_workgroup_storage_size, Ordering::Less);
508 $macro_name!(max_compute_invocations_per_workgroup, Ordering::Less);
509 $macro_name!(max_compute_workgroup_size_x, Ordering::Less);
510 $macro_name!(max_compute_workgroup_size_y, Ordering::Less);
511 $macro_name!(max_compute_workgroup_size_z, Ordering::Less);
512 $macro_name!(max_compute_workgroups_per_dimension, Ordering::Less);
513
514 $macro_name!(min_subgroup_size, Ordering::Greater);
515 $macro_name!(max_subgroup_size, Ordering::Less);
516
517 $macro_name!(max_push_constant_size, Ordering::Less);
518 $macro_name!(max_non_sampler_bindings, Ordering::Less);
519
520 $macro_name!(max_task_workgroup_total_count, Ordering::Less);
521 $macro_name!(max_task_workgroups_per_dimension, Ordering::Less);
522 $macro_name!(max_mesh_multiview_view_count, Ordering::Less);
523 $macro_name!(max_mesh_output_layers, Ordering::Less);
524
525 $macro_name!(max_blas_primitive_count, Ordering::Less);
526 $macro_name!(max_blas_geometry_count, Ordering::Less);
527 $macro_name!(max_tlas_instance_count, Ordering::Less);
528
529 $macro_name!(max_multiview_view_count, Ordering::Less);
530 };
531}
532
533/// Represents the sets of limits an adapter/device supports.
534///
535/// We provide three different defaults.
536/// - [`Limits::downlevel_defaults()`]. This is a set of limits that is guaranteed to work on almost
537/// all backends, including "downlevel" backends such as OpenGL and D3D11, other than WebGL. For
538/// most applications we recommend using these limits, assuming they are high enough for your
539/// application, and you do not intent to support WebGL.
540/// - [`Limits::downlevel_webgl2_defaults()`] This is a set of limits that is lower even than the
541/// [`downlevel_defaults()`], configured to be low enough to support running in the browser using
542/// WebGL2.
543/// - [`Limits::default()`]. This is the set of limits that is guaranteed to work on all modern
544/// backends and is guaranteed to be supported by WebGPU. Applications needing more modern
545/// features can use this as a reasonable set of limits if they are targeting only desktop and
546/// modern mobile devices.
547///
548/// We recommend starting with the most restrictive limits you can and manually increasing the
549/// limits you need boosted. This will let you stay running on all hardware that supports the limits
550/// you need.
551///
552/// Limits "better" than the default must be supported by the adapter and requested when requesting
553/// a device. If limits "better" than the adapter supports are requested, requesting a device will
554/// panic. Once a device is requested, you may only use resources up to the limits requested _even_
555/// if the adapter supports "better" limits.
556///
557/// Requesting limits that are "better" than you need may cause performance to decrease because the
558/// implementation needs to support more than is needed. You should ideally only request exactly
559/// what you need.
560///
561/// Corresponds to [WebGPU `GPUSupportedLimits`](
562/// https://gpuweb.github.io/gpuweb/#gpusupportedlimits).
563///
564/// [`downlevel_defaults()`]: Limits::downlevel_defaults
565#[repr(C)]
566#[derive(Clone, Debug, PartialEq, Eq, Hash)]
567#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
568#[cfg_attr(feature = "serde", serde(rename_all = "camelCase", default))]
569pub struct Limits {
570 /// Maximum allowed value for the `size.width` of a texture created with `TextureDimension::D1`.
571 /// Defaults to 8192. Higher is "better".
572 #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension1D"))]
573 pub max_texture_dimension_1d: u32,
574 /// Maximum allowed value for the `size.width` and `size.height` of a texture created with `TextureDimension::D2`.
575 /// Defaults to 8192. Higher is "better".
576 #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension2D"))]
577 pub max_texture_dimension_2d: u32,
578 /// Maximum allowed value for the `size.width`, `size.height`, and `size.depth_or_array_layers`
579 /// of a texture created with `TextureDimension::D3`.
580 /// Defaults to 2048. Higher is "better".
581 #[cfg_attr(feature = "serde", serde(rename = "maxTextureDimension3D"))]
582 pub max_texture_dimension_3d: u32,
583 /// Maximum allowed value for the `size.depth_or_array_layers` of a texture created with `TextureDimension::D2`.
584 /// Defaults to 256. Higher is "better".
585 pub max_texture_array_layers: u32,
586 /// Amount of bind groups that can be attached to a pipeline at the same time. Defaults to 4. Higher is "better".
587 pub max_bind_groups: u32,
588 /// Maximum binding index allowed in `create_bind_group_layout`. Defaults to 1000. Higher is "better".
589 pub max_bindings_per_bind_group: u32,
590 /// Amount of uniform buffer bindings that can be dynamic in a single pipeline. Defaults to 8. Higher is "better".
591 pub max_dynamic_uniform_buffers_per_pipeline_layout: u32,
592 /// Amount of storage buffer bindings that can be dynamic in a single pipeline. Defaults to 4. Higher is "better".
593 pub max_dynamic_storage_buffers_per_pipeline_layout: u32,
594 /// Amount of sampled textures visible in a single shader stage. Defaults to 16. Higher is "better".
595 pub max_sampled_textures_per_shader_stage: u32,
596 /// Amount of samplers visible in a single shader stage. Defaults to 16. Higher is "better".
597 pub max_samplers_per_shader_stage: u32,
598 /// Amount of storage buffers visible in a single shader stage. Defaults to 8. Higher is "better".
599 pub max_storage_buffers_per_shader_stage: u32,
600 /// Amount of storage textures visible in a single shader stage. Defaults to 4. Higher is "better".
601 pub max_storage_textures_per_shader_stage: u32,
602 /// Amount of uniform buffers visible in a single shader stage. Defaults to 12. Higher is "better".
603 pub max_uniform_buffers_per_shader_stage: u32,
604 /// Amount of individual resources within binding arrays that can be accessed in a single shader stage. Applies
605 /// to all types of bindings except samplers.
606 ///
607 /// This "defaults" to 0. However if binding arrays are supported, all devices can support 500,000. Higher is "better".
608 pub max_binding_array_elements_per_shader_stage: u32,
609 /// Amount of individual samplers within binding arrays that can be accessed in a single shader stage.
610 ///
611 /// This "defaults" to 0. However if binding arrays are supported, all devices can support 1,000. Higher is "better".
612 pub max_binding_array_sampler_elements_per_shader_stage: u32,
613 /// Maximum size in bytes of a binding to a uniform buffer. Defaults to 64 KiB. Higher is "better".
614 pub max_uniform_buffer_binding_size: u32,
615 /// Maximum size in bytes of a binding to a storage buffer. Defaults to 128 MiB. Higher is "better".
616 pub max_storage_buffer_binding_size: u32,
617 /// Maximum length of `VertexState::buffers` when creating a `RenderPipeline`.
618 /// Defaults to 8. Higher is "better".
619 pub max_vertex_buffers: u32,
620 /// A limit above which buffer allocations are guaranteed to fail.
621 /// Defaults to 256 MiB. Higher is "better".
622 ///
623 /// Buffer allocations below the maximum buffer size may not succeed depending on available memory,
624 /// fragmentation and other factors.
625 pub max_buffer_size: u64,
626 /// Maximum length of `VertexBufferLayout::attributes`, summed over all `VertexState::buffers`,
627 /// when creating a `RenderPipeline`.
628 /// Defaults to 16. Higher is "better".
629 pub max_vertex_attributes: u32,
630 /// Maximum value for `VertexBufferLayout::array_stride` when creating a `RenderPipeline`.
631 /// Defaults to 2048. Higher is "better".
632 pub max_vertex_buffer_array_stride: u32,
633 /// Required `BufferBindingType::Uniform` alignment for `BufferBinding::offset`
634 /// when creating a `BindGroup`, or for `set_bind_group` `dynamicOffsets`.
635 /// Defaults to 256. Lower is "better".
636 pub min_uniform_buffer_offset_alignment: u32,
637 /// Required `BufferBindingType::Storage` alignment for `BufferBinding::offset`
638 /// when creating a `BindGroup`, or for `set_bind_group` `dynamicOffsets`.
639 /// Defaults to 256. Lower is "better".
640 pub min_storage_buffer_offset_alignment: u32,
641 /// Maximum allowed number of components (scalars) of input or output locations for
642 /// inter-stage communication (vertex outputs to fragment inputs). Defaults to 60.
643 /// Higher is "better".
644 pub max_inter_stage_shader_components: u32,
645 /// The maximum allowed number of color attachments.
646 pub max_color_attachments: u32,
647 /// The maximum number of bytes necessary to hold one sample (pixel or subpixel) of render
648 /// pipeline output data, across all color attachments as described by [`TextureFormat::target_pixel_byte_cost`]
649 /// and [`TextureFormat::target_component_alignment`]. Defaults to 32. Higher is "better".
650 ///
651 /// ⚠️ `Rgba8Unorm`/`Rgba8Snorm`/`Bgra8Unorm`/`Bgra8Snorm` are deceptively 8 bytes per sample. ⚠️
652 pub max_color_attachment_bytes_per_sample: u32,
653 /// Maximum number of bytes used for workgroup memory in a compute entry point. Defaults to
654 /// 16384. Higher is "better".
655 pub max_compute_workgroup_storage_size: u32,
656 /// Maximum value of the product of the `workgroup_size` dimensions for a compute entry-point.
657 /// Defaults to 256. Higher is "better".
658 pub max_compute_invocations_per_workgroup: u32,
659 /// The maximum value of the `workgroup_size` X dimension for a compute stage `ShaderModule` entry-point.
660 /// Defaults to 256. Higher is "better".
661 pub max_compute_workgroup_size_x: u32,
662 /// The maximum value of the `workgroup_size` Y dimension for a compute stage `ShaderModule` entry-point.
663 /// Defaults to 256. Higher is "better".
664 pub max_compute_workgroup_size_y: u32,
665 /// The maximum value of the `workgroup_size` Z dimension for a compute stage `ShaderModule` entry-point.
666 /// Defaults to 64. Higher is "better".
667 pub max_compute_workgroup_size_z: u32,
668 /// The maximum value for each dimension of a `ComputePass::dispatch(x, y, z)` operation.
669 /// Defaults to 65535. Higher is "better".
670 pub max_compute_workgroups_per_dimension: u32,
671
672 /// Minimal number of invocations in a subgroup. Lower is "better".
673 pub min_subgroup_size: u32,
674 /// Maximal number of invocations in a subgroup. Higher is "better".
675 pub max_subgroup_size: u32,
676 /// Amount of storage available for push constants in bytes. Defaults to 0. Higher is "better".
677 /// Requesting more than 0 during device creation requires [`Features::PUSH_CONSTANTS`] to be enabled.
678 ///
679 /// Expect the size to be:
680 /// - Vulkan: 128-256 bytes
681 /// - DX12: 256 bytes
682 /// - Metal: 4096 bytes
683 /// - OpenGL doesn't natively support push constants, and are emulated with uniforms,
684 /// so this number is less useful but likely 256.
685 pub max_push_constant_size: u32,
686 /// Maximum number of live non-sampler bindings.
687 ///
688 /// This limit only affects the d3d12 backend. Using a large number will allow the device
689 /// to create many bind groups at the cost of a large up-front allocation at device creation.
690 pub max_non_sampler_bindings: u32,
691
692 /// The maximum total value of x*y*z for a given `draw_mesh_tasks` command
693 pub max_task_workgroup_total_count: u32,
694 /// The maximum value for each dimension of a `RenderPass::draw_mesh_tasks(x, y, z)` operation.
695 /// Defaults to 65535. Higher is "better".
696 pub max_task_workgroups_per_dimension: u32,
697 /// The maximum number of layers that can be output from a mesh shader
698 pub max_mesh_output_layers: u32,
699 /// The maximum number of views that can be used by a mesh shader in multiview rendering
700 pub max_mesh_multiview_view_count: u32,
701
702 /// The maximum number of primitive (ex: triangles, aabbs) a BLAS is allowed to have. Requesting
703 /// more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
704 /// is enabled.
705 pub max_blas_primitive_count: u32,
706 /// The maximum number of geometry descriptors a BLAS is allowed to have. Requesting
707 /// more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
708 /// is enabled.
709 pub max_blas_geometry_count: u32,
710 /// The maximum number of instances a TLAS is allowed to have. Requesting more than 0 during
711 /// device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
712 /// is enabled.
713 pub max_tlas_instance_count: u32,
714 /// The maximum number of acceleration structures allowed to be used in a shader stage.
715 /// Requesting more than 0 during device creation only makes sense if [`Features::EXPERIMENTAL_RAY_QUERY`]
716 /// is enabled.
717 pub max_acceleration_structures_per_shader_stage: u32,
718
719 /// The maximum number of views that can be used in multiview rendering
720 pub max_multiview_view_count: u32,
721}
722
723impl Default for Limits {
724 fn default() -> Self {
725 Self::defaults()
726 }
727}
728
729impl Limits {
730 /// These default limits are guaranteed to to work on all modern
731 /// backends and guaranteed to be supported by WebGPU
732 ///
733 /// Those limits are as follows:
734 /// ```rust
735 /// # use wgpu_types::Limits;
736 /// assert_eq!(Limits::defaults(), Limits {
737 /// max_texture_dimension_1d: 8192,
738 /// max_texture_dimension_2d: 8192,
739 /// max_texture_dimension_3d: 2048,
740 /// max_texture_array_layers: 256,
741 /// max_bind_groups: 4,
742 /// max_bindings_per_bind_group: 1000,
743 /// max_dynamic_uniform_buffers_per_pipeline_layout: 8,
744 /// max_dynamic_storage_buffers_per_pipeline_layout: 4,
745 /// max_sampled_textures_per_shader_stage: 16,
746 /// max_samplers_per_shader_stage: 16,
747 /// max_storage_buffers_per_shader_stage: 8,
748 /// max_storage_textures_per_shader_stage: 4,
749 /// max_uniform_buffers_per_shader_stage: 12,
750 /// max_binding_array_elements_per_shader_stage: 0,
751 /// max_binding_array_sampler_elements_per_shader_stage: 0,
752 /// max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
753 /// max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
754 /// max_vertex_buffers: 8,
755 /// max_buffer_size: 256 << 20, // (256 MiB)
756 /// max_vertex_attributes: 16,
757 /// max_vertex_buffer_array_stride: 2048,
758 /// min_uniform_buffer_offset_alignment: 256,
759 /// min_storage_buffer_offset_alignment: 256,
760 /// max_inter_stage_shader_components: 60,
761 /// max_color_attachments: 8,
762 /// max_color_attachment_bytes_per_sample: 32,
763 /// max_compute_workgroup_storage_size: 16384,
764 /// max_compute_invocations_per_workgroup: 256,
765 /// max_compute_workgroup_size_x: 256,
766 /// max_compute_workgroup_size_y: 256,
767 /// max_compute_workgroup_size_z: 64,
768 /// max_compute_workgroups_per_dimension: 65535,
769 /// min_subgroup_size: 0,
770 /// max_subgroup_size: 0,
771 /// max_push_constant_size: 0,
772 /// max_non_sampler_bindings: 1_000_000,
773 /// max_task_workgroup_total_count: 0,
774 /// max_task_workgroups_per_dimension: 0,
775 /// max_mesh_multiview_view_count: 0,
776 /// max_mesh_output_layers: 0,
777 /// max_blas_primitive_count: 0,
778 /// max_blas_geometry_count: 0,
779 /// max_tlas_instance_count: 0,
780 /// max_acceleration_structures_per_shader_stage: 0,
781 /// max_multiview_view_count: 0,
782 /// });
783 /// ```
784 ///
785 /// Rust doesn't allow const in trait implementations, so we break this out
786 /// to allow reusing these defaults in const contexts
787 #[must_use]
788 pub const fn defaults() -> Self {
789 Self {
790 max_texture_dimension_1d: 8192,
791 max_texture_dimension_2d: 8192,
792 max_texture_dimension_3d: 2048,
793 max_texture_array_layers: 256,
794 max_bind_groups: 4,
795 max_bindings_per_bind_group: 1000,
796 max_dynamic_uniform_buffers_per_pipeline_layout: 8,
797 max_dynamic_storage_buffers_per_pipeline_layout: 4,
798 max_sampled_textures_per_shader_stage: 16,
799 max_samplers_per_shader_stage: 16,
800 max_storage_buffers_per_shader_stage: 8,
801 max_storage_textures_per_shader_stage: 4,
802 max_uniform_buffers_per_shader_stage: 12,
803 max_binding_array_elements_per_shader_stage: 0,
804 max_binding_array_sampler_elements_per_shader_stage: 0,
805 max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
806 max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
807 max_vertex_buffers: 8,
808 max_buffer_size: 256 << 20, // (256 MiB)
809 max_vertex_attributes: 16,
810 max_vertex_buffer_array_stride: 2048,
811 min_uniform_buffer_offset_alignment: 256,
812 min_storage_buffer_offset_alignment: 256,
813 max_inter_stage_shader_components: 60,
814 max_color_attachments: 8,
815 max_color_attachment_bytes_per_sample: 32,
816 max_compute_workgroup_storage_size: 16384,
817 max_compute_invocations_per_workgroup: 256,
818 max_compute_workgroup_size_x: 256,
819 max_compute_workgroup_size_y: 256,
820 max_compute_workgroup_size_z: 64,
821 max_compute_workgroups_per_dimension: 65535,
822 min_subgroup_size: 0,
823 max_subgroup_size: 0,
824 max_push_constant_size: 0,
825 max_non_sampler_bindings: 1_000_000,
826
827 max_task_workgroup_total_count: 0,
828 max_task_workgroups_per_dimension: 0,
829 max_mesh_multiview_view_count: 0,
830 max_mesh_output_layers: 0,
831
832 max_blas_primitive_count: 0,
833 max_blas_geometry_count: 0,
834 max_tlas_instance_count: 0,
835 max_acceleration_structures_per_shader_stage: 0,
836
837 max_multiview_view_count: 0,
838 }
839 }
840
841 /// These default limits are guaranteed to be compatible with GLES-3.1, and D3D11
842 ///
843 /// Those limits are as follows (different from default are marked with *):
844 /// ```rust
845 /// # use wgpu_types::Limits;
846 /// assert_eq!(Limits::downlevel_defaults(), Limits {
847 /// max_texture_dimension_1d: 2048, // *
848 /// max_texture_dimension_2d: 2048, // *
849 /// max_texture_dimension_3d: 256, // *
850 /// max_texture_array_layers: 256,
851 /// max_bind_groups: 4,
852 /// max_bindings_per_bind_group: 1000,
853 /// max_dynamic_uniform_buffers_per_pipeline_layout: 8,
854 /// max_dynamic_storage_buffers_per_pipeline_layout: 4,
855 /// max_sampled_textures_per_shader_stage: 16,
856 /// max_samplers_per_shader_stage: 16,
857 /// max_storage_buffers_per_shader_stage: 4, // *
858 /// max_storage_textures_per_shader_stage: 4,
859 /// max_uniform_buffers_per_shader_stage: 12,
860 /// max_binding_array_elements_per_shader_stage: 0,
861 /// max_binding_array_sampler_elements_per_shader_stage: 0,
862 /// max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
863 /// max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
864 /// max_vertex_buffers: 8,
865 /// max_vertex_attributes: 16,
866 /// max_vertex_buffer_array_stride: 2048,
867 /// min_subgroup_size: 0,
868 /// max_subgroup_size: 0,
869 /// max_push_constant_size: 0,
870 /// min_uniform_buffer_offset_alignment: 256,
871 /// min_storage_buffer_offset_alignment: 256,
872 /// max_inter_stage_shader_components: 60,
873 /// max_color_attachments: 4,
874 /// max_color_attachment_bytes_per_sample: 32,
875 /// max_compute_workgroup_storage_size: 16352, // *
876 /// max_compute_invocations_per_workgroup: 256,
877 /// max_compute_workgroup_size_x: 256,
878 /// max_compute_workgroup_size_y: 256,
879 /// max_compute_workgroup_size_z: 64,
880 /// max_compute_workgroups_per_dimension: 65535,
881 /// max_buffer_size: 256 << 20, // (256 MiB)
882 /// max_non_sampler_bindings: 1_000_000,
883 ///
884 /// max_task_workgroup_total_count: 0,
885 /// max_task_workgroups_per_dimension: 0,
886 /// max_mesh_multiview_view_count: 0,
887 /// max_mesh_output_layers: 0,
888 ///
889 /// max_blas_primitive_count: 0,
890 /// max_blas_geometry_count: 0,
891 /// max_tlas_instance_count: 0,
892 /// max_acceleration_structures_per_shader_stage: 0,
893 ///
894 /// max_multiview_view_count: 0,
895 /// });
896 /// ```
897 #[must_use]
898 pub const fn downlevel_defaults() -> Self {
899 Self {
900 max_texture_dimension_1d: 2048,
901 max_texture_dimension_2d: 2048,
902 max_texture_dimension_3d: 256,
903 max_storage_buffers_per_shader_stage: 4,
904 max_uniform_buffer_binding_size: 16 << 10, // (16 KiB)
905 max_color_attachments: 4,
906 // see: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=7
907 max_compute_workgroup_storage_size: 16352,
908
909 max_task_workgroups_per_dimension: 0,
910 max_task_workgroup_total_count: 0,
911 max_mesh_multiview_view_count: 0,
912 max_mesh_output_layers: 0,
913 ..Self::defaults()
914 }
915 }
916
917 /// These default limits are guaranteed to be compatible with GLES-3.0, and D3D11, and WebGL2
918 ///
919 /// Those limits are as follows (different from `downlevel_defaults` are marked with +,
920 /// *'s from `downlevel_defaults` shown as well.):
921 /// ```rust
922 /// # use wgpu_types::Limits;
923 /// assert_eq!(Limits::downlevel_webgl2_defaults(), Limits {
924 /// max_texture_dimension_1d: 2048, // *
925 /// max_texture_dimension_2d: 2048, // *
926 /// max_texture_dimension_3d: 256, // *
927 /// max_texture_array_layers: 256,
928 /// max_bind_groups: 4,
929 /// max_bindings_per_bind_group: 1000,
930 /// max_dynamic_uniform_buffers_per_pipeline_layout: 8,
931 /// max_dynamic_storage_buffers_per_pipeline_layout: 0, // +
932 /// max_sampled_textures_per_shader_stage: 16,
933 /// max_samplers_per_shader_stage: 16,
934 /// max_storage_buffers_per_shader_stage: 0, // * +
935 /// max_storage_textures_per_shader_stage: 0, // +
936 /// max_uniform_buffers_per_shader_stage: 11, // +
937 /// max_binding_array_elements_per_shader_stage: 0,
938 /// max_binding_array_sampler_elements_per_shader_stage: 0,
939 /// max_uniform_buffer_binding_size: 16 << 10, // * (16 KiB)
940 /// max_storage_buffer_binding_size: 0, // * +
941 /// max_vertex_buffers: 8,
942 /// max_vertex_attributes: 16,
943 /// max_vertex_buffer_array_stride: 255, // +
944 /// min_subgroup_size: 0,
945 /// max_subgroup_size: 0,
946 /// max_push_constant_size: 0,
947 /// min_uniform_buffer_offset_alignment: 256,
948 /// min_storage_buffer_offset_alignment: 256,
949 /// max_inter_stage_shader_components: 31,
950 /// max_color_attachments: 4,
951 /// max_color_attachment_bytes_per_sample: 32,
952 /// max_compute_workgroup_storage_size: 0, // +
953 /// max_compute_invocations_per_workgroup: 0, // +
954 /// max_compute_workgroup_size_x: 0, // +
955 /// max_compute_workgroup_size_y: 0, // +
956 /// max_compute_workgroup_size_z: 0, // +
957 /// max_compute_workgroups_per_dimension: 0, // +
958 /// max_buffer_size: 256 << 20, // (256 MiB),
959 /// max_non_sampler_bindings: 1_000_000,
960 ///
961 /// max_task_workgroup_total_count: 0,
962 /// max_task_workgroups_per_dimension: 0,
963 /// max_mesh_multiview_view_count: 0,
964 /// max_mesh_output_layers: 0,
965 ///
966 /// max_blas_primitive_count: 0,
967 /// max_blas_geometry_count: 0,
968 /// max_tlas_instance_count: 0,
969 /// max_acceleration_structures_per_shader_stage: 0,
970 ///
971 /// max_multiview_view_count: 0,
972 /// });
973 /// ```
974 #[must_use]
975 pub const fn downlevel_webgl2_defaults() -> Self {
976 Self {
977 max_uniform_buffers_per_shader_stage: 11,
978 max_storage_buffers_per_shader_stage: 0,
979 max_storage_textures_per_shader_stage: 0,
980 max_dynamic_storage_buffers_per_pipeline_layout: 0,
981 max_storage_buffer_binding_size: 0,
982 max_vertex_buffer_array_stride: 255,
983 max_compute_workgroup_storage_size: 0,
984 max_compute_invocations_per_workgroup: 0,
985 max_compute_workgroup_size_x: 0,
986 max_compute_workgroup_size_y: 0,
987 max_compute_workgroup_size_z: 0,
988 max_compute_workgroups_per_dimension: 0,
989 min_subgroup_size: 0,
990 max_subgroup_size: 0,
991
992 // Value supported by Intel Celeron B830 on Windows (OpenGL 3.1)
993 max_inter_stage_shader_components: 31,
994
995 // Most of the values should be the same as the downlevel defaults
996 ..Self::downlevel_defaults()
997 }
998 }
999
1000 /// Modify the current limits to use the resolution limits of the other.
1001 ///
1002 /// This is useful because the swapchain might need to be larger than any other image in the application.
1003 ///
1004 /// If your application only needs 512x512, you might be running on a 4k display and need extremely high resolution limits.
1005 #[must_use]
1006 pub const fn using_resolution(self, other: Self) -> Self {
1007 Self {
1008 max_texture_dimension_1d: other.max_texture_dimension_1d,
1009 max_texture_dimension_2d: other.max_texture_dimension_2d,
1010 max_texture_dimension_3d: other.max_texture_dimension_3d,
1011 ..self
1012 }
1013 }
1014
1015 /// Modify the current limits to use the buffer alignment limits of the adapter.
1016 ///
1017 /// This is useful for when you'd like to dynamically use the "best" supported buffer alignments.
1018 #[must_use]
1019 pub const fn using_alignment(self, other: Self) -> Self {
1020 Self {
1021 min_uniform_buffer_offset_alignment: other.min_uniform_buffer_offset_alignment,
1022 min_storage_buffer_offset_alignment: other.min_storage_buffer_offset_alignment,
1023 ..self
1024 }
1025 }
1026
1027 /// The minimum guaranteed limits for acceleration structures if you enable [`Features::EXPERIMENTAL_RAY_QUERY`]
1028 #[must_use]
1029 pub const fn using_minimum_supported_acceleration_structure_values(self) -> Self {
1030 Self {
1031 max_blas_geometry_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum
1032 max_tlas_instance_count: (1 << 24) - 1, // 2^24 - 1: Vulkan's minimum
1033 max_blas_primitive_count: (1 << 24) - 1, // Should be 2^28: Metal's minimum, but due to an llvmpipe bug it is 2^24 - 1
1034 max_acceleration_structures_per_shader_stage: 16, // Vulkan's minimum
1035 ..self
1036 }
1037 }
1038
1039 /// Modify the current limits to use the acceleration structure limits of `other` (`other` could
1040 /// be the limits of the adapter).
1041 #[must_use]
1042 pub const fn using_acceleration_structure_values(self, other: Self) -> Self {
1043 Self {
1044 max_blas_geometry_count: other.max_blas_geometry_count,
1045 max_tlas_instance_count: other.max_tlas_instance_count,
1046 max_blas_primitive_count: other.max_blas_primitive_count,
1047 max_acceleration_structures_per_shader_stage: other
1048 .max_acceleration_structures_per_shader_stage,
1049 ..self
1050 }
1051 }
1052
1053 /// The recommended minimum limits for mesh shaders if you enable [`Features::EXPERIMENTAL_MESH_SHADER`]
1054 ///
1055 /// These are chosen somewhat arbitrarily. They are small enough that they should cover all physical devices,
1056 /// but not necessarily all use cases.
1057 #[must_use]
1058 pub const fn using_recommended_minimum_mesh_shader_values(self) -> Self {
1059 Self {
1060 // Literally just made this up as 256^2 or 2^16.
1061 // My GPU supports 2^22, and compute shaders don't have this kind of limit.
1062 // This very likely is never a real limiter
1063 max_task_workgroup_total_count: 65536,
1064 max_task_workgroups_per_dimension: 256,
1065 // llvmpipe reports 0 multiview count, which just means no multiview is allowed
1066 max_mesh_multiview_view_count: 0,
1067 // llvmpipe once again requires this to be 8. An RTX 3060 supports well over 1024.
1068 max_mesh_output_layers: 8,
1069 ..self
1070 }
1071 }
1072
1073 /// Compares every limits within self is within the limits given in `allowed`.
1074 ///
1075 /// If you need detailed information on failures, look at [`Limits::check_limits_with_fail_fn`].
1076 #[must_use]
1077 pub fn check_limits(&self, allowed: &Self) -> bool {
1078 let mut within = true;
1079 self.check_limits_with_fail_fn(allowed, true, |_, _, _| within = false);
1080 within
1081 }
1082
1083 /// Compares every limits within self is within the limits given in `allowed`.
1084 /// For an easy to use binary choice, use [`Limits::check_limits`].
1085 ///
1086 /// If a value is not within the allowed limit, this function calls the `fail_fn`
1087 /// with the:
1088 /// - limit name
1089 /// - self's limit
1090 /// - allowed's limit.
1091 ///
1092 /// If fatal is true, a single failure bails out the comparison after a single failure.
1093 pub fn check_limits_with_fail_fn(
1094 &self,
1095 allowed: &Self,
1096 fatal: bool,
1097 mut fail_fn: impl FnMut(&'static str, u64, u64),
1098 ) {
1099 macro_rules! check_with_fail_fn {
1100 ($name:ident, $ordering:expr) => {
1101 let invalid_ord = $ordering.reverse();
1102 // In the case of `min_subgroup_size`, requesting a value of
1103 // zero means "I'm not going to use subgroups", so we have to
1104 // special case that. If any of our minimum limits could
1105 // meaningfully go all the way to zero, that would conflict with
1106 // this.
1107 if self.$name != 0 && self.$name.cmp(&allowed.$name) == invalid_ord {
1108 fail_fn(stringify!($name), self.$name as u64, allowed.$name as u64);
1109 if fatal {
1110 return;
1111 }
1112 }
1113 };
1114 }
1115
1116 if self.min_subgroup_size > self.max_subgroup_size {
1117 fail_fn(
1118 "max_subgroup_size",
1119 self.min_subgroup_size as u64,
1120 allowed.min_subgroup_size as u64,
1121 );
1122 }
1123 with_limits!(check_with_fail_fn);
1124 }
1125
1126 /// For each limit in `other` that is better than the value in `self`,
1127 /// replace the value in `self` with the value from `other`.
1128 ///
1129 /// A request for a limit value less than the WebGPU-specified default must
1130 /// be ignored. This function is used to clamp such requests to the default
1131 /// value.
1132 ///
1133 /// This function is not for clamping requests for values beyond the
1134 /// supported limits. For that purpose the desired function would be
1135 /// `or_worse_values_from` (which doesn't exist, but could be added if
1136 /// needed).
1137 #[must_use]
1138 pub fn or_better_values_from(mut self, other: &Self) -> Self {
1139 macro_rules! or_better_value_from {
1140 ($name:ident, $ordering:expr) => {
1141 match $ordering {
1142 // Limits that are maximum values (most of them)
1143 Ordering::Less => self.$name = self.$name.max(other.$name),
1144 // Limits that are minimum values
1145 Ordering::Greater => self.$name = self.$name.min(other.$name),
1146 Ordering::Equal => unreachable!(),
1147 }
1148 };
1149 }
1150
1151 with_limits!(or_better_value_from);
1152
1153 self
1154 }
1155}
1156
1157/// Represents the sets of additional limits on an adapter,
1158/// which take place when running on downlevel backends.
1159#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1161pub struct DownlevelLimits {}
1162
1163#[allow(clippy::derivable_impls)]
1164impl Default for DownlevelLimits {
1165 fn default() -> Self {
1166 DownlevelLimits {}
1167 }
1168}
1169
1170/// Lists various ways the underlying platform does not conform to the WebGPU standard.
1171#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1173pub struct DownlevelCapabilities {
1174 /// Combined boolean flags.
1175 pub flags: DownlevelFlags,
1176 /// Additional limits
1177 pub limits: DownlevelLimits,
1178 /// Which collections of features shaders support. Defined in terms of D3D's shader models.
1179 pub shader_model: ShaderModel,
1180}
1181
1182impl Default for DownlevelCapabilities {
1183 fn default() -> Self {
1184 Self {
1185 flags: DownlevelFlags::all(),
1186 limits: DownlevelLimits::default(),
1187 shader_model: ShaderModel::Sm5,
1188 }
1189 }
1190}
1191
1192impl DownlevelCapabilities {
1193 /// Returns true if the underlying platform offers complete support of the baseline WebGPU standard.
1194 ///
1195 /// If this returns false, some parts of the API will result in validation errors where they would not normally.
1196 /// These parts can be determined by the values in this structure.
1197 #[must_use]
1198 pub fn is_webgpu_compliant(&self) -> bool {
1199 self.flags.contains(DownlevelFlags::compliant())
1200 && self.limits == DownlevelLimits::default()
1201 && self.shader_model >= ShaderModel::Sm5
1202 }
1203}
1204
1205bitflags::bitflags! {
1206 /// Binary flags listing features that may or may not be present on downlevel adapters.
1207 ///
1208 /// A downlevel adapter is a GPU adapter that wgpu supports, but with potentially limited
1209 /// features, due to the lack of hardware feature support.
1210 ///
1211 /// Flags that are **not** present for a downlevel adapter or device usually indicates
1212 /// non-compliance with the WebGPU specification, but not always.
1213 ///
1214 /// You can check whether a set of flags is compliant through the
1215 /// [`DownlevelCapabilities::is_webgpu_compliant()`] function.
1216 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1217 #[cfg_attr(feature = "serde", serde(transparent))]
1218 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1219 pub struct DownlevelFlags: u32 {
1220 /// The device supports compiling and using compute shaders.
1221 ///
1222 /// WebGL2, and GLES3.0 devices do not support compute.
1223 const COMPUTE_SHADERS = 1 << 0;
1224 /// Supports binding storage buffers and textures to fragment shaders.
1225 const FRAGMENT_WRITABLE_STORAGE = 1 << 1;
1226 /// Supports indirect drawing and dispatching.
1227 ///
1228 /// [`Self::COMPUTE_SHADERS`] must be present for this flag.
1229 ///
1230 /// WebGL2, GLES 3.0, and Metal on Apple1/Apple2 GPUs do not support indirect.
1231 const INDIRECT_EXECUTION = 1 << 2;
1232 /// Supports non-zero `base_vertex` parameter to direct indexed draw calls.
1233 ///
1234 /// Indirect calls, if supported, always support non-zero `base_vertex`.
1235 ///
1236 /// Supported by:
1237 /// - Vulkan
1238 /// - DX12
1239 /// - Metal on Apple3+ or Mac1+
1240 /// - OpenGL 3.2+
1241 /// - OpenGL ES 3.2
1242 const BASE_VERTEX = 1 << 3;
1243 /// Supports reading from a depth/stencil texture while using it as a read-only
1244 /// depth/stencil attachment.
1245 ///
1246 /// The WebGL2 and GLES backends do not support RODS.
1247 const READ_ONLY_DEPTH_STENCIL = 1 << 4;
1248 /// Supports textures with mipmaps which have a non power of two size.
1249 const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 1 << 5;
1250 /// Supports textures that are cube arrays.
1251 const CUBE_ARRAY_TEXTURES = 1 << 6;
1252 /// Supports comparison samplers.
1253 const COMPARISON_SAMPLERS = 1 << 7;
1254 /// Supports different blend operations per color attachment.
1255 const INDEPENDENT_BLEND = 1 << 8;
1256 /// Supports storage buffers in vertex shaders.
1257 const VERTEX_STORAGE = 1 << 9;
1258
1259 /// Supports samplers with anisotropic filtering. Note this isn't actually required by
1260 /// WebGPU, the implementation is allowed to completely ignore aniso clamp. This flag is
1261 /// here for native backends so they can communicate to the user of aniso is enabled.
1262 ///
1263 /// All backends and all devices support anisotropic filtering.
1264 const ANISOTROPIC_FILTERING = 1 << 10;
1265
1266 /// Supports storage buffers in fragment shaders.
1267 const FRAGMENT_STORAGE = 1 << 11;
1268
1269 /// Supports sample-rate shading.
1270 const MULTISAMPLED_SHADING = 1 << 12;
1271
1272 /// Supports copies between depth textures and buffers.
1273 ///
1274 /// GLES/WebGL don't support this.
1275 const DEPTH_TEXTURE_AND_BUFFER_COPIES = 1 << 13;
1276
1277 /// Supports all the texture usages described in WebGPU. If this isn't supported, you
1278 /// should call `get_texture_format_features` to get how you can use textures of a given format
1279 const WEBGPU_TEXTURE_FORMAT_SUPPORT = 1 << 14;
1280
1281 /// Supports buffer bindings with sizes that aren't a multiple of 16.
1282 ///
1283 /// WebGL doesn't support this.
1284 const BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED = 1 << 15;
1285
1286 /// Supports buffers to combine [`BufferUsages::INDEX`] with usages other than [`BufferUsages::COPY_DST`] and [`BufferUsages::COPY_SRC`].
1287 /// Furthermore, in absence of this feature it is not allowed to copy index buffers from/to buffers with a set of usage flags containing
1288 /// [`BufferUsages::VERTEX`]/[`BufferUsages::UNIFORM`]/[`BufferUsages::STORAGE`] or [`BufferUsages::INDIRECT`].
1289 ///
1290 /// WebGL doesn't support this.
1291 const UNRESTRICTED_INDEX_BUFFER = 1 << 16;
1292
1293 /// Supports full 32-bit range indices (2^32-1 as opposed to 2^24-1 without this flag)
1294 ///
1295 /// Corresponds to Vulkan's `VkPhysicalDeviceFeatures.fullDrawIndexUint32`
1296 const FULL_DRAW_INDEX_UINT32 = 1 << 17;
1297
1298 /// Supports depth bias clamping
1299 ///
1300 /// Corresponds to Vulkan's `VkPhysicalDeviceFeatures.depthBiasClamp`
1301 const DEPTH_BIAS_CLAMP = 1 << 18;
1302
1303 /// Supports specifying which view format values are allowed when create_view() is called on a texture.
1304 ///
1305 /// The WebGL and GLES backends doesn't support this.
1306 const VIEW_FORMATS = 1 << 19;
1307
1308 /// With this feature not present, there are the following restrictions on `Queue::copy_external_image_to_texture`:
1309 /// - The source must not be [`web_sys::OffscreenCanvas`]
1310 /// - [`CopyExternalImageSourceInfo::origin`] must be zero.
1311 /// - [`CopyExternalImageDestInfo::color_space`] must be srgb.
1312 /// - If the source is an [`web_sys::ImageBitmap`]:
1313 /// - [`CopyExternalImageSourceInfo::flip_y`] must be false.
1314 /// - [`CopyExternalImageDestInfo::premultiplied_alpha`] must be false.
1315 ///
1316 /// WebGL doesn't support this. WebGPU does.
1317 const UNRESTRICTED_EXTERNAL_TEXTURE_COPIES = 1 << 20;
1318
1319 /// Supports specifying which view formats are allowed when calling create_view on the texture returned by
1320 /// `Surface::get_current_texture`.
1321 ///
1322 /// The GLES/WebGL and Vulkan on Android doesn't support this.
1323 const SURFACE_VIEW_FORMATS = 1 << 21;
1324
1325 /// If this is true, calls to `CommandEncoder::resolve_query_set` will be performed on the queue timeline.
1326 ///
1327 /// If this is false, calls to `CommandEncoder::resolve_query_set` will be performed on the device (i.e. cpu) timeline
1328 /// and will block that timeline until the query has data. You may work around this limitation by waiting until the submit
1329 /// whose queries you are resolving is fully finished (through use of `queue.on_submitted_work_done`) and only
1330 /// then submitting the resolve_query_set command. The queries will be guaranteed finished, so will not block.
1331 ///
1332 /// Supported by:
1333 /// - Vulkan,
1334 /// - DX12
1335 /// - Metal
1336 /// - OpenGL 4.4+
1337 ///
1338 /// Not Supported by:
1339 /// - GL ES / WebGL
1340 const NONBLOCKING_QUERY_RESOLVE = 1 << 22;
1341
1342 /// Allows shaders to use `quantizeToF16`, `pack2x16float`, and `unpack2x16float`, which
1343 /// operate on `f16`-precision values stored in `f32`s.
1344 ///
1345 /// Not supported by Vulkan on Mesa when [`Features::SHADER_F16`] is absent.
1346 const SHADER_F16_IN_F32 = 1 << 23;
1347 }
1348}
1349
1350impl DownlevelFlags {
1351 /// All flags that indicate if the backend is WebGPU compliant
1352 #[must_use]
1353 pub const fn compliant() -> Self {
1354 // We use manual bit twiddling to make this a const fn as `Sub` and `.remove` aren't const
1355
1356 // WebGPU doesn't actually require aniso
1357 Self::from_bits_truncate(Self::all().bits() & !Self::ANISOTROPIC_FILTERING.bits())
1358 }
1359}
1360
1361/// Collections of shader features a device supports if they support less than WebGPU normally allows.
1362// TODO: Fill out the differences between shader models more completely
1363#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1364#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1365pub enum ShaderModel {
1366 /// Extremely limited shaders, including a total instruction limit.
1367 Sm2,
1368 /// Missing minor features and storage images.
1369 Sm4,
1370 /// WebGPU supports shader module 5.
1371 Sm5,
1372}
1373
1374/// Supported physical device types.
1375#[repr(u8)]
1376#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
1377#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1378pub enum DeviceType {
1379 /// Other or Unknown.
1380 Other,
1381 /// Integrated GPU with shared CPU/GPU memory.
1382 IntegratedGpu,
1383 /// Discrete GPU with separate CPU/GPU memory.
1384 DiscreteGpu,
1385 /// Virtual / Hosted.
1386 VirtualGpu,
1387 /// Cpu / Software Rendering.
1388 Cpu,
1389}
1390
1391//TODO: convert `vendor` and `device` to `u32`
1392
1393/// Information about an adapter.
1394#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1395#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1396pub struct AdapterInfo {
1397 /// Adapter name
1398 pub name: String,
1399 /// [`Backend`]-specific vendor ID of the adapter
1400 ///
1401 /// This generally is a 16-bit PCI vendor ID in the least significant bytes of this field.
1402 /// However, more significant bytes may be non-zero if the backend uses a different
1403 /// representation.
1404 ///
1405 /// * For [`Backend::Vulkan`], the [`VkPhysicalDeviceProperties::vendorID`] is used, which is
1406 /// a superset of PCI IDs.
1407 ///
1408 /// [`VkPhysicalDeviceProperties::vendorID`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
1409 pub vendor: u32,
1410 /// [`Backend`]-specific device ID of the adapter
1411 ///
1412 ///
1413 /// This generally is a 16-bit PCI device ID in the least significant bytes of this field.
1414 /// However, more significant bytes may be non-zero if the backend uses a different
1415 /// representation.
1416 ///
1417 /// * For [`Backend::Vulkan`], the [`VkPhysicalDeviceProperties::deviceID`] is used, which is
1418 /// a superset of PCI IDs.
1419 ///
1420 /// [`VkPhysicalDeviceProperties::deviceID`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html
1421 pub device: u32,
1422 /// Type of device
1423 pub device_type: DeviceType,
1424 /// [`Backend`]-specific PCI bus ID of the adapter.
1425 ///
1426 /// * For [`Backend::Vulkan`], [`VkPhysicalDevicePCIBusInfoPropertiesEXT`] is used,
1427 /// if available, in the form `bus:device.function`, e.g. `0000:01:00.0`.
1428 ///
1429 /// [`VkPhysicalDevicePCIBusInfoPropertiesEXT`]: https://registry.khronos.org/vulkan/specs/latest/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html
1430 pub device_pci_bus_id: String,
1431 /// Driver name
1432 pub driver: String,
1433 /// Driver info
1434 pub driver_info: String,
1435 /// Backend used for device
1436 pub backend: Backend,
1437 /// If true, adding [`TextureUsages::TRANSIENT`] to a texture will decrease memory usage.
1438 pub transient_saves_memory: bool,
1439}
1440
1441/// Hints to the device about the memory allocation strategy.
1442///
1443/// Some backends may ignore these hints.
1444#[derive(Clone, Debug, Default)]
1445#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1446pub enum MemoryHints {
1447 /// Favor performance over memory usage (the default value).
1448 #[default]
1449 Performance,
1450 /// Favor memory usage over performance.
1451 MemoryUsage,
1452 /// Applications that have control over the content that is rendered
1453 /// (typically games) may find an optimal compromise between memory
1454 /// usage and performance by specifying the allocation configuration.
1455 Manual {
1456 /// Defines the range of allowed memory block sizes for sub-allocated
1457 /// resources.
1458 ///
1459 /// The backend may attempt to group multiple resources into fewer
1460 /// device memory blocks (sub-allocation) for performance reasons.
1461 /// The start of the provided range specifies the initial memory
1462 /// block size for sub-allocated resources. After running out of
1463 /// space in existing memory blocks, the backend may chose to
1464 /// progressively increase the block size of subsequent allocations
1465 /// up to a limit specified by the end of the range.
1466 ///
1467 /// This does not limit resource sizes. If a resource does not fit
1468 /// in the specified range, it will typically be placed in a dedicated
1469 /// memory block.
1470 suballocated_device_memory_block_size: Range<u64>,
1471 },
1472}
1473
1474/// Describes a [`Device`](../wgpu/struct.Device.html).
1475///
1476/// Corresponds to [WebGPU `GPUDeviceDescriptor`](
1477/// https://gpuweb.github.io/gpuweb/#gpudevicedescriptor).
1478#[derive(Clone, Debug, Default)]
1479#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1480pub struct DeviceDescriptor<L> {
1481 /// Debug label for the device.
1482 pub label: L,
1483 /// Specifies the features that are required by the device request.
1484 /// The request will fail if the adapter cannot provide these features.
1485 ///
1486 /// Exactly the specified set of features, and no more or less,
1487 /// will be allowed in validation of API calls on the resulting device.
1488 pub required_features: Features,
1489 /// Specifies the limits that are required by the device request.
1490 /// The request will fail if the adapter cannot provide these limits.
1491 ///
1492 /// Exactly the specified limits, and no better or worse,
1493 /// will be allowed in validation of API calls on the resulting device.
1494 pub required_limits: Limits,
1495 /// Specifies whether `self.required_features` is allowed to contain experimental features.
1496 #[cfg_attr(feature = "serde", serde(skip))]
1497 pub experimental_features: ExperimentalFeatures,
1498 /// Hints for memory allocation strategies.
1499 pub memory_hints: MemoryHints,
1500 /// Whether API tracing for debugging is enabled,
1501 /// and where the trace is written if so.
1502 pub trace: Trace,
1503}
1504
1505impl<L> DeviceDescriptor<L> {
1506 /// Takes a closure and maps the label of the device descriptor into another.
1507 #[must_use]
1508 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> DeviceDescriptor<K> {
1509 DeviceDescriptor {
1510 label: fun(&self.label),
1511 required_features: self.required_features,
1512 required_limits: self.required_limits.clone(),
1513 experimental_features: self.experimental_features,
1514 memory_hints: self.memory_hints.clone(),
1515 trace: self.trace.clone(),
1516 }
1517 }
1518}
1519
1520/// Controls API call tracing and specifies where the trace is written.
1521///
1522/// **Note:** Tracing is currently unavailable.
1523/// See [issue 5974](https://github.com/gfx-rs/wgpu/issues/5974) for updates.
1524#[derive(Clone, Debug, Default)]
1525#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1526// This enum must be non-exhaustive so that enabling the "trace" feature is not a semver break.
1527#[non_exhaustive]
1528pub enum Trace {
1529 /// Tracing disabled.
1530 #[default]
1531 Off,
1532
1533 /// Tracing enabled.
1534 #[cfg(feature = "trace")]
1535 // This must be owned rather than `&'a Path`, because if it were that, then the lifetime
1536 // parameter would be unused when the "trace" feature is disabled, which is prohibited.
1537 Directory(std::path::PathBuf),
1538}
1539
1540bitflags::bitflags! {
1541 /// Describes the shader stages that a binding will be visible from.
1542 ///
1543 /// These can be combined so something that is visible from both vertex and fragment shaders can be defined as:
1544 ///
1545 /// `ShaderStages::VERTEX | ShaderStages::FRAGMENT`
1546 ///
1547 /// Corresponds to [WebGPU `GPUShaderStageFlags`](
1548 /// https://gpuweb.github.io/gpuweb/#typedefdef-gpushaderstageflags).
1549 #[repr(transparent)]
1550 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1551 #[cfg_attr(feature = "serde", serde(transparent))]
1552 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1553 pub struct ShaderStages: u32 {
1554 /// Binding is not visible from any shader stage.
1555 const NONE = 0;
1556 /// Binding is visible from the vertex shader of a render pipeline.
1557 const VERTEX = 1 << 0;
1558 /// Binding is visible from the fragment shader of a render pipeline.
1559 const FRAGMENT = 1 << 1;
1560 /// Binding is visible from the compute shader of a compute pipeline.
1561 const COMPUTE = 1 << 2;
1562 /// Binding is visible from the vertex and fragment shaders of a render pipeline.
1563 const VERTEX_FRAGMENT = Self::VERTEX.bits() | Self::FRAGMENT.bits();
1564 /// Binding is visible from the task shader of a mesh pipeline.
1565 const TASK = 1 << 3;
1566 /// Binding is visible from the mesh shader of a mesh pipeline.
1567 const MESH = 1 << 4;
1568 }
1569}
1570
1571/// Order in which texture data is laid out in memory.
1572#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
1573pub enum TextureDataOrder {
1574 /// The texture is laid out densely in memory as:
1575 ///
1576 /// ```text
1577 /// Layer0Mip0 Layer0Mip1 Layer0Mip2
1578 /// Layer1Mip0 Layer1Mip1 Layer1Mip2
1579 /// Layer2Mip0 Layer2Mip1 Layer2Mip2
1580 /// ````
1581 ///
1582 /// This is the layout used by dds files.
1583 #[default]
1584 LayerMajor,
1585 /// The texture is laid out densely in memory as:
1586 ///
1587 /// ```text
1588 /// Layer0Mip0 Layer1Mip0 Layer2Mip0
1589 /// Layer0Mip1 Layer1Mip1 Layer2Mip1
1590 /// Layer0Mip2 Layer1Mip2 Layer2Mip2
1591 /// ```
1592 ///
1593 /// This is the layout used by ktx and ktx2 files.
1594 MipMajor,
1595}
1596
1597/// Dimensions of a particular texture view.
1598///
1599/// Corresponds to [WebGPU `GPUTextureViewDimension`](
1600/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureviewdimension).
1601#[repr(C)]
1602#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1603#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1604pub enum TextureViewDimension {
1605 /// A one dimensional texture. `texture_1d` in WGSL and `texture1D` in GLSL.
1606 #[cfg_attr(feature = "serde", serde(rename = "1d"))]
1607 D1,
1608 /// A two dimensional texture. `texture_2d` in WGSL and `texture2D` in GLSL.
1609 #[cfg_attr(feature = "serde", serde(rename = "2d"))]
1610 #[default]
1611 D2,
1612 /// A two dimensional array texture. `texture_2d_array` in WGSL and `texture2DArray` in GLSL.
1613 #[cfg_attr(feature = "serde", serde(rename = "2d-array"))]
1614 D2Array,
1615 /// A cubemap texture. `texture_cube` in WGSL and `textureCube` in GLSL.
1616 #[cfg_attr(feature = "serde", serde(rename = "cube"))]
1617 Cube,
1618 /// A cubemap array texture. `texture_cube_array` in WGSL and `textureCubeArray` in GLSL.
1619 #[cfg_attr(feature = "serde", serde(rename = "cube-array"))]
1620 CubeArray,
1621 /// A three dimensional texture. `texture_3d` in WGSL and `texture3D` in GLSL.
1622 #[cfg_attr(feature = "serde", serde(rename = "3d"))]
1623 D3,
1624}
1625
1626impl TextureViewDimension {
1627 /// Get the texture dimension required of this texture view dimension.
1628 #[must_use]
1629 pub fn compatible_texture_dimension(self) -> TextureDimension {
1630 match self {
1631 Self::D1 => TextureDimension::D1,
1632 Self::D2 | Self::D2Array | Self::Cube | Self::CubeArray => TextureDimension::D2,
1633 Self::D3 => TextureDimension::D3,
1634 }
1635 }
1636}
1637
1638/// Alpha blend factor.
1639///
1640/// Corresponds to [WebGPU `GPUBlendFactor`](
1641/// https://gpuweb.github.io/gpuweb/#enumdef-gpublendfactor). Values using `Src1`
1642/// require [`Features::DUAL_SOURCE_BLENDING`] and can only be used with the first
1643/// render target.
1644///
1645/// For further details on how the blend factors are applied, see the analogous
1646/// functionality in OpenGL: <https://www.khronos.org/opengl/wiki/Blending#Blending_Parameters>.
1647#[repr(C)]
1648#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1649#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1650#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1651pub enum BlendFactor {
1652 /// 0.0
1653 Zero = 0,
1654 /// 1.0
1655 One = 1,
1656 /// S.component
1657 Src = 2,
1658 /// 1.0 - S.component
1659 OneMinusSrc = 3,
1660 /// S.alpha
1661 SrcAlpha = 4,
1662 /// 1.0 - S.alpha
1663 OneMinusSrcAlpha = 5,
1664 /// D.component
1665 Dst = 6,
1666 /// 1.0 - D.component
1667 OneMinusDst = 7,
1668 /// D.alpha
1669 DstAlpha = 8,
1670 /// 1.0 - D.alpha
1671 OneMinusDstAlpha = 9,
1672 /// min(S.alpha, 1.0 - D.alpha)
1673 SrcAlphaSaturated = 10,
1674 /// Constant
1675 Constant = 11,
1676 /// 1.0 - Constant
1677 OneMinusConstant = 12,
1678 /// S1.component
1679 Src1 = 13,
1680 /// 1.0 - S1.component
1681 OneMinusSrc1 = 14,
1682 /// S1.alpha
1683 Src1Alpha = 15,
1684 /// 1.0 - S1.alpha
1685 OneMinusSrc1Alpha = 16,
1686}
1687
1688impl BlendFactor {
1689 /// Returns `true` if the blend factor references the second blend source.
1690 ///
1691 /// Note that the usage of those blend factors require [`Features::DUAL_SOURCE_BLENDING`].
1692 #[must_use]
1693 pub fn ref_second_blend_source(&self) -> bool {
1694 match self {
1695 BlendFactor::Src1
1696 | BlendFactor::OneMinusSrc1
1697 | BlendFactor::Src1Alpha
1698 | BlendFactor::OneMinusSrc1Alpha => true,
1699 _ => false,
1700 }
1701 }
1702}
1703
1704/// Alpha blend operation.
1705///
1706/// Corresponds to [WebGPU `GPUBlendOperation`](
1707/// https://gpuweb.github.io/gpuweb/#enumdef-gpublendoperation).
1708///
1709/// For further details on how the blend operations are applied, see
1710/// the analogous functionality in OpenGL: <https://www.khronos.org/opengl/wiki/Blending#Blend_Equations>.
1711#[repr(C)]
1712#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1713#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1714#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1715pub enum BlendOperation {
1716 /// Src + Dst
1717 #[default]
1718 Add = 0,
1719 /// Src - Dst
1720 Subtract = 1,
1721 /// Dst - Src
1722 ReverseSubtract = 2,
1723 /// min(Src, Dst)
1724 Min = 3,
1725 /// max(Src, Dst)
1726 Max = 4,
1727}
1728
1729/// Describes a blend component of a [`BlendState`].
1730///
1731/// Corresponds to [WebGPU `GPUBlendComponent`](
1732/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendcomponent).
1733#[repr(C)]
1734#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1735#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1736#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1737pub struct BlendComponent {
1738 /// Multiplier for the source, which is produced by the fragment shader.
1739 pub src_factor: BlendFactor,
1740 /// Multiplier for the destination, which is stored in the target.
1741 pub dst_factor: BlendFactor,
1742 /// The binary operation applied to the source and destination,
1743 /// multiplied by their respective factors.
1744 pub operation: BlendOperation,
1745}
1746
1747impl BlendComponent {
1748 /// Default blending state that replaces destination with the source.
1749 pub const REPLACE: Self = Self {
1750 src_factor: BlendFactor::One,
1751 dst_factor: BlendFactor::Zero,
1752 operation: BlendOperation::Add,
1753 };
1754
1755 /// Blend state of `(1 * src) + ((1 - src_alpha) * dst)`.
1756 pub const OVER: Self = Self {
1757 src_factor: BlendFactor::One,
1758 dst_factor: BlendFactor::OneMinusSrcAlpha,
1759 operation: BlendOperation::Add,
1760 };
1761
1762 /// Returns true if the state relies on the constant color, which is
1763 /// set independently on a render command encoder.
1764 #[must_use]
1765 pub fn uses_constant(&self) -> bool {
1766 match (self.src_factor, self.dst_factor) {
1767 (BlendFactor::Constant, _)
1768 | (BlendFactor::OneMinusConstant, _)
1769 | (_, BlendFactor::Constant)
1770 | (_, BlendFactor::OneMinusConstant) => true,
1771 (_, _) => false,
1772 }
1773 }
1774}
1775
1776impl Default for BlendComponent {
1777 fn default() -> Self {
1778 Self::REPLACE
1779 }
1780}
1781
1782/// Describe the blend state of a render pipeline,
1783/// within [`ColorTargetState`].
1784///
1785/// Corresponds to [WebGPU `GPUBlendState`](
1786/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendstate).
1787#[repr(C)]
1788#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1789#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1790#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1791pub struct BlendState {
1792 /// Color equation.
1793 pub color: BlendComponent,
1794 /// Alpha equation.
1795 pub alpha: BlendComponent,
1796}
1797
1798impl BlendState {
1799 /// Blend mode that does no color blending, just overwrites the output with the contents of the shader.
1800 pub const REPLACE: Self = Self {
1801 color: BlendComponent::REPLACE,
1802 alpha: BlendComponent::REPLACE,
1803 };
1804
1805 /// Blend mode that does standard alpha blending with non-premultiplied alpha.
1806 pub const ALPHA_BLENDING: Self = Self {
1807 color: BlendComponent {
1808 src_factor: BlendFactor::SrcAlpha,
1809 dst_factor: BlendFactor::OneMinusSrcAlpha,
1810 operation: BlendOperation::Add,
1811 },
1812 alpha: BlendComponent::OVER,
1813 };
1814
1815 /// Blend mode that does standard alpha blending with premultiplied alpha.
1816 pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
1817 color: BlendComponent::OVER,
1818 alpha: BlendComponent::OVER,
1819 };
1820}
1821
1822/// Describes the color state of a render pipeline.
1823///
1824/// Corresponds to [WebGPU `GPUColorTargetState`](
1825/// https://gpuweb.github.io/gpuweb/#dictdef-gpucolortargetstate).
1826#[repr(C)]
1827#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1828#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1829#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1830pub struct ColorTargetState {
1831 /// The [`TextureFormat`] of the image that this pipeline will render to. Must match the format
1832 /// of the corresponding color attachment in [`CommandEncoder::begin_render_pass`][CEbrp]
1833 ///
1834 /// [CEbrp]: ../wgpu/struct.CommandEncoder.html#method.begin_render_pass
1835 pub format: TextureFormat,
1836 /// The blending that is used for this pipeline.
1837 #[cfg_attr(feature = "serde", serde(default))]
1838 pub blend: Option<BlendState>,
1839 /// Mask which enables/disables writes to different color/alpha channel.
1840 #[cfg_attr(feature = "serde", serde(default))]
1841 pub write_mask: ColorWrites,
1842}
1843
1844impl From<TextureFormat> for ColorTargetState {
1845 fn from(format: TextureFormat) -> Self {
1846 Self {
1847 format,
1848 blend: None,
1849 write_mask: ColorWrites::ALL,
1850 }
1851 }
1852}
1853
1854/// Primitive type the input mesh is composed of.
1855///
1856/// Corresponds to [WebGPU `GPUPrimitiveTopology`](
1857/// https://gpuweb.github.io/gpuweb/#enumdef-gpuprimitivetopology).
1858#[repr(C)]
1859#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1860#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1861#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1862pub enum PrimitiveTopology {
1863 /// Vertex data is a list of points. Each vertex is a new point.
1864 PointList = 0,
1865 /// Vertex data is a list of lines. Each pair of vertices composes a new line.
1866 ///
1867 /// Vertices `0 1 2 3` create two lines `0 1` and `2 3`
1868 LineList = 1,
1869 /// Vertex data is a strip of lines. Each set of two adjacent vertices form a line.
1870 ///
1871 /// Vertices `0 1 2 3` create three lines `0 1`, `1 2`, and `2 3`.
1872 LineStrip = 2,
1873 /// Vertex data is a list of triangles. Each set of 3 vertices composes a new triangle.
1874 ///
1875 /// Vertices `0 1 2 3 4 5` create two triangles `0 1 2` and `3 4 5`
1876 #[default]
1877 TriangleList = 3,
1878 /// Vertex data is a triangle strip. Each set of three adjacent vertices form a triangle.
1879 ///
1880 /// Vertices `0 1 2 3 4 5` create four triangles `0 1 2`, `2 1 3`, `2 3 4`, and `4 3 5`
1881 TriangleStrip = 4,
1882}
1883
1884impl PrimitiveTopology {
1885 /// Returns true for strip topologies.
1886 #[must_use]
1887 pub fn is_strip(&self) -> bool {
1888 match *self {
1889 Self::PointList | Self::LineList | Self::TriangleList => false,
1890 Self::LineStrip | Self::TriangleStrip => true,
1891 }
1892 }
1893}
1894
1895/// Vertex winding order which classifies the "front" face of a triangle.
1896///
1897/// Corresponds to [WebGPU `GPUFrontFace`](
1898/// https://gpuweb.github.io/gpuweb/#enumdef-gpufrontface).
1899#[repr(C)]
1900#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
1901#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1902#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1903pub enum FrontFace {
1904 /// Triangles with vertices in counter clockwise order are considered the front face.
1905 ///
1906 /// This is the default with right handed coordinate spaces.
1907 #[default]
1908 Ccw = 0,
1909 /// Triangles with vertices in clockwise order are considered the front face.
1910 ///
1911 /// This is the default with left handed coordinate spaces.
1912 Cw = 1,
1913}
1914
1915/// Face of a vertex.
1916///
1917/// Corresponds to [WebGPU `GPUCullMode`](
1918/// https://gpuweb.github.io/gpuweb/#enumdef-gpucullmode),
1919/// except that the `"none"` value is represented using `Option<Face>` instead.
1920#[repr(C)]
1921#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1922#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1923#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1924pub enum Face {
1925 /// Front face
1926 Front = 0,
1927 /// Back face
1928 Back = 1,
1929}
1930
1931/// Type of drawing mode for polygons
1932#[repr(C)]
1933#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
1934#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1935#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
1936pub enum PolygonMode {
1937 /// Polygons are filled
1938 #[default]
1939 Fill = 0,
1940 /// Polygons are drawn as line segments
1941 Line = 1,
1942 /// Polygons are drawn as points
1943 Point = 2,
1944}
1945
1946/// Describes the state of primitive assembly and rasterization in a render pipeline.
1947///
1948/// Corresponds to [WebGPU `GPUPrimitiveState`](
1949/// https://gpuweb.github.io/gpuweb/#dictdef-gpuprimitivestate).
1950#[repr(C)]
1951#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
1952#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1953#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1954pub struct PrimitiveState {
1955 /// The primitive topology used to interpret vertices.
1956 pub topology: PrimitiveTopology,
1957 /// When drawing strip topologies with indices, this is the required format for the index buffer.
1958 /// This has no effect on non-indexed or non-strip draws.
1959 ///
1960 /// Specifying this value enables primitive restart, allowing individual strips to be separated
1961 /// with the index value `0xFFFF` when using `Uint16`, or `0xFFFFFFFF` when using `Uint32`.
1962 #[cfg_attr(feature = "serde", serde(default))]
1963 pub strip_index_format: Option<IndexFormat>,
1964 /// The face to consider the front for the purpose of culling and stencil operations.
1965 #[cfg_attr(feature = "serde", serde(default))]
1966 pub front_face: FrontFace,
1967 /// The face culling mode.
1968 #[cfg_attr(feature = "serde", serde(default))]
1969 pub cull_mode: Option<Face>,
1970 /// If set to true, the polygon depth is not clipped to 0-1 before rasterization.
1971 ///
1972 /// Enabling this requires [`Features::DEPTH_CLIP_CONTROL`] to be enabled.
1973 #[cfg_attr(feature = "serde", serde(default))]
1974 pub unclipped_depth: bool,
1975 /// Controls the way each polygon is rasterized. Can be either `Fill` (default), `Line` or `Point`
1976 ///
1977 /// Setting this to `Line` requires [`Features::POLYGON_MODE_LINE`] to be enabled.
1978 ///
1979 /// Setting this to `Point` requires [`Features::POLYGON_MODE_POINT`] to be enabled.
1980 #[cfg_attr(feature = "serde", serde(default))]
1981 pub polygon_mode: PolygonMode,
1982 /// If set to true, the primitives are rendered with conservative overestimation. I.e. any rastered pixel touched by it is filled.
1983 /// Only valid for `[PolygonMode::Fill`]!
1984 ///
1985 /// Enabling this requires [`Features::CONSERVATIVE_RASTERIZATION`] to be enabled.
1986 pub conservative: bool,
1987}
1988
1989/// Describes the multi-sampling state of a render pipeline.
1990///
1991/// Corresponds to [WebGPU `GPUMultisampleState`](
1992/// https://gpuweb.github.io/gpuweb/#dictdef-gpumultisamplestate).
1993#[repr(C)]
1994#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1995#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1996#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1997pub struct MultisampleState {
1998 /// The number of samples calculated per pixel (for MSAA). For non-multisampled textures,
1999 /// this should be `1`
2000 pub count: u32,
2001 /// Bitmask that restricts the samples of a pixel modified by this pipeline. All samples
2002 /// can be enabled using the value `!0`
2003 pub mask: u64,
2004 /// When enabled, produces another sample mask per pixel based on the alpha output value, that
2005 /// is ANDed with the sample mask and the primitive coverage to restrict the set of samples
2006 /// affected by a primitive.
2007 ///
2008 /// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one
2009 /// is guaranteed to be all 1-s.
2010 pub alpha_to_coverage_enabled: bool,
2011}
2012
2013impl Default for MultisampleState {
2014 fn default() -> Self {
2015 MultisampleState {
2016 count: 1,
2017 mask: !0,
2018 alpha_to_coverage_enabled: false,
2019 }
2020 }
2021}
2022
2023bitflags::bitflags! {
2024 /// Feature flags for a texture format.
2025 #[repr(transparent)]
2026 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2027 #[cfg_attr(feature = "serde", serde(transparent))]
2028 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2029 pub struct TextureFormatFeatureFlags: u32 {
2030 /// If not present, the texture can't be sampled with a filtering sampler.
2031 /// This may overwrite TextureSampleType::Float.filterable
2032 const FILTERABLE = 1 << 0;
2033 /// Allows [`TextureDescriptor::sample_count`] to be `2`.
2034 const MULTISAMPLE_X2 = 1 << 1;
2035 /// Allows [`TextureDescriptor::sample_count`] to be `4`.
2036 const MULTISAMPLE_X4 = 1 << 2 ;
2037 /// Allows [`TextureDescriptor::sample_count`] to be `8`.
2038 const MULTISAMPLE_X8 = 1 << 3 ;
2039 /// Allows [`TextureDescriptor::sample_count`] to be `16`.
2040 const MULTISAMPLE_X16 = 1 << 4;
2041 /// Allows a texture of this format to back a view passed as `resolve_target`
2042 /// to a render pass for an automatic driver-implemented resolve.
2043 const MULTISAMPLE_RESOLVE = 1 << 5;
2044 /// When used as a STORAGE texture, then a texture with this format can be bound with
2045 /// [`StorageTextureAccess::ReadOnly`].
2046 const STORAGE_READ_ONLY = 1 << 6;
2047 /// When used as a STORAGE texture, then a texture with this format can be bound with
2048 /// [`StorageTextureAccess::WriteOnly`].
2049 const STORAGE_WRITE_ONLY = 1 << 7;
2050 /// When used as a STORAGE texture, then a texture with this format can be bound with
2051 /// [`StorageTextureAccess::ReadWrite`].
2052 const STORAGE_READ_WRITE = 1 << 8;
2053 /// When used as a STORAGE texture, then a texture with this format can be bound with
2054 /// [`StorageTextureAccess::Atomic`].
2055 const STORAGE_ATOMIC = 1 << 9;
2056 /// If not present, the texture can't be blended into the render target.
2057 const BLENDABLE = 1 << 10;
2058 }
2059}
2060
2061impl TextureFormatFeatureFlags {
2062 /// Sample count supported by a given texture format.
2063 ///
2064 /// returns `true` if `count` is a supported sample count.
2065 #[must_use]
2066 pub fn sample_count_supported(&self, count: u32) -> bool {
2067 use TextureFormatFeatureFlags as tfsc;
2068
2069 match count {
2070 1 => true,
2071 2 => self.contains(tfsc::MULTISAMPLE_X2),
2072 4 => self.contains(tfsc::MULTISAMPLE_X4),
2073 8 => self.contains(tfsc::MULTISAMPLE_X8),
2074 16 => self.contains(tfsc::MULTISAMPLE_X16),
2075 _ => false,
2076 }
2077 }
2078
2079 /// A `Vec` of supported sample counts.
2080 #[must_use]
2081 pub fn supported_sample_counts(&self) -> Vec<u32> {
2082 let all_possible_sample_counts: [u32; 5] = [1, 2, 4, 8, 16];
2083 all_possible_sample_counts
2084 .into_iter()
2085 .filter(|&sc| self.sample_count_supported(sc))
2086 .collect()
2087 }
2088}
2089
2090/// Features supported by a given texture format
2091///
2092/// Features are defined by WebGPU specification unless [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] is enabled.
2093#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
2094#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2095pub struct TextureFormatFeatures {
2096 /// Valid bits for `TextureDescriptor::Usage` provided for format creation.
2097 pub allowed_usages: TextureUsages,
2098 /// Additional property flags for the format.
2099 pub flags: TextureFormatFeatureFlags,
2100}
2101
2102/// ASTC block dimensions
2103#[repr(C)]
2104#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
2105#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2106pub enum AstcBlock {
2107 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px).
2108 B4x4,
2109 /// 5x4 block compressed texture. 16 bytes per block (6.4 bit/px).
2110 B5x4,
2111 /// 5x5 block compressed texture. 16 bytes per block (5.12 bit/px).
2112 B5x5,
2113 /// 6x5 block compressed texture. 16 bytes per block (4.27 bit/px).
2114 B6x5,
2115 /// 6x6 block compressed texture. 16 bytes per block (3.56 bit/px).
2116 B6x6,
2117 /// 8x5 block compressed texture. 16 bytes per block (3.2 bit/px).
2118 B8x5,
2119 /// 8x6 block compressed texture. 16 bytes per block (2.67 bit/px).
2120 B8x6,
2121 /// 8x8 block compressed texture. 16 bytes per block (2 bit/px).
2122 B8x8,
2123 /// 10x5 block compressed texture. 16 bytes per block (2.56 bit/px).
2124 B10x5,
2125 /// 10x6 block compressed texture. 16 bytes per block (2.13 bit/px).
2126 B10x6,
2127 /// 10x8 block compressed texture. 16 bytes per block (1.6 bit/px).
2128 B10x8,
2129 /// 10x10 block compressed texture. 16 bytes per block (1.28 bit/px).
2130 B10x10,
2131 /// 12x10 block compressed texture. 16 bytes per block (1.07 bit/px).
2132 B12x10,
2133 /// 12x12 block compressed texture. 16 bytes per block (0.89 bit/px).
2134 B12x12,
2135}
2136
2137/// ASTC RGBA channel
2138#[repr(C)]
2139#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
2140#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2141pub enum AstcChannel {
2142 /// 8 bit integer RGBA, [0, 255] converted to/from linear-color float [0, 1] in shader.
2143 ///
2144 /// [`Features::TEXTURE_COMPRESSION_ASTC`] must be enabled to use this channel.
2145 Unorm,
2146 /// 8 bit integer RGBA, Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2147 ///
2148 /// [`Features::TEXTURE_COMPRESSION_ASTC`] must be enabled to use this channel.
2149 UnormSrgb,
2150 /// floating-point RGBA, linear-color float can be outside of the [0, 1] range.
2151 ///
2152 /// [`Features::TEXTURE_COMPRESSION_ASTC_HDR`] must be enabled to use this channel.
2153 Hdr,
2154}
2155
2156/// Format in which a texture’s texels are stored in GPU memory.
2157///
2158/// Certain formats additionally specify a conversion.
2159/// When these formats are used in a shader, the conversion automatically takes place when loading
2160/// from or storing to the texture.
2161///
2162/// * `Unorm` formats linearly scale the integer range of the storage format to a floating-point
2163/// range of 0 to 1, inclusive.
2164/// * `Snorm` formats linearly scale the integer range of the storage format to a floating-point
2165/// range of −1 to 1, inclusive, except that the most negative value
2166/// (−128 for 8-bit, −32768 for 16-bit) is excluded; on conversion,
2167/// it is treated as identical to the second most negative
2168/// (−127 for 8-bit, −32767 for 16-bit),
2169/// so that the positive and negative ranges are symmetric.
2170/// * `UnormSrgb` formats apply the [sRGB transfer function] so that the storage is sRGB encoded
2171/// while the shader works with linear intensity values.
2172/// * `Uint`, `Sint`, and `Float` formats perform no conversion.
2173///
2174/// Corresponds to [WebGPU `GPUTextureFormat`](
2175/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureformat).
2176///
2177/// [sRGB transfer function]: https://en.wikipedia.org/wiki/SRGB#Transfer_function_(%22gamma%22)
2178#[repr(C)]
2179#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
2180pub enum TextureFormat {
2181 // Normal 8 bit formats
2182 /// Red channel only. 8 bit integer per channel. [0, 255] converted to/from float [0, 1] in shader.
2183 R8Unorm,
2184 /// Red channel only. 8 bit integer per channel. [−127, 127] converted to/from float [−1, 1] in shader.
2185 R8Snorm,
2186 /// Red channel only. 8 bit integer per channel. Unsigned in shader.
2187 R8Uint,
2188 /// Red channel only. 8 bit integer per channel. Signed in shader.
2189 R8Sint,
2190
2191 // Normal 16 bit formats
2192 /// Red channel only. 16 bit integer per channel. Unsigned in shader.
2193 R16Uint,
2194 /// Red channel only. 16 bit integer per channel. Signed in shader.
2195 R16Sint,
2196 /// Red channel only. 16 bit integer per channel. [0, 65535] converted to/from float [0, 1] in shader.
2197 ///
2198 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2199 R16Unorm,
2200 /// Red channel only. 16 bit integer per channel. [−32767, 32767] converted to/from float [−1, 1] in shader.
2201 ///
2202 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2203 R16Snorm,
2204 /// Red channel only. 16 bit float per channel. Float in shader.
2205 R16Float,
2206 /// Red and green channels. 8 bit integer per channel. [0, 255] converted to/from float [0, 1] in shader.
2207 Rg8Unorm,
2208 /// Red and green channels. 8 bit integer per channel. [−127, 127] converted to/from float [−1, 1] in shader.
2209 Rg8Snorm,
2210 /// Red and green channels. 8 bit integer per channel. Unsigned in shader.
2211 Rg8Uint,
2212 /// Red and green channels. 8 bit integer per channel. Signed in shader.
2213 Rg8Sint,
2214
2215 // Normal 32 bit formats
2216 /// Red channel only. 32 bit integer per channel. Unsigned in shader.
2217 R32Uint,
2218 /// Red channel only. 32 bit integer per channel. Signed in shader.
2219 R32Sint,
2220 /// Red channel only. 32 bit float per channel. Float in shader.
2221 R32Float,
2222 /// Red and green channels. 16 bit integer per channel. Unsigned in shader.
2223 Rg16Uint,
2224 /// Red and green channels. 16 bit integer per channel. Signed in shader.
2225 Rg16Sint,
2226 /// Red and green channels. 16 bit integer per channel. [0, 65535] converted to/from float [0, 1] in shader.
2227 ///
2228 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2229 Rg16Unorm,
2230 /// Red and green channels. 16 bit integer per channel. [−32767, 32767] converted to/from float [−1, 1] in shader.
2231 ///
2232 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2233 Rg16Snorm,
2234 /// Red and green channels. 16 bit float per channel. Float in shader.
2235 Rg16Float,
2236 /// Red, green, blue, and alpha channels. 8 bit integer per channel. [0, 255] converted to/from float [0, 1] in shader.
2237 Rgba8Unorm,
2238 /// Red, green, blue, and alpha channels. 8 bit integer per channel. Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2239 Rgba8UnormSrgb,
2240 /// Red, green, blue, and alpha channels. 8 bit integer per channel. [−127, 127] converted to/from float [−1, 1] in shader.
2241 Rgba8Snorm,
2242 /// Red, green, blue, and alpha channels. 8 bit integer per channel. Unsigned in shader.
2243 Rgba8Uint,
2244 /// Red, green, blue, and alpha channels. 8 bit integer per channel. Signed in shader.
2245 Rgba8Sint,
2246 /// Blue, green, red, and alpha channels. 8 bit integer per channel. [0, 255] converted to/from float [0, 1] in shader.
2247 Bgra8Unorm,
2248 /// Blue, green, red, and alpha channels. 8 bit integer per channel. Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2249 Bgra8UnormSrgb,
2250
2251 // Packed 32 bit formats
2252 /// Packed unsigned float with 9 bits mantisa for each RGB component, then a common 5 bits exponent
2253 Rgb9e5Ufloat,
2254 /// Red, green, blue, and alpha channels. 10 bit integer for RGB channels, 2 bit integer for alpha channel. Unsigned in shader.
2255 Rgb10a2Uint,
2256 /// Red, green, blue, and alpha channels. 10 bit integer for RGB channels, 2 bit integer for alpha channel. [0, 1023] ([0, 3] for alpha) converted to/from float [0, 1] in shader.
2257 Rgb10a2Unorm,
2258 /// Red, green, and blue channels. 11 bit float with no sign bit for RG channels. 10 bit float with no sign bit for blue channel. Float in shader.
2259 Rg11b10Ufloat,
2260
2261 // Normal 64 bit formats
2262 /// Red channel only. 64 bit integer per channel. Unsigned in shader.
2263 ///
2264 /// [`Features::TEXTURE_INT64_ATOMIC`] must be enabled to use this texture format.
2265 R64Uint,
2266 /// Red and green channels. 32 bit integer per channel. Unsigned in shader.
2267 Rg32Uint,
2268 /// Red and green channels. 32 bit integer per channel. Signed in shader.
2269 Rg32Sint,
2270 /// Red and green channels. 32 bit float per channel. Float in shader.
2271 Rg32Float,
2272 /// Red, green, blue, and alpha channels. 16 bit integer per channel. Unsigned in shader.
2273 Rgba16Uint,
2274 /// Red, green, blue, and alpha channels. 16 bit integer per channel. Signed in shader.
2275 Rgba16Sint,
2276 /// Red, green, blue, and alpha channels. 16 bit integer per channel. [0, 65535] converted to/from float [0, 1] in shader.
2277 ///
2278 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2279 Rgba16Unorm,
2280 /// Red, green, blue, and alpha. 16 bit integer per channel. [−32767, 32767] converted to/from float [−1, 1] in shader.
2281 ///
2282 /// [`Features::TEXTURE_FORMAT_16BIT_NORM`] must be enabled to use this texture format.
2283 Rgba16Snorm,
2284 /// Red, green, blue, and alpha channels. 16 bit float per channel. Float in shader.
2285 Rgba16Float,
2286
2287 // Normal 128 bit formats
2288 /// Red, green, blue, and alpha channels. 32 bit integer per channel. Unsigned in shader.
2289 Rgba32Uint,
2290 /// Red, green, blue, and alpha channels. 32 bit integer per channel. Signed in shader.
2291 Rgba32Sint,
2292 /// Red, green, blue, and alpha channels. 32 bit float per channel. Float in shader.
2293 Rgba32Float,
2294
2295 // Depth and stencil formats
2296 /// Stencil format with 8 bit integer stencil.
2297 Stencil8,
2298 /// Special depth format with 16 bit integer depth.
2299 Depth16Unorm,
2300 /// Special depth format with at least 24 bit integer depth.
2301 Depth24Plus,
2302 /// Special depth/stencil format with at least 24 bit integer depth and 8 bits integer stencil.
2303 Depth24PlusStencil8,
2304 /// Special depth format with 32 bit floating point depth.
2305 Depth32Float,
2306 /// Special depth/stencil format with 32 bit floating point depth and 8 bits integer stencil.
2307 ///
2308 /// [`Features::DEPTH32FLOAT_STENCIL8`] must be enabled to use this texture format.
2309 Depth32FloatStencil8,
2310
2311 /// YUV 4:2:0 chroma subsampled format.
2312 ///
2313 /// Contains two planes:
2314 /// - 0: Single 8 bit channel luminance.
2315 /// - 1: Dual 8 bit channel chrominance at half width and half height.
2316 ///
2317 /// Valid view formats for luminance are [`TextureFormat::R8Unorm`].
2318 ///
2319 /// Valid view formats for chrominance are [`TextureFormat::Rg8Unorm`].
2320 ///
2321 /// Width and height must be even.
2322 ///
2323 /// [`Features::TEXTURE_FORMAT_NV12`] must be enabled to use this texture format.
2324 NV12,
2325
2326 /// YUV 4:2:0 chroma subsampled format.
2327 ///
2328 /// Contains two planes:
2329 /// - 0: Single 16 bit channel luminance, of which only the high 10 bits
2330 /// are used.
2331 /// - 1: Dual 16 bit channel chrominance at half width and half height, of
2332 /// which only the high 10 bits are used.
2333 ///
2334 /// Valid view formats for luminance are [`TextureFormat::R16Unorm`].
2335 ///
2336 /// Valid view formats for chrominance are [`TextureFormat::Rg16Unorm`].
2337 ///
2338 /// Width and height must be even.
2339 ///
2340 /// [`Features::TEXTURE_FORMAT_P010`] must be enabled to use this texture format.
2341 P010,
2342
2343 // Compressed textures usable with `TEXTURE_COMPRESSION_BC` feature. `TEXTURE_COMPRESSION_SLICED_3D` is required to use with 3D textures.
2344 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). 4 color + alpha pallet. 5 bit R + 6 bit G + 5 bit B + 1 bit alpha.
2345 /// [0, 63] ([0, 1] for alpha) converted to/from float [0, 1] in shader.
2346 ///
2347 /// Also known as DXT1.
2348 ///
2349 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2350 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2351 Bc1RgbaUnorm,
2352 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). 4 color + alpha pallet. 5 bit R + 6 bit G + 5 bit B + 1 bit alpha.
2353 /// Srgb-color [0, 63] ([0, 1] for alpha) converted to/from linear-color float [0, 1] in shader.
2354 ///
2355 /// Also known as DXT1.
2356 ///
2357 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2358 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2359 Bc1RgbaUnormSrgb,
2360 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 4 color pallet. 5 bit R + 6 bit G + 5 bit B + 4 bit alpha.
2361 /// [0, 63] ([0, 15] for alpha) converted to/from float [0, 1] in shader.
2362 ///
2363 /// Also known as DXT3.
2364 ///
2365 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2366 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2367 Bc2RgbaUnorm,
2368 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 4 color pallet. 5 bit R + 6 bit G + 5 bit B + 4 bit alpha.
2369 /// Srgb-color [0, 63] ([0, 255] for alpha) converted to/from linear-color float [0, 1] in shader.
2370 ///
2371 /// Also known as DXT3.
2372 ///
2373 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2374 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2375 Bc2RgbaUnormSrgb,
2376 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 4 color pallet + 8 alpha pallet. 5 bit R + 6 bit G + 5 bit B + 8 bit alpha.
2377 /// [0, 63] ([0, 255] for alpha) converted to/from float [0, 1] in shader.
2378 ///
2379 /// Also known as DXT5.
2380 ///
2381 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2382 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2383 Bc3RgbaUnorm,
2384 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 4 color pallet + 8 alpha pallet. 5 bit R + 6 bit G + 5 bit B + 8 bit alpha.
2385 /// Srgb-color [0, 63] ([0, 255] for alpha) converted to/from linear-color float [0, 1] in shader.
2386 ///
2387 /// Also known as DXT5.
2388 ///
2389 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2390 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2391 Bc3RgbaUnormSrgb,
2392 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). 8 color pallet. 8 bit R.
2393 /// [0, 255] converted to/from float [0, 1] in shader.
2394 ///
2395 /// Also known as RGTC1.
2396 ///
2397 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2398 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2399 Bc4RUnorm,
2400 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). 8 color pallet. 8 bit R.
2401 /// [−127, 127] converted to/from float [−1, 1] in shader.
2402 ///
2403 /// Also known as RGTC1.
2404 ///
2405 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2406 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2407 Bc4RSnorm,
2408 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 8 color red pallet + 8 color green pallet. 8 bit RG.
2409 /// [0, 255] converted to/from float [0, 1] in shader.
2410 ///
2411 /// Also known as RGTC2.
2412 ///
2413 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2414 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2415 Bc5RgUnorm,
2416 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). 8 color red pallet + 8 color green pallet. 8 bit RG.
2417 /// [−127, 127] converted to/from float [−1, 1] in shader.
2418 ///
2419 /// Also known as RGTC2.
2420 ///
2421 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2422 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2423 Bc5RgSnorm,
2424 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Variable sized pallet. 16 bit unsigned float RGB. Float in shader.
2425 ///
2426 /// Also known as BPTC (float).
2427 ///
2428 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2429 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2430 Bc6hRgbUfloat,
2431 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Variable sized pallet. 16 bit signed float RGB. Float in shader.
2432 ///
2433 /// Also known as BPTC (float).
2434 ///
2435 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2436 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2437 Bc6hRgbFloat,
2438 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Variable sized pallet. 8 bit integer RGBA.
2439 /// [0, 255] converted to/from float [0, 1] in shader.
2440 ///
2441 /// Also known as BPTC (unorm).
2442 ///
2443 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2444 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2445 Bc7RgbaUnorm,
2446 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Variable sized pallet. 8 bit integer RGBA.
2447 /// Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2448 ///
2449 /// Also known as BPTC (unorm).
2450 ///
2451 /// [`Features::TEXTURE_COMPRESSION_BC`] must be enabled to use this texture format.
2452 /// [`Features::TEXTURE_COMPRESSION_BC_SLICED_3D`] must be enabled to use this texture format with 3D dimension.
2453 Bc7RgbaUnormSrgb,
2454 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 8 bit integer RGB.
2455 /// [0, 255] converted to/from float [0, 1] in shader.
2456 ///
2457 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2458 Etc2Rgb8Unorm,
2459 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 8 bit integer RGB.
2460 /// Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2461 ///
2462 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2463 Etc2Rgb8UnormSrgb,
2464 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 8 bit integer RGB + 1 bit alpha.
2465 /// [0, 255] ([0, 1] for alpha) converted to/from float [0, 1] in shader.
2466 ///
2467 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2468 Etc2Rgb8A1Unorm,
2469 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 8 bit integer RGB + 1 bit alpha.
2470 /// Srgb-color [0, 255] ([0, 1] for alpha) converted to/from linear-color float [0, 1] in shader.
2471 ///
2472 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2473 Etc2Rgb8A1UnormSrgb,
2474 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer RGB + 8 bit alpha.
2475 /// [0, 255] converted to/from float [0, 1] in shader.
2476 ///
2477 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2478 Etc2Rgba8Unorm,
2479 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer RGB + 8 bit alpha.
2480 /// Srgb-color [0, 255] converted to/from linear-color float [0, 1] in shader.
2481 ///
2482 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2483 Etc2Rgba8UnormSrgb,
2484 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 11 bit integer R.
2485 /// [0, 255] converted to/from float [0, 1] in shader.
2486 ///
2487 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2488 EacR11Unorm,
2489 /// 4x4 block compressed texture. 8 bytes per block (4 bit/px). Complex pallet. 11 bit integer R.
2490 /// [−127, 127] converted to/from float [−1, 1] in shader.
2491 ///
2492 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2493 EacR11Snorm,
2494 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 11 bit integer R + 11 bit integer G.
2495 /// [0, 255] converted to/from float [0, 1] in shader.
2496 ///
2497 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2498 EacRg11Unorm,
2499 /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 11 bit integer R + 11 bit integer G.
2500 /// [−127, 127] converted to/from float [−1, 1] in shader.
2501 ///
2502 /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format.
2503 EacRg11Snorm,
2504 /// block compressed texture. 16 bytes per block.
2505 ///
2506 /// Features [`TEXTURE_COMPRESSION_ASTC`] or [`TEXTURE_COMPRESSION_ASTC_HDR`]
2507 /// must be enabled to use this texture format.
2508 ///
2509 /// [`TEXTURE_COMPRESSION_ASTC`]: Features::TEXTURE_COMPRESSION_ASTC
2510 /// [`TEXTURE_COMPRESSION_ASTC_HDR`]: Features::TEXTURE_COMPRESSION_ASTC_HDR
2511 Astc {
2512 /// compressed block dimensions
2513 block: AstcBlock,
2514 /// ASTC RGBA channel
2515 channel: AstcChannel,
2516 },
2517}
2518
2519#[cfg(any(feature = "serde", test))]
2520impl<'de> Deserialize<'de> for TextureFormat {
2521 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2522 where
2523 D: serde::Deserializer<'de>,
2524 {
2525 use serde::de::{self, Error, Unexpected};
2526
2527 struct TextureFormatVisitor;
2528
2529 impl de::Visitor<'_> for TextureFormatVisitor {
2530 type Value = TextureFormat;
2531
2532 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
2533 formatter.write_str("a valid texture format")
2534 }
2535
2536 fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E> {
2537 let format = match s {
2538 "r8unorm" => TextureFormat::R8Unorm,
2539 "r8snorm" => TextureFormat::R8Snorm,
2540 "r8uint" => TextureFormat::R8Uint,
2541 "r8sint" => TextureFormat::R8Sint,
2542 "r16uint" => TextureFormat::R16Uint,
2543 "r16sint" => TextureFormat::R16Sint,
2544 "r16unorm" => TextureFormat::R16Unorm,
2545 "r16snorm" => TextureFormat::R16Snorm,
2546 "r16float" => TextureFormat::R16Float,
2547 "rg8unorm" => TextureFormat::Rg8Unorm,
2548 "rg8snorm" => TextureFormat::Rg8Snorm,
2549 "rg8uint" => TextureFormat::Rg8Uint,
2550 "rg8sint" => TextureFormat::Rg8Sint,
2551 "r32uint" => TextureFormat::R32Uint,
2552 "r32sint" => TextureFormat::R32Sint,
2553 "r32float" => TextureFormat::R32Float,
2554 "rg16uint" => TextureFormat::Rg16Uint,
2555 "rg16sint" => TextureFormat::Rg16Sint,
2556 "rg16unorm" => TextureFormat::Rg16Unorm,
2557 "rg16snorm" => TextureFormat::Rg16Snorm,
2558 "rg16float" => TextureFormat::Rg16Float,
2559 "rgba8unorm" => TextureFormat::Rgba8Unorm,
2560 "rgba8unorm-srgb" => TextureFormat::Rgba8UnormSrgb,
2561 "rgba8snorm" => TextureFormat::Rgba8Snorm,
2562 "rgba8uint" => TextureFormat::Rgba8Uint,
2563 "rgba8sint" => TextureFormat::Rgba8Sint,
2564 "bgra8unorm" => TextureFormat::Bgra8Unorm,
2565 "bgra8unorm-srgb" => TextureFormat::Bgra8UnormSrgb,
2566 "rgb10a2uint" => TextureFormat::Rgb10a2Uint,
2567 "rgb10a2unorm" => TextureFormat::Rgb10a2Unorm,
2568 "rg11b10ufloat" => TextureFormat::Rg11b10Ufloat,
2569 "r64uint" => TextureFormat::R64Uint,
2570 "rg32uint" => TextureFormat::Rg32Uint,
2571 "rg32sint" => TextureFormat::Rg32Sint,
2572 "rg32float" => TextureFormat::Rg32Float,
2573 "rgba16uint" => TextureFormat::Rgba16Uint,
2574 "rgba16sint" => TextureFormat::Rgba16Sint,
2575 "rgba16unorm" => TextureFormat::Rgba16Unorm,
2576 "rgba16snorm" => TextureFormat::Rgba16Snorm,
2577 "rgba16float" => TextureFormat::Rgba16Float,
2578 "rgba32uint" => TextureFormat::Rgba32Uint,
2579 "rgba32sint" => TextureFormat::Rgba32Sint,
2580 "rgba32float" => TextureFormat::Rgba32Float,
2581 "stencil8" => TextureFormat::Stencil8,
2582 "depth32float" => TextureFormat::Depth32Float,
2583 "depth32float-stencil8" => TextureFormat::Depth32FloatStencil8,
2584 "depth16unorm" => TextureFormat::Depth16Unorm,
2585 "depth24plus" => TextureFormat::Depth24Plus,
2586 "depth24plus-stencil8" => TextureFormat::Depth24PlusStencil8,
2587 "nv12" => TextureFormat::NV12,
2588 "p010" => TextureFormat::P010,
2589 "rgb9e5ufloat" => TextureFormat::Rgb9e5Ufloat,
2590 "bc1-rgba-unorm" => TextureFormat::Bc1RgbaUnorm,
2591 "bc1-rgba-unorm-srgb" => TextureFormat::Bc1RgbaUnormSrgb,
2592 "bc2-rgba-unorm" => TextureFormat::Bc2RgbaUnorm,
2593 "bc2-rgba-unorm-srgb" => TextureFormat::Bc2RgbaUnormSrgb,
2594 "bc3-rgba-unorm" => TextureFormat::Bc3RgbaUnorm,
2595 "bc3-rgba-unorm-srgb" => TextureFormat::Bc3RgbaUnormSrgb,
2596 "bc4-r-unorm" => TextureFormat::Bc4RUnorm,
2597 "bc4-r-snorm" => TextureFormat::Bc4RSnorm,
2598 "bc5-rg-unorm" => TextureFormat::Bc5RgUnorm,
2599 "bc5-rg-snorm" => TextureFormat::Bc5RgSnorm,
2600 "bc6h-rgb-ufloat" => TextureFormat::Bc6hRgbUfloat,
2601 "bc6h-rgb-float" => TextureFormat::Bc6hRgbFloat,
2602 "bc7-rgba-unorm" => TextureFormat::Bc7RgbaUnorm,
2603 "bc7-rgba-unorm-srgb" => TextureFormat::Bc7RgbaUnormSrgb,
2604 "etc2-rgb8unorm" => TextureFormat::Etc2Rgb8Unorm,
2605 "etc2-rgb8unorm-srgb" => TextureFormat::Etc2Rgb8UnormSrgb,
2606 "etc2-rgb8a1unorm" => TextureFormat::Etc2Rgb8A1Unorm,
2607 "etc2-rgb8a1unorm-srgb" => TextureFormat::Etc2Rgb8A1UnormSrgb,
2608 "etc2-rgba8unorm" => TextureFormat::Etc2Rgba8Unorm,
2609 "etc2-rgba8unorm-srgb" => TextureFormat::Etc2Rgba8UnormSrgb,
2610 "eac-r11unorm" => TextureFormat::EacR11Unorm,
2611 "eac-r11snorm" => TextureFormat::EacR11Snorm,
2612 "eac-rg11unorm" => TextureFormat::EacRg11Unorm,
2613 "eac-rg11snorm" => TextureFormat::EacRg11Snorm,
2614 other => {
2615 if let Some(parts) = other.strip_prefix("astc-") {
2616 let (block, channel) = parts
2617 .split_once('-')
2618 .ok_or_else(|| E::invalid_value(Unexpected::Str(s), &self))?;
2619
2620 let block = match block {
2621 "4x4" => AstcBlock::B4x4,
2622 "5x4" => AstcBlock::B5x4,
2623 "5x5" => AstcBlock::B5x5,
2624 "6x5" => AstcBlock::B6x5,
2625 "6x6" => AstcBlock::B6x6,
2626 "8x5" => AstcBlock::B8x5,
2627 "8x6" => AstcBlock::B8x6,
2628 "8x8" => AstcBlock::B8x8,
2629 "10x5" => AstcBlock::B10x5,
2630 "10x6" => AstcBlock::B10x6,
2631 "10x8" => AstcBlock::B10x8,
2632 "10x10" => AstcBlock::B10x10,
2633 "12x10" => AstcBlock::B12x10,
2634 "12x12" => AstcBlock::B12x12,
2635 _ => return Err(E::invalid_value(Unexpected::Str(s), &self)),
2636 };
2637
2638 let channel = match channel {
2639 "unorm" => AstcChannel::Unorm,
2640 "unorm-srgb" => AstcChannel::UnormSrgb,
2641 "hdr" => AstcChannel::Hdr,
2642 _ => return Err(E::invalid_value(Unexpected::Str(s), &self)),
2643 };
2644
2645 TextureFormat::Astc { block, channel }
2646 } else {
2647 return Err(E::invalid_value(Unexpected::Str(s), &self));
2648 }
2649 }
2650 };
2651
2652 Ok(format)
2653 }
2654 }
2655
2656 deserializer.deserialize_str(TextureFormatVisitor)
2657 }
2658}
2659
2660#[cfg(any(feature = "serde", test))]
2661impl Serialize for TextureFormat {
2662 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2663 where
2664 S: serde::Serializer,
2665 {
2666 let s: String;
2667 let name = match *self {
2668 TextureFormat::R8Unorm => "r8unorm",
2669 TextureFormat::R8Snorm => "r8snorm",
2670 TextureFormat::R8Uint => "r8uint",
2671 TextureFormat::R8Sint => "r8sint",
2672 TextureFormat::R16Uint => "r16uint",
2673 TextureFormat::R16Sint => "r16sint",
2674 TextureFormat::R16Unorm => "r16unorm",
2675 TextureFormat::R16Snorm => "r16snorm",
2676 TextureFormat::R16Float => "r16float",
2677 TextureFormat::Rg8Unorm => "rg8unorm",
2678 TextureFormat::Rg8Snorm => "rg8snorm",
2679 TextureFormat::Rg8Uint => "rg8uint",
2680 TextureFormat::Rg8Sint => "rg8sint",
2681 TextureFormat::R32Uint => "r32uint",
2682 TextureFormat::R32Sint => "r32sint",
2683 TextureFormat::R32Float => "r32float",
2684 TextureFormat::Rg16Uint => "rg16uint",
2685 TextureFormat::Rg16Sint => "rg16sint",
2686 TextureFormat::Rg16Unorm => "rg16unorm",
2687 TextureFormat::Rg16Snorm => "rg16snorm",
2688 TextureFormat::Rg16Float => "rg16float",
2689 TextureFormat::Rgba8Unorm => "rgba8unorm",
2690 TextureFormat::Rgba8UnormSrgb => "rgba8unorm-srgb",
2691 TextureFormat::Rgba8Snorm => "rgba8snorm",
2692 TextureFormat::Rgba8Uint => "rgba8uint",
2693 TextureFormat::Rgba8Sint => "rgba8sint",
2694 TextureFormat::Bgra8Unorm => "bgra8unorm",
2695 TextureFormat::Bgra8UnormSrgb => "bgra8unorm-srgb",
2696 TextureFormat::Rgb10a2Uint => "rgb10a2uint",
2697 TextureFormat::Rgb10a2Unorm => "rgb10a2unorm",
2698 TextureFormat::Rg11b10Ufloat => "rg11b10ufloat",
2699 TextureFormat::R64Uint => "r64uint",
2700 TextureFormat::Rg32Uint => "rg32uint",
2701 TextureFormat::Rg32Sint => "rg32sint",
2702 TextureFormat::Rg32Float => "rg32float",
2703 TextureFormat::Rgba16Uint => "rgba16uint",
2704 TextureFormat::Rgba16Sint => "rgba16sint",
2705 TextureFormat::Rgba16Unorm => "rgba16unorm",
2706 TextureFormat::Rgba16Snorm => "rgba16snorm",
2707 TextureFormat::Rgba16Float => "rgba16float",
2708 TextureFormat::Rgba32Uint => "rgba32uint",
2709 TextureFormat::Rgba32Sint => "rgba32sint",
2710 TextureFormat::Rgba32Float => "rgba32float",
2711 TextureFormat::Stencil8 => "stencil8",
2712 TextureFormat::Depth32Float => "depth32float",
2713 TextureFormat::Depth16Unorm => "depth16unorm",
2714 TextureFormat::Depth32FloatStencil8 => "depth32float-stencil8",
2715 TextureFormat::Depth24Plus => "depth24plus",
2716 TextureFormat::Depth24PlusStencil8 => "depth24plus-stencil8",
2717 TextureFormat::NV12 => "nv12",
2718 TextureFormat::P010 => "p010",
2719 TextureFormat::Rgb9e5Ufloat => "rgb9e5ufloat",
2720 TextureFormat::Bc1RgbaUnorm => "bc1-rgba-unorm",
2721 TextureFormat::Bc1RgbaUnormSrgb => "bc1-rgba-unorm-srgb",
2722 TextureFormat::Bc2RgbaUnorm => "bc2-rgba-unorm",
2723 TextureFormat::Bc2RgbaUnormSrgb => "bc2-rgba-unorm-srgb",
2724 TextureFormat::Bc3RgbaUnorm => "bc3-rgba-unorm",
2725 TextureFormat::Bc3RgbaUnormSrgb => "bc3-rgba-unorm-srgb",
2726 TextureFormat::Bc4RUnorm => "bc4-r-unorm",
2727 TextureFormat::Bc4RSnorm => "bc4-r-snorm",
2728 TextureFormat::Bc5RgUnorm => "bc5-rg-unorm",
2729 TextureFormat::Bc5RgSnorm => "bc5-rg-snorm",
2730 TextureFormat::Bc6hRgbUfloat => "bc6h-rgb-ufloat",
2731 TextureFormat::Bc6hRgbFloat => "bc6h-rgb-float",
2732 TextureFormat::Bc7RgbaUnorm => "bc7-rgba-unorm",
2733 TextureFormat::Bc7RgbaUnormSrgb => "bc7-rgba-unorm-srgb",
2734 TextureFormat::Etc2Rgb8Unorm => "etc2-rgb8unorm",
2735 TextureFormat::Etc2Rgb8UnormSrgb => "etc2-rgb8unorm-srgb",
2736 TextureFormat::Etc2Rgb8A1Unorm => "etc2-rgb8a1unorm",
2737 TextureFormat::Etc2Rgb8A1UnormSrgb => "etc2-rgb8a1unorm-srgb",
2738 TextureFormat::Etc2Rgba8Unorm => "etc2-rgba8unorm",
2739 TextureFormat::Etc2Rgba8UnormSrgb => "etc2-rgba8unorm-srgb",
2740 TextureFormat::EacR11Unorm => "eac-r11unorm",
2741 TextureFormat::EacR11Snorm => "eac-r11snorm",
2742 TextureFormat::EacRg11Unorm => "eac-rg11unorm",
2743 TextureFormat::EacRg11Snorm => "eac-rg11snorm",
2744 TextureFormat::Astc { block, channel } => {
2745 let block = match block {
2746 AstcBlock::B4x4 => "4x4",
2747 AstcBlock::B5x4 => "5x4",
2748 AstcBlock::B5x5 => "5x5",
2749 AstcBlock::B6x5 => "6x5",
2750 AstcBlock::B6x6 => "6x6",
2751 AstcBlock::B8x5 => "8x5",
2752 AstcBlock::B8x6 => "8x6",
2753 AstcBlock::B8x8 => "8x8",
2754 AstcBlock::B10x5 => "10x5",
2755 AstcBlock::B10x6 => "10x6",
2756 AstcBlock::B10x8 => "10x8",
2757 AstcBlock::B10x10 => "10x10",
2758 AstcBlock::B12x10 => "12x10",
2759 AstcBlock::B12x12 => "12x12",
2760 };
2761
2762 let channel = match channel {
2763 AstcChannel::Unorm => "unorm",
2764 AstcChannel::UnormSrgb => "unorm-srgb",
2765 AstcChannel::Hdr => "hdr",
2766 };
2767
2768 s = format!("astc-{block}-{channel}");
2769 &s
2770 }
2771 };
2772 serializer.serialize_str(name)
2773 }
2774}
2775
2776impl TextureAspect {
2777 /// Returns the texture aspect for a given plane.
2778 #[must_use]
2779 pub fn from_plane(plane: u32) -> Option<Self> {
2780 Some(match plane {
2781 0 => Self::Plane0,
2782 1 => Self::Plane1,
2783 2 => Self::Plane2,
2784 _ => return None,
2785 })
2786 }
2787
2788 /// Returns the plane for a given texture aspect.
2789 #[must_use]
2790 pub fn to_plane(&self) -> Option<u32> {
2791 match self {
2792 TextureAspect::Plane0 => Some(0),
2793 TextureAspect::Plane1 => Some(1),
2794 TextureAspect::Plane2 => Some(2),
2795 _ => None,
2796 }
2797 }
2798}
2799
2800// There are some additional texture format helpers in `wgpu-core/src/conv.rs`,
2801// that may need to be modified along with the ones here.
2802impl TextureFormat {
2803 /// Returns the aspect-specific format of the original format
2804 ///
2805 /// see <https://gpuweb.github.io/gpuweb/#abstract-opdef-resolving-gputextureaspect>
2806 #[must_use]
2807 pub fn aspect_specific_format(&self, aspect: TextureAspect) -> Option<Self> {
2808 match (*self, aspect) {
2809 (Self::Stencil8, TextureAspect::StencilOnly) => Some(*self),
2810 (
2811 Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float,
2812 TextureAspect::DepthOnly,
2813 ) => Some(*self),
2814 (
2815 Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8,
2816 TextureAspect::StencilOnly,
2817 ) => Some(Self::Stencil8),
2818 (Self::Depth24PlusStencil8, TextureAspect::DepthOnly) => Some(Self::Depth24Plus),
2819 (Self::Depth32FloatStencil8, TextureAspect::DepthOnly) => Some(Self::Depth32Float),
2820 (Self::NV12, TextureAspect::Plane0) => Some(Self::R8Unorm),
2821 (Self::NV12, TextureAspect::Plane1) => Some(Self::Rg8Unorm),
2822 (Self::P010, TextureAspect::Plane0) => Some(Self::R16Unorm),
2823 (Self::P010, TextureAspect::Plane1) => Some(Self::Rg16Unorm),
2824 // views to multi-planar formats must specify the plane
2825 (format, TextureAspect::All) if !format.is_multi_planar_format() => Some(format),
2826 _ => None,
2827 }
2828 }
2829
2830 /// Returns `true` if `self` is a depth or stencil component of the given
2831 /// combined depth-stencil format
2832 #[must_use]
2833 pub fn is_depth_stencil_component(&self, combined_format: Self) -> bool {
2834 match (combined_format, *self) {
2835 (Self::Depth24PlusStencil8, Self::Depth24Plus | Self::Stencil8)
2836 | (Self::Depth32FloatStencil8, Self::Depth32Float | Self::Stencil8) => true,
2837 _ => false,
2838 }
2839 }
2840
2841 /// Returns `true` if the format is a depth and/or stencil format
2842 ///
2843 /// see <https://gpuweb.github.io/gpuweb/#depth-formats>
2844 #[must_use]
2845 pub fn is_depth_stencil_format(&self) -> bool {
2846 match *self {
2847 Self::Stencil8
2848 | Self::Depth16Unorm
2849 | Self::Depth24Plus
2850 | Self::Depth24PlusStencil8
2851 | Self::Depth32Float
2852 | Self::Depth32FloatStencil8 => true,
2853 _ => false,
2854 }
2855 }
2856
2857 /// Returns `true` if the format is a combined depth-stencil format
2858 ///
2859 /// see <https://gpuweb.github.io/gpuweb/#combined-depth-stencil-format>
2860 #[must_use]
2861 pub fn is_combined_depth_stencil_format(&self) -> bool {
2862 match *self {
2863 Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => true,
2864 _ => false,
2865 }
2866 }
2867
2868 /// Returns `true` if the format is a multi-planar format
2869 #[must_use]
2870 pub fn is_multi_planar_format(&self) -> bool {
2871 self.planes().is_some()
2872 }
2873
2874 /// Returns the number of planes a multi-planar format has.
2875 #[must_use]
2876 pub fn planes(&self) -> Option<u32> {
2877 match *self {
2878 Self::NV12 => Some(2),
2879 Self::P010 => Some(2),
2880 _ => None,
2881 }
2882 }
2883
2884 /// Returns `true` if the format has a color aspect
2885 #[must_use]
2886 pub fn has_color_aspect(&self) -> bool {
2887 !self.is_depth_stencil_format()
2888 }
2889
2890 /// Returns `true` if the format has a depth aspect
2891 #[must_use]
2892 pub fn has_depth_aspect(&self) -> bool {
2893 match *self {
2894 Self::Depth16Unorm
2895 | Self::Depth24Plus
2896 | Self::Depth24PlusStencil8
2897 | Self::Depth32Float
2898 | Self::Depth32FloatStencil8 => true,
2899 _ => false,
2900 }
2901 }
2902
2903 /// Returns `true` if the format has a stencil aspect
2904 #[must_use]
2905 pub fn has_stencil_aspect(&self) -> bool {
2906 match *self {
2907 Self::Stencil8 | Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => true,
2908 _ => false,
2909 }
2910 }
2911
2912 /// Returns the size multiple requirement for a texture using this format.
2913 #[must_use]
2914 pub fn size_multiple_requirement(&self) -> (u32, u32) {
2915 match *self {
2916 Self::NV12 => (2, 2),
2917 Self::P010 => (2, 2),
2918 _ => self.block_dimensions(),
2919 }
2920 }
2921
2922 /// Returns the dimension of a [block](https://gpuweb.github.io/gpuweb/#texel-block) of texels.
2923 ///
2924 /// Uncompressed formats have a block dimension of `(1, 1)`.
2925 #[must_use]
2926 pub fn block_dimensions(&self) -> (u32, u32) {
2927 match *self {
2928 Self::R8Unorm
2929 | Self::R8Snorm
2930 | Self::R8Uint
2931 | Self::R8Sint
2932 | Self::R16Uint
2933 | Self::R16Sint
2934 | Self::R16Unorm
2935 | Self::R16Snorm
2936 | Self::R16Float
2937 | Self::Rg8Unorm
2938 | Self::Rg8Snorm
2939 | Self::Rg8Uint
2940 | Self::Rg8Sint
2941 | Self::R32Uint
2942 | Self::R32Sint
2943 | Self::R32Float
2944 | Self::Rg16Uint
2945 | Self::Rg16Sint
2946 | Self::Rg16Unorm
2947 | Self::Rg16Snorm
2948 | Self::Rg16Float
2949 | Self::Rgba8Unorm
2950 | Self::Rgba8UnormSrgb
2951 | Self::Rgba8Snorm
2952 | Self::Rgba8Uint
2953 | Self::Rgba8Sint
2954 | Self::Bgra8Unorm
2955 | Self::Bgra8UnormSrgb
2956 | Self::Rgb9e5Ufloat
2957 | Self::Rgb10a2Uint
2958 | Self::Rgb10a2Unorm
2959 | Self::Rg11b10Ufloat
2960 | Self::R64Uint
2961 | Self::Rg32Uint
2962 | Self::Rg32Sint
2963 | Self::Rg32Float
2964 | Self::Rgba16Uint
2965 | Self::Rgba16Sint
2966 | Self::Rgba16Unorm
2967 | Self::Rgba16Snorm
2968 | Self::Rgba16Float
2969 | Self::Rgba32Uint
2970 | Self::Rgba32Sint
2971 | Self::Rgba32Float
2972 | Self::Stencil8
2973 | Self::Depth16Unorm
2974 | Self::Depth24Plus
2975 | Self::Depth24PlusStencil8
2976 | Self::Depth32Float
2977 | Self::Depth32FloatStencil8
2978 | Self::NV12
2979 | Self::P010 => (1, 1),
2980
2981 Self::Bc1RgbaUnorm
2982 | Self::Bc1RgbaUnormSrgb
2983 | Self::Bc2RgbaUnorm
2984 | Self::Bc2RgbaUnormSrgb
2985 | Self::Bc3RgbaUnorm
2986 | Self::Bc3RgbaUnormSrgb
2987 | Self::Bc4RUnorm
2988 | Self::Bc4RSnorm
2989 | Self::Bc5RgUnorm
2990 | Self::Bc5RgSnorm
2991 | Self::Bc6hRgbUfloat
2992 | Self::Bc6hRgbFloat
2993 | Self::Bc7RgbaUnorm
2994 | Self::Bc7RgbaUnormSrgb => (4, 4),
2995
2996 Self::Etc2Rgb8Unorm
2997 | Self::Etc2Rgb8UnormSrgb
2998 | Self::Etc2Rgb8A1Unorm
2999 | Self::Etc2Rgb8A1UnormSrgb
3000 | Self::Etc2Rgba8Unorm
3001 | Self::Etc2Rgba8UnormSrgb
3002 | Self::EacR11Unorm
3003 | Self::EacR11Snorm
3004 | Self::EacRg11Unorm
3005 | Self::EacRg11Snorm => (4, 4),
3006
3007 Self::Astc { block, .. } => match block {
3008 AstcBlock::B4x4 => (4, 4),
3009 AstcBlock::B5x4 => (5, 4),
3010 AstcBlock::B5x5 => (5, 5),
3011 AstcBlock::B6x5 => (6, 5),
3012 AstcBlock::B6x6 => (6, 6),
3013 AstcBlock::B8x5 => (8, 5),
3014 AstcBlock::B8x6 => (8, 6),
3015 AstcBlock::B8x8 => (8, 8),
3016 AstcBlock::B10x5 => (10, 5),
3017 AstcBlock::B10x6 => (10, 6),
3018 AstcBlock::B10x8 => (10, 8),
3019 AstcBlock::B10x10 => (10, 10),
3020 AstcBlock::B12x10 => (12, 10),
3021 AstcBlock::B12x12 => (12, 12),
3022 },
3023 }
3024 }
3025
3026 /// Returns `true` for compressed formats.
3027 #[must_use]
3028 pub fn is_compressed(&self) -> bool {
3029 self.block_dimensions() != (1, 1)
3030 }
3031
3032 /// Returns `true` for BCn compressed formats.
3033 #[must_use]
3034 pub fn is_bcn(&self) -> bool {
3035 self.required_features() == Features::TEXTURE_COMPRESSION_BC
3036 }
3037
3038 /// Returns `true` for ASTC compressed formats.
3039 #[must_use]
3040 pub fn is_astc(&self) -> bool {
3041 self.required_features() == Features::TEXTURE_COMPRESSION_ASTC
3042 || self.required_features() == Features::TEXTURE_COMPRESSION_ASTC_HDR
3043 }
3044
3045 /// Returns the required features (if any) in order to use the texture.
3046 #[must_use]
3047 pub fn required_features(&self) -> Features {
3048 match *self {
3049 Self::R8Unorm
3050 | Self::R8Snorm
3051 | Self::R8Uint
3052 | Self::R8Sint
3053 | Self::R16Uint
3054 | Self::R16Sint
3055 | Self::R16Float
3056 | Self::Rg8Unorm
3057 | Self::Rg8Snorm
3058 | Self::Rg8Uint
3059 | Self::Rg8Sint
3060 | Self::R32Uint
3061 | Self::R32Sint
3062 | Self::R32Float
3063 | Self::Rg16Uint
3064 | Self::Rg16Sint
3065 | Self::Rg16Float
3066 | Self::Rgba8Unorm
3067 | Self::Rgba8UnormSrgb
3068 | Self::Rgba8Snorm
3069 | Self::Rgba8Uint
3070 | Self::Rgba8Sint
3071 | Self::Bgra8Unorm
3072 | Self::Bgra8UnormSrgb
3073 | Self::Rgb9e5Ufloat
3074 | Self::Rgb10a2Uint
3075 | Self::Rgb10a2Unorm
3076 | Self::Rg11b10Ufloat
3077 | Self::Rg32Uint
3078 | Self::Rg32Sint
3079 | Self::Rg32Float
3080 | Self::Rgba16Uint
3081 | Self::Rgba16Sint
3082 | Self::Rgba16Float
3083 | Self::Rgba32Uint
3084 | Self::Rgba32Sint
3085 | Self::Rgba32Float
3086 | Self::Stencil8
3087 | Self::Depth16Unorm
3088 | Self::Depth24Plus
3089 | Self::Depth24PlusStencil8
3090 | Self::Depth32Float => Features::empty(),
3091
3092 Self::R64Uint => Features::TEXTURE_INT64_ATOMIC,
3093
3094 Self::Depth32FloatStencil8 => Features::DEPTH32FLOAT_STENCIL8,
3095
3096 Self::NV12 => Features::TEXTURE_FORMAT_NV12,
3097 Self::P010 => Features::TEXTURE_FORMAT_P010,
3098
3099 Self::R16Unorm
3100 | Self::R16Snorm
3101 | Self::Rg16Unorm
3102 | Self::Rg16Snorm
3103 | Self::Rgba16Unorm
3104 | Self::Rgba16Snorm => Features::TEXTURE_FORMAT_16BIT_NORM,
3105
3106 Self::Bc1RgbaUnorm
3107 | Self::Bc1RgbaUnormSrgb
3108 | Self::Bc2RgbaUnorm
3109 | Self::Bc2RgbaUnormSrgb
3110 | Self::Bc3RgbaUnorm
3111 | Self::Bc3RgbaUnormSrgb
3112 | Self::Bc4RUnorm
3113 | Self::Bc4RSnorm
3114 | Self::Bc5RgUnorm
3115 | Self::Bc5RgSnorm
3116 | Self::Bc6hRgbUfloat
3117 | Self::Bc6hRgbFloat
3118 | Self::Bc7RgbaUnorm
3119 | Self::Bc7RgbaUnormSrgb => Features::TEXTURE_COMPRESSION_BC,
3120
3121 Self::Etc2Rgb8Unorm
3122 | Self::Etc2Rgb8UnormSrgb
3123 | Self::Etc2Rgb8A1Unorm
3124 | Self::Etc2Rgb8A1UnormSrgb
3125 | Self::Etc2Rgba8Unorm
3126 | Self::Etc2Rgba8UnormSrgb
3127 | Self::EacR11Unorm
3128 | Self::EacR11Snorm
3129 | Self::EacRg11Unorm
3130 | Self::EacRg11Snorm => Features::TEXTURE_COMPRESSION_ETC2,
3131
3132 Self::Astc { channel, .. } => match channel {
3133 AstcChannel::Hdr => Features::TEXTURE_COMPRESSION_ASTC_HDR,
3134 AstcChannel::Unorm | AstcChannel::UnormSrgb => Features::TEXTURE_COMPRESSION_ASTC,
3135 },
3136 }
3137 }
3138
3139 /// Returns the format features guaranteed by the WebGPU spec.
3140 ///
3141 /// Additional features are available if `Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES` is enabled.
3142 #[must_use]
3143 pub fn guaranteed_format_features(&self, device_features: Features) -> TextureFormatFeatures {
3144 // Multisampling
3145 let none = TextureFormatFeatureFlags::empty();
3146 let msaa = TextureFormatFeatureFlags::MULTISAMPLE_X4;
3147 let msaa_resolve = msaa | TextureFormatFeatureFlags::MULTISAMPLE_RESOLVE;
3148
3149 let s_ro_wo = TextureFormatFeatureFlags::STORAGE_READ_ONLY
3150 | TextureFormatFeatureFlags::STORAGE_WRITE_ONLY;
3151 let s_all = s_ro_wo | TextureFormatFeatureFlags::STORAGE_READ_WRITE;
3152
3153 // Flags
3154 let basic =
3155 TextureUsages::COPY_SRC | TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING;
3156 let attachment = basic | TextureUsages::RENDER_ATTACHMENT | TextureUsages::TRANSIENT;
3157 let storage = basic | TextureUsages::STORAGE_BINDING;
3158 let binding = TextureUsages::TEXTURE_BINDING;
3159 let all_flags = attachment | storage | binding;
3160 let atomic_64 = if device_features.contains(Features::TEXTURE_ATOMIC) {
3161 storage | binding | TextureUsages::STORAGE_ATOMIC
3162 } else {
3163 storage | binding
3164 };
3165 let atomic = attachment | atomic_64;
3166 let (rg11b10f_f, rg11b10f_u) =
3167 if device_features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
3168 (msaa_resolve, attachment)
3169 } else {
3170 (msaa, basic)
3171 };
3172 let (bgra8unorm_f, bgra8unorm) = if device_features.contains(Features::BGRA8UNORM_STORAGE) {
3173 (
3174 msaa_resolve | TextureFormatFeatureFlags::STORAGE_WRITE_ONLY,
3175 attachment | TextureUsages::STORAGE_BINDING,
3176 )
3177 } else {
3178 (msaa_resolve, attachment)
3179 };
3180
3181 #[rustfmt::skip] // lets make a nice table
3182 let (
3183 mut flags,
3184 allowed_usages,
3185 ) = match *self {
3186 Self::R8Unorm => (msaa_resolve, attachment),
3187 Self::R8Snorm => ( none, basic),
3188 Self::R8Uint => ( msaa, attachment),
3189 Self::R8Sint => ( msaa, attachment),
3190 Self::R16Uint => ( msaa, attachment),
3191 Self::R16Sint => ( msaa, attachment),
3192 Self::R16Float => (msaa_resolve, attachment),
3193 Self::Rg8Unorm => (msaa_resolve, attachment),
3194 Self::Rg8Snorm => ( none, basic),
3195 Self::Rg8Uint => ( msaa, attachment),
3196 Self::Rg8Sint => ( msaa, attachment),
3197 Self::R32Uint => ( s_all, atomic),
3198 Self::R32Sint => ( s_all, atomic),
3199 Self::R32Float => (msaa | s_all, all_flags),
3200 Self::Rg16Uint => ( msaa, attachment),
3201 Self::Rg16Sint => ( msaa, attachment),
3202 Self::Rg16Float => (msaa_resolve, attachment),
3203 Self::Rgba8Unorm => (msaa_resolve | s_ro_wo, all_flags),
3204 Self::Rgba8UnormSrgb => (msaa_resolve, attachment),
3205 Self::Rgba8Snorm => ( s_ro_wo, storage),
3206 Self::Rgba8Uint => ( msaa | s_ro_wo, all_flags),
3207 Self::Rgba8Sint => ( msaa | s_ro_wo, all_flags),
3208 Self::Bgra8Unorm => (bgra8unorm_f, bgra8unorm),
3209 Self::Bgra8UnormSrgb => (msaa_resolve, attachment),
3210 Self::Rgb10a2Uint => ( msaa, attachment),
3211 Self::Rgb10a2Unorm => (msaa_resolve, attachment),
3212 Self::Rg11b10Ufloat => ( rg11b10f_f, rg11b10f_u),
3213 Self::R64Uint => ( s_ro_wo, atomic_64),
3214 Self::Rg32Uint => ( s_ro_wo, all_flags),
3215 Self::Rg32Sint => ( s_ro_wo, all_flags),
3216 Self::Rg32Float => ( s_ro_wo, all_flags),
3217 Self::Rgba16Uint => ( msaa | s_ro_wo, all_flags),
3218 Self::Rgba16Sint => ( msaa | s_ro_wo, all_flags),
3219 Self::Rgba16Float => (msaa_resolve | s_ro_wo, all_flags),
3220 Self::Rgba32Uint => ( s_ro_wo, all_flags),
3221 Self::Rgba32Sint => ( s_ro_wo, all_flags),
3222 Self::Rgba32Float => ( s_ro_wo, all_flags),
3223
3224 Self::Stencil8 => ( msaa, attachment),
3225 Self::Depth16Unorm => ( msaa, attachment),
3226 Self::Depth24Plus => ( msaa, attachment),
3227 Self::Depth24PlusStencil8 => ( msaa, attachment),
3228 Self::Depth32Float => ( msaa, attachment),
3229 Self::Depth32FloatStencil8 => ( msaa, attachment),
3230
3231 // We only support sampling nv12 and p010 textures until we
3232 // implement transfer plane data.
3233 Self::NV12 => ( none, binding),
3234 Self::P010 => ( none, binding),
3235
3236 Self::R16Unorm => ( msaa | s_ro_wo, storage),
3237 Self::R16Snorm => ( msaa | s_ro_wo, storage),
3238 Self::Rg16Unorm => ( msaa | s_ro_wo, storage),
3239 Self::Rg16Snorm => ( msaa | s_ro_wo, storage),
3240 Self::Rgba16Unorm => ( msaa | s_ro_wo, storage),
3241 Self::Rgba16Snorm => ( msaa | s_ro_wo, storage),
3242
3243 Self::Rgb9e5Ufloat => ( none, basic),
3244
3245 Self::Bc1RgbaUnorm => ( none, basic),
3246 Self::Bc1RgbaUnormSrgb => ( none, basic),
3247 Self::Bc2RgbaUnorm => ( none, basic),
3248 Self::Bc2RgbaUnormSrgb => ( none, basic),
3249 Self::Bc3RgbaUnorm => ( none, basic),
3250 Self::Bc3RgbaUnormSrgb => ( none, basic),
3251 Self::Bc4RUnorm => ( none, basic),
3252 Self::Bc4RSnorm => ( none, basic),
3253 Self::Bc5RgUnorm => ( none, basic),
3254 Self::Bc5RgSnorm => ( none, basic),
3255 Self::Bc6hRgbUfloat => ( none, basic),
3256 Self::Bc6hRgbFloat => ( none, basic),
3257 Self::Bc7RgbaUnorm => ( none, basic),
3258 Self::Bc7RgbaUnormSrgb => ( none, basic),
3259
3260 Self::Etc2Rgb8Unorm => ( none, basic),
3261 Self::Etc2Rgb8UnormSrgb => ( none, basic),
3262 Self::Etc2Rgb8A1Unorm => ( none, basic),
3263 Self::Etc2Rgb8A1UnormSrgb => ( none, basic),
3264 Self::Etc2Rgba8Unorm => ( none, basic),
3265 Self::Etc2Rgba8UnormSrgb => ( none, basic),
3266 Self::EacR11Unorm => ( none, basic),
3267 Self::EacR11Snorm => ( none, basic),
3268 Self::EacRg11Unorm => ( none, basic),
3269 Self::EacRg11Snorm => ( none, basic),
3270
3271 Self::Astc { .. } => ( none, basic),
3272 };
3273
3274 // Get whether the format is filterable, taking features into account
3275 let sample_type1 = self.sample_type(None, Some(device_features));
3276 let is_filterable = sample_type1 == Some(TextureSampleType::Float { filterable: true });
3277
3278 // Features that enable filtering don't affect blendability
3279 let sample_type2 = self.sample_type(None, None);
3280 let is_blendable = sample_type2 == Some(TextureSampleType::Float { filterable: true });
3281
3282 flags.set(TextureFormatFeatureFlags::FILTERABLE, is_filterable);
3283 flags.set(TextureFormatFeatureFlags::BLENDABLE, is_blendable);
3284 flags.set(
3285 TextureFormatFeatureFlags::STORAGE_ATOMIC,
3286 allowed_usages.contains(TextureUsages::STORAGE_ATOMIC),
3287 );
3288
3289 TextureFormatFeatures {
3290 allowed_usages,
3291 flags,
3292 }
3293 }
3294
3295 /// Returns the sample type compatible with this format and aspect.
3296 ///
3297 /// Returns `None` only if this is a combined depth-stencil format or a multi-planar format
3298 /// and `TextureAspect::All` or no `aspect` was provided.
3299 #[must_use]
3300 pub fn sample_type(
3301 &self,
3302 aspect: Option<TextureAspect>,
3303 device_features: Option<Features>,
3304 ) -> Option<TextureSampleType> {
3305 let float = TextureSampleType::Float { filterable: true };
3306 let unfilterable_float = TextureSampleType::Float { filterable: false };
3307 let float32_sample_type = TextureSampleType::Float {
3308 filterable: device_features
3309 .unwrap_or(Features::empty())
3310 .contains(Features::FLOAT32_FILTERABLE),
3311 };
3312 let depth = TextureSampleType::Depth;
3313 let uint = TextureSampleType::Uint;
3314 let sint = TextureSampleType::Sint;
3315
3316 match *self {
3317 Self::R8Unorm
3318 | Self::R8Snorm
3319 | Self::Rg8Unorm
3320 | Self::Rg8Snorm
3321 | Self::Rgba8Unorm
3322 | Self::Rgba8UnormSrgb
3323 | Self::Rgba8Snorm
3324 | Self::Bgra8Unorm
3325 | Self::Bgra8UnormSrgb
3326 | Self::R16Float
3327 | Self::Rg16Float
3328 | Self::Rgba16Float
3329 | Self::Rgb10a2Unorm
3330 | Self::Rg11b10Ufloat => Some(float),
3331
3332 Self::R32Float | Self::Rg32Float | Self::Rgba32Float => Some(float32_sample_type),
3333
3334 Self::R8Uint
3335 | Self::Rg8Uint
3336 | Self::Rgba8Uint
3337 | Self::R16Uint
3338 | Self::Rg16Uint
3339 | Self::Rgba16Uint
3340 | Self::R32Uint
3341 | Self::R64Uint
3342 | Self::Rg32Uint
3343 | Self::Rgba32Uint
3344 | Self::Rgb10a2Uint => Some(uint),
3345
3346 Self::R8Sint
3347 | Self::Rg8Sint
3348 | Self::Rgba8Sint
3349 | Self::R16Sint
3350 | Self::Rg16Sint
3351 | Self::Rgba16Sint
3352 | Self::R32Sint
3353 | Self::Rg32Sint
3354 | Self::Rgba32Sint => Some(sint),
3355
3356 Self::Stencil8 => Some(uint),
3357 Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => Some(depth),
3358 Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect {
3359 Some(TextureAspect::DepthOnly) => Some(depth),
3360 Some(TextureAspect::StencilOnly) => Some(uint),
3361 _ => None,
3362 },
3363
3364 Self::NV12 | Self::P010 => match aspect {
3365 Some(TextureAspect::Plane0) | Some(TextureAspect::Plane1) => {
3366 Some(unfilterable_float)
3367 }
3368 _ => None,
3369 },
3370
3371 Self::R16Unorm
3372 | Self::R16Snorm
3373 | Self::Rg16Unorm
3374 | Self::Rg16Snorm
3375 | Self::Rgba16Unorm
3376 | Self::Rgba16Snorm => Some(float),
3377
3378 Self::Rgb9e5Ufloat => Some(float),
3379
3380 Self::Bc1RgbaUnorm
3381 | Self::Bc1RgbaUnormSrgb
3382 | Self::Bc2RgbaUnorm
3383 | Self::Bc2RgbaUnormSrgb
3384 | Self::Bc3RgbaUnorm
3385 | Self::Bc3RgbaUnormSrgb
3386 | Self::Bc4RUnorm
3387 | Self::Bc4RSnorm
3388 | Self::Bc5RgUnorm
3389 | Self::Bc5RgSnorm
3390 | Self::Bc6hRgbUfloat
3391 | Self::Bc6hRgbFloat
3392 | Self::Bc7RgbaUnorm
3393 | Self::Bc7RgbaUnormSrgb => Some(float),
3394
3395 Self::Etc2Rgb8Unorm
3396 | Self::Etc2Rgb8UnormSrgb
3397 | Self::Etc2Rgb8A1Unorm
3398 | Self::Etc2Rgb8A1UnormSrgb
3399 | Self::Etc2Rgba8Unorm
3400 | Self::Etc2Rgba8UnormSrgb
3401 | Self::EacR11Unorm
3402 | Self::EacR11Snorm
3403 | Self::EacRg11Unorm
3404 | Self::EacRg11Snorm => Some(float),
3405
3406 Self::Astc { .. } => Some(float),
3407 }
3408 }
3409
3410 /// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable.
3411 ///
3412 /// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint).
3413 ///
3414 /// Note that for uncompressed formats this is the same as the size of a single texel,
3415 /// since uncompressed formats have a block size of 1x1.
3416 ///
3417 /// Returns `None` if any of the following are true:
3418 /// - the format is a combined depth-stencil and no `aspect` was provided
3419 /// - the format is a multi-planar format and no `aspect` was provided
3420 /// - the format is `Depth24Plus`
3421 /// - the format is `Depth24PlusStencil8` and `aspect` is depth.
3422 #[deprecated(since = "0.19.0", note = "Use `block_copy_size` instead.")]
3423 #[must_use]
3424 pub fn block_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
3425 self.block_copy_size(aspect)
3426 }
3427
3428 /// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable.
3429 ///
3430 /// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint).
3431 ///
3432 /// Note that for uncompressed formats this is the same as the size of a single texel,
3433 /// since uncompressed formats have a block size of 1x1.
3434 ///
3435 /// Returns `None` if any of the following are true:
3436 /// - the format is a combined depth-stencil and no `aspect` was provided
3437 /// - the format is a multi-planar format and no `aspect` was provided
3438 /// - the format is `Depth24Plus`
3439 /// - the format is `Depth24PlusStencil8` and `aspect` is depth.
3440 #[must_use]
3441 pub fn block_copy_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
3442 match *self {
3443 Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1),
3444
3445 Self::Rg8Unorm | Self::Rg8Snorm | Self::Rg8Uint | Self::Rg8Sint => Some(2),
3446 Self::R16Unorm | Self::R16Snorm | Self::R16Uint | Self::R16Sint | Self::R16Float => {
3447 Some(2)
3448 }
3449
3450 Self::Rgba8Unorm
3451 | Self::Rgba8UnormSrgb
3452 | Self::Rgba8Snorm
3453 | Self::Rgba8Uint
3454 | Self::Rgba8Sint
3455 | Self::Bgra8Unorm
3456 | Self::Bgra8UnormSrgb => Some(4),
3457 Self::Rg16Unorm
3458 | Self::Rg16Snorm
3459 | Self::Rg16Uint
3460 | Self::Rg16Sint
3461 | Self::Rg16Float => Some(4),
3462 Self::R32Uint | Self::R32Sint | Self::R32Float => Some(4),
3463 Self::Rgb9e5Ufloat | Self::Rgb10a2Uint | Self::Rgb10a2Unorm | Self::Rg11b10Ufloat => {
3464 Some(4)
3465 }
3466
3467 Self::Rgba16Unorm
3468 | Self::Rgba16Snorm
3469 | Self::Rgba16Uint
3470 | Self::Rgba16Sint
3471 | Self::Rgba16Float => Some(8),
3472 Self::R64Uint | Self::Rg32Uint | Self::Rg32Sint | Self::Rg32Float => Some(8),
3473
3474 Self::Rgba32Uint | Self::Rgba32Sint | Self::Rgba32Float => Some(16),
3475
3476 Self::Stencil8 => Some(1),
3477 Self::Depth16Unorm => Some(2),
3478 Self::Depth32Float => Some(4),
3479 Self::Depth24Plus => None,
3480 Self::Depth24PlusStencil8 => match aspect {
3481 Some(TextureAspect::DepthOnly) => None,
3482 Some(TextureAspect::StencilOnly) => Some(1),
3483 _ => None,
3484 },
3485 Self::Depth32FloatStencil8 => match aspect {
3486 Some(TextureAspect::DepthOnly) => Some(4),
3487 Some(TextureAspect::StencilOnly) => Some(1),
3488 _ => None,
3489 },
3490
3491 Self::NV12 => match aspect {
3492 Some(TextureAspect::Plane0) => Some(1),
3493 Some(TextureAspect::Plane1) => Some(2),
3494 _ => None,
3495 },
3496
3497 Self::P010 => match aspect {
3498 Some(TextureAspect::Plane0) => Some(2),
3499 Some(TextureAspect::Plane1) => Some(4),
3500 _ => None,
3501 },
3502
3503 Self::Bc1RgbaUnorm | Self::Bc1RgbaUnormSrgb | Self::Bc4RUnorm | Self::Bc4RSnorm => {
3504 Some(8)
3505 }
3506 Self::Bc2RgbaUnorm
3507 | Self::Bc2RgbaUnormSrgb
3508 | Self::Bc3RgbaUnorm
3509 | Self::Bc3RgbaUnormSrgb
3510 | Self::Bc5RgUnorm
3511 | Self::Bc5RgSnorm
3512 | Self::Bc6hRgbUfloat
3513 | Self::Bc6hRgbFloat
3514 | Self::Bc7RgbaUnorm
3515 | Self::Bc7RgbaUnormSrgb => Some(16),
3516
3517 Self::Etc2Rgb8Unorm
3518 | Self::Etc2Rgb8UnormSrgb
3519 | Self::Etc2Rgb8A1Unorm
3520 | Self::Etc2Rgb8A1UnormSrgb
3521 | Self::EacR11Unorm
3522 | Self::EacR11Snorm => Some(8),
3523 Self::Etc2Rgba8Unorm
3524 | Self::Etc2Rgba8UnormSrgb
3525 | Self::EacRg11Unorm
3526 | Self::EacRg11Snorm => Some(16),
3527
3528 Self::Astc { .. } => Some(16),
3529 }
3530 }
3531
3532 /// The largest number that can be returned by [`Self::target_pixel_byte_cost`].
3533 pub const MAX_TARGET_PIXEL_BYTE_COST: u32 = 16;
3534
3535 /// The number of bytes occupied per pixel in a color attachment
3536 /// <https://gpuweb.github.io/gpuweb/#render-target-pixel-byte-cost>
3537 #[must_use]
3538 pub fn target_pixel_byte_cost(&self) -> Option<u32> {
3539 match *self {
3540 Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1),
3541 Self::Rg8Unorm
3542 | Self::Rg8Snorm
3543 | Self::Rg8Uint
3544 | Self::Rg8Sint
3545 | Self::R16Uint
3546 | Self::R16Sint
3547 | Self::R16Unorm
3548 | Self::R16Snorm
3549 | Self::R16Float => Some(2),
3550 Self::Rgba8Uint
3551 | Self::Rgba8Sint
3552 | Self::Rg16Uint
3553 | Self::Rg16Sint
3554 | Self::Rg16Unorm
3555 | Self::Rg16Snorm
3556 | Self::Rg16Float
3557 | Self::R32Uint
3558 | Self::R32Sint
3559 | Self::R32Float => Some(4),
3560 // Despite being 4 bytes per pixel, these are 8 bytes per pixel in the table
3561 Self::Rgba8Unorm
3562 | Self::Rgba8UnormSrgb
3563 | Self::Rgba8Snorm
3564 | Self::Bgra8Unorm
3565 | Self::Bgra8UnormSrgb
3566 // ---
3567 | Self::Rgba16Uint
3568 | Self::Rgba16Sint
3569 | Self::Rgba16Unorm
3570 | Self::Rgba16Snorm
3571 | Self::Rgba16Float
3572 | Self::R64Uint
3573 | Self::Rg32Uint
3574 | Self::Rg32Sint
3575 | Self::Rg32Float
3576 | Self::Rgb10a2Uint
3577 | Self::Rgb10a2Unorm
3578 | Self::Rg11b10Ufloat => Some(8),
3579 Self::Rgba32Uint | Self::Rgba32Sint | Self::Rgba32Float => Some(16),
3580 // ⚠️ If you add formats with larger sizes, make sure you change `MAX_TARGET_PIXEL_BYTE_COST`` ⚠️
3581 Self::Stencil8
3582 | Self::Depth16Unorm
3583 | Self::Depth24Plus
3584 | Self::Depth24PlusStencil8
3585 | Self::Depth32Float
3586 | Self::Depth32FloatStencil8
3587 | Self::NV12
3588 | Self::P010
3589 | Self::Rgb9e5Ufloat
3590 | Self::Bc1RgbaUnorm
3591 | Self::Bc1RgbaUnormSrgb
3592 | Self::Bc2RgbaUnorm
3593 | Self::Bc2RgbaUnormSrgb
3594 | Self::Bc3RgbaUnorm
3595 | Self::Bc3RgbaUnormSrgb
3596 | Self::Bc4RUnorm
3597 | Self::Bc4RSnorm
3598 | Self::Bc5RgUnorm
3599 | Self::Bc5RgSnorm
3600 | Self::Bc6hRgbUfloat
3601 | Self::Bc6hRgbFloat
3602 | Self::Bc7RgbaUnorm
3603 | Self::Bc7RgbaUnormSrgb
3604 | Self::Etc2Rgb8Unorm
3605 | Self::Etc2Rgb8UnormSrgb
3606 | Self::Etc2Rgb8A1Unorm
3607 | Self::Etc2Rgb8A1UnormSrgb
3608 | Self::Etc2Rgba8Unorm
3609 | Self::Etc2Rgba8UnormSrgb
3610 | Self::EacR11Unorm
3611 | Self::EacR11Snorm
3612 | Self::EacRg11Unorm
3613 | Self::EacRg11Snorm
3614 | Self::Astc { .. } => None,
3615 }
3616 }
3617
3618 /// See <https://gpuweb.github.io/gpuweb/#render-target-component-alignment>
3619 #[must_use]
3620 pub fn target_component_alignment(&self) -> Option<u32> {
3621 match *self {
3622 Self::R8Unorm
3623 | Self::R8Snorm
3624 | Self::R8Uint
3625 | Self::R8Sint
3626 | Self::Rg8Unorm
3627 | Self::Rg8Snorm
3628 | Self::Rg8Uint
3629 | Self::Rg8Sint
3630 | Self::Rgba8Unorm
3631 | Self::Rgba8UnormSrgb
3632 | Self::Rgba8Snorm
3633 | Self::Rgba8Uint
3634 | Self::Rgba8Sint
3635 | Self::Bgra8Unorm
3636 | Self::Bgra8UnormSrgb => Some(1),
3637 Self::R16Uint
3638 | Self::R16Sint
3639 | Self::R16Unorm
3640 | Self::R16Snorm
3641 | Self::R16Float
3642 | Self::Rg16Uint
3643 | Self::Rg16Sint
3644 | Self::Rg16Unorm
3645 | Self::Rg16Snorm
3646 | Self::Rg16Float
3647 | Self::Rgba16Uint
3648 | Self::Rgba16Sint
3649 | Self::Rgba16Unorm
3650 | Self::Rgba16Snorm
3651 | Self::Rgba16Float => Some(2),
3652 Self::R32Uint
3653 | Self::R32Sint
3654 | Self::R32Float
3655 | Self::R64Uint
3656 | Self::Rg32Uint
3657 | Self::Rg32Sint
3658 | Self::Rg32Float
3659 | Self::Rgba32Uint
3660 | Self::Rgba32Sint
3661 | Self::Rgba32Float
3662 | Self::Rgb10a2Uint
3663 | Self::Rgb10a2Unorm
3664 | Self::Rg11b10Ufloat => Some(4),
3665 Self::Stencil8
3666 | Self::Depth16Unorm
3667 | Self::Depth24Plus
3668 | Self::Depth24PlusStencil8
3669 | Self::Depth32Float
3670 | Self::Depth32FloatStencil8
3671 | Self::NV12
3672 | Self::P010
3673 | Self::Rgb9e5Ufloat
3674 | Self::Bc1RgbaUnorm
3675 | Self::Bc1RgbaUnormSrgb
3676 | Self::Bc2RgbaUnorm
3677 | Self::Bc2RgbaUnormSrgb
3678 | Self::Bc3RgbaUnorm
3679 | Self::Bc3RgbaUnormSrgb
3680 | Self::Bc4RUnorm
3681 | Self::Bc4RSnorm
3682 | Self::Bc5RgUnorm
3683 | Self::Bc5RgSnorm
3684 | Self::Bc6hRgbUfloat
3685 | Self::Bc6hRgbFloat
3686 | Self::Bc7RgbaUnorm
3687 | Self::Bc7RgbaUnormSrgb
3688 | Self::Etc2Rgb8Unorm
3689 | Self::Etc2Rgb8UnormSrgb
3690 | Self::Etc2Rgb8A1Unorm
3691 | Self::Etc2Rgb8A1UnormSrgb
3692 | Self::Etc2Rgba8Unorm
3693 | Self::Etc2Rgba8UnormSrgb
3694 | Self::EacR11Unorm
3695 | Self::EacR11Snorm
3696 | Self::EacRg11Unorm
3697 | Self::EacRg11Snorm
3698 | Self::Astc { .. } => None,
3699 }
3700 }
3701
3702 /// Returns the number of components this format has.
3703 #[must_use]
3704 pub fn components(&self) -> u8 {
3705 self.components_with_aspect(TextureAspect::All)
3706 }
3707
3708 /// Returns the number of components this format has taking into account the `aspect`.
3709 ///
3710 /// The `aspect` is only relevant for combined depth-stencil formats and multi-planar formats.
3711 #[must_use]
3712 pub fn components_with_aspect(&self, aspect: TextureAspect) -> u8 {
3713 match *self {
3714 Self::R8Unorm
3715 | Self::R8Snorm
3716 | Self::R8Uint
3717 | Self::R8Sint
3718 | Self::R16Unorm
3719 | Self::R16Snorm
3720 | Self::R16Uint
3721 | Self::R16Sint
3722 | Self::R16Float
3723 | Self::R32Uint
3724 | Self::R32Sint
3725 | Self::R32Float
3726 | Self::R64Uint => 1,
3727
3728 Self::Rg8Unorm
3729 | Self::Rg8Snorm
3730 | Self::Rg8Uint
3731 | Self::Rg8Sint
3732 | Self::Rg16Unorm
3733 | Self::Rg16Snorm
3734 | Self::Rg16Uint
3735 | Self::Rg16Sint
3736 | Self::Rg16Float
3737 | Self::Rg32Uint
3738 | Self::Rg32Sint
3739 | Self::Rg32Float => 2,
3740
3741 Self::Rgba8Unorm
3742 | Self::Rgba8UnormSrgb
3743 | Self::Rgba8Snorm
3744 | Self::Rgba8Uint
3745 | Self::Rgba8Sint
3746 | Self::Bgra8Unorm
3747 | Self::Bgra8UnormSrgb
3748 | Self::Rgba16Unorm
3749 | Self::Rgba16Snorm
3750 | Self::Rgba16Uint
3751 | Self::Rgba16Sint
3752 | Self::Rgba16Float
3753 | Self::Rgba32Uint
3754 | Self::Rgba32Sint
3755 | Self::Rgba32Float => 4,
3756
3757 Self::Rgb9e5Ufloat | Self::Rg11b10Ufloat => 3,
3758 Self::Rgb10a2Uint | Self::Rgb10a2Unorm => 4,
3759
3760 Self::Stencil8 | Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => 1,
3761
3762 Self::Depth24PlusStencil8 | Self::Depth32FloatStencil8 => match aspect {
3763 TextureAspect::DepthOnly | TextureAspect::StencilOnly => 1,
3764 _ => 2,
3765 },
3766
3767 Self::NV12 | Self::P010 => match aspect {
3768 TextureAspect::Plane0 => 1,
3769 TextureAspect::Plane1 => 2,
3770 _ => 3,
3771 },
3772
3773 Self::Bc4RUnorm | Self::Bc4RSnorm => 1,
3774 Self::Bc5RgUnorm | Self::Bc5RgSnorm => 2,
3775 Self::Bc6hRgbUfloat | Self::Bc6hRgbFloat => 3,
3776 Self::Bc1RgbaUnorm
3777 | Self::Bc1RgbaUnormSrgb
3778 | Self::Bc2RgbaUnorm
3779 | Self::Bc2RgbaUnormSrgb
3780 | Self::Bc3RgbaUnorm
3781 | Self::Bc3RgbaUnormSrgb
3782 | Self::Bc7RgbaUnorm
3783 | Self::Bc7RgbaUnormSrgb => 4,
3784
3785 Self::EacR11Unorm | Self::EacR11Snorm => 1,
3786 Self::EacRg11Unorm | Self::EacRg11Snorm => 2,
3787 Self::Etc2Rgb8Unorm | Self::Etc2Rgb8UnormSrgb => 3,
3788 Self::Etc2Rgb8A1Unorm
3789 | Self::Etc2Rgb8A1UnormSrgb
3790 | Self::Etc2Rgba8Unorm
3791 | Self::Etc2Rgba8UnormSrgb => 4,
3792
3793 Self::Astc { .. } => 4,
3794 }
3795 }
3796
3797 /// Strips the `Srgb` suffix from the given texture format.
3798 #[must_use]
3799 pub fn remove_srgb_suffix(&self) -> TextureFormat {
3800 match *self {
3801 Self::Rgba8UnormSrgb => Self::Rgba8Unorm,
3802 Self::Bgra8UnormSrgb => Self::Bgra8Unorm,
3803 Self::Bc1RgbaUnormSrgb => Self::Bc1RgbaUnorm,
3804 Self::Bc2RgbaUnormSrgb => Self::Bc2RgbaUnorm,
3805 Self::Bc3RgbaUnormSrgb => Self::Bc3RgbaUnorm,
3806 Self::Bc7RgbaUnormSrgb => Self::Bc7RgbaUnorm,
3807 Self::Etc2Rgb8UnormSrgb => Self::Etc2Rgb8Unorm,
3808 Self::Etc2Rgb8A1UnormSrgb => Self::Etc2Rgb8A1Unorm,
3809 Self::Etc2Rgba8UnormSrgb => Self::Etc2Rgba8Unorm,
3810 Self::Astc {
3811 block,
3812 channel: AstcChannel::UnormSrgb,
3813 } => Self::Astc {
3814 block,
3815 channel: AstcChannel::Unorm,
3816 },
3817 _ => *self,
3818 }
3819 }
3820
3821 /// Adds an `Srgb` suffix to the given texture format, if the format supports it.
3822 #[must_use]
3823 pub fn add_srgb_suffix(&self) -> TextureFormat {
3824 match *self {
3825 Self::Rgba8Unorm => Self::Rgba8UnormSrgb,
3826 Self::Bgra8Unorm => Self::Bgra8UnormSrgb,
3827 Self::Bc1RgbaUnorm => Self::Bc1RgbaUnormSrgb,
3828 Self::Bc2RgbaUnorm => Self::Bc2RgbaUnormSrgb,
3829 Self::Bc3RgbaUnorm => Self::Bc3RgbaUnormSrgb,
3830 Self::Bc7RgbaUnorm => Self::Bc7RgbaUnormSrgb,
3831 Self::Etc2Rgb8Unorm => Self::Etc2Rgb8UnormSrgb,
3832 Self::Etc2Rgb8A1Unorm => Self::Etc2Rgb8A1UnormSrgb,
3833 Self::Etc2Rgba8Unorm => Self::Etc2Rgba8UnormSrgb,
3834 Self::Astc {
3835 block,
3836 channel: AstcChannel::Unorm,
3837 } => Self::Astc {
3838 block,
3839 channel: AstcChannel::UnormSrgb,
3840 },
3841 _ => *self,
3842 }
3843 }
3844
3845 /// Returns `true` for srgb formats.
3846 #[must_use]
3847 pub fn is_srgb(&self) -> bool {
3848 *self != self.remove_srgb_suffix()
3849 }
3850
3851 /// Returns the theoretical memory footprint of a texture with the given format and dimensions.
3852 ///
3853 /// Actual memory usage may greatly exceed this value due to alignment and padding.
3854 #[must_use]
3855 pub fn theoretical_memory_footprint(&self, size: Extent3d) -> u64 {
3856 let (block_width, block_height) = self.block_dimensions();
3857
3858 let block_size = self.block_copy_size(None);
3859
3860 let approximate_block_size = match block_size {
3861 Some(size) => size,
3862 None => match self {
3863 // One f16 per pixel
3864 Self::Depth16Unorm => 2,
3865 // One u24 per pixel, padded to 4 bytes
3866 Self::Depth24Plus => 4,
3867 // One u24 per pixel, plus one u8 per pixel
3868 Self::Depth24PlusStencil8 => 4,
3869 // One f32 per pixel
3870 Self::Depth32Float => 4,
3871 // One f32 per pixel, plus one u8 per pixel, with 3 bytes intermediary padding
3872 Self::Depth32FloatStencil8 => 8,
3873 // One u8 per pixel
3874 Self::Stencil8 => 1,
3875 // Two chroma bytes per block, one luma byte per block
3876 Self::NV12 => 3,
3877 // Two chroma u16s and one luma u16 per block
3878 Self::P010 => 6,
3879 f => {
3880 log::warn!("Memory footprint for format {f:?} is not implemented");
3881 0
3882 }
3883 },
3884 };
3885
3886 let width_blocks = size.width.div_ceil(block_width) as u64;
3887 let height_blocks = size.height.div_ceil(block_height) as u64;
3888
3889 let total_blocks = width_blocks * height_blocks * size.depth_or_array_layers as u64;
3890
3891 total_blocks * approximate_block_size as u64
3892 }
3893}
3894
3895#[test]
3896fn texture_format_serialize() {
3897 use alloc::string::ToString;
3898
3899 assert_eq!(
3900 serde_json::to_string(&TextureFormat::R8Unorm).unwrap(),
3901 "\"r8unorm\"".to_string()
3902 );
3903 assert_eq!(
3904 serde_json::to_string(&TextureFormat::R8Snorm).unwrap(),
3905 "\"r8snorm\"".to_string()
3906 );
3907 assert_eq!(
3908 serde_json::to_string(&TextureFormat::R8Uint).unwrap(),
3909 "\"r8uint\"".to_string()
3910 );
3911 assert_eq!(
3912 serde_json::to_string(&TextureFormat::R8Sint).unwrap(),
3913 "\"r8sint\"".to_string()
3914 );
3915 assert_eq!(
3916 serde_json::to_string(&TextureFormat::R16Uint).unwrap(),
3917 "\"r16uint\"".to_string()
3918 );
3919 assert_eq!(
3920 serde_json::to_string(&TextureFormat::R16Sint).unwrap(),
3921 "\"r16sint\"".to_string()
3922 );
3923 assert_eq!(
3924 serde_json::to_string(&TextureFormat::R16Unorm).unwrap(),
3925 "\"r16unorm\"".to_string()
3926 );
3927 assert_eq!(
3928 serde_json::to_string(&TextureFormat::R16Snorm).unwrap(),
3929 "\"r16snorm\"".to_string()
3930 );
3931 assert_eq!(
3932 serde_json::to_string(&TextureFormat::R16Float).unwrap(),
3933 "\"r16float\"".to_string()
3934 );
3935 assert_eq!(
3936 serde_json::to_string(&TextureFormat::Rg8Unorm).unwrap(),
3937 "\"rg8unorm\"".to_string()
3938 );
3939 assert_eq!(
3940 serde_json::to_string(&TextureFormat::Rg8Snorm).unwrap(),
3941 "\"rg8snorm\"".to_string()
3942 );
3943 assert_eq!(
3944 serde_json::to_string(&TextureFormat::Rg8Uint).unwrap(),
3945 "\"rg8uint\"".to_string()
3946 );
3947 assert_eq!(
3948 serde_json::to_string(&TextureFormat::Rg8Sint).unwrap(),
3949 "\"rg8sint\"".to_string()
3950 );
3951 assert_eq!(
3952 serde_json::to_string(&TextureFormat::R32Uint).unwrap(),
3953 "\"r32uint\"".to_string()
3954 );
3955 assert_eq!(
3956 serde_json::to_string(&TextureFormat::R32Sint).unwrap(),
3957 "\"r32sint\"".to_string()
3958 );
3959 assert_eq!(
3960 serde_json::to_string(&TextureFormat::R32Float).unwrap(),
3961 "\"r32float\"".to_string()
3962 );
3963 assert_eq!(
3964 serde_json::to_string(&TextureFormat::Rg16Uint).unwrap(),
3965 "\"rg16uint\"".to_string()
3966 );
3967 assert_eq!(
3968 serde_json::to_string(&TextureFormat::Rg16Sint).unwrap(),
3969 "\"rg16sint\"".to_string()
3970 );
3971 assert_eq!(
3972 serde_json::to_string(&TextureFormat::Rg16Unorm).unwrap(),
3973 "\"rg16unorm\"".to_string()
3974 );
3975 assert_eq!(
3976 serde_json::to_string(&TextureFormat::Rg16Snorm).unwrap(),
3977 "\"rg16snorm\"".to_string()
3978 );
3979 assert_eq!(
3980 serde_json::to_string(&TextureFormat::Rg16Float).unwrap(),
3981 "\"rg16float\"".to_string()
3982 );
3983 assert_eq!(
3984 serde_json::to_string(&TextureFormat::Rgba8Unorm).unwrap(),
3985 "\"rgba8unorm\"".to_string()
3986 );
3987 assert_eq!(
3988 serde_json::to_string(&TextureFormat::Rgba8UnormSrgb).unwrap(),
3989 "\"rgba8unorm-srgb\"".to_string()
3990 );
3991 assert_eq!(
3992 serde_json::to_string(&TextureFormat::Rgba8Snorm).unwrap(),
3993 "\"rgba8snorm\"".to_string()
3994 );
3995 assert_eq!(
3996 serde_json::to_string(&TextureFormat::Rgba8Uint).unwrap(),
3997 "\"rgba8uint\"".to_string()
3998 );
3999 assert_eq!(
4000 serde_json::to_string(&TextureFormat::Rgba8Sint).unwrap(),
4001 "\"rgba8sint\"".to_string()
4002 );
4003 assert_eq!(
4004 serde_json::to_string(&TextureFormat::Bgra8Unorm).unwrap(),
4005 "\"bgra8unorm\"".to_string()
4006 );
4007 assert_eq!(
4008 serde_json::to_string(&TextureFormat::Bgra8UnormSrgb).unwrap(),
4009 "\"bgra8unorm-srgb\"".to_string()
4010 );
4011 assert_eq!(
4012 serde_json::to_string(&TextureFormat::Rgb10a2Uint).unwrap(),
4013 "\"rgb10a2uint\"".to_string()
4014 );
4015 assert_eq!(
4016 serde_json::to_string(&TextureFormat::Rgb10a2Unorm).unwrap(),
4017 "\"rgb10a2unorm\"".to_string()
4018 );
4019 assert_eq!(
4020 serde_json::to_string(&TextureFormat::Rg11b10Ufloat).unwrap(),
4021 "\"rg11b10ufloat\"".to_string()
4022 );
4023 assert_eq!(
4024 serde_json::to_string(&TextureFormat::R64Uint).unwrap(),
4025 "\"r64uint\"".to_string()
4026 );
4027 assert_eq!(
4028 serde_json::to_string(&TextureFormat::Rg32Uint).unwrap(),
4029 "\"rg32uint\"".to_string()
4030 );
4031 assert_eq!(
4032 serde_json::to_string(&TextureFormat::Rg32Sint).unwrap(),
4033 "\"rg32sint\"".to_string()
4034 );
4035 assert_eq!(
4036 serde_json::to_string(&TextureFormat::Rg32Float).unwrap(),
4037 "\"rg32float\"".to_string()
4038 );
4039 assert_eq!(
4040 serde_json::to_string(&TextureFormat::Rgba16Uint).unwrap(),
4041 "\"rgba16uint\"".to_string()
4042 );
4043 assert_eq!(
4044 serde_json::to_string(&TextureFormat::Rgba16Sint).unwrap(),
4045 "\"rgba16sint\"".to_string()
4046 );
4047 assert_eq!(
4048 serde_json::to_string(&TextureFormat::Rgba16Unorm).unwrap(),
4049 "\"rgba16unorm\"".to_string()
4050 );
4051 assert_eq!(
4052 serde_json::to_string(&TextureFormat::Rgba16Snorm).unwrap(),
4053 "\"rgba16snorm\"".to_string()
4054 );
4055 assert_eq!(
4056 serde_json::to_string(&TextureFormat::Rgba16Float).unwrap(),
4057 "\"rgba16float\"".to_string()
4058 );
4059 assert_eq!(
4060 serde_json::to_string(&TextureFormat::Rgba32Uint).unwrap(),
4061 "\"rgba32uint\"".to_string()
4062 );
4063 assert_eq!(
4064 serde_json::to_string(&TextureFormat::Rgba32Sint).unwrap(),
4065 "\"rgba32sint\"".to_string()
4066 );
4067 assert_eq!(
4068 serde_json::to_string(&TextureFormat::Rgba32Float).unwrap(),
4069 "\"rgba32float\"".to_string()
4070 );
4071 assert_eq!(
4072 serde_json::to_string(&TextureFormat::Stencil8).unwrap(),
4073 "\"stencil8\"".to_string()
4074 );
4075 assert_eq!(
4076 serde_json::to_string(&TextureFormat::Depth32Float).unwrap(),
4077 "\"depth32float\"".to_string()
4078 );
4079 assert_eq!(
4080 serde_json::to_string(&TextureFormat::Depth16Unorm).unwrap(),
4081 "\"depth16unorm\"".to_string()
4082 );
4083 assert_eq!(
4084 serde_json::to_string(&TextureFormat::Depth32FloatStencil8).unwrap(),
4085 "\"depth32float-stencil8\"".to_string()
4086 );
4087 assert_eq!(
4088 serde_json::to_string(&TextureFormat::Depth24Plus).unwrap(),
4089 "\"depth24plus\"".to_string()
4090 );
4091 assert_eq!(
4092 serde_json::to_string(&TextureFormat::Depth24PlusStencil8).unwrap(),
4093 "\"depth24plus-stencil8\"".to_string()
4094 );
4095 assert_eq!(
4096 serde_json::to_string(&TextureFormat::Rgb9e5Ufloat).unwrap(),
4097 "\"rgb9e5ufloat\"".to_string()
4098 );
4099 assert_eq!(
4100 serde_json::to_string(&TextureFormat::Bc1RgbaUnorm).unwrap(),
4101 "\"bc1-rgba-unorm\"".to_string()
4102 );
4103 assert_eq!(
4104 serde_json::to_string(&TextureFormat::Bc1RgbaUnormSrgb).unwrap(),
4105 "\"bc1-rgba-unorm-srgb\"".to_string()
4106 );
4107 assert_eq!(
4108 serde_json::to_string(&TextureFormat::Bc2RgbaUnorm).unwrap(),
4109 "\"bc2-rgba-unorm\"".to_string()
4110 );
4111 assert_eq!(
4112 serde_json::to_string(&TextureFormat::Bc2RgbaUnormSrgb).unwrap(),
4113 "\"bc2-rgba-unorm-srgb\"".to_string()
4114 );
4115 assert_eq!(
4116 serde_json::to_string(&TextureFormat::Bc3RgbaUnorm).unwrap(),
4117 "\"bc3-rgba-unorm\"".to_string()
4118 );
4119 assert_eq!(
4120 serde_json::to_string(&TextureFormat::Bc3RgbaUnormSrgb).unwrap(),
4121 "\"bc3-rgba-unorm-srgb\"".to_string()
4122 );
4123 assert_eq!(
4124 serde_json::to_string(&TextureFormat::Bc4RUnorm).unwrap(),
4125 "\"bc4-r-unorm\"".to_string()
4126 );
4127 assert_eq!(
4128 serde_json::to_string(&TextureFormat::Bc4RSnorm).unwrap(),
4129 "\"bc4-r-snorm\"".to_string()
4130 );
4131 assert_eq!(
4132 serde_json::to_string(&TextureFormat::Bc5RgUnorm).unwrap(),
4133 "\"bc5-rg-unorm\"".to_string()
4134 );
4135 assert_eq!(
4136 serde_json::to_string(&TextureFormat::Bc5RgSnorm).unwrap(),
4137 "\"bc5-rg-snorm\"".to_string()
4138 );
4139 assert_eq!(
4140 serde_json::to_string(&TextureFormat::Bc6hRgbUfloat).unwrap(),
4141 "\"bc6h-rgb-ufloat\"".to_string()
4142 );
4143 assert_eq!(
4144 serde_json::to_string(&TextureFormat::Bc6hRgbFloat).unwrap(),
4145 "\"bc6h-rgb-float\"".to_string()
4146 );
4147 assert_eq!(
4148 serde_json::to_string(&TextureFormat::Bc7RgbaUnorm).unwrap(),
4149 "\"bc7-rgba-unorm\"".to_string()
4150 );
4151 assert_eq!(
4152 serde_json::to_string(&TextureFormat::Bc7RgbaUnormSrgb).unwrap(),
4153 "\"bc7-rgba-unorm-srgb\"".to_string()
4154 );
4155 assert_eq!(
4156 serde_json::to_string(&TextureFormat::Etc2Rgb8Unorm).unwrap(),
4157 "\"etc2-rgb8unorm\"".to_string()
4158 );
4159 assert_eq!(
4160 serde_json::to_string(&TextureFormat::Etc2Rgb8UnormSrgb).unwrap(),
4161 "\"etc2-rgb8unorm-srgb\"".to_string()
4162 );
4163 assert_eq!(
4164 serde_json::to_string(&TextureFormat::Etc2Rgb8A1Unorm).unwrap(),
4165 "\"etc2-rgb8a1unorm\"".to_string()
4166 );
4167 assert_eq!(
4168 serde_json::to_string(&TextureFormat::Etc2Rgb8A1UnormSrgb).unwrap(),
4169 "\"etc2-rgb8a1unorm-srgb\"".to_string()
4170 );
4171 assert_eq!(
4172 serde_json::to_string(&TextureFormat::Etc2Rgba8Unorm).unwrap(),
4173 "\"etc2-rgba8unorm\"".to_string()
4174 );
4175 assert_eq!(
4176 serde_json::to_string(&TextureFormat::Etc2Rgba8UnormSrgb).unwrap(),
4177 "\"etc2-rgba8unorm-srgb\"".to_string()
4178 );
4179 assert_eq!(
4180 serde_json::to_string(&TextureFormat::EacR11Unorm).unwrap(),
4181 "\"eac-r11unorm\"".to_string()
4182 );
4183 assert_eq!(
4184 serde_json::to_string(&TextureFormat::EacR11Snorm).unwrap(),
4185 "\"eac-r11snorm\"".to_string()
4186 );
4187 assert_eq!(
4188 serde_json::to_string(&TextureFormat::EacRg11Unorm).unwrap(),
4189 "\"eac-rg11unorm\"".to_string()
4190 );
4191 assert_eq!(
4192 serde_json::to_string(&TextureFormat::EacRg11Snorm).unwrap(),
4193 "\"eac-rg11snorm\"".to_string()
4194 );
4195}
4196
4197#[test]
4198fn texture_format_deserialize() {
4199 assert_eq!(
4200 serde_json::from_str::<TextureFormat>("\"r8unorm\"").unwrap(),
4201 TextureFormat::R8Unorm
4202 );
4203 assert_eq!(
4204 serde_json::from_str::<TextureFormat>("\"r8snorm\"").unwrap(),
4205 TextureFormat::R8Snorm
4206 );
4207 assert_eq!(
4208 serde_json::from_str::<TextureFormat>("\"r8uint\"").unwrap(),
4209 TextureFormat::R8Uint
4210 );
4211 assert_eq!(
4212 serde_json::from_str::<TextureFormat>("\"r8sint\"").unwrap(),
4213 TextureFormat::R8Sint
4214 );
4215 assert_eq!(
4216 serde_json::from_str::<TextureFormat>("\"r16uint\"").unwrap(),
4217 TextureFormat::R16Uint
4218 );
4219 assert_eq!(
4220 serde_json::from_str::<TextureFormat>("\"r16sint\"").unwrap(),
4221 TextureFormat::R16Sint
4222 );
4223 assert_eq!(
4224 serde_json::from_str::<TextureFormat>("\"r16unorm\"").unwrap(),
4225 TextureFormat::R16Unorm
4226 );
4227 assert_eq!(
4228 serde_json::from_str::<TextureFormat>("\"r16snorm\"").unwrap(),
4229 TextureFormat::R16Snorm
4230 );
4231 assert_eq!(
4232 serde_json::from_str::<TextureFormat>("\"r16float\"").unwrap(),
4233 TextureFormat::R16Float
4234 );
4235 assert_eq!(
4236 serde_json::from_str::<TextureFormat>("\"rg8unorm\"").unwrap(),
4237 TextureFormat::Rg8Unorm
4238 );
4239 assert_eq!(
4240 serde_json::from_str::<TextureFormat>("\"rg8snorm\"").unwrap(),
4241 TextureFormat::Rg8Snorm
4242 );
4243 assert_eq!(
4244 serde_json::from_str::<TextureFormat>("\"rg8uint\"").unwrap(),
4245 TextureFormat::Rg8Uint
4246 );
4247 assert_eq!(
4248 serde_json::from_str::<TextureFormat>("\"rg8sint\"").unwrap(),
4249 TextureFormat::Rg8Sint
4250 );
4251 assert_eq!(
4252 serde_json::from_str::<TextureFormat>("\"r32uint\"").unwrap(),
4253 TextureFormat::R32Uint
4254 );
4255 assert_eq!(
4256 serde_json::from_str::<TextureFormat>("\"r32sint\"").unwrap(),
4257 TextureFormat::R32Sint
4258 );
4259 assert_eq!(
4260 serde_json::from_str::<TextureFormat>("\"r32float\"").unwrap(),
4261 TextureFormat::R32Float
4262 );
4263 assert_eq!(
4264 serde_json::from_str::<TextureFormat>("\"rg16uint\"").unwrap(),
4265 TextureFormat::Rg16Uint
4266 );
4267 assert_eq!(
4268 serde_json::from_str::<TextureFormat>("\"rg16sint\"").unwrap(),
4269 TextureFormat::Rg16Sint
4270 );
4271 assert_eq!(
4272 serde_json::from_str::<TextureFormat>("\"rg16unorm\"").unwrap(),
4273 TextureFormat::Rg16Unorm
4274 );
4275 assert_eq!(
4276 serde_json::from_str::<TextureFormat>("\"rg16snorm\"").unwrap(),
4277 TextureFormat::Rg16Snorm
4278 );
4279 assert_eq!(
4280 serde_json::from_str::<TextureFormat>("\"rg16float\"").unwrap(),
4281 TextureFormat::Rg16Float
4282 );
4283 assert_eq!(
4284 serde_json::from_str::<TextureFormat>("\"rgba8unorm\"").unwrap(),
4285 TextureFormat::Rgba8Unorm
4286 );
4287 assert_eq!(
4288 serde_json::from_str::<TextureFormat>("\"rgba8unorm-srgb\"").unwrap(),
4289 TextureFormat::Rgba8UnormSrgb
4290 );
4291 assert_eq!(
4292 serde_json::from_str::<TextureFormat>("\"rgba8snorm\"").unwrap(),
4293 TextureFormat::Rgba8Snorm
4294 );
4295 assert_eq!(
4296 serde_json::from_str::<TextureFormat>("\"rgba8uint\"").unwrap(),
4297 TextureFormat::Rgba8Uint
4298 );
4299 assert_eq!(
4300 serde_json::from_str::<TextureFormat>("\"rgba8sint\"").unwrap(),
4301 TextureFormat::Rgba8Sint
4302 );
4303 assert_eq!(
4304 serde_json::from_str::<TextureFormat>("\"bgra8unorm\"").unwrap(),
4305 TextureFormat::Bgra8Unorm
4306 );
4307 assert_eq!(
4308 serde_json::from_str::<TextureFormat>("\"bgra8unorm-srgb\"").unwrap(),
4309 TextureFormat::Bgra8UnormSrgb
4310 );
4311 assert_eq!(
4312 serde_json::from_str::<TextureFormat>("\"rgb10a2uint\"").unwrap(),
4313 TextureFormat::Rgb10a2Uint
4314 );
4315 assert_eq!(
4316 serde_json::from_str::<TextureFormat>("\"rgb10a2unorm\"").unwrap(),
4317 TextureFormat::Rgb10a2Unorm
4318 );
4319 assert_eq!(
4320 serde_json::from_str::<TextureFormat>("\"rg11b10ufloat\"").unwrap(),
4321 TextureFormat::Rg11b10Ufloat
4322 );
4323 assert_eq!(
4324 serde_json::from_str::<TextureFormat>("\"r64uint\"").unwrap(),
4325 TextureFormat::R64Uint
4326 );
4327 assert_eq!(
4328 serde_json::from_str::<TextureFormat>("\"rg32uint\"").unwrap(),
4329 TextureFormat::Rg32Uint
4330 );
4331 assert_eq!(
4332 serde_json::from_str::<TextureFormat>("\"rg32sint\"").unwrap(),
4333 TextureFormat::Rg32Sint
4334 );
4335 assert_eq!(
4336 serde_json::from_str::<TextureFormat>("\"rg32float\"").unwrap(),
4337 TextureFormat::Rg32Float
4338 );
4339 assert_eq!(
4340 serde_json::from_str::<TextureFormat>("\"rgba16uint\"").unwrap(),
4341 TextureFormat::Rgba16Uint
4342 );
4343 assert_eq!(
4344 serde_json::from_str::<TextureFormat>("\"rgba16sint\"").unwrap(),
4345 TextureFormat::Rgba16Sint
4346 );
4347 assert_eq!(
4348 serde_json::from_str::<TextureFormat>("\"rgba16unorm\"").unwrap(),
4349 TextureFormat::Rgba16Unorm
4350 );
4351 assert_eq!(
4352 serde_json::from_str::<TextureFormat>("\"rgba16snorm\"").unwrap(),
4353 TextureFormat::Rgba16Snorm
4354 );
4355 assert_eq!(
4356 serde_json::from_str::<TextureFormat>("\"rgba16float\"").unwrap(),
4357 TextureFormat::Rgba16Float
4358 );
4359 assert_eq!(
4360 serde_json::from_str::<TextureFormat>("\"rgba32uint\"").unwrap(),
4361 TextureFormat::Rgba32Uint
4362 );
4363 assert_eq!(
4364 serde_json::from_str::<TextureFormat>("\"rgba32sint\"").unwrap(),
4365 TextureFormat::Rgba32Sint
4366 );
4367 assert_eq!(
4368 serde_json::from_str::<TextureFormat>("\"rgba32float\"").unwrap(),
4369 TextureFormat::Rgba32Float
4370 );
4371 assert_eq!(
4372 serde_json::from_str::<TextureFormat>("\"stencil8\"").unwrap(),
4373 TextureFormat::Stencil8
4374 );
4375 assert_eq!(
4376 serde_json::from_str::<TextureFormat>("\"depth32float\"").unwrap(),
4377 TextureFormat::Depth32Float
4378 );
4379 assert_eq!(
4380 serde_json::from_str::<TextureFormat>("\"depth16unorm\"").unwrap(),
4381 TextureFormat::Depth16Unorm
4382 );
4383 assert_eq!(
4384 serde_json::from_str::<TextureFormat>("\"depth32float-stencil8\"").unwrap(),
4385 TextureFormat::Depth32FloatStencil8
4386 );
4387 assert_eq!(
4388 serde_json::from_str::<TextureFormat>("\"depth24plus\"").unwrap(),
4389 TextureFormat::Depth24Plus
4390 );
4391 assert_eq!(
4392 serde_json::from_str::<TextureFormat>("\"depth24plus-stencil8\"").unwrap(),
4393 TextureFormat::Depth24PlusStencil8
4394 );
4395 assert_eq!(
4396 serde_json::from_str::<TextureFormat>("\"rgb9e5ufloat\"").unwrap(),
4397 TextureFormat::Rgb9e5Ufloat
4398 );
4399 assert_eq!(
4400 serde_json::from_str::<TextureFormat>("\"bc1-rgba-unorm\"").unwrap(),
4401 TextureFormat::Bc1RgbaUnorm
4402 );
4403 assert_eq!(
4404 serde_json::from_str::<TextureFormat>("\"bc1-rgba-unorm-srgb\"").unwrap(),
4405 TextureFormat::Bc1RgbaUnormSrgb
4406 );
4407 assert_eq!(
4408 serde_json::from_str::<TextureFormat>("\"bc2-rgba-unorm\"").unwrap(),
4409 TextureFormat::Bc2RgbaUnorm
4410 );
4411 assert_eq!(
4412 serde_json::from_str::<TextureFormat>("\"bc2-rgba-unorm-srgb\"").unwrap(),
4413 TextureFormat::Bc2RgbaUnormSrgb
4414 );
4415 assert_eq!(
4416 serde_json::from_str::<TextureFormat>("\"bc3-rgba-unorm\"").unwrap(),
4417 TextureFormat::Bc3RgbaUnorm
4418 );
4419 assert_eq!(
4420 serde_json::from_str::<TextureFormat>("\"bc3-rgba-unorm-srgb\"").unwrap(),
4421 TextureFormat::Bc3RgbaUnormSrgb
4422 );
4423 assert_eq!(
4424 serde_json::from_str::<TextureFormat>("\"bc4-r-unorm\"").unwrap(),
4425 TextureFormat::Bc4RUnorm
4426 );
4427 assert_eq!(
4428 serde_json::from_str::<TextureFormat>("\"bc4-r-snorm\"").unwrap(),
4429 TextureFormat::Bc4RSnorm
4430 );
4431 assert_eq!(
4432 serde_json::from_str::<TextureFormat>("\"bc5-rg-unorm\"").unwrap(),
4433 TextureFormat::Bc5RgUnorm
4434 );
4435 assert_eq!(
4436 serde_json::from_str::<TextureFormat>("\"bc5-rg-snorm\"").unwrap(),
4437 TextureFormat::Bc5RgSnorm
4438 );
4439 assert_eq!(
4440 serde_json::from_str::<TextureFormat>("\"bc6h-rgb-ufloat\"").unwrap(),
4441 TextureFormat::Bc6hRgbUfloat
4442 );
4443 assert_eq!(
4444 serde_json::from_str::<TextureFormat>("\"bc6h-rgb-float\"").unwrap(),
4445 TextureFormat::Bc6hRgbFloat
4446 );
4447 assert_eq!(
4448 serde_json::from_str::<TextureFormat>("\"bc7-rgba-unorm\"").unwrap(),
4449 TextureFormat::Bc7RgbaUnorm
4450 );
4451 assert_eq!(
4452 serde_json::from_str::<TextureFormat>("\"bc7-rgba-unorm-srgb\"").unwrap(),
4453 TextureFormat::Bc7RgbaUnormSrgb
4454 );
4455 assert_eq!(
4456 serde_json::from_str::<TextureFormat>("\"etc2-rgb8unorm\"").unwrap(),
4457 TextureFormat::Etc2Rgb8Unorm
4458 );
4459 assert_eq!(
4460 serde_json::from_str::<TextureFormat>("\"etc2-rgb8unorm-srgb\"").unwrap(),
4461 TextureFormat::Etc2Rgb8UnormSrgb
4462 );
4463 assert_eq!(
4464 serde_json::from_str::<TextureFormat>("\"etc2-rgb8a1unorm\"").unwrap(),
4465 TextureFormat::Etc2Rgb8A1Unorm
4466 );
4467 assert_eq!(
4468 serde_json::from_str::<TextureFormat>("\"etc2-rgb8a1unorm-srgb\"").unwrap(),
4469 TextureFormat::Etc2Rgb8A1UnormSrgb
4470 );
4471 assert_eq!(
4472 serde_json::from_str::<TextureFormat>("\"etc2-rgba8unorm\"").unwrap(),
4473 TextureFormat::Etc2Rgba8Unorm
4474 );
4475 assert_eq!(
4476 serde_json::from_str::<TextureFormat>("\"etc2-rgba8unorm-srgb\"").unwrap(),
4477 TextureFormat::Etc2Rgba8UnormSrgb
4478 );
4479 assert_eq!(
4480 serde_json::from_str::<TextureFormat>("\"eac-r11unorm\"").unwrap(),
4481 TextureFormat::EacR11Unorm
4482 );
4483 assert_eq!(
4484 serde_json::from_str::<TextureFormat>("\"eac-r11snorm\"").unwrap(),
4485 TextureFormat::EacR11Snorm
4486 );
4487 assert_eq!(
4488 serde_json::from_str::<TextureFormat>("\"eac-rg11unorm\"").unwrap(),
4489 TextureFormat::EacRg11Unorm
4490 );
4491 assert_eq!(
4492 serde_json::from_str::<TextureFormat>("\"eac-rg11snorm\"").unwrap(),
4493 TextureFormat::EacRg11Snorm
4494 );
4495}
4496
4497/// Color write mask. Disabled color channels will not be written to.
4498///
4499/// Corresponds to [WebGPU `GPUColorWriteFlags`](
4500/// https://gpuweb.github.io/gpuweb/#typedefdef-gpucolorwriteflags).
4501#[repr(transparent)]
4502#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4503#[cfg_attr(feature = "serde", serde(transparent))]
4504#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
4505pub struct ColorWrites(u32);
4506
4507bitflags::bitflags! {
4508 impl ColorWrites: u32 {
4509 /// Enable red channel writes
4510 const RED = 1 << 0;
4511 /// Enable green channel writes
4512 const GREEN = 1 << 1;
4513 /// Enable blue channel writes
4514 const BLUE = 1 << 2;
4515 /// Enable alpha channel writes
4516 const ALPHA = 1 << 3;
4517 /// Enable red, green, and blue channel writes
4518 const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
4519 /// Enable writes to all channels.
4520 const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
4521 }
4522}
4523
4524impl Default for ColorWrites {
4525 fn default() -> Self {
4526 Self::ALL
4527 }
4528}
4529
4530/// Passed to `Device::poll` to control how and if it should block.
4531#[derive(Clone, Debug)]
4532pub enum PollType<T> {
4533 /// On wgpu-core based backends, block until the given submission has
4534 /// completed execution, and any callbacks have been invoked.
4535 ///
4536 /// On WebGPU, this has no effect. Callbacks are invoked from the
4537 /// window event loop.
4538 Wait {
4539 /// Submission index to wait for.
4540 ///
4541 /// If not specified, will wait for the most recent submission at the time of the poll.
4542 /// By the time the method returns, more submissions may have taken place.
4543 submission_index: Option<T>,
4544
4545 /// Max time to wait for the submission to complete.
4546 ///
4547 /// If not specified, will wait indefinitely (or until an error is detected).
4548 /// If waiting for the GPU device takes this long or longer, the poll will return [`PollError::Timeout`].
4549 timeout: Option<Duration>,
4550 },
4551
4552 /// Check the device for a single time without blocking.
4553 Poll,
4554}
4555
4556impl<T> PollType<T> {
4557 /// Wait indefinitely until for the most recent submission to complete.
4558 ///
4559 /// This is a convenience function that creates a [`Self::Wait`] variant with
4560 /// no timeout and no submission index.
4561 #[must_use]
4562 pub const fn wait_indefinitely() -> Self {
4563 Self::Wait {
4564 submission_index: None,
4565 timeout: None,
4566 }
4567 }
4568
4569 /// This `PollType` represents a wait of some kind.
4570 #[must_use]
4571 pub fn is_wait(&self) -> bool {
4572 match *self {
4573 Self::Wait { .. } => true,
4574 Self::Poll => false,
4575 }
4576 }
4577
4578 /// Map on the wait index type.
4579 #[must_use]
4580 pub fn map_index<U, F>(self, func: F) -> PollType<U>
4581 where
4582 F: FnOnce(T) -> U,
4583 {
4584 match self {
4585 Self::Wait {
4586 submission_index,
4587 timeout,
4588 } => PollType::Wait {
4589 submission_index: submission_index.map(func),
4590 timeout,
4591 },
4592 Self::Poll => PollType::Poll,
4593 }
4594 }
4595}
4596
4597/// Error states after a device poll.
4598#[derive(Debug)]
4599pub enum PollError {
4600 /// The requested Wait timed out before the submission was completed.
4601 Timeout,
4602 /// The requested Wait was given a wrong submission index.
4603 WrongSubmissionIndex(u64, u64),
4604}
4605
4606// This impl could be derived by `thiserror`, but by not doing so, we can reduce the number of
4607// dependencies this early in the dependency graph, which may improve build parallelism.
4608impl fmt::Display for PollError {
4609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4610 match self {
4611 PollError::Timeout => {
4612 f.write_str("The requested Wait timed out before the submission was completed.")
4613 }
4614 PollError::WrongSubmissionIndex(requested, successful) => write!(
4615 f,
4616 "Tried to wait using a submission index ({requested}) \
4617 that has not been returned by a successful submission \
4618 (last successful submission: {successful}"
4619 ),
4620 }
4621 }
4622}
4623
4624impl core::error::Error for PollError {}
4625
4626/// Status of device poll operation.
4627#[derive(Debug, PartialEq, Eq)]
4628pub enum PollStatus {
4629 /// There are no active submissions in flight as of the beginning of the poll call.
4630 /// Other submissions may have been queued on other threads during the call.
4631 ///
4632 /// This implies that the given Wait was satisfied before the timeout.
4633 QueueEmpty,
4634
4635 /// The requested Wait was satisfied before the timeout.
4636 WaitSucceeded,
4637
4638 /// This was a poll.
4639 Poll,
4640}
4641
4642impl PollStatus {
4643 /// Returns true if the result is [`Self::QueueEmpty`].
4644 #[must_use]
4645 pub fn is_queue_empty(&self) -> bool {
4646 matches!(self, Self::QueueEmpty)
4647 }
4648
4649 /// Returns true if the result is either [`Self::WaitSucceeded`] or [`Self::QueueEmpty`].
4650 #[must_use]
4651 pub fn wait_finished(&self) -> bool {
4652 matches!(self, Self::WaitSucceeded | Self::QueueEmpty)
4653 }
4654}
4655
4656/// State of the stencil operation (fixed-pipeline stage).
4657///
4658/// For use in [`DepthStencilState`].
4659///
4660/// Corresponds to a portion of [WebGPU `GPUDepthStencilState`](
4661/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
4662#[repr(C)]
4663#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
4664#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4665pub struct StencilState {
4666 /// Front face mode.
4667 pub front: StencilFaceState,
4668 /// Back face mode.
4669 pub back: StencilFaceState,
4670 /// Stencil values are AND'd with this mask when reading and writing from the stencil buffer. Only low 8 bits are used.
4671 pub read_mask: u32,
4672 /// Stencil values are AND'd with this mask when writing to the stencil buffer. Only low 8 bits are used.
4673 pub write_mask: u32,
4674}
4675
4676impl StencilState {
4677 /// Returns true if the stencil test is enabled.
4678 #[must_use]
4679 pub fn is_enabled(&self) -> bool {
4680 (self.front != StencilFaceState::IGNORE || self.back != StencilFaceState::IGNORE)
4681 && (self.read_mask != 0 || self.write_mask != 0)
4682 }
4683 /// Returns true if the state doesn't mutate the target values.
4684 #[must_use]
4685 pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
4686 // The rules are defined in step 7 of the "Device timeline initialization steps"
4687 // subsection of the "Render Pipeline Creation" section of WebGPU
4688 // (link to the section: https://gpuweb.github.io/gpuweb/#render-pipeline-creation)
4689
4690 if self.write_mask == 0 {
4691 return true;
4692 }
4693
4694 let front_ro = cull_mode == Some(Face::Front) || self.front.is_read_only();
4695 let back_ro = cull_mode == Some(Face::Back) || self.back.is_read_only();
4696
4697 front_ro && back_ro
4698 }
4699 /// Returns true if the stencil state uses the reference value for testing.
4700 #[must_use]
4701 pub fn needs_ref_value(&self) -> bool {
4702 self.front.needs_ref_value() || self.back.needs_ref_value()
4703 }
4704}
4705
4706/// Describes the biasing setting for the depth target.
4707///
4708/// For use in [`DepthStencilState`].
4709///
4710/// Corresponds to a portion of [WebGPU `GPUDepthStencilState`](
4711/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
4712#[repr(C)]
4713#[derive(Clone, Copy, Debug, Default)]
4714#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4715pub struct DepthBiasState {
4716 /// Constant depth biasing factor, in basic units of the depth format.
4717 pub constant: i32,
4718 /// Slope depth biasing factor.
4719 pub slope_scale: f32,
4720 /// Depth bias clamp value (absolute).
4721 pub clamp: f32,
4722}
4723
4724impl DepthBiasState {
4725 /// Returns true if the depth biasing is enabled.
4726 #[must_use]
4727 pub fn is_enabled(&self) -> bool {
4728 self.constant != 0 || self.slope_scale != 0.0
4729 }
4730}
4731
4732impl Hash for DepthBiasState {
4733 fn hash<H: Hasher>(&self, state: &mut H) {
4734 self.constant.hash(state);
4735 self.slope_scale.to_bits().hash(state);
4736 self.clamp.to_bits().hash(state);
4737 }
4738}
4739
4740impl PartialEq for DepthBiasState {
4741 fn eq(&self, other: &Self) -> bool {
4742 (self.constant == other.constant)
4743 && (self.slope_scale.to_bits() == other.slope_scale.to_bits())
4744 && (self.clamp.to_bits() == other.clamp.to_bits())
4745 }
4746}
4747
4748impl Eq for DepthBiasState {}
4749
4750/// Operation to perform to the output attachment at the start of a render pass.
4751///
4752/// Corresponds to [WebGPU `GPULoadOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpuloadop),
4753/// plus the corresponding clearValue.
4754#[repr(u8)]
4755#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
4756#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4757#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
4758pub enum LoadOp<V> {
4759 /// Loads the specified value for this attachment into the render pass.
4760 ///
4761 /// On some GPU hardware (primarily mobile), "clear" is significantly cheaper
4762 /// because it avoids loading data from main memory into tile-local memory.
4763 ///
4764 /// On other GPU hardware, there isn’t a significant difference.
4765 ///
4766 /// As a result, it is recommended to use "clear" rather than "load" in cases
4767 /// where the initial value doesn’t matter
4768 /// (e.g. the render target will be cleared using a skybox).
4769 Clear(V) = 0,
4770 /// Loads the existing value for this attachment into the render pass.
4771 Load = 1,
4772}
4773
4774impl<V> LoadOp<V> {
4775 /// Returns true if variants are same (ignoring clear value)
4776 pub fn eq_variant<T>(&self, other: LoadOp<T>) -> bool {
4777 matches!(
4778 (self, other),
4779 (LoadOp::Clear(_), LoadOp::Clear(_)) | (LoadOp::Load, LoadOp::Load)
4780 )
4781 }
4782}
4783
4784impl<V: Default> Default for LoadOp<V> {
4785 fn default() -> Self {
4786 Self::Clear(Default::default())
4787 }
4788}
4789
4790/// Operation to perform to the output attachment at the end of a render pass.
4791///
4792/// Corresponds to [WebGPU `GPUStoreOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpustoreop).
4793#[repr(C)]
4794#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
4795#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4796#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
4797pub enum StoreOp {
4798 /// Stores the resulting value of the render pass for this attachment.
4799 #[default]
4800 Store = 0,
4801 /// Discards the resulting value of the render pass for this attachment.
4802 ///
4803 /// The attachment will be treated as uninitialized afterwards.
4804 /// (If only either Depth or Stencil texture-aspects is set to `Discard`,
4805 /// the respective other texture-aspect will be preserved.)
4806 ///
4807 /// This can be significantly faster on tile-based render hardware.
4808 ///
4809 /// Prefer this if the attachment is not read by subsequent passes.
4810 Discard = 1,
4811}
4812
4813/// Pair of load and store operations for an attachment aspect.
4814///
4815/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
4816/// separate `loadOp` and `storeOp` fields are used instead.
4817#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
4818#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4819pub struct Operations<V> {
4820 /// How data should be read through this attachment.
4821 pub load: LoadOp<V>,
4822 /// Whether data will be written to through this attachment.
4823 ///
4824 /// Note that resolve textures (if specified) are always written to,
4825 /// regardless of this setting.
4826 pub store: StoreOp,
4827}
4828
4829impl<V: Default> Default for Operations<V> {
4830 #[inline]
4831 fn default() -> Self {
4832 Self {
4833 load: LoadOp::<V>::default(),
4834 store: StoreOp::default(),
4835 }
4836 }
4837}
4838
4839/// Describes the depth/stencil state in a render pipeline.
4840///
4841/// Corresponds to [WebGPU `GPUDepthStencilState`](
4842/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
4843#[repr(C)]
4844#[derive(Clone, Debug, Hash, PartialEq, Eq)]
4845#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4846pub struct DepthStencilState {
4847 /// Format of the depth/stencil buffer, must be special depth format. Must match the format
4848 /// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`][CEbrp].
4849 ///
4850 /// [CEbrp]: ../wgpu/struct.CommandEncoder.html#method.begin_render_pass
4851 pub format: TextureFormat,
4852 /// If disabled, depth will not be written to.
4853 pub depth_write_enabled: bool,
4854 /// Comparison function used to compare depth values in the depth test.
4855 pub depth_compare: CompareFunction,
4856 /// Stencil state.
4857 #[cfg_attr(feature = "serde", serde(default))]
4858 pub stencil: StencilState,
4859 /// Depth bias state.
4860 #[cfg_attr(feature = "serde", serde(default))]
4861 pub bias: DepthBiasState,
4862}
4863
4864impl DepthStencilState {
4865 /// Returns true if the depth testing is enabled.
4866 #[must_use]
4867 pub fn is_depth_enabled(&self) -> bool {
4868 self.depth_compare != CompareFunction::Always || self.depth_write_enabled
4869 }
4870
4871 /// Returns true if the state doesn't mutate the depth buffer.
4872 #[must_use]
4873 pub fn is_depth_read_only(&self) -> bool {
4874 !self.depth_write_enabled
4875 }
4876
4877 /// Returns true if the state doesn't mutate the stencil.
4878 #[must_use]
4879 pub fn is_stencil_read_only(&self, cull_mode: Option<Face>) -> bool {
4880 self.stencil.is_read_only(cull_mode)
4881 }
4882
4883 /// Returns true if the state doesn't mutate either depth or stencil of the target.
4884 #[must_use]
4885 pub fn is_read_only(&self, cull_mode: Option<Face>) -> bool {
4886 self.is_depth_read_only() && self.is_stencil_read_only(cull_mode)
4887 }
4888}
4889
4890/// Format of indices used with pipeline.
4891///
4892/// Corresponds to [WebGPU `GPUIndexFormat`](
4893/// https://gpuweb.github.io/gpuweb/#enumdef-gpuindexformat).
4894#[repr(C)]
4895#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
4896#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4897#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
4898pub enum IndexFormat {
4899 /// Indices are 16 bit unsigned integers.
4900 Uint16 = 0,
4901 /// Indices are 32 bit unsigned integers.
4902 #[default]
4903 Uint32 = 1,
4904}
4905
4906impl IndexFormat {
4907 /// Returns the size in bytes of the index format
4908 pub fn byte_size(&self) -> usize {
4909 match self {
4910 IndexFormat::Uint16 => 2,
4911 IndexFormat::Uint32 => 4,
4912 }
4913 }
4914}
4915
4916/// Operation to perform on the stencil value.
4917///
4918/// Corresponds to [WebGPU `GPUStencilOperation`](
4919/// https://gpuweb.github.io/gpuweb/#enumdef-gpustenciloperation).
4920#[repr(C)]
4921#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
4922#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4923#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
4924pub enum StencilOperation {
4925 /// Keep stencil value unchanged.
4926 #[default]
4927 Keep = 0,
4928 /// Set stencil value to zero.
4929 Zero = 1,
4930 /// Replace stencil value with value provided in most recent call to
4931 /// [`RenderPass::set_stencil_reference`][RPssr].
4932 ///
4933 /// [RPssr]: ../wgpu/struct.RenderPass.html#method.set_stencil_reference
4934 Replace = 2,
4935 /// Bitwise inverts stencil value.
4936 Invert = 3,
4937 /// Increments stencil value by one, clamping on overflow.
4938 IncrementClamp = 4,
4939 /// Decrements stencil value by one, clamping on underflow.
4940 DecrementClamp = 5,
4941 /// Increments stencil value by one, wrapping on overflow.
4942 IncrementWrap = 6,
4943 /// Decrements stencil value by one, wrapping on underflow.
4944 DecrementWrap = 7,
4945}
4946
4947/// Describes stencil state in a render pipeline.
4948///
4949/// If you are not using stencil state, set this to [`StencilFaceState::IGNORE`].
4950///
4951/// Corresponds to [WebGPU `GPUStencilFaceState`](
4952/// https://gpuweb.github.io/gpuweb/#dictdef-gpustencilfacestate).
4953#[repr(C)]
4954#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4955#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4956#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
4957pub struct StencilFaceState {
4958 /// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer.
4959 pub compare: CompareFunction,
4960 /// Operation that is performed when stencil test fails.
4961 pub fail_op: StencilOperation,
4962 /// Operation that is performed when depth test fails but stencil test succeeds.
4963 pub depth_fail_op: StencilOperation,
4964 /// Operation that is performed when stencil test success.
4965 pub pass_op: StencilOperation,
4966}
4967
4968impl StencilFaceState {
4969 /// Ignore the stencil state for the face.
4970 pub const IGNORE: Self = StencilFaceState {
4971 compare: CompareFunction::Always,
4972 fail_op: StencilOperation::Keep,
4973 depth_fail_op: StencilOperation::Keep,
4974 pass_op: StencilOperation::Keep,
4975 };
4976
4977 /// Returns true if the face state uses the reference value for testing or operation.
4978 #[must_use]
4979 pub fn needs_ref_value(&self) -> bool {
4980 self.compare.needs_ref_value()
4981 || self.fail_op == StencilOperation::Replace
4982 || self.depth_fail_op == StencilOperation::Replace
4983 || self.pass_op == StencilOperation::Replace
4984 }
4985
4986 /// Returns true if the face state doesn't mutate the target values.
4987 #[must_use]
4988 pub fn is_read_only(&self) -> bool {
4989 self.pass_op == StencilOperation::Keep
4990 && self.depth_fail_op == StencilOperation::Keep
4991 && self.fail_op == StencilOperation::Keep
4992 }
4993}
4994
4995impl Default for StencilFaceState {
4996 fn default() -> Self {
4997 Self::IGNORE
4998 }
4999}
5000
5001/// Comparison function used for depth and stencil operations.
5002///
5003/// Corresponds to [WebGPU `GPUCompareFunction`](
5004/// https://gpuweb.github.io/gpuweb/#enumdef-gpucomparefunction).
5005#[repr(C)]
5006#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
5007#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5008#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
5009pub enum CompareFunction {
5010 /// Function never passes
5011 Never = 1,
5012 /// Function passes if new value less than existing value
5013 Less = 2,
5014 /// Function passes if new value is equal to existing value. When using
5015 /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
5016 /// output as `@invariant` to prevent artifacting.
5017 Equal = 3,
5018 /// Function passes if new value is less than or equal to existing value
5019 LessEqual = 4,
5020 /// Function passes if new value is greater than existing value
5021 Greater = 5,
5022 /// Function passes if new value is not equal to existing value. When using
5023 /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
5024 /// output as `@invariant` to prevent artifacting.
5025 NotEqual = 6,
5026 /// Function passes if new value is greater than or equal to existing value
5027 GreaterEqual = 7,
5028 /// Function always passes
5029 Always = 8,
5030}
5031
5032impl CompareFunction {
5033 /// Returns true if the comparison depends on the reference value.
5034 #[must_use]
5035 pub fn needs_ref_value(self) -> bool {
5036 match self {
5037 Self::Never | Self::Always => false,
5038 _ => true,
5039 }
5040 }
5041}
5042
5043/// Whether a vertex buffer is indexed by vertex or by instance.
5044///
5045/// Consider a call to [`RenderPass::draw`] like this:
5046///
5047/// ```ignore
5048/// render_pass.draw(vertices, instances)
5049/// ```
5050///
5051/// where `vertices` is a `Range<u32>` of vertex indices, and
5052/// `instances` is a `Range<u32>` of instance indices.
5053///
5054/// For this call, `wgpu` invokes the vertex shader entry point once
5055/// for every possible `(v, i)` pair, where `v` is drawn from
5056/// `vertices` and `i` is drawn from `instances`. These invocations
5057/// may happen in any order, and will usually run in parallel.
5058///
5059/// Each vertex buffer has a step mode, established by the
5060/// [`step_mode`] field of its [`VertexBufferLayout`], given when the
5061/// pipeline was created. Buffers whose step mode is [`Vertex`] use
5062/// `v` as the index into their contents, whereas buffers whose step
5063/// mode is [`Instance`] use `i`. The indicated buffer element then
5064/// contributes zero or more attribute values for the `(v, i)` vertex
5065/// shader invocation to use, based on the [`VertexBufferLayout`]'s
5066/// [`attributes`] list.
5067///
5068/// You can visualize the results from all these vertex shader
5069/// invocations as a matrix with a row for each `i` from `instances`,
5070/// and with a column for each `v` from `vertices`. In one sense, `v`
5071/// and `i` are symmetrical: both are used to index vertex buffers and
5072/// provide attribute values. But the key difference between `v` and
5073/// `i` is that line and triangle primitives are built from the values
5074/// of each row, along which `i` is constant and `v` varies, not the
5075/// columns.
5076///
5077/// An indexed draw call works similarly:
5078///
5079/// ```ignore
5080/// render_pass.draw_indexed(indices, base_vertex, instances)
5081/// ```
5082///
5083/// The only difference is that `v` values are drawn from the contents
5084/// of the index buffer—specifically, the subrange of the index
5085/// buffer given by `indices`—instead of simply being sequential
5086/// integers, as they are in a `draw` call.
5087///
5088/// A non-instanced call, where `instances` is `0..1`, is simply a
5089/// matrix with only one row.
5090///
5091/// Corresponds to [WebGPU `GPUVertexStepMode`](
5092/// https://gpuweb.github.io/gpuweb/#enumdef-gpuvertexstepmode).
5093///
5094/// [`RenderPass::draw`]: ../wgpu/struct.RenderPass.html#method.draw
5095/// [`VertexBufferLayout`]: ../wgpu/struct.VertexBufferLayout.html
5096/// [`step_mode`]: ../wgpu/struct.VertexBufferLayout.html#structfield.step_mode
5097/// [`attributes`]: ../wgpu/struct.VertexBufferLayout.html#structfield.attributes
5098/// [`Vertex`]: VertexStepMode::Vertex
5099/// [`Instance`]: VertexStepMode::Instance
5100#[repr(C)]
5101#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
5102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5103#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
5104pub enum VertexStepMode {
5105 /// Vertex data is advanced every vertex.
5106 #[default]
5107 Vertex = 0,
5108 /// Vertex data is advanced every instance.
5109 Instance = 1,
5110}
5111
5112/// Vertex inputs (attributes) to shaders.
5113///
5114/// These are used to specify the individual attributes within a [`VertexBufferLayout`].
5115/// See its documentation for an example.
5116///
5117/// The [`vertex_attr_array!`] macro can help create these with appropriate offsets.
5118///
5119/// Corresponds to [WebGPU `GPUVertexAttribute`](
5120/// https://gpuweb.github.io/gpuweb/#dictdef-gpuvertexattribute).
5121///
5122/// [`vertex_attr_array!`]: ../wgpu/macro.vertex_attr_array.html
5123/// [`VertexBufferLayout`]: ../wgpu/struct.VertexBufferLayout.html
5124#[repr(C)]
5125#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5127#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
5128pub struct VertexAttribute {
5129 /// Format of the input
5130 pub format: VertexFormat,
5131 /// Byte offset of the start of the input
5132 pub offset: BufferAddress,
5133 /// Location for this input. Must match the location in the shader.
5134 pub shader_location: ShaderLocation,
5135}
5136
5137/// Vertex Format for a [`VertexAttribute`] (input).
5138///
5139/// Corresponds to [WebGPU `GPUVertexFormat`](
5140/// https://gpuweb.github.io/gpuweb/#enumdef-gpuvertexformat).
5141#[repr(C)]
5142#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
5143#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5144#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
5145pub enum VertexFormat {
5146 /// One unsigned byte (u8). `u32` in shaders.
5147 Uint8 = 0,
5148 /// Two unsigned bytes (u8). `vec2<u32>` in shaders.
5149 Uint8x2 = 1,
5150 /// Four unsigned bytes (u8). `vec4<u32>` in shaders.
5151 Uint8x4 = 2,
5152 /// One signed byte (i8). `i32` in shaders.
5153 Sint8 = 3,
5154 /// Two signed bytes (i8). `vec2<i32>` in shaders.
5155 Sint8x2 = 4,
5156 /// Four signed bytes (i8). `vec4<i32>` in shaders.
5157 Sint8x4 = 5,
5158 /// One unsigned byte (u8). [0, 255] converted to float [0, 1] `f32` in shaders.
5159 Unorm8 = 6,
5160 /// Two unsigned bytes (u8). [0, 255] converted to float [0, 1] `vec2<f32>` in shaders.
5161 Unorm8x2 = 7,
5162 /// Four unsigned bytes (u8). [0, 255] converted to float [0, 1] `vec4<f32>` in shaders.
5163 Unorm8x4 = 8,
5164 /// One signed byte (i8). [−127, 127] converted to float [−1, 1] `f32` in shaders.
5165 Snorm8 = 9,
5166 /// Two signed bytes (i8). [−127, 127] converted to float [−1, 1] `vec2<f32>` in shaders.
5167 Snorm8x2 = 10,
5168 /// Four signed bytes (i8). [−127, 127] converted to float [−1, 1] `vec4<f32>` in shaders.
5169 Snorm8x4 = 11,
5170 /// One unsigned short (u16). `u32` in shaders.
5171 Uint16 = 12,
5172 /// Two unsigned shorts (u16). `vec2<u32>` in shaders.
5173 Uint16x2 = 13,
5174 /// Four unsigned shorts (u16). `vec4<u32>` in shaders.
5175 Uint16x4 = 14,
5176 /// One signed short (u16). `i32` in shaders.
5177 Sint16 = 15,
5178 /// Two signed shorts (i16). `vec2<i32>` in shaders.
5179 Sint16x2 = 16,
5180 /// Four signed shorts (i16). `vec4<i32>` in shaders.
5181 Sint16x4 = 17,
5182 /// One unsigned short (u16). [0, 65535] converted to float [0, 1] `f32` in shaders.
5183 Unorm16 = 18,
5184 /// Two unsigned shorts (u16). [0, 65535] converted to float [0, 1] `vec2<f32>` in shaders.
5185 Unorm16x2 = 19,
5186 /// Four unsigned shorts (u16). [0, 65535] converted to float [0, 1] `vec4<f32>` in shaders.
5187 Unorm16x4 = 20,
5188 /// One signed short (i16). [−32767, 32767] converted to float [−1, 1] `f32` in shaders.
5189 Snorm16 = 21,
5190 /// Two signed shorts (i16). [−32767, 32767] converted to float [−1, 1] `vec2<f32>` in shaders.
5191 Snorm16x2 = 22,
5192 /// Four signed shorts (i16). [−32767, 32767] converted to float [−1, 1] `vec4<f32>` in shaders.
5193 Snorm16x4 = 23,
5194 /// One half-precision float (no Rust equiv). `f32` in shaders.
5195 Float16 = 24,
5196 /// Two half-precision floats (no Rust equiv). `vec2<f32>` in shaders.
5197 Float16x2 = 25,
5198 /// Four half-precision floats (no Rust equiv). `vec4<f32>` in shaders.
5199 Float16x4 = 26,
5200 /// One single-precision float (f32). `f32` in shaders.
5201 Float32 = 27,
5202 /// Two single-precision floats (f32). `vec2<f32>` in shaders.
5203 Float32x2 = 28,
5204 /// Three single-precision floats (f32). `vec3<f32>` in shaders.
5205 Float32x3 = 29,
5206 /// Four single-precision floats (f32). `vec4<f32>` in shaders.
5207 Float32x4 = 30,
5208 /// One unsigned int (u32). `u32` in shaders.
5209 Uint32 = 31,
5210 /// Two unsigned ints (u32). `vec2<u32>` in shaders.
5211 Uint32x2 = 32,
5212 /// Three unsigned ints (u32). `vec3<u32>` in shaders.
5213 Uint32x3 = 33,
5214 /// Four unsigned ints (u32). `vec4<u32>` in shaders.
5215 Uint32x4 = 34,
5216 /// One signed int (i32). `i32` in shaders.
5217 Sint32 = 35,
5218 /// Two signed ints (i32). `vec2<i32>` in shaders.
5219 Sint32x2 = 36,
5220 /// Three signed ints (i32). `vec3<i32>` in shaders.
5221 Sint32x3 = 37,
5222 /// Four signed ints (i32). `vec4<i32>` in shaders.
5223 Sint32x4 = 38,
5224 /// One double-precision float (f64). `f32` in shaders. Requires [`Features::VERTEX_ATTRIBUTE_64BIT`].
5225 Float64 = 39,
5226 /// Two double-precision floats (f64). `vec2<f32>` in shaders. Requires [`Features::VERTEX_ATTRIBUTE_64BIT`].
5227 Float64x2 = 40,
5228 /// Three double-precision floats (f64). `vec3<f32>` in shaders. Requires [`Features::VERTEX_ATTRIBUTE_64BIT`].
5229 Float64x3 = 41,
5230 /// Four double-precision floats (f64). `vec4<f32>` in shaders. Requires [`Features::VERTEX_ATTRIBUTE_64BIT`].
5231 Float64x4 = 42,
5232 /// Three unsigned 10-bit integers and one 2-bit integer, packed into a 32-bit integer (u32). [0, 1024] converted to float [0, 1] `vec4<f32>` in shaders.
5233 #[cfg_attr(feature = "serde", serde(rename = "unorm10-10-10-2"))]
5234 Unorm10_10_10_2 = 43,
5235 /// Four unsigned 8-bit integers, packed into a 32-bit integer (u32). [0, 255] converted to float [0, 1] `vec4<f32>` in shaders.
5236 #[cfg_attr(feature = "serde", serde(rename = "unorm8x4-bgra"))]
5237 Unorm8x4Bgra = 44,
5238}
5239
5240impl VertexFormat {
5241 /// Returns the byte size of the format.
5242 #[must_use]
5243 pub const fn size(&self) -> u64 {
5244 match self {
5245 Self::Uint8 | Self::Sint8 | Self::Unorm8 | Self::Snorm8 => 1,
5246 Self::Uint8x2
5247 | Self::Sint8x2
5248 | Self::Unorm8x2
5249 | Self::Snorm8x2
5250 | Self::Uint16
5251 | Self::Sint16
5252 | Self::Unorm16
5253 | Self::Snorm16
5254 | Self::Float16 => 2,
5255 Self::Uint8x4
5256 | Self::Sint8x4
5257 | Self::Unorm8x4
5258 | Self::Snorm8x4
5259 | Self::Uint16x2
5260 | Self::Sint16x2
5261 | Self::Unorm16x2
5262 | Self::Snorm16x2
5263 | Self::Float16x2
5264 | Self::Float32
5265 | Self::Uint32
5266 | Self::Sint32
5267 | Self::Unorm10_10_10_2
5268 | Self::Unorm8x4Bgra => 4,
5269 Self::Uint16x4
5270 | Self::Sint16x4
5271 | Self::Unorm16x4
5272 | Self::Snorm16x4
5273 | Self::Float16x4
5274 | Self::Float32x2
5275 | Self::Uint32x2
5276 | Self::Sint32x2
5277 | Self::Float64 => 8,
5278 Self::Float32x3 | Self::Uint32x3 | Self::Sint32x3 => 12,
5279 Self::Float32x4 | Self::Uint32x4 | Self::Sint32x4 | Self::Float64x2 => 16,
5280 Self::Float64x3 => 24,
5281 Self::Float64x4 => 32,
5282 }
5283 }
5284
5285 /// Returns the size read by an acceleration structure build of the vertex format. This is
5286 /// slightly different from [`Self::size`] because the alpha component of 4-component formats
5287 /// are not read in an acceleration structure build, allowing for a smaller stride.
5288 #[must_use]
5289 pub const fn min_acceleration_structure_vertex_stride(&self) -> u64 {
5290 match self {
5291 Self::Float16x2 | Self::Snorm16x2 => 4,
5292 Self::Float32x3 => 12,
5293 Self::Float32x2 => 8,
5294 // This is the minimum value from DirectX
5295 // > A16 component is ignored, other data can be packed there, such as setting vertex stride to 6 bytes
5296 //
5297 // https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html#d3d12_raytracing_geometry_triangles_desc
5298 //
5299 // Vulkan does not express a minimum stride.
5300 Self::Float16x4 | Self::Snorm16x4 => 6,
5301 _ => unreachable!(),
5302 }
5303 }
5304
5305 /// Returns the alignment required for `wgpu::BlasTriangleGeometry::vertex_stride`
5306 #[must_use]
5307 pub const fn acceleration_structure_stride_alignment(&self) -> u64 {
5308 match self {
5309 Self::Float16x4 | Self::Float16x2 | Self::Snorm16x4 | Self::Snorm16x2 => 2,
5310 Self::Float32x2 | Self::Float32x3 => 4,
5311 _ => unreachable!(),
5312 }
5313 }
5314}
5315
5316bitflags::bitflags! {
5317 /// Different ways that you can use a buffer.
5318 ///
5319 /// The usages determine what kind of memory the buffer is allocated from and what
5320 /// actions the buffer can partake in.
5321 ///
5322 /// Specifying only usages the application will actually perform may increase performance.
5323 /// Additionally, on the WebGL backend, there are restrictions on [`BufferUsages::INDEX`];
5324 /// see [`DownlevelFlags::UNRESTRICTED_INDEX_BUFFER`] for more information.
5325 ///
5326 /// Corresponds to [WebGPU `GPUBufferUsageFlags`](
5327 /// https://gpuweb.github.io/gpuweb/#typedefdef-gpubufferusageflags).
5328 #[repr(transparent)]
5329 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5330 #[cfg_attr(feature = "serde", serde(transparent))]
5331 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
5332 pub struct BufferUsages: u32 {
5333 /// Allow a buffer to be mapped for reading using [`Buffer::map_async`] + [`Buffer::get_mapped_range`].
5334 /// This does not include creating a buffer with [`BufferDescriptor::mapped_at_creation`] set.
5335 ///
5336 /// If [`Features::MAPPABLE_PRIMARY_BUFFERS`] isn't enabled, the only other usage a buffer
5337 /// may have is COPY_DST.
5338 const MAP_READ = 1 << 0;
5339 /// Allow a buffer to be mapped for writing using [`Buffer::map_async`] + [`Buffer::get_mapped_range_mut`].
5340 /// This does not include creating a buffer with [`BufferDescriptor::mapped_at_creation`] set.
5341 ///
5342 /// If [`Features::MAPPABLE_PRIMARY_BUFFERS`] feature isn't enabled, the only other usage a buffer
5343 /// may have is COPY_SRC.
5344 const MAP_WRITE = 1 << 1;
5345 /// Allow a buffer to be the source buffer for a [`CommandEncoder::copy_buffer_to_buffer`] or [`CommandEncoder::copy_buffer_to_texture`]
5346 /// operation.
5347 const COPY_SRC = 1 << 2;
5348 /// Allow a buffer to be the destination buffer for a [`CommandEncoder::copy_buffer_to_buffer`], [`CommandEncoder::copy_texture_to_buffer`],
5349 /// [`CommandEncoder::clear_buffer`] or [`Queue::write_buffer`] operation.
5350 const COPY_DST = 1 << 3;
5351 /// Allow a buffer to be the index buffer in a draw operation.
5352 const INDEX = 1 << 4;
5353 /// Allow a buffer to be the vertex buffer in a draw operation.
5354 const VERTEX = 1 << 5;
5355 /// Allow a buffer to be a [`BufferBindingType::Uniform`] inside a bind group.
5356 const UNIFORM = 1 << 6;
5357 /// Allow a buffer to be a [`BufferBindingType::Storage`] inside a bind group.
5358 const STORAGE = 1 << 7;
5359 /// Allow a buffer to be the indirect buffer in an indirect draw call.
5360 const INDIRECT = 1 << 8;
5361 /// Allow a buffer to be the destination buffer for a [`CommandEncoder::resolve_query_set`] operation.
5362 const QUERY_RESOLVE = 1 << 9;
5363 /// Allows a buffer to be used as input for a bottom level acceleration structure build
5364 const BLAS_INPUT = 1 << 10;
5365 /// Allows a buffer to be used as input for a top level acceleration structure build
5366 const TLAS_INPUT = 1 << 11;
5367 }
5368}
5369
5370bitflags::bitflags! {
5371 /// Similar to `BufferUsages`, but used only for `CommandEncoder::transition_resources`.
5372 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5373 #[cfg_attr(feature = "serde", serde(transparent))]
5374 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
5375 pub struct BufferUses: u16 {
5376 /// The argument to a read-only mapping.
5377 const MAP_READ = 1 << 0;
5378 /// The argument to a write-only mapping.
5379 const MAP_WRITE = 1 << 1;
5380 /// The source of a hardware copy.
5381 /// cbindgen:ignore
5382 const COPY_SRC = 1 << 2;
5383 /// The destination of a hardware copy.
5384 /// cbindgen:ignore
5385 const COPY_DST = 1 << 3;
5386 /// The index buffer used for drawing.
5387 const INDEX = 1 << 4;
5388 /// A vertex buffer used for drawing.
5389 const VERTEX = 1 << 5;
5390 /// A uniform buffer bound in a bind group.
5391 const UNIFORM = 1 << 6;
5392 /// A read-only storage buffer used in a bind group.
5393 /// cbindgen:ignore
5394 const STORAGE_READ_ONLY = 1 << 7;
5395 /// A read-write buffer used in a bind group.
5396 /// cbindgen:ignore
5397 const STORAGE_READ_WRITE = 1 << 8;
5398 /// The indirect or count buffer in a indirect draw or dispatch.
5399 const INDIRECT = 1 << 9;
5400 /// A buffer used to store query results.
5401 const QUERY_RESOLVE = 1 << 10;
5402 /// Buffer used for acceleration structure building.
5403 const ACCELERATION_STRUCTURE_SCRATCH = 1 << 11;
5404 /// Buffer used for bottom level acceleration structure building.
5405 const BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 12;
5406 /// Buffer used for top level acceleration structure building.
5407 const TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 13;
5408 /// A buffer used to store the compacted size of an acceleration structure
5409 const ACCELERATION_STRUCTURE_QUERY = 1 << 14;
5410 /// The combination of states that a buffer may be in _at the same time_.
5411 const INCLUSIVE = Self::MAP_READ.bits() | Self::COPY_SRC.bits() |
5412 Self::INDEX.bits() | Self::VERTEX.bits() | Self::UNIFORM.bits() |
5413 Self::STORAGE_READ_ONLY.bits() | Self::INDIRECT.bits() | Self::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits() | Self::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits();
5414 /// The combination of states that a buffer must exclusively be in.
5415 const EXCLUSIVE = Self::MAP_WRITE.bits() | Self::COPY_DST.bits() | Self::STORAGE_READ_WRITE.bits() | Self::ACCELERATION_STRUCTURE_SCRATCH.bits();
5416 /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
5417 /// If a usage is ordered, then if the buffer state doesn't change between draw calls, there
5418 /// are no barriers needed for synchronization.
5419 const ORDERED = Self::INCLUSIVE.bits() | Self::MAP_WRITE.bits();
5420 }
5421}
5422
5423/// A buffer transition for use with `CommandEncoder::transition_resources`.
5424#[derive(Clone, Debug)]
5425#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5426pub struct BufferTransition<T> {
5427 /// The buffer to transition.
5428 pub buffer: T,
5429 /// The new state to transition to.
5430 pub state: BufferUses,
5431}
5432
5433/// Describes a [`Buffer`](../wgpu/struct.Buffer.html).
5434///
5435/// Corresponds to [WebGPU `GPUBufferDescriptor`](
5436/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
5437#[repr(C)]
5438#[derive(Clone, Debug, PartialEq, Eq, Hash)]
5439#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5440pub struct BufferDescriptor<L> {
5441 /// Debug label of a buffer. This will show up in graphics debuggers for easy identification.
5442 pub label: L,
5443 /// Size of a buffer, in bytes.
5444 pub size: BufferAddress,
5445 /// Usages of a buffer. If the buffer is used in any way that isn't specified here, the operation
5446 /// will panic.
5447 ///
5448 /// Specifying only usages the application will actually perform may increase performance.
5449 /// Additionally, on the WebGL backend, there are restrictions on [`BufferUsages::INDEX`];
5450 /// see [`DownlevelFlags::UNRESTRICTED_INDEX_BUFFER`] for more information.
5451 pub usage: BufferUsages,
5452 /// Allows a buffer to be mapped immediately after they are made. It does not have to be [`BufferUsages::MAP_READ`] or
5453 /// [`BufferUsages::MAP_WRITE`], all buffers are allowed to be mapped at creation.
5454 ///
5455 /// If this is `true`, [`size`](#structfield.size) must be a multiple of
5456 /// [`COPY_BUFFER_ALIGNMENT`].
5457 pub mapped_at_creation: bool,
5458}
5459
5460impl<L> BufferDescriptor<L> {
5461 /// Takes a closure and maps the label of the buffer descriptor into another.
5462 #[must_use]
5463 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> BufferDescriptor<K> {
5464 BufferDescriptor {
5465 label: fun(&self.label),
5466 size: self.size,
5467 usage: self.usage,
5468 mapped_at_creation: self.mapped_at_creation,
5469 }
5470 }
5471}
5472
5473/// Describes a [`CommandEncoder`](../wgpu/struct.CommandEncoder.html).
5474///
5475/// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`](
5476/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor).
5477#[repr(C)]
5478#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5479#[derive(Clone, Debug, PartialEq, Eq, Hash)]
5480pub struct CommandEncoderDescriptor<L> {
5481 /// Debug label for the command encoder. This will show up in graphics debuggers for easy identification.
5482 pub label: L,
5483}
5484
5485impl<L> CommandEncoderDescriptor<L> {
5486 /// Takes a closure and maps the label of the command encoder descriptor into another.
5487 #[must_use]
5488 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CommandEncoderDescriptor<K> {
5489 CommandEncoderDescriptor {
5490 label: fun(&self.label),
5491 }
5492 }
5493}
5494
5495impl<T> Default for CommandEncoderDescriptor<Option<T>> {
5496 fn default() -> Self {
5497 Self { label: None }
5498 }
5499}
5500
5501/// Timing and queueing with which frames are actually displayed to the user.
5502///
5503/// Use this as part of a [`SurfaceConfiguration`] to control the behavior of
5504/// [`SurfaceTexture::present()`].
5505///
5506/// Some modes are only supported by some backends.
5507/// You can use one of the `Auto*` modes, [`Fifo`](Self::Fifo),
5508/// or choose one of the supported modes from [`SurfaceCapabilities::present_modes`].
5509///
5510/// [presented]: ../wgpu/struct.SurfaceTexture.html#method.present
5511/// [`SurfaceTexture::present()`]: ../wgpu/struct.SurfaceTexture.html#method.present
5512#[repr(C)]
5513#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
5514#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5515pub enum PresentMode {
5516 /// Chooses the first supported mode out of:
5517 ///
5518 /// 1. [`FifoRelaxed`](Self::FifoRelaxed)
5519 /// 2. [`Fifo`](Self::Fifo)
5520 ///
5521 /// Because of the fallback behavior, this is supported everywhere.
5522 AutoVsync = 0,
5523
5524 /// Chooses the first supported mode out of:
5525 ///
5526 /// 1. [`Immediate`](Self::Immediate)
5527 /// 2. [`Mailbox`](Self::Mailbox)
5528 /// 3. [`Fifo`](Self::Fifo)
5529 ///
5530 /// Because of the fallback behavior, this is supported everywhere.
5531 AutoNoVsync = 1,
5532
5533 /// Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
5534 /// long. Every vertical blanking period, the presentation engine will pop a frame
5535 /// off the queue to display. If there is no frame to display, it will present the same
5536 /// frame again until the next vblank.
5537 ///
5538 /// When a present command is executed on the GPU, the presented image is added on the queue.
5539 ///
5540 /// Calls to [`Surface::get_current_texture()`] will block until there is a spot in the queue.
5541 ///
5542 /// * **Tearing:** No tearing will be observed.
5543 /// * **Supported on**: All platforms.
5544 /// * **Also known as**: "Vsync On"
5545 ///
5546 /// This is the [default](Self::default) value for `PresentMode`.
5547 /// If you don't know what mode to choose, choose this mode.
5548 ///
5549 /// [`Surface::get_current_texture()`]: ../wgpu/struct.Surface.html#method.get_current_texture
5550 #[default]
5551 Fifo = 2,
5552
5553 /// Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
5554 /// long. Every vertical blanking period, the presentation engine will pop a frame
5555 /// off the queue to display. If there is no frame to display, it will present the
5556 /// same frame until there is a frame in the queue. The moment there is a frame in the
5557 /// queue, it will immediately pop the frame off the queue.
5558 ///
5559 /// When a present command is executed on the GPU, the presented image is added on the queue.
5560 ///
5561 /// Calls to [`Surface::get_current_texture()`] will block until there is a spot in the queue.
5562 ///
5563 /// * **Tearing**:
5564 /// Tearing will be observed if frames last more than one vblank as the front buffer.
5565 /// * **Supported on**: AMD on Vulkan.
5566 /// * **Also known as**: "Adaptive Vsync"
5567 ///
5568 /// [`Surface::get_current_texture()`]: ../wgpu/struct.Surface.html#method.get_current_texture
5569 FifoRelaxed = 3,
5570
5571 /// Presentation frames are not queued at all. The moment a present command
5572 /// is executed on the GPU, the presented image is swapped onto the front buffer
5573 /// immediately.
5574 ///
5575 /// * **Tearing**: Tearing can be observed.
5576 /// * **Supported on**: Most platforms except older DX12 and Wayland.
5577 /// * **Also known as**: "Vsync Off"
5578 Immediate = 4,
5579
5580 /// Presentation frames are kept in a single-frame queue. Every vertical blanking period,
5581 /// the presentation engine will pop a frame from the queue. If there is no frame to display,
5582 /// it will present the same frame again until the next vblank.
5583 ///
5584 /// When a present command is executed on the GPU, the frame will be put into the queue.
5585 /// If there was already a frame in the queue, the new frame will _replace_ the old frame
5586 /// on the queue.
5587 ///
5588 /// * **Tearing**: No tearing will be observed.
5589 /// * **Supported on**: DX12 on Windows 10, NVidia on Vulkan and Wayland on Vulkan.
5590 /// * **Also known as**: "Fast Vsync"
5591 Mailbox = 5,
5592}
5593
5594/// Specifies how the alpha channel of the textures should be handled during
5595/// compositing.
5596#[repr(C)]
5597#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5598#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5599#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
5600pub enum CompositeAlphaMode {
5601 /// Chooses either `Opaque` or `Inherit` automatically,depending on the
5602 /// `alpha_mode` that the current surface can support.
5603 Auto = 0,
5604 /// The alpha channel, if it exists, of the textures is ignored in the
5605 /// compositing process. Instead, the textures is treated as if it has a
5606 /// constant alpha of 1.0.
5607 Opaque = 1,
5608 /// The alpha channel, if it exists, of the textures is respected in the
5609 /// compositing process. The non-alpha channels of the textures are
5610 /// expected to already be multiplied by the alpha channel by the
5611 /// application.
5612 PreMultiplied = 2,
5613 /// The alpha channel, if it exists, of the textures is respected in the
5614 /// compositing process. The non-alpha channels of the textures are not
5615 /// expected to already be multiplied by the alpha channel by the
5616 /// application; instead, the compositor will multiply the non-alpha
5617 /// channels of the texture by the alpha channel during compositing.
5618 PostMultiplied = 3,
5619 /// The alpha channel, if it exists, of the textures is unknown for processing
5620 /// during compositing. Instead, the application is responsible for setting
5621 /// the composite alpha blending mode using native WSI command. If not set,
5622 /// then a platform-specific default will be used.
5623 Inherit = 4,
5624}
5625
5626impl Default for CompositeAlphaMode {
5627 fn default() -> Self {
5628 Self::Auto
5629 }
5630}
5631
5632bitflags::bitflags! {
5633 /// Different ways that you can use a texture.
5634 ///
5635 /// The usages determine what kind of memory the texture is allocated from and what
5636 /// actions the texture can partake in.
5637 ///
5638 /// Corresponds to [WebGPU `GPUTextureUsageFlags`](
5639 /// https://gpuweb.github.io/gpuweb/#typedefdef-gputextureusageflags).
5640 #[repr(transparent)]
5641 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5642 #[cfg_attr(feature = "serde", serde(transparent))]
5643 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
5644 pub struct TextureUsages: u32 {
5645 //
5646 // ---- Start numbering at 1 << 0 ----
5647 //
5648 // WebGPU features:
5649 //
5650 /// Allows a texture to be the source in a [`CommandEncoder::copy_texture_to_buffer`] or
5651 /// [`CommandEncoder::copy_texture_to_texture`] operation.
5652 const COPY_SRC = 1 << 0;
5653 /// Allows a texture to be the destination in a [`CommandEncoder::copy_buffer_to_texture`],
5654 /// [`CommandEncoder::copy_texture_to_texture`], or [`Queue::write_texture`] operation.
5655 const COPY_DST = 1 << 1;
5656 /// Allows a texture to be a [`BindingType::Texture`] in a bind group.
5657 const TEXTURE_BINDING = 1 << 2;
5658 /// Allows a texture to be a [`BindingType::StorageTexture`] in a bind group.
5659 const STORAGE_BINDING = 1 << 3;
5660 /// Allows a texture to be an output attachment of a render pass.
5661 ///
5662 /// Consider adding [`TextureUsages::TRANSIENT`] if the contents are not reused.
5663 const RENDER_ATTACHMENT = 1 << 4;
5664
5665 //
5666 // ---- Restart Numbering for Native Features ---
5667 //
5668 // Native Features:
5669 //
5670 /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`].
5671 const STORAGE_ATOMIC = 1 << 16;
5672 /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth.
5673 ///
5674 /// No-op on platforms on platforms that do not benefit from transient textures.
5675 /// Generally mobile and Apple chips care about this.
5676 ///
5677 /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] and requires it.
5678 ///
5679 /// Requires [`StoreOp::Discard`].
5680 const TRANSIENT = 1 << 17;
5681 }
5682}
5683
5684bitflags::bitflags! {
5685 /// Similar to `TextureUsages`, but used only for `CommandEncoder::transition_resources`.
5686 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
5687 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5688 #[cfg_attr(feature = "serde", serde(transparent))]
5689 pub struct TextureUses: u16 {
5690 /// The texture is in unknown state.
5691 const UNINITIALIZED = 1 << 0;
5692 /// Ready to present image to the surface.
5693 const PRESENT = 1 << 1;
5694 /// The source of a hardware copy.
5695 /// cbindgen:ignore
5696 const COPY_SRC = 1 << 2;
5697 /// The destination of a hardware copy.
5698 /// cbindgen:ignore
5699 const COPY_DST = 1 << 3;
5700 /// Read-only sampled or fetched resource.
5701 const RESOURCE = 1 << 4;
5702 /// The color target of a renderpass.
5703 const COLOR_TARGET = 1 << 5;
5704 /// Read-only depth stencil usage.
5705 const DEPTH_STENCIL_READ = 1 << 6;
5706 /// Read-write depth stencil usage
5707 const DEPTH_STENCIL_WRITE = 1 << 7;
5708 /// Read-only storage texture usage. Corresponds to a UAV in d3d, so is exclusive, despite being read only.
5709 /// cbindgen:ignore
5710 const STORAGE_READ_ONLY = 1 << 8;
5711 /// Write-only storage texture usage.
5712 /// cbindgen:ignore
5713 const STORAGE_WRITE_ONLY = 1 << 9;
5714 /// Read-write storage texture usage.
5715 /// cbindgen:ignore
5716 const STORAGE_READ_WRITE = 1 << 10;
5717 /// Image atomic enabled storage.
5718 /// cbindgen:ignore
5719 const STORAGE_ATOMIC = 1 << 11;
5720 /// Transient texture that may not have any backing memory. Not a resource state stored in the trackers, only used for passing down usages to create_texture.
5721 const TRANSIENT = 1 << 12;
5722 /// The combination of states that a texture may be in _at the same time_.
5723 /// cbindgen:ignore
5724 const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits();
5725 /// The combination of states that a texture must exclusively be in.
5726 /// cbindgen:ignore
5727 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();
5728 /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
5729 /// If a usage is ordered, then if the texture state doesn't change between draw calls, there
5730 /// are no barriers needed for synchronization.
5731 /// cbindgen:ignore
5732 const ORDERED = Self::INCLUSIVE.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ_ONLY.bits();
5733
5734 /// Flag used by the wgpu-core texture tracker to say a texture is in different states for every sub-resource
5735 const COMPLEX = 1 << 13;
5736 /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource.
5737 /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized.
5738 const UNKNOWN = 1 << 14;
5739 }
5740}
5741
5742/// A texture transition for use with `CommandEncoder::transition_resources`.
5743#[derive(Clone, Debug)]
5744#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5745pub struct TextureTransition<T> {
5746 /// The texture to transition.
5747 pub texture: T,
5748 /// An optional selector to transition only part of the texture.
5749 ///
5750 /// If None, the entire texture will be transitioned.
5751 pub selector: Option<TextureSelector>,
5752 /// The new state to transition to.
5753 pub state: TextureUses,
5754}
5755
5756/// Specifies a particular set of subresources in a texture.
5757#[derive(Clone, Debug, PartialEq, Eq)]
5758#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5759pub struct TextureSelector {
5760 /// Range of mips to use.
5761 pub mips: Range<u32>,
5762 /// Range of layers to use.
5763 pub layers: Range<u32>,
5764}
5765
5766/// Defines the capabilities of a given surface and adapter.
5767#[derive(Debug)]
5768pub struct SurfaceCapabilities {
5769 /// List of supported formats to use with the given adapter. The first format in the vector is preferred.
5770 ///
5771 /// Returns an empty vector if the surface is incompatible with the adapter.
5772 pub formats: Vec<TextureFormat>,
5773 /// List of supported presentation modes to use with the given adapter.
5774 ///
5775 /// Returns an empty vector if the surface is incompatible with the adapter.
5776 pub present_modes: Vec<PresentMode>,
5777 /// List of supported alpha modes to use with the given adapter.
5778 ///
5779 /// Will return at least one element, [`CompositeAlphaMode::Opaque`] or [`CompositeAlphaMode::Inherit`].
5780 pub alpha_modes: Vec<CompositeAlphaMode>,
5781 /// Bitflag of supported texture usages for the surface to use with the given adapter.
5782 ///
5783 /// The usage [`TextureUsages::RENDER_ATTACHMENT`] is guaranteed.
5784 pub usages: TextureUsages,
5785}
5786
5787impl Default for SurfaceCapabilities {
5788 fn default() -> Self {
5789 Self {
5790 formats: Vec::new(),
5791 present_modes: Vec::new(),
5792 alpha_modes: vec![CompositeAlphaMode::Opaque],
5793 usages: TextureUsages::RENDER_ATTACHMENT,
5794 }
5795 }
5796}
5797
5798/// Configures a [`Surface`] for presentation.
5799///
5800/// [`Surface`]: ../wgpu/struct.Surface.html
5801#[repr(C)]
5802#[derive(Clone, Debug, PartialEq, Eq, Hash)]
5803#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5804pub struct SurfaceConfiguration<V> {
5805 /// The usage of the swap chain. The only usage guaranteed to be supported is [`TextureUsages::RENDER_ATTACHMENT`].
5806 pub usage: TextureUsages,
5807 /// The texture format of the swap chain. The only formats that are guaranteed are
5808 /// [`TextureFormat::Bgra8Unorm`] and [`TextureFormat::Bgra8UnormSrgb`].
5809 pub format: TextureFormat,
5810 /// Width of the swap chain. Must be the same size as the surface, and nonzero.
5811 ///
5812 /// If this is not the same size as the underlying surface (e.g. if it is
5813 /// set once, and the window is later resized), the behaviour is defined
5814 /// but platform-specific, and may change in the future (currently macOS
5815 /// scales the surface, other platforms may do something else).
5816 pub width: u32,
5817 /// Height of the swap chain. Must be the same size as the surface, and nonzero.
5818 ///
5819 /// If this is not the same size as the underlying surface (e.g. if it is
5820 /// set once, and the window is later resized), the behaviour is defined
5821 /// but platform-specific, and may change in the future (currently macOS
5822 /// scales the surface, other platforms may do something else).
5823 pub height: u32,
5824 /// Presentation mode of the swap chain. Fifo is the only mode guaranteed to be supported.
5825 /// `FifoRelaxed`, `Immediate`, and `Mailbox` will crash if unsupported, while `AutoVsync` and
5826 /// `AutoNoVsync` will gracefully do a designed sets of fallbacks if their primary modes are
5827 /// unsupported.
5828 pub present_mode: PresentMode,
5829 /// Desired maximum number of monitor refreshes between a [`Surface::get_current_texture`] call and the
5830 /// texture being presented to the screen. This is sometimes called "Frames in Flight".
5831 ///
5832 /// Defaults to `2` when created via [`Surface::get_default_config`] as this is a reasonable default.
5833 ///
5834 /// This is ultimately a hint to the backend implementation and will always be clamped
5835 /// to the supported range.
5836 ///
5837 /// Typical values are `1` to `3`, but higher values are valid, though likely to be clamped.
5838 /// * Choose `1` to minimize latency above all else. This only gives a single monitor refresh for all of
5839 /// the CPU and GPU work to complete. ⚠️ As a result of these short swapchains, the CPU and GPU
5840 /// cannot run in parallel, prioritizing latency over throughput. For applications like GUIs doing
5841 /// a small amount of GPU work each frame that need low latency, this is a reasonable choice.
5842 /// * Choose `2` for a balance between latency and throughput. The CPU and GPU both can each use
5843 /// a full monitor refresh to do their computations. This is a reasonable default for most applications.
5844 /// * Choose `3` or higher to maximize throughput, sacrificing latency when the the CPU and GPU
5845 /// are using less than a full monitor refresh each. For applications that use CPU-side pipelining
5846 /// of frames this may be a reasonable choice. ⚠️ On 60hz displays the latency can be very noticeable.
5847 ///
5848 /// This maps to the backend in the following ways:
5849 /// - Vulkan: Number of frames in the swapchain is `desired_maximum_frame_latency + 1`,
5850 /// clamped to the supported range.
5851 /// - DX12: Calls [`IDXGISwapChain2::SetMaximumFrameLatency(desired_maximum_frame_latency)`][SMFL].
5852 /// - Metal: Sets the `maximumDrawableCount` of the underlying `CAMetalLayer` to
5853 /// `desired_maximum_frame_latency + 1`, clamped to the supported range.
5854 /// - OpenGL: Ignored
5855 ///
5856 /// It also has various subtle interactions with various present modes and APIs.
5857 /// - DX12 + Mailbox: Limits framerate to `desired_maximum_frame_latency * Monitor Hz` fps.
5858 /// - Vulkan/Metal + Mailbox: If this is set to `2`, limits framerate to `2 * Monitor Hz` fps. `3` or higher is unlimited.
5859 ///
5860 /// [`Surface::get_current_texture`]: ../wgpu/struct.Surface.html#method.get_current_texture
5861 /// [`Surface::get_default_config`]: ../wgpu/struct.Surface.html#method.get_default_config
5862 /// [SMFL]: https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-idxgiswapchain2-setmaximumframelatency
5863 pub desired_maximum_frame_latency: u32,
5864 /// Specifies how the alpha channel of the textures should be handled during compositing.
5865 pub alpha_mode: CompositeAlphaMode,
5866 /// Specifies what view formats will be allowed when calling `Texture::create_view` on the texture returned by `Surface::get_current_texture`.
5867 ///
5868 /// View formats of the same format as the texture are always allowed.
5869 ///
5870 /// Note: currently, only the srgb-ness is allowed to change. (ex: `Rgba8Unorm` texture + `Rgba8UnormSrgb` view)
5871 pub view_formats: V,
5872}
5873
5874impl<V: Clone> SurfaceConfiguration<V> {
5875 /// Map `view_formats` of the texture descriptor into another.
5876 pub fn map_view_formats<M>(&self, fun: impl FnOnce(V) -> M) -> SurfaceConfiguration<M> {
5877 SurfaceConfiguration {
5878 usage: self.usage,
5879 format: self.format,
5880 width: self.width,
5881 height: self.height,
5882 present_mode: self.present_mode,
5883 desired_maximum_frame_latency: self.desired_maximum_frame_latency,
5884 alpha_mode: self.alpha_mode,
5885 view_formats: fun(self.view_formats.clone()),
5886 }
5887 }
5888}
5889
5890/// Status of the received surface image.
5891#[repr(C)]
5892#[derive(Debug)]
5893pub enum SurfaceStatus {
5894 /// No issues.
5895 Good,
5896 /// The swap chain is operational, but it does no longer perfectly
5897 /// match the surface. A re-configuration is needed.
5898 Suboptimal,
5899 /// Unable to get the next frame, timed out.
5900 Timeout,
5901 /// The surface under the swap chain has changed.
5902 Outdated,
5903 /// The surface under the swap chain is lost.
5904 Lost,
5905 /// The surface status is not known since `Surface::get_current_texture` previously failed.
5906 Unknown,
5907}
5908
5909/// Nanosecond timestamp used by the presentation engine.
5910///
5911/// The specific clock depends on the window system integration (WSI) API used.
5912///
5913/// <table>
5914/// <tr>
5915/// <td>WSI</td>
5916/// <td>Clock</td>
5917/// </tr>
5918/// <tr>
5919/// <td>IDXGISwapchain</td>
5920/// <td><a href="https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter">QueryPerformanceCounter</a></td>
5921/// </tr>
5922/// <tr>
5923/// <td>IPresentationManager</td>
5924/// <td><a href="https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise">QueryInterruptTimePrecise</a></td>
5925/// </tr>
5926/// <tr>
5927/// <td>CAMetalLayer</td>
5928/// <td><a href="https://developer.apple.com/documentation/kernel/1462446-mach_absolute_time">mach_absolute_time</a></td>
5929/// </tr>
5930/// <tr>
5931/// <td>VK_GOOGLE_display_timing</td>
5932/// <td><a href="https://linux.die.net/man/3/clock_gettime">clock_gettime(CLOCK_MONOTONIC)</a></td>
5933/// </tr>
5934/// </table>
5935#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
5936pub struct PresentationTimestamp(
5937 /// Timestamp in nanoseconds.
5938 pub u128,
5939);
5940
5941impl PresentationTimestamp {
5942 /// A timestamp that is invalid due to the platform not having a timestamp system.
5943 pub const INVALID_TIMESTAMP: Self = Self(u128::MAX);
5944
5945 /// Returns true if this timestamp is the invalid timestamp.
5946 #[must_use]
5947 pub fn is_invalid(self) -> bool {
5948 self == Self::INVALID_TIMESTAMP
5949 }
5950}
5951
5952/// RGBA double precision color.
5953///
5954/// This is not to be used as a generic color type, only for specific wgpu interfaces.
5955#[repr(C)]
5956#[derive(Clone, Copy, Debug, Default, PartialEq)]
5957#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5958#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
5959pub struct Color {
5960 /// Red component of the color
5961 pub r: f64,
5962 /// Green component of the color
5963 pub g: f64,
5964 /// Blue component of the color
5965 pub b: f64,
5966 /// Alpha component of the color
5967 pub a: f64,
5968}
5969
5970#[allow(missing_docs)]
5971impl Color {
5972 pub const TRANSPARENT: Self = Self {
5973 r: 0.0,
5974 g: 0.0,
5975 b: 0.0,
5976 a: 0.0,
5977 };
5978 pub const BLACK: Self = Self {
5979 r: 0.0,
5980 g: 0.0,
5981 b: 0.0,
5982 a: 1.0,
5983 };
5984 pub const WHITE: Self = Self {
5985 r: 1.0,
5986 g: 1.0,
5987 b: 1.0,
5988 a: 1.0,
5989 };
5990 pub const RED: Self = Self {
5991 r: 1.0,
5992 g: 0.0,
5993 b: 0.0,
5994 a: 1.0,
5995 };
5996 pub const GREEN: Self = Self {
5997 r: 0.0,
5998 g: 1.0,
5999 b: 0.0,
6000 a: 1.0,
6001 };
6002 pub const BLUE: Self = Self {
6003 r: 0.0,
6004 g: 0.0,
6005 b: 1.0,
6006 a: 1.0,
6007 };
6008}
6009
6010/// Dimensionality of a texture.
6011///
6012/// Corresponds to [WebGPU `GPUTextureDimension`](
6013/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturedimension).
6014#[repr(C)]
6015#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
6016#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6017pub enum TextureDimension {
6018 /// 1D texture
6019 #[cfg_attr(feature = "serde", serde(rename = "1d"))]
6020 D1,
6021 /// 2D texture
6022 #[cfg_attr(feature = "serde", serde(rename = "2d"))]
6023 D2,
6024 /// 3D texture
6025 #[cfg_attr(feature = "serde", serde(rename = "3d"))]
6026 D3,
6027}
6028
6029/// Origin of a copy from a 2D image.
6030///
6031/// Corresponds to [WebGPU `GPUOrigin2D`](
6032/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin2ddict).
6033#[repr(C)]
6034#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6035#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6036#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
6037pub struct Origin2d {
6038 #[allow(missing_docs)]
6039 pub x: u32,
6040 #[allow(missing_docs)]
6041 pub y: u32,
6042}
6043
6044impl Origin2d {
6045 /// Zero origin.
6046 pub const ZERO: Self = Self { x: 0, y: 0 };
6047
6048 /// Adds the third dimension to this origin
6049 #[must_use]
6050 pub fn to_3d(self, z: u32) -> Origin3d {
6051 Origin3d {
6052 x: self.x,
6053 y: self.y,
6054 z,
6055 }
6056 }
6057}
6058
6059impl core::fmt::Debug for Origin2d {
6060 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
6061 (self.x, self.y).fmt(f)
6062 }
6063}
6064
6065/// Origin of a copy to/from a texture.
6066///
6067/// Corresponds to [WebGPU `GPUOrigin3D`](
6068/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin3ddict).
6069#[repr(C)]
6070#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6071#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6072#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
6073pub struct Origin3d {
6074 /// X position of the origin
6075 pub x: u32,
6076 /// Y position of the origin
6077 pub y: u32,
6078 /// Z position of the origin
6079 pub z: u32,
6080}
6081
6082impl Origin3d {
6083 /// Zero origin.
6084 pub const ZERO: Self = Self { x: 0, y: 0, z: 0 };
6085
6086 /// Removes the third dimension from this origin
6087 #[must_use]
6088 pub fn to_2d(self) -> Origin2d {
6089 Origin2d {
6090 x: self.x,
6091 y: self.y,
6092 }
6093 }
6094}
6095
6096impl Default for Origin3d {
6097 fn default() -> Self {
6098 Self::ZERO
6099 }
6100}
6101
6102impl core::fmt::Debug for Origin3d {
6103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
6104 (self.x, self.y, self.z).fmt(f)
6105 }
6106}
6107
6108/// Extent of a texture related operation.
6109///
6110/// Corresponds to [WebGPU `GPUExtent3D`](
6111/// https://gpuweb.github.io/gpuweb/#dictdef-gpuextent3ddict).
6112#[repr(C)]
6113#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6114#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6115#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
6116pub struct Extent3d {
6117 /// Width of the extent
6118 pub width: u32,
6119 /// Height of the extent
6120 pub height: u32,
6121 /// The depth of the extent or the number of array layers
6122 #[cfg_attr(feature = "serde", serde(default = "default_depth"))]
6123 pub depth_or_array_layers: u32,
6124}
6125
6126impl core::fmt::Debug for Extent3d {
6127 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
6128 (self.width, self.height, self.depth_or_array_layers).fmt(f)
6129 }
6130}
6131
6132#[cfg(feature = "serde")]
6133fn default_depth() -> u32 {
6134 1
6135}
6136
6137impl Default for Extent3d {
6138 fn default() -> Self {
6139 Self {
6140 width: 1,
6141 height: 1,
6142 depth_or_array_layers: 1,
6143 }
6144 }
6145}
6146
6147impl Extent3d {
6148 /// Calculates the [physical size] backing a texture of the given
6149 /// format and extent. This includes padding to the block width
6150 /// and height of the format.
6151 ///
6152 /// This is the texture extent that you must upload at when uploading to _mipmaps_ of compressed textures.
6153 ///
6154 /// [physical size]: https://gpuweb.github.io/gpuweb/#physical-miplevel-specific-texture-extent
6155 #[must_use]
6156 pub fn physical_size(&self, format: TextureFormat) -> Self {
6157 let (block_width, block_height) = format.block_dimensions();
6158
6159 let width = self.width.div_ceil(block_width) * block_width;
6160 let height = self.height.div_ceil(block_height) * block_height;
6161
6162 Self {
6163 width,
6164 height,
6165 depth_or_array_layers: self.depth_or_array_layers,
6166 }
6167 }
6168
6169 /// Calculates the maximum possible count of mipmaps.
6170 ///
6171 /// Treats the depth as part of the mipmaps. If calculating
6172 /// for a 2DArray texture, which does not mipmap depth, set depth to 1.
6173 #[must_use]
6174 pub fn max_mips(&self, dim: TextureDimension) -> u32 {
6175 match dim {
6176 TextureDimension::D1 => 1,
6177 TextureDimension::D2 => {
6178 let max_dim = self.width.max(self.height);
6179 32 - max_dim.leading_zeros()
6180 }
6181 TextureDimension::D3 => {
6182 let max_dim = self.width.max(self.height.max(self.depth_or_array_layers));
6183 32 - max_dim.leading_zeros()
6184 }
6185 }
6186 }
6187
6188 /// Calculates the extent at a given mip level.
6189 /// Does *not* account for memory size being a multiple of block size.
6190 ///
6191 /// <https://gpuweb.github.io/gpuweb/#logical-miplevel-specific-texture-extent>
6192 #[must_use]
6193 pub fn mip_level_size(&self, level: u32, dim: TextureDimension) -> Self {
6194 Self {
6195 width: u32::max(1, self.width >> level),
6196 height: match dim {
6197 TextureDimension::D1 => 1,
6198 _ => u32::max(1, self.height >> level),
6199 },
6200 depth_or_array_layers: match dim {
6201 TextureDimension::D1 => 1,
6202 TextureDimension::D2 => self.depth_or_array_layers,
6203 TextureDimension::D3 => u32::max(1, self.depth_or_array_layers >> level),
6204 },
6205 }
6206 }
6207}
6208
6209#[test]
6210fn test_physical_size() {
6211 let format = TextureFormat::Bc1RgbaUnormSrgb; // 4x4 blocks
6212 assert_eq!(
6213 Extent3d {
6214 width: 7,
6215 height: 7,
6216 depth_or_array_layers: 1
6217 }
6218 .physical_size(format),
6219 Extent3d {
6220 width: 8,
6221 height: 8,
6222 depth_or_array_layers: 1
6223 }
6224 );
6225 // Doesn't change, already aligned
6226 assert_eq!(
6227 Extent3d {
6228 width: 8,
6229 height: 8,
6230 depth_or_array_layers: 1
6231 }
6232 .physical_size(format),
6233 Extent3d {
6234 width: 8,
6235 height: 8,
6236 depth_or_array_layers: 1
6237 }
6238 );
6239 let format = TextureFormat::Astc {
6240 block: AstcBlock::B8x5,
6241 channel: AstcChannel::Unorm,
6242 }; // 8x5 blocks
6243 assert_eq!(
6244 Extent3d {
6245 width: 7,
6246 height: 7,
6247 depth_or_array_layers: 1
6248 }
6249 .physical_size(format),
6250 Extent3d {
6251 width: 8,
6252 height: 10,
6253 depth_or_array_layers: 1
6254 }
6255 );
6256}
6257
6258#[test]
6259fn test_max_mips() {
6260 // 1D
6261 assert_eq!(
6262 Extent3d {
6263 width: 240,
6264 height: 1,
6265 depth_or_array_layers: 1
6266 }
6267 .max_mips(TextureDimension::D1),
6268 1
6269 );
6270 // 2D
6271 assert_eq!(
6272 Extent3d {
6273 width: 1,
6274 height: 1,
6275 depth_or_array_layers: 1
6276 }
6277 .max_mips(TextureDimension::D2),
6278 1
6279 );
6280 assert_eq!(
6281 Extent3d {
6282 width: 60,
6283 height: 60,
6284 depth_or_array_layers: 1
6285 }
6286 .max_mips(TextureDimension::D2),
6287 6
6288 );
6289 assert_eq!(
6290 Extent3d {
6291 width: 240,
6292 height: 1,
6293 depth_or_array_layers: 1000
6294 }
6295 .max_mips(TextureDimension::D2),
6296 8
6297 );
6298 // 3D
6299 assert_eq!(
6300 Extent3d {
6301 width: 16,
6302 height: 30,
6303 depth_or_array_layers: 60
6304 }
6305 .max_mips(TextureDimension::D3),
6306 6
6307 );
6308}
6309
6310/// Describes a [`TextureView`].
6311///
6312/// For use with [`Texture::create_view()`].
6313///
6314/// Corresponds to [WebGPU `GPUTextureViewDescriptor`](
6315/// https://gpuweb.github.io/gpuweb/#dictdef-gputextureviewdescriptor).
6316///
6317/// [`TextureView`]: ../wgpu/struct.TextureView.html
6318/// [`Texture::create_view()`]: ../wgpu/struct.Texture.html#method.create_view
6319#[derive(Clone, Debug, Default, Eq, PartialEq)]
6320pub struct TextureViewDescriptor<L> {
6321 /// Debug label of the texture view. This will show up in graphics debuggers for easy identification.
6322 pub label: L,
6323 /// Format of the texture view. Either must be the same as the texture format or in the list
6324 /// of `view_formats` in the texture's descriptor.
6325 pub format: Option<TextureFormat>,
6326 /// The dimension of the texture view. For 1D textures, this must be `D1`. For 2D textures it must be one of
6327 /// `D2`, `D2Array`, `Cube`, and `CubeArray`. For 3D textures it must be `D3`
6328 pub dimension: Option<TextureViewDimension>,
6329 /// The allowed usage(s) for the texture view. Must be a subset of the usage flags of the texture.
6330 /// If not provided, defaults to the full set of usage flags of the texture.
6331 pub usage: Option<TextureUsages>,
6332 /// Aspect of the texture. Color textures must be [`TextureAspect::All`].
6333 pub aspect: TextureAspect,
6334 /// Base mip level.
6335 pub base_mip_level: u32,
6336 /// Mip level count.
6337 /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
6338 /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
6339 pub mip_level_count: Option<u32>,
6340 /// Base array layer.
6341 pub base_array_layer: u32,
6342 /// Layer count.
6343 /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
6344 /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
6345 pub array_layer_count: Option<u32>,
6346}
6347
6348/// Describes a [`Texture`](../wgpu/struct.Texture.html).
6349///
6350/// Corresponds to [WebGPU `GPUTextureDescriptor`](
6351/// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor).
6352#[repr(C)]
6353#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6355pub struct TextureDescriptor<L, V> {
6356 /// Debug label of the texture. This will show up in graphics debuggers for easy identification.
6357 pub label: L,
6358 /// Size of the texture. All components must be greater than zero. For a
6359 /// regular 1D/2D texture, the unused sizes will be 1. For 2DArray textures,
6360 /// Z is the number of 2D textures in that array.
6361 pub size: Extent3d,
6362 /// Mip count of texture. For a texture with no extra mips, this must be 1.
6363 pub mip_level_count: u32,
6364 /// Sample count of texture. If this is not 1, texture must have [`BindingType::Texture::multisampled`] set to true.
6365 pub sample_count: u32,
6366 /// Dimensions of the texture.
6367 pub dimension: TextureDimension,
6368 /// Format of the texture.
6369 pub format: TextureFormat,
6370 /// Allowed usages of the texture. If used in other ways, the operation will panic.
6371 pub usage: TextureUsages,
6372 /// Specifies what view formats will be allowed when calling `Texture::create_view` on this texture.
6373 ///
6374 /// View formats of the same format as the texture are always allowed.
6375 ///
6376 /// Note: currently, only the srgb-ness is allowed to change. (ex: `Rgba8Unorm` texture + `Rgba8UnormSrgb` view)
6377 pub view_formats: V,
6378}
6379
6380impl<L, V> TextureDescriptor<L, V> {
6381 /// Takes a closure and maps the label of the texture descriptor into another.
6382 #[must_use]
6383 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor<K, V>
6384 where
6385 V: Clone,
6386 {
6387 TextureDescriptor {
6388 label: fun(&self.label),
6389 size: self.size,
6390 mip_level_count: self.mip_level_count,
6391 sample_count: self.sample_count,
6392 dimension: self.dimension,
6393 format: self.format,
6394 usage: self.usage,
6395 view_formats: self.view_formats.clone(),
6396 }
6397 }
6398
6399 /// Maps the label and view formats of the texture descriptor into another.
6400 #[must_use]
6401 pub fn map_label_and_view_formats<K, M>(
6402 &self,
6403 l_fun: impl FnOnce(&L) -> K,
6404 v_fun: impl FnOnce(V) -> M,
6405 ) -> TextureDescriptor<K, M>
6406 where
6407 V: Clone,
6408 {
6409 TextureDescriptor {
6410 label: l_fun(&self.label),
6411 size: self.size,
6412 mip_level_count: self.mip_level_count,
6413 sample_count: self.sample_count,
6414 dimension: self.dimension,
6415 format: self.format,
6416 usage: self.usage,
6417 view_formats: v_fun(self.view_formats.clone()),
6418 }
6419 }
6420
6421 /// Calculates the extent at a given mip level.
6422 ///
6423 /// If the given mip level is larger than possible, returns None.
6424 ///
6425 /// Treats the depth as part of the mipmaps. If calculating
6426 /// for a 2DArray texture, which does not mipmap depth, set depth to 1.
6427 ///
6428 /// ```rust
6429 /// # use wgpu_types as wgpu;
6430 /// # type TextureDescriptor<'a> = wgpu::TextureDescriptor<(), &'a [wgpu::TextureFormat]>;
6431 /// let desc = TextureDescriptor {
6432 /// label: (),
6433 /// size: wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 },
6434 /// mip_level_count: 7,
6435 /// sample_count: 1,
6436 /// dimension: wgpu::TextureDimension::D3,
6437 /// format: wgpu::TextureFormat::Rgba8Sint,
6438 /// usage: wgpu::TextureUsages::empty(),
6439 /// view_formats: &[],
6440 /// };
6441 ///
6442 /// assert_eq!(desc.mip_level_size(0), Some(wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 }));
6443 /// assert_eq!(desc.mip_level_size(1), Some(wgpu::Extent3d { width: 50, height: 30, depth_or_array_layers: 1 }));
6444 /// assert_eq!(desc.mip_level_size(2), Some(wgpu::Extent3d { width: 25, height: 15, depth_or_array_layers: 1 }));
6445 /// assert_eq!(desc.mip_level_size(3), Some(wgpu::Extent3d { width: 12, height: 7, depth_or_array_layers: 1 }));
6446 /// assert_eq!(desc.mip_level_size(4), Some(wgpu::Extent3d { width: 6, height: 3, depth_or_array_layers: 1 }));
6447 /// assert_eq!(desc.mip_level_size(5), Some(wgpu::Extent3d { width: 3, height: 1, depth_or_array_layers: 1 }));
6448 /// assert_eq!(desc.mip_level_size(6), Some(wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 }));
6449 /// assert_eq!(desc.mip_level_size(7), None);
6450 /// ```
6451 #[must_use]
6452 pub fn mip_level_size(&self, level: u32) -> Option<Extent3d> {
6453 if level >= self.mip_level_count {
6454 return None;
6455 }
6456
6457 Some(self.size.mip_level_size(level, self.dimension))
6458 }
6459
6460 /// Computes the render extent of this texture.
6461 ///
6462 /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-compute-render-extent>
6463 #[must_use]
6464 pub fn compute_render_extent(&self, mip_level: u32, plane: Option<u32>) -> Extent3d {
6465 let width = self.size.width >> mip_level;
6466 let height = self.size.height >> mip_level;
6467
6468 let (width, height) = match (self.format, plane) {
6469 (TextureFormat::NV12 | TextureFormat::P010, Some(0)) => (width, height),
6470 (TextureFormat::NV12 | TextureFormat::P010, Some(1)) => (width / 2, height / 2),
6471 _ => {
6472 debug_assert!(!self.format.is_multi_planar_format());
6473 (width, height)
6474 }
6475 };
6476
6477 Extent3d {
6478 width,
6479 height,
6480 depth_or_array_layers: 1,
6481 }
6482 }
6483
6484 /// Returns the number of array layers.
6485 ///
6486 /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-array-layer-count>
6487 #[must_use]
6488 pub fn array_layer_count(&self) -> u32 {
6489 match self.dimension {
6490 TextureDimension::D1 | TextureDimension::D3 => 1,
6491 TextureDimension::D2 => self.size.depth_or_array_layers,
6492 }
6493 }
6494}
6495
6496/// Format of an `ExternalTexture`. This indicates the number of underlying
6497/// planes used by the `ExternalTexture` as well as each plane's format.
6498#[repr(C)]
6499#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
6500#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6501pub enum ExternalTextureFormat {
6502 /// Single [`TextureFormat::Rgba8Unorm`] or [`TextureFormat::Bgra8Unorm`] format plane.
6503 Rgba,
6504 /// [`TextureFormat::R8Unorm`] Y plane, and [`TextureFormat::Rg8Unorm`]
6505 /// interleaved CbCr plane.
6506 Nv12,
6507 /// Separate [`TextureFormat::R8Unorm`] Y, Cb, and Cr planes.
6508 Yu12,
6509}
6510
6511/// Parameters describing a gamma encoding transfer function in the form
6512/// tf = { k * linear | linear < b
6513/// { a * pow(linear, 1/g) - (a-1) | linear >= b
6514#[repr(C)]
6515#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Zeroable, bytemuck::Pod)]
6516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6517#[allow(missing_docs)]
6518pub struct ExternalTextureTransferFunction {
6519 pub a: f32,
6520 pub b: f32,
6521 pub g: f32,
6522 pub k: f32,
6523}
6524
6525impl Default for ExternalTextureTransferFunction {
6526 fn default() -> Self {
6527 Self {
6528 a: 1.0,
6529 b: 1.0,
6530 g: 1.0,
6531 k: 1.0,
6532 }
6533 }
6534}
6535
6536/// Describes an [`ExternalTexture`](../wgpu/struct.ExternalTexture.html).
6537///
6538/// Note that [`width`] and [`height`] are the values that should be returned by
6539/// size queries in shader code; they do not necessarily match the dimensions of
6540/// the underlying plane texture(s). As a special case, if `(width, height)` is
6541/// `(0, 0)`, the actual size of the first underlying plane should be used instead.
6542///
6543/// The size given by [`width`] and [`height`] must be consistent with
6544/// [`sample_transform`]: they should be the size in texels of the rectangle
6545/// covered by the square (0,0)..(1,1) after [`sample_transform`] has been applied
6546/// to it.
6547///
6548/// [`width`]: Self::width
6549/// [`height`]: Self::height
6550/// [`sample_transform`]: Self::sample_transform
6551///
6552/// Corresponds to [WebGPU `GPUExternalTextureDescriptor`](
6553/// https://gpuweb.github.io/gpuweb/#dictdef-gpuexternaltexturedescriptor).
6554#[repr(C)]
6555#[derive(Clone, Debug, PartialEq)]
6556#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6557pub struct ExternalTextureDescriptor<L> {
6558 /// Debug label of the external texture. This will show up in graphics
6559 /// debuggers for easy identification.
6560 pub label: L,
6561
6562 /// Width of the external texture.
6563 pub width: u32,
6564
6565 /// Height of the external texture.
6566 pub height: u32,
6567
6568 /// Format of the external texture.
6569 pub format: ExternalTextureFormat,
6570
6571 /// 4x4 column-major matrix with which to convert sampled YCbCr values
6572 /// to RGBA.
6573 /// This is ignored when `format` is [`ExternalTextureFormat::Rgba`].
6574 pub yuv_conversion_matrix: [f32; 16],
6575
6576 /// 3x3 column-major matrix to transform linear RGB values in the source
6577 /// color space to linear RGB values in the destination color space. In
6578 /// combination with [`Self::src_transfer_function`] and
6579 /// [`Self::dst_transfer_function`] this can be used to ensure that
6580 /// [`ImageSample`] and [`ImageLoad`] operations return values in the
6581 /// desired destination color space rather than the source color space of
6582 /// the underlying planes.
6583 ///
6584 /// [`ImageSample`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageSample
6585 /// [`ImageLoad`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageLoad
6586 pub gamut_conversion_matrix: [f32; 9],
6587
6588 /// Transfer function for the source color space. The *inverse* of this
6589 /// will be applied to decode non-linear RGB to linear RGB in the source
6590 /// color space.
6591 pub src_transfer_function: ExternalTextureTransferFunction,
6592
6593 /// Transfer function for the destination color space. This will be applied
6594 /// to encode linear RGB to non-linear RGB in the destination color space.
6595 pub dst_transfer_function: ExternalTextureTransferFunction,
6596
6597 /// Transform to apply to [`ImageSample`] coordinates.
6598 ///
6599 /// This is a 3x2 column-major matrix representing an affine transform from
6600 /// normalized texture coordinates to the normalized coordinates that should
6601 /// be sampled from the external texture's underlying plane(s).
6602 ///
6603 /// This transform may scale, translate, flip, and rotate in 90-degree
6604 /// increments, but the result of transforming the rectangle (0,0)..(1,1)
6605 /// must be an axis-aligned rectangle that falls within the bounds of
6606 /// (0,0)..(1,1).
6607 ///
6608 /// [`ImageSample`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageSample
6609 pub sample_transform: [f32; 6],
6610
6611 /// Transform to apply to [`ImageLoad`] coordinates.
6612 ///
6613 /// This is a 3x2 column-major matrix representing an affine transform from
6614 /// non-normalized texel coordinates to the non-normalized coordinates of
6615 /// the texel that should be loaded from the external texture's underlying
6616 /// plane 0. For planes 1 and 2, if present, plane 0's coordinates are
6617 /// scaled according to the textures' relative sizes.
6618 ///
6619 /// This transform may scale, translate, flip, and rotate in 90-degree
6620 /// increments, but the result of transforming the rectangle (0,0)..([`width`],
6621 /// [`height`]) must be an axis-aligned rectangle that falls within the bounds
6622 /// of (0,0)..([`width`], [`height`]).
6623 ///
6624 /// [`ImageLoad`]: https://docs.rs/naga/latest/naga/ir/enum.Expression.html#variant.ImageLoad
6625 /// [`width`]: Self::width
6626 /// [`height`]: Self::height
6627 pub load_transform: [f32; 6],
6628}
6629
6630impl<L> ExternalTextureDescriptor<L> {
6631 /// Takes a closure and maps the label of the external texture descriptor into another.
6632 #[must_use]
6633 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> ExternalTextureDescriptor<K> {
6634 ExternalTextureDescriptor {
6635 label: fun(&self.label),
6636 width: self.width,
6637 height: self.height,
6638 format: self.format,
6639 yuv_conversion_matrix: self.yuv_conversion_matrix,
6640 sample_transform: self.sample_transform,
6641 load_transform: self.load_transform,
6642 gamut_conversion_matrix: self.gamut_conversion_matrix,
6643 src_transfer_function: self.src_transfer_function,
6644 dst_transfer_function: self.dst_transfer_function,
6645 }
6646 }
6647
6648 /// The number of underlying planes used by the external texture.
6649 pub fn num_planes(&self) -> usize {
6650 match self.format {
6651 ExternalTextureFormat::Rgba => 1,
6652 ExternalTextureFormat::Nv12 => 2,
6653 ExternalTextureFormat::Yu12 => 3,
6654 }
6655 }
6656}
6657
6658/// Describes a `Sampler`.
6659///
6660/// For use with `Device::create_sampler`.
6661///
6662/// Corresponds to [WebGPU `GPUSamplerDescriptor`](
6663/// https://gpuweb.github.io/gpuweb/#dictdef-gpusamplerdescriptor).
6664#[derive(Clone, Debug, PartialEq)]
6665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6666pub struct SamplerDescriptor<L> {
6667 /// Debug label of the sampler. This will show up in graphics debuggers for easy identification.
6668 pub label: L,
6669 /// How to deal with out of bounds accesses in the u (i.e. x) direction
6670 pub address_mode_u: AddressMode,
6671 /// How to deal with out of bounds accesses in the v (i.e. y) direction
6672 pub address_mode_v: AddressMode,
6673 /// How to deal with out of bounds accesses in the w (i.e. z) direction
6674 pub address_mode_w: AddressMode,
6675 /// How to filter the texture when it needs to be magnified (made larger)
6676 pub mag_filter: FilterMode,
6677 /// How to filter the texture when it needs to be minified (made smaller)
6678 pub min_filter: FilterMode,
6679 /// How to filter between mip map levels
6680 pub mipmap_filter: MipmapFilterMode,
6681 /// Minimum level of detail (i.e. mip level) to use
6682 pub lod_min_clamp: f32,
6683 /// Maximum level of detail (i.e. mip level) to use
6684 pub lod_max_clamp: f32,
6685 /// If this is enabled, this is a comparison sampler using the given comparison function.
6686 pub compare: Option<CompareFunction>,
6687 /// Must be at least 1. If this is not 1, all filter modes must be linear.
6688 pub anisotropy_clamp: u16,
6689 /// Border color to use when `address_mode` is [`AddressMode::ClampToBorder`]
6690 pub border_color: Option<SamplerBorderColor>,
6691}
6692
6693impl<L: Default> Default for SamplerDescriptor<L> {
6694 fn default() -> Self {
6695 Self {
6696 label: Default::default(),
6697 address_mode_u: Default::default(),
6698 address_mode_v: Default::default(),
6699 address_mode_w: Default::default(),
6700 mag_filter: Default::default(),
6701 min_filter: Default::default(),
6702 mipmap_filter: Default::default(),
6703 lod_min_clamp: 0.0,
6704 lod_max_clamp: 32.0,
6705 compare: None,
6706 anisotropy_clamp: 1,
6707 border_color: None,
6708 }
6709 }
6710}
6711
6712/// Selects a subset of the data a [`Texture`] holds.
6713///
6714/// Used in [texture views](TextureViewDescriptor) and
6715/// [texture copy operations](TexelCopyTextureInfo).
6716///
6717/// Corresponds to [WebGPU `GPUTextureAspect`](
6718/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureaspect).
6719///
6720/// [`Texture`]: ../wgpu/struct.Texture.html
6721#[repr(C)]
6722#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
6723#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6724#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
6725pub enum TextureAspect {
6726 /// Depth, Stencil, and Color.
6727 #[default]
6728 All,
6729 /// Stencil.
6730 StencilOnly,
6731 /// Depth.
6732 DepthOnly,
6733 /// Plane 0.
6734 Plane0,
6735 /// Plane 1.
6736 Plane1,
6737 /// Plane 2.
6738 Plane2,
6739}
6740
6741/// How edges should be handled in texture addressing.
6742///
6743/// Corresponds to [WebGPU `GPUAddressMode`](
6744/// https://gpuweb.github.io/gpuweb/#enumdef-gpuaddressmode).
6745#[repr(C)]
6746#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
6747#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6748#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
6749pub enum AddressMode {
6750 /// Clamp the value to the edge of the texture
6751 ///
6752 /// -0.25 -> 0.0
6753 /// 1.25 -> 1.0
6754 #[default]
6755 ClampToEdge = 0,
6756 /// Repeat the texture in a tiling fashion
6757 ///
6758 /// -0.25 -> 0.75
6759 /// 1.25 -> 0.25
6760 Repeat = 1,
6761 /// Repeat the texture, mirroring it every repeat
6762 ///
6763 /// -0.25 -> 0.25
6764 /// 1.25 -> 0.75
6765 MirrorRepeat = 2,
6766 /// Clamp the value to the border of the texture
6767 /// Requires feature [`Features::ADDRESS_MODE_CLAMP_TO_BORDER`]
6768 ///
6769 /// -0.25 -> border
6770 /// 1.25 -> border
6771 ClampToBorder = 3,
6772}
6773
6774/// Texel mixing mode when sampling between texels.
6775///
6776/// Corresponds to [WebGPU `GPUFilterMode`](
6777/// https://gpuweb.github.io/gpuweb/#enumdef-gpufiltermode).
6778#[repr(C)]
6779#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
6780#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6781#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
6782pub enum FilterMode {
6783 /// Nearest neighbor sampling.
6784 ///
6785 /// This creates a pixelated effect.
6786 #[default]
6787 Nearest = 0,
6788 /// Linear Interpolation
6789 ///
6790 /// This makes textures smooth but blurry.
6791 Linear = 1,
6792}
6793
6794/// Texel mixing mode when sampling between texels.
6795///
6796/// Corresponds to [WebGPU `GPUMipmapFilterMode`](
6797/// https://gpuweb.github.io/gpuweb/#enumdef-gpumipmapfiltermode).
6798#[repr(C)]
6799#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
6800#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6801#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
6802pub enum MipmapFilterMode {
6803 /// Nearest neighbor sampling.
6804 ///
6805 /// Return the value of the texel nearest to the texture coordinates.
6806 #[default]
6807 Nearest = 0,
6808 /// Linear Interpolation
6809 ///
6810 /// Select two texels in each dimension and return a linear interpolation between their values.
6811 Linear = 1,
6812}
6813
6814/// A range of push constant memory to pass to a shader stage.
6815#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6816#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6817pub struct PushConstantRange {
6818 /// Stage push constant range is visible from. Each stage can only be served by at most one range.
6819 /// One range can serve multiple stages however.
6820 pub stages: ShaderStages,
6821 /// Range in push constant memory to use for the stage. Must be less than [`Limits::max_push_constant_size`].
6822 /// Start and end must be aligned to the 4s.
6823 pub range: Range<u32>,
6824}
6825
6826/// Describes a [`CommandBuffer`](../wgpu/struct.CommandBuffer.html).
6827///
6828/// Corresponds to [WebGPU `GPUCommandBufferDescriptor`](
6829/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandbufferdescriptor).
6830#[repr(C)]
6831#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
6832#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6833pub struct CommandBufferDescriptor<L> {
6834 /// Debug label of this command buffer.
6835 pub label: L,
6836}
6837
6838impl<L> CommandBufferDescriptor<L> {
6839 /// Takes a closure and maps the label of the command buffer descriptor into another.
6840 #[must_use]
6841 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CommandBufferDescriptor<K> {
6842 CommandBufferDescriptor {
6843 label: fun(&self.label),
6844 }
6845 }
6846}
6847
6848/// Describes the depth/stencil attachment for render bundles.
6849///
6850/// Corresponds to a portion of [WebGPU `GPURenderBundleEncoderDescriptor`](
6851/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor).
6852#[repr(C)]
6853#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
6854#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6855pub struct RenderBundleDepthStencil {
6856 /// Format of the attachment.
6857 pub format: TextureFormat,
6858 /// If the depth aspect of the depth stencil attachment is going to be written to.
6859 ///
6860 /// This must match the [`RenderPassDepthStencilAttachment::depth_ops`] of the renderpass this render bundle is executed in.
6861 /// If `depth_ops` is `Some(..)` this must be false. If it is `None` this must be true.
6862 ///
6863 /// [`RenderPassDepthStencilAttachment::depth_ops`]: ../wgpu/struct.RenderPassDepthStencilAttachment.html#structfield.depth_ops
6864 pub depth_read_only: bool,
6865
6866 /// If the stencil aspect of the depth stencil attachment is going to be written to.
6867 ///
6868 /// This must match the [`RenderPassDepthStencilAttachment::stencil_ops`] of the renderpass this render bundle is executed in.
6869 /// If `depth_ops` is `Some(..)` this must be false. If it is `None` this must be true.
6870 ///
6871 /// [`RenderPassDepthStencilAttachment::stencil_ops`]: ../wgpu/struct.RenderPassDepthStencilAttachment.html#structfield.stencil_ops
6872 pub stencil_read_only: bool,
6873}
6874
6875/// Describes a [`RenderBundle`](../wgpu/struct.RenderBundle.html).
6876///
6877/// Corresponds to [WebGPU `GPURenderBundleDescriptor`](
6878/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundledescriptor).
6879#[repr(C)]
6880#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6881#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6882pub struct RenderBundleDescriptor<L> {
6883 /// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
6884 pub label: L,
6885}
6886
6887impl<L> RenderBundleDescriptor<L> {
6888 /// Takes a closure and maps the label of the render bundle descriptor into another.
6889 #[must_use]
6890 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> RenderBundleDescriptor<K> {
6891 RenderBundleDescriptor {
6892 label: fun(&self.label),
6893 }
6894 }
6895}
6896
6897impl<T> Default for RenderBundleDescriptor<Option<T>> {
6898 fn default() -> Self {
6899 Self { label: None }
6900 }
6901}
6902
6903/// Layout of a texture in a buffer's memory.
6904///
6905/// The bytes per row and rows per image can be hard to figure out so here are some examples:
6906///
6907/// | Resolution | Format | Bytes per block | Pixels per block | Bytes per row | Rows per image |
6908/// |------------|--------|-----------------|------------------|----------------------------------------|------------------------------|
6909/// | 256x256 | RGBA8 | 4 | 1 * 1 * 1 | 256 * 4 = Some(1024) | None |
6910/// | 32x16x8 | RGBA8 | 4 | 1 * 1 * 1 | 32 * 4 = 128 padded to 256 = Some(256) | None |
6911/// | 256x256 | BC3 | 16 | 4 * 4 * 1 | 16 * (256 / 4) = 1024 = Some(1024) | None |
6912/// | 64x64x8 | BC3 | 16 | 4 * 4 * 1 | 16 * (64 / 4) = 256 = Some(256) | 64 / 4 = 16 = Some(16) |
6913///
6914/// Corresponds to [WebGPU `GPUTexelCopyBufferLayout`](
6915/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagedatalayout).
6916#[repr(C)]
6917#[derive(Clone, Copy, Debug, Default)]
6918#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6919pub struct TexelCopyBufferLayout {
6920 /// Offset into the buffer that is the start of the texture. Must be a multiple of texture block size.
6921 /// For non-compressed textures, this is 1.
6922 pub offset: BufferAddress,
6923 /// Bytes per "row" in an image.
6924 ///
6925 /// A row is one row of pixels or of compressed blocks in the x direction.
6926 ///
6927 /// This value is required if there are multiple rows (i.e. height or depth is more than one pixel or pixel block for compressed textures)
6928 ///
6929 /// Must be a multiple of 256 for [`CommandEncoder::copy_buffer_to_texture`][CEcbtt]
6930 /// and [`CommandEncoder::copy_texture_to_buffer`][CEcttb]. You must manually pad the
6931 /// image such that this is a multiple of 256. It will not affect the image data.
6932 ///
6933 /// [`Queue::write_texture`][Qwt] does not have this requirement.
6934 ///
6935 /// Must be a multiple of the texture block size. For non-compressed textures, this is 1.
6936 ///
6937 /// [CEcbtt]: ../wgpu/struct.CommandEncoder.html#method.copy_buffer_to_texture
6938 /// [CEcttb]: ../wgpu/struct.CommandEncoder.html#method.copy_texture_to_buffer
6939 /// [Qwt]: ../wgpu/struct.Queue.html#method.write_texture
6940 pub bytes_per_row: Option<u32>,
6941 /// "Rows" that make up a single "image".
6942 ///
6943 /// A row is one row of pixels or of compressed blocks in the x direction.
6944 ///
6945 /// An image is one layer in the z direction of a 3D image or 2DArray texture.
6946 ///
6947 /// The amount of rows per image may be larger than the actual amount of rows of data.
6948 ///
6949 /// Required if there are multiple images (i.e. the depth is more than one).
6950 pub rows_per_image: Option<u32>,
6951}
6952
6953/// Specific type of a buffer binding.
6954///
6955/// Corresponds to [WebGPU `GPUBufferBindingType`](
6956/// https://gpuweb.github.io/gpuweb/#enumdef-gpubufferbindingtype).
6957#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
6958#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6959pub enum BufferBindingType {
6960 /// A buffer for uniform values.
6961 ///
6962 /// Example WGSL syntax:
6963 /// ```rust,ignore
6964 /// struct Globals {
6965 /// a_uniform: vec2<f32>,
6966 /// another_uniform: vec2<f32>,
6967 /// }
6968 /// @group(0) @binding(0)
6969 /// var<uniform> globals: Globals;
6970 /// ```
6971 ///
6972 /// Example GLSL syntax:
6973 /// ```cpp,ignore
6974 /// layout(std140, binding = 0)
6975 /// uniform Globals {
6976 /// vec2 aUniform;
6977 /// vec2 anotherUniform;
6978 /// };
6979 /// ```
6980 #[default]
6981 Uniform,
6982 /// A storage buffer.
6983 ///
6984 /// Example WGSL syntax:
6985 /// ```rust,ignore
6986 /// @group(0) @binding(0)
6987 /// var<storage, read_write> my_element: array<vec4<f32>>;
6988 /// ```
6989 ///
6990 /// Example GLSL syntax:
6991 /// ```cpp,ignore
6992 /// layout (set=0, binding=0) buffer myStorageBuffer {
6993 /// vec4 myElement[];
6994 /// };
6995 /// ```
6996 Storage {
6997 /// If `true`, the buffer can only be read in the shader,
6998 /// and it:
6999 /// - may or may not be annotated with `read` (WGSL).
7000 /// - must be annotated with `readonly` (GLSL).
7001 ///
7002 /// Example WGSL syntax:
7003 /// ```rust,ignore
7004 /// @group(0) @binding(0)
7005 /// var<storage, read> my_element: array<vec4<f32>>;
7006 /// ```
7007 ///
7008 /// Example GLSL syntax:
7009 /// ```cpp,ignore
7010 /// layout (set=0, binding=0) readonly buffer myStorageBuffer {
7011 /// vec4 myElement[];
7012 /// };
7013 /// ```
7014 read_only: bool,
7015 },
7016}
7017
7018/// Specific type of a sample in a texture binding.
7019///
7020/// Corresponds to [WebGPU `GPUTextureSampleType`](
7021/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturesampletype).
7022#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7023#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7024pub enum TextureSampleType {
7025 /// Sampling returns floats.
7026 ///
7027 /// Example WGSL syntax:
7028 /// ```rust,ignore
7029 /// @group(0) @binding(0)
7030 /// var t: texture_2d<f32>;
7031 /// ```
7032 ///
7033 /// Example GLSL syntax:
7034 /// ```cpp,ignore
7035 /// layout(binding = 0)
7036 /// uniform texture2D t;
7037 /// ```
7038 Float {
7039 /// If this is `false`, the texture can't be sampled with
7040 /// a filtering sampler.
7041 ///
7042 /// Even if this is `true`, it's possible to sample with
7043 /// a **non-filtering** sampler.
7044 filterable: bool,
7045 },
7046 /// Sampling does the depth reference comparison.
7047 ///
7048 /// This is also compatible with a non-filtering sampler.
7049 ///
7050 /// Example WGSL syntax:
7051 /// ```rust,ignore
7052 /// @group(0) @binding(0)
7053 /// var t: texture_depth_2d;
7054 /// ```
7055 ///
7056 /// Example GLSL syntax:
7057 /// ```cpp,ignore
7058 /// layout(binding = 0)
7059 /// uniform texture2DShadow t;
7060 /// ```
7061 Depth,
7062 /// Sampling returns signed integers.
7063 ///
7064 /// Example WGSL syntax:
7065 /// ```rust,ignore
7066 /// @group(0) @binding(0)
7067 /// var t: texture_2d<i32>;
7068 /// ```
7069 ///
7070 /// Example GLSL syntax:
7071 /// ```cpp,ignore
7072 /// layout(binding = 0)
7073 /// uniform itexture2D t;
7074 /// ```
7075 Sint,
7076 /// Sampling returns unsigned integers.
7077 ///
7078 /// Example WGSL syntax:
7079 /// ```rust,ignore
7080 /// @group(0) @binding(0)
7081 /// var t: texture_2d<u32>;
7082 /// ```
7083 ///
7084 /// Example GLSL syntax:
7085 /// ```cpp,ignore
7086 /// layout(binding = 0)
7087 /// uniform utexture2D t;
7088 /// ```
7089 Uint,
7090}
7091
7092impl Default for TextureSampleType {
7093 fn default() -> Self {
7094 Self::Float { filterable: true }
7095 }
7096}
7097
7098/// Specific type of a sample in a texture binding.
7099///
7100/// For use in [`BindingType::StorageTexture`].
7101///
7102/// Corresponds to [WebGPU `GPUStorageTextureAccess`](
7103/// https://gpuweb.github.io/gpuweb/#enumdef-gpustoragetextureaccess).
7104#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7106#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
7107pub enum StorageTextureAccess {
7108 /// The texture can only be written in the shader and it:
7109 /// - may or may not be annotated with `write` (WGSL).
7110 /// - must be annotated with `writeonly` (GLSL).
7111 ///
7112 /// Example WGSL syntax:
7113 /// ```rust,ignore
7114 /// @group(0) @binding(0)
7115 /// var my_storage_image: texture_storage_2d<r32float, write>;
7116 /// ```
7117 ///
7118 /// Example GLSL syntax:
7119 /// ```cpp,ignore
7120 /// layout(set=0, binding=0, r32f) writeonly uniform image2D myStorageImage;
7121 /// ```
7122 WriteOnly,
7123 /// The texture can only be read in the shader and it must be annotated with `read` (WGSL) or
7124 /// `readonly` (GLSL).
7125 ///
7126 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
7127 /// mode. This is a native-only extension.
7128 ///
7129 /// Example WGSL syntax:
7130 /// ```rust,ignore
7131 /// @group(0) @binding(0)
7132 /// var my_storage_image: texture_storage_2d<r32float, read>;
7133 /// ```
7134 ///
7135 /// Example GLSL syntax:
7136 /// ```cpp,ignore
7137 /// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
7138 /// ```
7139 ReadOnly,
7140 /// The texture can be both read and written in the shader and must be annotated with
7141 /// `read_write` in WGSL.
7142 ///
7143 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
7144 /// mode. This is a nonstandard, native-only extension.
7145 ///
7146 /// Example WGSL syntax:
7147 /// ```rust,ignore
7148 /// @group(0) @binding(0)
7149 /// var my_storage_image: texture_storage_2d<r32float, read_write>;
7150 /// ```
7151 ///
7152 /// Example GLSL syntax:
7153 /// ```cpp,ignore
7154 /// layout(set=0, binding=0, r32f) uniform image2D myStorageImage;
7155 /// ```
7156 ReadWrite,
7157 /// The texture can be both read and written in the shader via atomics and must be annotated
7158 /// with `read_write` in WGSL.
7159 ///
7160 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
7161 /// mode. This is a nonstandard, native-only extension.
7162 ///
7163 /// Example WGSL syntax:
7164 /// ```rust,ignore
7165 /// @group(0) @binding(0)
7166 /// var my_storage_image: texture_storage_2d<r32uint, atomic>;
7167 /// ```
7168 Atomic,
7169}
7170
7171/// Specific type of a sampler binding.
7172///
7173/// For use in [`BindingType::Sampler`].
7174///
7175/// Corresponds to [WebGPU `GPUSamplerBindingType`](
7176/// https://gpuweb.github.io/gpuweb/#enumdef-gpusamplerbindingtype).
7177#[repr(C)]
7178#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7179#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7180#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
7181pub enum SamplerBindingType {
7182 /// The sampling result is produced based on more than a single color sample from a texture,
7183 /// e.g. when bilinear interpolation is enabled.
7184 Filtering,
7185 /// The sampling result is produced based on a single color sample from a texture.
7186 NonFiltering,
7187 /// Use as a comparison sampler instead of a normal sampler.
7188 /// For more info take a look at the analogous functionality in OpenGL: <https://www.khronos.org/opengl/wiki/Sampler_Object#Comparison_mode>.
7189 Comparison,
7190}
7191
7192/// Type of a binding in a [bind group layout][`BindGroupLayoutEntry`].
7193///
7194/// For each binding in a layout, a [`BindGroup`] must provide a [`BindingResource`] of the
7195/// corresponding type.
7196///
7197/// Corresponds to WebGPU's mutually exclusive fields within [`GPUBindGroupLayoutEntry`](
7198/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry).
7199///
7200/// [`BindingResource`]: ../wgpu/enum.BindingResource.html
7201/// [`BindGroup`]: ../wgpu/struct.BindGroup.html
7202#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7203#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7204pub enum BindingType {
7205 /// A buffer binding.
7206 ///
7207 /// Corresponds to [WebGPU `GPUBufferBindingLayout`](
7208 /// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferbindinglayout).
7209 Buffer {
7210 /// Sub-type of the buffer binding.
7211 ty: BufferBindingType,
7212
7213 /// Indicates that the binding has a dynamic offset.
7214 ///
7215 /// One offset must be passed to [`RenderPass::set_bind_group`][RPsbg]
7216 /// for each dynamic binding in increasing order of binding number.
7217 ///
7218 /// [RPsbg]: ../wgpu/struct.RenderPass.html#method.set_bind_group
7219 #[cfg_attr(feature = "serde", serde(default))]
7220 has_dynamic_offset: bool,
7221
7222 /// The minimum size for a [`BufferBinding`] matching this entry, in bytes.
7223 ///
7224 /// If this is `Some(size)`:
7225 ///
7226 /// - When calling [`create_bind_group`], the resource at this bind point
7227 /// must be a [`BindingResource::Buffer`] whose effective size is at
7228 /// least `size`.
7229 ///
7230 /// - When calling [`create_render_pipeline`] or [`create_compute_pipeline`],
7231 /// `size` must be at least the [minimum buffer binding size] for the
7232 /// shader module global at this bind point: large enough to hold the
7233 /// global's value, along with one element of a trailing runtime-sized
7234 /// array, if present.
7235 ///
7236 /// If this is `None`:
7237 ///
7238 /// - Each draw or dispatch command checks that the buffer range at this
7239 /// bind point satisfies the [minimum buffer binding size].
7240 ///
7241 /// [`BufferBinding`]: ../wgpu/struct.BufferBinding.html
7242 /// [`create_bind_group`]: ../wgpu/struct.Device.html#method.create_bind_group
7243 /// [`BindingResource::Buffer`]: ../wgpu/enum.BindingResource.html#variant.Buffer
7244 /// [minimum buffer binding size]: https://www.w3.org/TR/webgpu/#minimum-buffer-binding-size
7245 /// [`create_render_pipeline`]: ../wgpu/struct.Device.html#method.create_render_pipeline
7246 /// [`create_compute_pipeline`]: ../wgpu/struct.Device.html#method.create_compute_pipeline
7247 #[cfg_attr(feature = "serde", serde(default))]
7248 min_binding_size: Option<BufferSize>,
7249 },
7250 /// A sampler that can be used to sample a texture.
7251 ///
7252 /// Example WGSL syntax:
7253 /// ```rust,ignore
7254 /// @group(0) @binding(0)
7255 /// var s: sampler;
7256 /// ```
7257 ///
7258 /// Example GLSL syntax:
7259 /// ```cpp,ignore
7260 /// layout(binding = 0)
7261 /// uniform sampler s;
7262 /// ```
7263 ///
7264 /// Corresponds to [WebGPU `GPUSamplerBindingLayout`](
7265 /// https://gpuweb.github.io/gpuweb/#dictdef-gpusamplerbindinglayout).
7266 Sampler(SamplerBindingType),
7267 /// A texture binding.
7268 ///
7269 /// Example WGSL syntax:
7270 /// ```rust,ignore
7271 /// @group(0) @binding(0)
7272 /// var t: texture_2d<f32>;
7273 /// ```
7274 ///
7275 /// Example GLSL syntax:
7276 /// ```cpp,ignore
7277 /// layout(binding = 0)
7278 /// uniform texture2D t;
7279 /// ```
7280 ///
7281 /// Corresponds to [WebGPU `GPUTextureBindingLayout`](
7282 /// https://gpuweb.github.io/gpuweb/#dictdef-gputexturebindinglayout).
7283 Texture {
7284 /// Sample type of the texture binding.
7285 sample_type: TextureSampleType,
7286 /// Dimension of the texture view that is going to be sampled.
7287 view_dimension: TextureViewDimension,
7288 /// True if the texture has a sample count greater than 1. If this is true,
7289 /// the texture must be declared as `texture_multisampled_2d` or
7290 /// `texture_depth_multisampled_2d` in the shader, and read using `textureLoad`.
7291 multisampled: bool,
7292 },
7293 /// A storage texture.
7294 ///
7295 /// Example WGSL syntax:
7296 /// ```rust,ignore
7297 /// @group(0) @binding(0)
7298 /// var my_storage_image: texture_storage_2d<r32float, write>;
7299 /// ```
7300 ///
7301 /// Example GLSL syntax:
7302 /// ```cpp,ignore
7303 /// layout(set=0, binding=0, r32f) writeonly uniform image2D myStorageImage;
7304 /// ```
7305 /// Note that the texture format must be specified in the shader, along with the
7306 /// access mode. For WGSL, the format must be one of the enumerants in the list
7307 /// of [storage texel formats](https://gpuweb.github.io/gpuweb/wgsl/#storage-texel-formats).
7308 ///
7309 /// Corresponds to [WebGPU `GPUStorageTextureBindingLayout`](
7310 /// https://gpuweb.github.io/gpuweb/#dictdef-gpustoragetexturebindinglayout).
7311 StorageTexture {
7312 /// Allowed access to this texture.
7313 access: StorageTextureAccess,
7314 /// Format of the texture.
7315 format: TextureFormat,
7316 /// Dimension of the texture view that is going to be sampled.
7317 view_dimension: TextureViewDimension,
7318 },
7319
7320 /// A ray-tracing acceleration structure binding.
7321 ///
7322 /// Example WGSL syntax:
7323 /// ```rust,ignore
7324 /// @group(0) @binding(0)
7325 /// var as: acceleration_structure;
7326 /// ```
7327 ///
7328 /// or with vertex return enabled
7329 /// ```rust,ignore
7330 /// @group(0) @binding(0)
7331 /// var as: acceleration_structure<vertex_return>;
7332 /// ```
7333 ///
7334 /// Example GLSL syntax:
7335 /// ```cpp,ignore
7336 /// layout(binding = 0)
7337 /// uniform accelerationStructureEXT as;
7338 /// ```
7339 AccelerationStructure {
7340 /// Whether this acceleration structure can be used to
7341 /// create a ray query that has flag vertex return in the shader
7342 ///
7343 /// If enabled requires [`Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN`]
7344 vertex_return: bool,
7345 },
7346
7347 /// An external texture binding.
7348 ///
7349 /// Example WGSL syntax:
7350 /// ```rust,ignore
7351 /// @group(0) @binding(0)
7352 /// var t: texture_external;
7353 /// ```
7354 ///
7355 /// Corresponds to [WebGPU `GPUExternalTextureBindingLayout`](
7356 /// https://gpuweb.github.io/gpuweb/#dictdef-gpuexternaltexturebindinglayout).
7357 ///
7358 /// Requires [`Features::EXTERNAL_TEXTURE`]
7359 ExternalTexture,
7360}
7361
7362impl BindingType {
7363 /// Returns true for buffer bindings with dynamic offset enabled.
7364 #[must_use]
7365 pub fn has_dynamic_offset(&self) -> bool {
7366 match *self {
7367 Self::Buffer {
7368 has_dynamic_offset, ..
7369 } => has_dynamic_offset,
7370 _ => false,
7371 }
7372 }
7373}
7374
7375/// Describes a single binding inside a bind group.
7376///
7377/// Corresponds to [WebGPU `GPUBindGroupLayoutEntry`](
7378/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry).
7379#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
7380#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7381pub struct BindGroupLayoutEntry {
7382 /// Binding index. Must match shader index and be unique inside a `BindGroupLayout`. A binding
7383 /// of index 1, would be described as `@group(0) @binding(1)` in shaders.
7384 pub binding: u32,
7385 /// Which shader stages can see this binding.
7386 pub visibility: ShaderStages,
7387 /// The type of the binding
7388 pub ty: BindingType,
7389 /// If the binding is an array of multiple resources. Corresponds to `binding_array<T>` in the shader.
7390 ///
7391 /// When this is `Some` the following validation applies:
7392 /// - Size must be of value 1 or greater.
7393 /// - When `ty == BindingType::Texture`, [`Features::TEXTURE_BINDING_ARRAY`] must be supported.
7394 /// - When `ty == BindingType::Sampler`, [`Features::TEXTURE_BINDING_ARRAY`] must be supported.
7395 /// - When `ty == BindingType::Buffer`, [`Features::BUFFER_BINDING_ARRAY`] must be supported.
7396 /// - When `ty == BindingType::Buffer` and `ty.ty == BufferBindingType::Storage`, [`Features::STORAGE_RESOURCE_BINDING_ARRAY`] must be supported.
7397 /// - When `ty == BindingType::StorageTexture`, [`Features::STORAGE_RESOURCE_BINDING_ARRAY`] must be supported.
7398 /// - When any binding in the group is an array, no `BindingType::Buffer` in the group may have `has_dynamic_offset == true`
7399 /// - When any binding in the group is an array, no `BindingType::Buffer` in the group may have `ty.ty == BufferBindingType::Uniform`.
7400 ///
7401 #[cfg_attr(feature = "serde", serde(default))]
7402 pub count: Option<NonZeroU32>,
7403}
7404
7405/// View of a buffer which can be used to copy to/from a texture.
7406///
7407/// Corresponds to [WebGPU `GPUTexelCopyBufferInfo`](
7408/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
7409#[repr(C)]
7410#[derive(Copy, Clone, Debug)]
7411#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7412pub struct TexelCopyBufferInfo<B> {
7413 /// The buffer to be copied to/from.
7414 pub buffer: B,
7415 /// The layout of the texture data in this buffer.
7416 pub layout: TexelCopyBufferLayout,
7417}
7418
7419/// View of a texture which can be used to copy to/from a buffer/texture.
7420///
7421/// Corresponds to [WebGPU `GPUTexelCopyTextureInfo`](
7422/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
7423#[repr(C)]
7424#[derive(Copy, Clone, Debug)]
7425#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7426pub struct TexelCopyTextureInfo<T> {
7427 /// The texture to be copied to/from.
7428 pub texture: T,
7429 /// The target mip level of the texture.
7430 pub mip_level: u32,
7431 /// The base texel of the texture in the selected `mip_level`. Together
7432 /// with the `copy_size` argument to copy functions, defines the
7433 /// sub-region of the texture to copy.
7434 #[cfg_attr(feature = "serde", serde(default))]
7435 pub origin: Origin3d,
7436 /// The copy aspect.
7437 #[cfg_attr(feature = "serde", serde(default))]
7438 pub aspect: TextureAspect,
7439}
7440
7441impl<T> TexelCopyTextureInfo<T> {
7442 /// Adds color space and premultiplied alpha information to make this
7443 /// descriptor tagged.
7444 pub fn to_tagged(
7445 self,
7446 color_space: PredefinedColorSpace,
7447 premultiplied_alpha: bool,
7448 ) -> CopyExternalImageDestInfo<T> {
7449 CopyExternalImageDestInfo {
7450 texture: self.texture,
7451 mip_level: self.mip_level,
7452 origin: self.origin,
7453 aspect: self.aspect,
7454 color_space,
7455 premultiplied_alpha,
7456 }
7457 }
7458}
7459
7460/// View of an external texture that can be used to copy to a texture.
7461///
7462/// Corresponds to [WebGPU `GPUCopyExternalImageSourceInfo`](
7463/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopyexternalimage).
7464#[cfg(all(target_arch = "wasm32", feature = "web"))]
7465#[derive(Clone, Debug)]
7466pub struct CopyExternalImageSourceInfo {
7467 /// The texture to be copied from. The copy source data is captured at the moment
7468 /// the copy is issued.
7469 pub source: ExternalImageSource,
7470 /// The base texel used for copying from the external image. Together
7471 /// with the `copy_size` argument to copy functions, defines the
7472 /// sub-region of the image to copy.
7473 ///
7474 /// Relative to the top left of the image.
7475 ///
7476 /// Must be [`Origin2d::ZERO`] if [`DownlevelFlags::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES`] is not supported.
7477 pub origin: Origin2d,
7478 /// If the Y coordinate of the image should be flipped. Even if this is
7479 /// true, `origin` is still relative to the top left.
7480 pub flip_y: bool,
7481}
7482
7483/// Source of an external texture copy.
7484///
7485/// Corresponds to the [implicit union type on WebGPU `GPUCopyExternalImageSourceInfo.source`](
7486/// https://gpuweb.github.io/gpuweb/#dom-gpuimagecopyexternalimage-source).
7487#[cfg(all(target_arch = "wasm32", feature = "web"))]
7488#[derive(Clone, Debug)]
7489pub enum ExternalImageSource {
7490 /// Copy from a previously-decoded image bitmap.
7491 ImageBitmap(web_sys::ImageBitmap),
7492 /// Copy from an image element.
7493 HTMLImageElement(web_sys::HtmlImageElement),
7494 /// Copy from a current frame of a video element.
7495 HTMLVideoElement(web_sys::HtmlVideoElement),
7496 /// Copy from an image.
7497 ImageData(web_sys::ImageData),
7498 /// Copy from a on-screen canvas.
7499 HTMLCanvasElement(web_sys::HtmlCanvasElement),
7500 /// Copy from a off-screen canvas.
7501 ///
7502 /// Requires [`DownlevelFlags::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES`]
7503 OffscreenCanvas(web_sys::OffscreenCanvas),
7504 /// Copy from a video frame.
7505 #[cfg(web_sys_unstable_apis)]
7506 VideoFrame(web_sys::VideoFrame),
7507}
7508
7509#[cfg(all(target_arch = "wasm32", feature = "web"))]
7510impl ExternalImageSource {
7511 /// Gets the pixel, not css, width of the source.
7512 pub fn width(&self) -> u32 {
7513 match self {
7514 ExternalImageSource::ImageBitmap(b) => b.width(),
7515 ExternalImageSource::HTMLImageElement(i) => i.width(),
7516 ExternalImageSource::HTMLVideoElement(v) => v.video_width(),
7517 ExternalImageSource::ImageData(i) => i.width(),
7518 ExternalImageSource::HTMLCanvasElement(c) => c.width(),
7519 ExternalImageSource::OffscreenCanvas(c) => c.width(),
7520 #[cfg(web_sys_unstable_apis)]
7521 ExternalImageSource::VideoFrame(v) => v.display_width(),
7522 }
7523 }
7524
7525 /// Gets the pixel, not css, height of the source.
7526 pub fn height(&self) -> u32 {
7527 match self {
7528 ExternalImageSource::ImageBitmap(b) => b.height(),
7529 ExternalImageSource::HTMLImageElement(i) => i.height(),
7530 ExternalImageSource::HTMLVideoElement(v) => v.video_height(),
7531 ExternalImageSource::ImageData(i) => i.height(),
7532 ExternalImageSource::HTMLCanvasElement(c) => c.height(),
7533 ExternalImageSource::OffscreenCanvas(c) => c.height(),
7534 #[cfg(web_sys_unstable_apis)]
7535 ExternalImageSource::VideoFrame(v) => v.display_height(),
7536 }
7537 }
7538}
7539
7540#[cfg(all(target_arch = "wasm32", feature = "web"))]
7541impl core::ops::Deref for ExternalImageSource {
7542 type Target = js_sys::Object;
7543
7544 fn deref(&self) -> &Self::Target {
7545 match self {
7546 Self::ImageBitmap(b) => b,
7547 Self::HTMLImageElement(i) => i,
7548 Self::HTMLVideoElement(v) => v,
7549 Self::ImageData(i) => i,
7550 Self::HTMLCanvasElement(c) => c,
7551 Self::OffscreenCanvas(c) => c,
7552 #[cfg(web_sys_unstable_apis)]
7553 Self::VideoFrame(v) => v,
7554 }
7555 }
7556}
7557
7558#[cfg(all(
7559 target_arch = "wasm32",
7560 feature = "web",
7561 feature = "fragile-send-sync-non-atomic-wasm",
7562 not(target_feature = "atomics")
7563))]
7564unsafe impl Send for ExternalImageSource {}
7565#[cfg(all(
7566 target_arch = "wasm32",
7567 feature = "web",
7568 feature = "fragile-send-sync-non-atomic-wasm",
7569 not(target_feature = "atomics")
7570))]
7571unsafe impl Sync for ExternalImageSource {}
7572
7573/// Color spaces supported on the web.
7574///
7575/// Corresponds to [HTML Canvas `PredefinedColorSpace`](
7576/// https://html.spec.whatwg.org/multipage/canvas.html#predefinedcolorspace).
7577#[derive(Copy, Clone, Debug, PartialEq, Eq)]
7578#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7579#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
7580pub enum PredefinedColorSpace {
7581 /// sRGB color space
7582 Srgb,
7583 /// Display-P3 color space
7584 DisplayP3,
7585}
7586
7587/// View of a texture which can be used to copy to a texture, including
7588/// color space and alpha premultiplication information.
7589///
7590/// Corresponds to [WebGPU `GPUCopyExternalImageDestInfo`](
7591/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged).
7592#[derive(Copy, Clone, Debug)]
7593#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7594pub struct CopyExternalImageDestInfo<T> {
7595 /// The texture to be copied to/from.
7596 pub texture: T,
7597 /// The target mip level of the texture.
7598 pub mip_level: u32,
7599 /// The base texel of the texture in the selected `mip_level`.
7600 pub origin: Origin3d,
7601 /// The copy aspect.
7602 pub aspect: TextureAspect,
7603 /// The color space of this texture.
7604 pub color_space: PredefinedColorSpace,
7605 /// The premultiplication of this texture
7606 pub premultiplied_alpha: bool,
7607}
7608
7609impl<T> CopyExternalImageDestInfo<T> {
7610 /// Removes the colorspace information from the type.
7611 pub fn to_untagged(self) -> TexelCopyTextureInfo<T> {
7612 TexelCopyTextureInfo {
7613 texture: self.texture,
7614 mip_level: self.mip_level,
7615 origin: self.origin,
7616 aspect: self.aspect,
7617 }
7618 }
7619}
7620
7621/// Subresource range within an image
7622#[repr(C)]
7623#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
7624#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7625#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
7626pub struct ImageSubresourceRange {
7627 /// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA].
7628 ///
7629 /// [TAA]: ../wgpu/enum.TextureAspect.html#variant.All
7630 pub aspect: TextureAspect,
7631 /// Base mip level.
7632 pub base_mip_level: u32,
7633 /// Mip level count.
7634 /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
7635 /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
7636 pub mip_level_count: Option<u32>,
7637 /// Base array layer.
7638 pub base_array_layer: u32,
7639 /// Layer count.
7640 /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
7641 /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
7642 pub array_layer_count: Option<u32>,
7643}
7644
7645impl ImageSubresourceRange {
7646 /// Returns if the given range represents a full resource, with a texture of the given
7647 /// layer count and mip count.
7648 ///
7649 /// ```rust
7650 /// # use wgpu_types as wgpu;
7651 ///
7652 /// let range_none = wgpu::ImageSubresourceRange {
7653 /// aspect: wgpu::TextureAspect::All,
7654 /// base_mip_level: 0,
7655 /// mip_level_count: None,
7656 /// base_array_layer: 0,
7657 /// array_layer_count: None,
7658 /// };
7659 /// assert_eq!(range_none.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), true);
7660 ///
7661 /// let range_some = wgpu::ImageSubresourceRange {
7662 /// aspect: wgpu::TextureAspect::All,
7663 /// base_mip_level: 0,
7664 /// mip_level_count: Some(5),
7665 /// base_array_layer: 0,
7666 /// array_layer_count: Some(10),
7667 /// };
7668 /// assert_eq!(range_some.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), true);
7669 ///
7670 /// let range_mixed = wgpu::ImageSubresourceRange {
7671 /// aspect: wgpu::TextureAspect::StencilOnly,
7672 /// base_mip_level: 0,
7673 /// // Only partial resource
7674 /// mip_level_count: Some(3),
7675 /// base_array_layer: 0,
7676 /// array_layer_count: None,
7677 /// };
7678 /// assert_eq!(range_mixed.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), false);
7679 /// ```
7680 #[must_use]
7681 pub fn is_full_resource(
7682 &self,
7683 format: TextureFormat,
7684 mip_levels: u32,
7685 array_layers: u32,
7686 ) -> bool {
7687 // Mip level count and array layer count need to deal with both the None and Some(count) case.
7688 let mip_level_count = self.mip_level_count.unwrap_or(mip_levels);
7689 let array_layer_count = self.array_layer_count.unwrap_or(array_layers);
7690
7691 let aspect_eq = Some(format) == format.aspect_specific_format(self.aspect);
7692
7693 let base_mip_level_eq = self.base_mip_level == 0;
7694 let mip_level_count_eq = mip_level_count == mip_levels;
7695
7696 let base_array_layer_eq = self.base_array_layer == 0;
7697 let array_layer_count_eq = array_layer_count == array_layers;
7698
7699 aspect_eq
7700 && base_mip_level_eq
7701 && mip_level_count_eq
7702 && base_array_layer_eq
7703 && array_layer_count_eq
7704 }
7705
7706 /// Returns the mip level range of a subresource range describes for a specific texture.
7707 #[must_use]
7708 pub fn mip_range(&self, mip_level_count: u32) -> Range<u32> {
7709 self.base_mip_level..match self.mip_level_count {
7710 Some(mip_level_count) => self.base_mip_level + mip_level_count,
7711 None => mip_level_count,
7712 }
7713 }
7714
7715 /// Returns the layer range of a subresource range describes for a specific texture.
7716 #[must_use]
7717 pub fn layer_range(&self, array_layer_count: u32) -> Range<u32> {
7718 self.base_array_layer..match self.array_layer_count {
7719 Some(array_layer_count) => self.base_array_layer + array_layer_count,
7720 None => array_layer_count,
7721 }
7722 }
7723}
7724
7725/// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`]
7726#[repr(C)]
7727#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
7728#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7729pub enum SamplerBorderColor {
7730 /// [0, 0, 0, 0]
7731 TransparentBlack,
7732 /// [0, 0, 0, 1]
7733 OpaqueBlack,
7734 /// [1, 1, 1, 1]
7735 OpaqueWhite,
7736
7737 /// On the Metal backend, this is equivalent to `TransparentBlack` for
7738 /// textures that have an alpha component, and equivalent to `OpaqueBlack`
7739 /// for textures that do not have an alpha component. On other backends,
7740 /// this is equivalent to `TransparentBlack`. Requires
7741 /// [`Features::ADDRESS_MODE_CLAMP_TO_ZERO`]. Not supported on the web.
7742 Zero,
7743}
7744
7745/// Describes how to create a `QuerySet`.
7746///
7747/// Corresponds to [WebGPU `GPUQuerySetDescriptor`](
7748/// https://gpuweb.github.io/gpuweb/#dictdef-gpuquerysetdescriptor).
7749#[derive(Clone, Debug)]
7750#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7751pub struct QuerySetDescriptor<L> {
7752 /// Debug label for the query set.
7753 pub label: L,
7754 /// Kind of query that this query set should contain.
7755 pub ty: QueryType,
7756 /// Total count of queries the set contains. Must not be zero.
7757 /// Must not be greater than [`QUERY_SET_MAX_QUERIES`].
7758 pub count: u32,
7759}
7760
7761impl<L> QuerySetDescriptor<L> {
7762 /// Takes a closure and maps the label of the query set descriptor into another.
7763 #[must_use]
7764 pub fn map_label<'a, K>(&'a self, fun: impl FnOnce(&'a L) -> K) -> QuerySetDescriptor<K> {
7765 QuerySetDescriptor {
7766 label: fun(&self.label),
7767 ty: self.ty,
7768 count: self.count,
7769 }
7770 }
7771}
7772
7773/// Type of query contained in a [`QuerySet`].
7774///
7775/// Corresponds to [WebGPU `GPUQueryType`](
7776/// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype).
7777///
7778/// [`QuerySet`]: ../wgpu/struct.QuerySet.html
7779#[derive(Copy, Clone, Debug)]
7780#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7781pub enum QueryType {
7782 /// Query returns a single 64-bit number, serving as an occlusion boolean.
7783 Occlusion,
7784 /// Query returns up to 5 64-bit numbers based on the given flags.
7785 ///
7786 /// See [`PipelineStatisticsTypes`]'s documentation for more information
7787 /// on how they get resolved.
7788 ///
7789 /// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled to use this query type.
7790 PipelineStatistics(PipelineStatisticsTypes),
7791 /// Query returns a 64-bit number indicating the GPU-timestamp
7792 /// where all previous commands have finished executing.
7793 ///
7794 /// Must be multiplied by [`Queue::get_timestamp_period`][Qgtp] to get
7795 /// the value in nanoseconds. Absolute values have no meaning,
7796 /// but timestamps can be subtracted to get the time it takes
7797 /// for a string of operations to complete.
7798 ///
7799 /// [`Features::TIMESTAMP_QUERY`] must be enabled to use this query type.
7800 ///
7801 /// [Qgtp]: ../wgpu/struct.Queue.html#method.get_timestamp_period
7802 Timestamp,
7803}
7804
7805bitflags::bitflags! {
7806 /// Flags for which pipeline data should be recorded in a query.
7807 ///
7808 /// Used in [`QueryType`].
7809 ///
7810 /// The amount of values written when resolved depends
7811 /// on the amount of flags set. For example, if 3 flags are set, 3
7812 /// 64-bit values will be written per query.
7813 ///
7814 /// The order they are written is the order they are declared
7815 /// in these bitflags. For example, if you enabled `CLIPPER_PRIMITIVES_OUT`
7816 /// and `COMPUTE_SHADER_INVOCATIONS`, it would write 16 bytes,
7817 /// the first 8 bytes being the primitive out value, the last 8
7818 /// bytes being the compute shader invocation count.
7819 #[repr(transparent)]
7820 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7821 #[cfg_attr(feature = "serde", serde(transparent))]
7822 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
7823 pub struct PipelineStatisticsTypes : u8 {
7824 /// Amount of times the vertex shader is ran. Accounts for
7825 /// the vertex cache when doing indexed rendering.
7826 const VERTEX_SHADER_INVOCATIONS = 1 << 0;
7827 /// Amount of times the clipper is invoked. This
7828 /// is also the amount of triangles output by the vertex shader.
7829 const CLIPPER_INVOCATIONS = 1 << 1;
7830 /// Amount of primitives that are not culled by the clipper.
7831 /// This is the amount of triangles that are actually on screen
7832 /// and will be rasterized and rendered.
7833 const CLIPPER_PRIMITIVES_OUT = 1 << 2;
7834 /// Amount of times the fragment shader is ran. Accounts for
7835 /// fragment shaders running in 2x2 blocks in order to get
7836 /// derivatives.
7837 const FRAGMENT_SHADER_INVOCATIONS = 1 << 3;
7838 /// Amount of times a compute shader is invoked. This will
7839 /// be equivalent to the dispatch count times the workgroup size.
7840 const COMPUTE_SHADER_INVOCATIONS = 1 << 4;
7841 }
7842}
7843
7844/// Argument buffer layout for `draw_indirect` commands.
7845#[repr(C)]
7846#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
7847pub struct DrawIndirectArgs {
7848 /// The number of vertices to draw.
7849 pub vertex_count: u32,
7850 /// The number of instances to draw.
7851 pub instance_count: u32,
7852 /// The Index of the first vertex to draw.
7853 pub first_vertex: u32,
7854 /// The instance ID of the first instance to draw.
7855 ///
7856 /// Has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`](crate::Features::INDIRECT_FIRST_INSTANCE) is enabled.
7857 pub first_instance: u32,
7858}
7859
7860impl DrawIndirectArgs {
7861 /// Returns the bytes representation of the struct, ready to be written in a buffer.
7862 #[must_use]
7863 pub fn as_bytes(&self) -> &[u8] {
7864 bytemuck::bytes_of(self)
7865 }
7866}
7867
7868/// Argument buffer layout for `draw_indexed_indirect` commands.
7869#[repr(C)]
7870#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
7871pub struct DrawIndexedIndirectArgs {
7872 /// The number of indices to draw.
7873 pub index_count: u32,
7874 /// The number of instances to draw.
7875 pub instance_count: u32,
7876 /// The first index within the index buffer.
7877 pub first_index: u32,
7878 /// The value added to the vertex index before indexing into the vertex buffer.
7879 pub base_vertex: i32,
7880 /// The instance ID of the first instance to draw.
7881 ///
7882 /// Has to be 0, unless [`Features::INDIRECT_FIRST_INSTANCE`](crate::Features::INDIRECT_FIRST_INSTANCE) is enabled.
7883 pub first_instance: u32,
7884}
7885
7886impl DrawIndexedIndirectArgs {
7887 /// Returns the bytes representation of the struct, ready to be written in a buffer.
7888 #[must_use]
7889 pub fn as_bytes(&self) -> &[u8] {
7890 bytemuck::bytes_of(self)
7891 }
7892}
7893
7894/// Argument buffer layout for `dispatch_indirect` commands.
7895#[repr(C)]
7896#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
7897pub struct DispatchIndirectArgs {
7898 /// The number of work groups in X dimension.
7899 pub x: u32,
7900 /// The number of work groups in Y dimension.
7901 pub y: u32,
7902 /// The number of work groups in Z dimension.
7903 pub z: u32,
7904}
7905
7906impl DispatchIndirectArgs {
7907 /// Returns the bytes representation of the struct, ready to be written into a buffer.
7908 #[must_use]
7909 pub fn as_bytes(&self) -> &[u8] {
7910 bytemuck::bytes_of(self)
7911 }
7912}
7913
7914/// Describes how shader bound checks should be performed.
7915#[derive(Copy, Clone, Debug)]
7916#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7917pub struct ShaderRuntimeChecks {
7918 /// Enforce bounds checks in shaders, even if the underlying driver doesn't
7919 /// support doing so natively.
7920 ///
7921 /// When this is `true`, `wgpu` promises that shaders can only read or
7922 /// write the accessible region of a bindgroup's buffer bindings. If
7923 /// the underlying graphics platform cannot implement these bounds checks
7924 /// itself, `wgpu` will inject bounds checks before presenting the
7925 /// shader to the platform.
7926 ///
7927 /// When this is `false`, `wgpu` only enforces such bounds checks if the
7928 /// underlying platform provides a way to do so itself. `wgpu` does not
7929 /// itself add any bounds checks to generated shader code.
7930 ///
7931 /// Note that `wgpu` users may try to initialize only those portions of
7932 /// buffers that they anticipate might be read from. Passing `false` here
7933 /// may allow shaders to see wider regions of the buffers than expected,
7934 /// making such deferred initialization visible to the application.
7935 pub bounds_checks: bool,
7936 ///
7937 /// If false, the caller MUST ensure that all passed shaders do not contain any infinite loops.
7938 ///
7939 /// If it does, backend compilers MAY treat such a loop as unreachable code and draw
7940 /// conclusions about other safety-critical code paths. This option SHOULD NOT be disabled
7941 /// when running untrusted code.
7942 pub force_loop_bounding: bool,
7943}
7944
7945impl ShaderRuntimeChecks {
7946 /// Creates a new configuration where the shader is fully checked.
7947 #[must_use]
7948 pub const fn checked() -> Self {
7949 unsafe { Self::all(true) }
7950 }
7951
7952 /// Creates a new configuration where none of the checks are performed.
7953 ///
7954 /// # Safety
7955 ///
7956 /// See the documentation for the `set_*` methods for the safety requirements
7957 /// of each sub-configuration.
7958 #[must_use]
7959 pub const fn unchecked() -> Self {
7960 unsafe { Self::all(false) }
7961 }
7962
7963 /// Creates a new configuration where all checks are enabled or disabled. To safely
7964 /// create a configuration with all checks enabled, use [`ShaderRuntimeChecks::checked`].
7965 ///
7966 /// # Safety
7967 ///
7968 /// See the documentation for the `set_*` methods for the safety requirements
7969 /// of each sub-configuration.
7970 #[must_use]
7971 pub const unsafe fn all(all_checks: bool) -> Self {
7972 Self {
7973 bounds_checks: all_checks,
7974 force_loop_bounding: all_checks,
7975 }
7976 }
7977}
7978
7979impl Default for ShaderRuntimeChecks {
7980 fn default() -> Self {
7981 Self::checked()
7982 }
7983}
7984
7985#[derive(Clone, Debug, PartialEq, Eq)]
7986#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7987/// Descriptor for all size defining attributes of a single triangle geometry inside a bottom level acceleration structure.
7988pub struct BlasTriangleGeometrySizeDescriptor {
7989 /// Format of a vertex position, must be [`VertexFormat::Float32x3`]
7990 /// with just [`Features::EXPERIMENTAL_RAY_QUERY`]
7991 /// but [`Features::EXTENDED_ACCELERATION_STRUCTURE_VERTEX_FORMATS`] adds more.
7992 pub vertex_format: VertexFormat,
7993 /// Number of vertices.
7994 pub vertex_count: u32,
7995 /// Format of an index. Only needed if an index buffer is used.
7996 /// If `index_format` is provided `index_count` is required.
7997 pub index_format: Option<IndexFormat>,
7998 /// Number of indices. Only needed if an index buffer is used.
7999 /// If `index_count` is provided `index_format` is required.
8000 pub index_count: Option<u32>,
8001 /// Flags for the geometry.
8002 pub flags: AccelerationStructureGeometryFlags,
8003}
8004
8005#[derive(Clone, Debug)]
8006#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8007/// Descriptor for all size defining attributes of all geometries inside a bottom level acceleration structure.
8008pub enum BlasGeometrySizeDescriptors {
8009 /// Triangle geometry version.
8010 Triangles {
8011 /// Descriptor for each triangle geometry.
8012 descriptors: Vec<BlasTriangleGeometrySizeDescriptor>,
8013 },
8014}
8015
8016#[repr(u8)]
8017#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
8018#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8019/// Update mode for acceleration structure builds.
8020pub enum AccelerationStructureUpdateMode {
8021 /// Always perform a full build.
8022 Build,
8023 /// If possible, perform an incremental update.
8024 ///
8025 /// Not advised for major topology changes.
8026 /// (Useful for e.g. skinning)
8027 PreferUpdate,
8028}
8029
8030#[repr(C)]
8031#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8032#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8033/// Descriptor for creating a bottom level acceleration structure.
8034pub struct CreateBlasDescriptor<L> {
8035 /// Label for the bottom level acceleration structure.
8036 pub label: L,
8037 /// Flags for the bottom level acceleration structure.
8038 pub flags: AccelerationStructureFlags,
8039 /// Update mode for the bottom level acceleration structure.
8040 pub update_mode: AccelerationStructureUpdateMode,
8041}
8042
8043impl<L> CreateBlasDescriptor<L> {
8044 /// Takes a closure and maps the label of the blas descriptor into another.
8045 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CreateBlasDescriptor<K> {
8046 CreateBlasDescriptor {
8047 label: fun(&self.label),
8048 flags: self.flags,
8049 update_mode: self.update_mode,
8050 }
8051 }
8052}
8053
8054#[repr(C)]
8055#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8056#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8057/// Descriptor for creating a top level acceleration structure.
8058pub struct CreateTlasDescriptor<L> {
8059 /// Label for the top level acceleration structure.
8060 pub label: L,
8061 /// Number of instances that can be stored in the acceleration structure.
8062 pub max_instances: u32,
8063 /// Flags for the bottom level acceleration structure.
8064 pub flags: AccelerationStructureFlags,
8065 /// Update mode for the bottom level acceleration structure.
8066 pub update_mode: AccelerationStructureUpdateMode,
8067}
8068
8069impl<L> CreateTlasDescriptor<L> {
8070 /// Takes a closure and maps the label of the blas descriptor into another.
8071 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> CreateTlasDescriptor<K> {
8072 CreateTlasDescriptor {
8073 label: fun(&self.label),
8074 flags: self.flags,
8075 update_mode: self.update_mode,
8076 max_instances: self.max_instances,
8077 }
8078 }
8079}
8080
8081bitflags::bitflags!(
8082 /// Flags for acceleration structures
8083 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8084 #[cfg_attr(feature = "serde", serde(transparent))]
8085 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8086 pub struct AccelerationStructureFlags: u8 {
8087 /// Allow for incremental updates (no change in size), currently this is unimplemented
8088 /// and will build as normal (this is fine, update vs build should be unnoticeable)
8089 const ALLOW_UPDATE = 1 << 0;
8090 /// Allow the acceleration structure to be compacted in a copy operation
8091 /// (`Blas::prepare_for_compaction`, `CommandEncoder::compact_blas`).
8092 const ALLOW_COMPACTION = 1 << 1;
8093 /// Optimize for fast ray tracing performance, recommended if the geometry is unlikely
8094 /// to change (e.g. in a game: non-interactive scene geometry)
8095 const PREFER_FAST_TRACE = 1 << 2;
8096 /// Optimize for fast build time, recommended if geometry is likely to change frequently
8097 /// (e.g. in a game: player model).
8098 const PREFER_FAST_BUILD = 1 << 3;
8099 /// Optimize for low memory footprint (both while building and in the output BLAS).
8100 const LOW_MEMORY = 1 << 4;
8101 /// Use `BlasTriangleGeometry::transform_buffer` when building a BLAS (only allowed in
8102 /// BLAS creation)
8103 const USE_TRANSFORM = 1 << 5;
8104 /// Allow retrieval of the vertices of the triangle hit by a ray.
8105 const ALLOW_RAY_HIT_VERTEX_RETURN = 1 << 6;
8106 }
8107);
8108
8109bitflags::bitflags!(
8110 /// Flags for acceleration structure geometries
8111 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8112 #[cfg_attr(feature = "serde", serde(transparent))]
8113 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8114 pub struct AccelerationStructureGeometryFlags: u8 {
8115 /// Is OPAQUE (is there no alpha test) recommended as currently in naga there is no
8116 /// candidate intersections yet so currently BLASes without this flag will not have hits.
8117 /// Not enabling this makes the BLAS unable to be interacted with in WGSL.
8118 const OPAQUE = 1 << 0;
8119 /// NO_DUPLICATE_ANY_HIT_INVOCATION, not useful unless using hal with wgpu, ray-tracing
8120 /// pipelines are not supported in wgpu so any-hit shaders do not exist. For when any-hit
8121 /// shaders are implemented (or experienced users who combine this with an underlying library:
8122 /// for any primitive (triangle or AABB) multiple any-hit shaders sometimes may be invoked
8123 /// (especially in AABBs like a sphere), if this flag in present only one hit on a primitive may
8124 /// invoke an any-hit shader.
8125 const NO_DUPLICATE_ANY_HIT_INVOCATION = 1 << 1;
8126 }
8127);
8128
8129#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8130/// What a copy between acceleration structures should do
8131pub enum AccelerationStructureCopy {
8132 /// Directly duplicate an acceleration structure to another
8133 Clone,
8134 /// Duplicate and compact an acceleration structure
8135 Compact,
8136}
8137
8138#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8139/// What type the data of an acceleration structure is
8140pub enum AccelerationStructureType {
8141 /// The types of the acceleration structure are triangles
8142 Triangles,
8143 /// The types of the acceleration structure are axis aligned bounding boxes
8144 AABBs,
8145 /// The types of the acceleration structure are instances
8146 Instances,
8147}
8148
8149/// Alignment requirement for transform buffers used in acceleration structure builds
8150pub const TRANSFORM_BUFFER_ALIGNMENT: BufferAddress = 16;
8151
8152/// Alignment requirement for instance buffers used in acceleration structure builds (`build_acceleration_structures_unsafe_tlas`)
8153pub const INSTANCE_BUFFER_ALIGNMENT: BufferAddress = 16;
8154
8155pub use send_sync::*;
8156
8157#[doc(hidden)]
8158mod send_sync {
8159 pub trait WasmNotSendSync: WasmNotSend + WasmNotSync {}
8160 impl<T: WasmNotSend + WasmNotSync> WasmNotSendSync for T {}
8161 #[cfg(any(
8162 not(target_arch = "wasm32"),
8163 all(
8164 feature = "fragile-send-sync-non-atomic-wasm",
8165 not(target_feature = "atomics")
8166 )
8167 ))]
8168 pub trait WasmNotSend: Send {}
8169 #[cfg(any(
8170 not(target_arch = "wasm32"),
8171 all(
8172 feature = "fragile-send-sync-non-atomic-wasm",
8173 not(target_feature = "atomics")
8174 )
8175 ))]
8176 impl<T: Send> WasmNotSend for T {}
8177 #[cfg(not(any(
8178 not(target_arch = "wasm32"),
8179 all(
8180 feature = "fragile-send-sync-non-atomic-wasm",
8181 not(target_feature = "atomics")
8182 )
8183 )))]
8184 pub trait WasmNotSend {}
8185 #[cfg(not(any(
8186 not(target_arch = "wasm32"),
8187 all(
8188 feature = "fragile-send-sync-non-atomic-wasm",
8189 not(target_feature = "atomics")
8190 )
8191 )))]
8192 impl<T> WasmNotSend for T {}
8193
8194 #[cfg(any(
8195 not(target_arch = "wasm32"),
8196 all(
8197 feature = "fragile-send-sync-non-atomic-wasm",
8198 not(target_feature = "atomics")
8199 )
8200 ))]
8201 pub trait WasmNotSync: Sync {}
8202 #[cfg(any(
8203 not(target_arch = "wasm32"),
8204 all(
8205 feature = "fragile-send-sync-non-atomic-wasm",
8206 not(target_feature = "atomics")
8207 )
8208 ))]
8209 impl<T: Sync> WasmNotSync for T {}
8210 #[cfg(not(any(
8211 not(target_arch = "wasm32"),
8212 all(
8213 feature = "fragile-send-sync-non-atomic-wasm",
8214 not(target_feature = "atomics")
8215 )
8216 )))]
8217 pub trait WasmNotSync {}
8218 #[cfg(not(any(
8219 not(target_arch = "wasm32"),
8220 all(
8221 feature = "fragile-send-sync-non-atomic-wasm",
8222 not(target_feature = "atomics")
8223 )
8224 )))]
8225 impl<T> WasmNotSync for T {}
8226}
8227
8228/// Corresponds to a [`GPUDeviceLostReason`].
8229///
8230/// [`GPUDeviceLostReason`]: https://www.w3.org/TR/webgpu/#enumdef-gpudevicelostreason
8231#[repr(u8)]
8232#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8233#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8234pub enum DeviceLostReason {
8235 /// The device was lost for an unspecific reason, including driver errors.
8236 Unknown = 0,
8237 /// The device's `destroy` method was called.
8238 Destroyed = 1,
8239}
8240
8241/// Descriptor for a shader module given by any of several sources.
8242/// These shaders are passed through directly to the underlying api.
8243/// At least one shader type that may be used by the backend must be `Some` or a panic is raised.
8244#[derive(Debug, Clone)]
8245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8246pub struct CreateShaderModuleDescriptorPassthrough<'a, L> {
8247 /// Entrypoint. Unused for Spir-V.
8248 pub entry_point: String,
8249 /// Debug label of the shader module. This will show up in graphics debuggers for easy identification.
8250 pub label: L,
8251 /// Number of workgroups in each dimension x, y and z. Unused for Spir-V.
8252 pub num_workgroups: (u32, u32, u32),
8253 /// Runtime checks that should be enabled.
8254 pub runtime_checks: ShaderRuntimeChecks,
8255
8256 /// Binary SPIR-V data, in 4-byte words.
8257 pub spirv: Option<Cow<'a, [u32]>>,
8258 /// Shader DXIL source.
8259 pub dxil: Option<Cow<'a, [u8]>>,
8260 /// Shader MSL source.
8261 pub msl: Option<Cow<'a, str>>,
8262 /// Shader HLSL source.
8263 pub hlsl: Option<Cow<'a, str>>,
8264 /// Shader GLSL source (currently unused).
8265 pub glsl: Option<Cow<'a, str>>,
8266 /// Shader WGSL source.
8267 pub wgsl: Option<Cow<'a, str>>,
8268}
8269
8270// This is so people don't have to fill in fields they don't use, like num_workgroups,
8271// entry_point, or other shader languages they didn't compile for
8272impl<'a, L: Default> Default for CreateShaderModuleDescriptorPassthrough<'a, L> {
8273 fn default() -> Self {
8274 Self {
8275 entry_point: "".into(),
8276 label: Default::default(),
8277 num_workgroups: (0, 0, 0),
8278 runtime_checks: ShaderRuntimeChecks::unchecked(),
8279 spirv: None,
8280 dxil: None,
8281 msl: None,
8282 hlsl: None,
8283 glsl: None,
8284 wgsl: None,
8285 }
8286 }
8287}
8288
8289impl<'a, L> CreateShaderModuleDescriptorPassthrough<'a, L> {
8290 /// Takes a closure and maps the label of the shader module descriptor into another.
8291 pub fn map_label<K>(
8292 &self,
8293 fun: impl FnOnce(&L) -> K,
8294 ) -> CreateShaderModuleDescriptorPassthrough<'a, K> {
8295 CreateShaderModuleDescriptorPassthrough {
8296 entry_point: self.entry_point.clone(),
8297 label: fun(&self.label),
8298 num_workgroups: self.num_workgroups,
8299 runtime_checks: self.runtime_checks,
8300 spirv: self.spirv.clone(),
8301 dxil: self.dxil.clone(),
8302 msl: self.msl.clone(),
8303 hlsl: self.hlsl.clone(),
8304 glsl: self.glsl.clone(),
8305 wgsl: self.wgsl.clone(),
8306 }
8307 }
8308
8309 #[cfg(feature = "trace")]
8310 /// Returns the source data for tracing purpose.
8311 pub fn trace_data(&self) -> &[u8] {
8312 if let Some(spirv) = &self.spirv {
8313 bytemuck::cast_slice(spirv)
8314 } else if let Some(msl) = &self.msl {
8315 msl.as_bytes()
8316 } else if let Some(dxil) = &self.dxil {
8317 dxil
8318 } else {
8319 panic!("No binary data provided to `ShaderModuleDescriptorGeneric`")
8320 }
8321 }
8322
8323 #[cfg(feature = "trace")]
8324 /// Returns the binary file extension for tracing purpose.
8325 pub fn trace_binary_ext(&self) -> &'static str {
8326 if self.spirv.is_some() {
8327 "spv"
8328 } else if self.msl.is_some() {
8329 "msl"
8330 } else if self.dxil.is_some() {
8331 "dxil"
8332 } else {
8333 panic!("No binary data provided to `ShaderModuleDescriptorGeneric`")
8334 }
8335 }
8336}