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