wgpu_types/texture.rs
1use core::ops::Range;
2
3use crate::{link_to_wgpu_docs, link_to_wgpu_item, Extent3d, Origin3d};
4
5#[cfg(any(feature = "serde", test))]
6use serde::{Deserialize, Serialize};
7
8#[cfg(doc)]
9use crate::{BindingType, Features};
10
11mod external_image;
12mod external_texture;
13mod format;
14
15pub use external_image::*;
16pub use external_texture::*;
17pub use format::*;
18
19/// Dimensionality of a texture.
20///
21/// Corresponds to [WebGPU `GPUTextureDimension`](
22/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturedimension).
23#[repr(C)]
24#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26pub enum TextureDimension {
27 /// 1D texture
28 #[cfg_attr(feature = "serde", serde(rename = "1d"))]
29 D1,
30 /// 2D texture
31 #[cfg_attr(feature = "serde", serde(rename = "2d"))]
32 D2,
33 /// 3D texture
34 #[cfg_attr(feature = "serde", serde(rename = "3d"))]
35 D3,
36}
37
38/// Order in which texture data is laid out in memory.
39#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
40#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41pub enum TextureDataOrder {
42 /// The texture is laid out densely in memory as:
43 ///
44 /// ```text
45 /// Layer0Mip0 Layer0Mip1 Layer0Mip2
46 /// Layer1Mip0 Layer1Mip1 Layer1Mip2
47 /// Layer2Mip0 Layer2Mip1 Layer2Mip2
48 /// ````
49 ///
50 /// This is the layout used by dds files.
51 #[default]
52 LayerMajor,
53 /// The texture is laid out densely in memory as:
54 ///
55 /// ```text
56 /// Layer0Mip0 Layer1Mip0 Layer2Mip0
57 /// Layer0Mip1 Layer1Mip1 Layer2Mip1
58 /// Layer0Mip2 Layer1Mip2 Layer2Mip2
59 /// ```
60 ///
61 /// This is the layout used by ktx and ktx2 files.
62 MipMajor,
63}
64
65/// Dimensions of a particular texture view.
66///
67/// Corresponds to [WebGPU `GPUTextureViewDimension`](
68/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureviewdimension).
69#[repr(C)]
70#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72pub enum TextureViewDimension {
73 /// A one dimensional texture. `texture_1d` in WGSL and `texture1D` in GLSL.
74 #[cfg_attr(feature = "serde", serde(rename = "1d"))]
75 D1,
76 /// A two dimensional texture. `texture_2d` in WGSL and `texture2D` in GLSL.
77 #[cfg_attr(feature = "serde", serde(rename = "2d"))]
78 #[default]
79 D2,
80 /// A two dimensional array texture. `texture_2d_array` in WGSL and `texture2DArray` in GLSL.
81 #[cfg_attr(feature = "serde", serde(rename = "2d-array"))]
82 D2Array,
83 /// A cubemap texture. `texture_cube` in WGSL and `textureCube` in GLSL.
84 #[cfg_attr(feature = "serde", serde(rename = "cube"))]
85 Cube,
86 /// A cubemap array texture. `texture_cube_array` in WGSL and `textureCubeArray` in GLSL.
87 #[cfg_attr(feature = "serde", serde(rename = "cube-array"))]
88 CubeArray,
89 /// A three dimensional texture. `texture_3d` in WGSL and `texture3D` in GLSL.
90 #[cfg_attr(feature = "serde", serde(rename = "3d"))]
91 D3,
92}
93
94impl TextureViewDimension {
95 /// Get the texture dimension required of this texture view dimension.
96 #[must_use]
97 pub fn compatible_texture_dimension(self) -> TextureDimension {
98 match self {
99 Self::D1 => TextureDimension::D1,
100 Self::D2 | Self::D2Array | Self::Cube | Self::CubeArray => TextureDimension::D2,
101 Self::D3 => TextureDimension::D3,
102 }
103 }
104}
105
106/// Selects a subset of the data a [`Texture`] holds.
107///
108/// Used in [texture views](TextureViewDescriptor) and
109/// [texture copy operations](TexelCopyTextureInfo).
110///
111/// Corresponds to [WebGPU `GPUTextureAspect`](
112/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureaspect).
113///
114#[doc = link_to_wgpu_item!(struct Texture)]
115#[repr(C)]
116#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
117#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
118#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
119pub enum TextureAspect {
120 /// Depth, Stencil, and Color.
121 #[default]
122 All,
123 /// Stencil.
124 StencilOnly,
125 /// Depth.
126 DepthOnly,
127 /// Plane 0.
128 Plane0,
129 /// Plane 1.
130 Plane1,
131 /// Plane 2.
132 Plane2,
133}
134
135impl TextureAspect {
136 /// Returns the texture aspect for a given plane.
137 #[must_use]
138 pub fn from_plane(plane: u32) -> Option<Self> {
139 Some(match plane {
140 0 => Self::Plane0,
141 1 => Self::Plane1,
142 2 => Self::Plane2,
143 _ => return None,
144 })
145 }
146
147 /// Returns the plane for a given texture aspect.
148 #[must_use]
149 pub fn to_plane(&self) -> Option<u32> {
150 match self {
151 TextureAspect::Plane0 => Some(0),
152 TextureAspect::Plane1 => Some(1),
153 TextureAspect::Plane2 => Some(2),
154 _ => None,
155 }
156 }
157}
158
159bitflags::bitflags! {
160 /// Different ways that you can use a texture.
161 ///
162 /// The usages determine what kind of memory the texture is allocated from and what
163 /// actions the texture can partake in.
164 ///
165 /// Corresponds to [WebGPU `GPUTextureUsageFlags`](
166 /// https://gpuweb.github.io/gpuweb/#typedefdef-gputextureusageflags).
167 #[repr(transparent)]
168 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
169 #[cfg_attr(feature = "serde", serde(transparent))]
170 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
171 pub struct TextureUsages: u32 {
172 //
173 // ---- Start numbering at 1 << 0 ----
174 //
175 // WebGPU features:
176 //
177 /// Allows a texture to be the source in a [`CommandEncoder::copy_texture_to_buffer`] or
178 /// [`CommandEncoder::copy_texture_to_texture`] operation.
179 const COPY_SRC = 1 << 0;
180 /// Allows a texture to be the destination in a [`CommandEncoder::copy_buffer_to_texture`],
181 /// [`CommandEncoder::copy_texture_to_texture`], or [`Queue::write_texture`] operation.
182 const COPY_DST = 1 << 1;
183 /// Allows a texture to be a [`BindingType::Texture`] in a bind group.
184 const TEXTURE_BINDING = 1 << 2;
185 /// Allows a texture to be a [`BindingType::StorageTexture`] in a bind group.
186 const STORAGE_BINDING = 1 << 3;
187 /// Allows a texture to be an output attachment of a render pass.
188 ///
189 /// Consider adding [`TextureUsages::TRANSIENT`] if the contents are not reused.
190 const RENDER_ATTACHMENT = 1 << 4;
191
192 //
193 // ---- Restart Numbering for Native Features ---
194 //
195 // Native Features:
196 //
197 /// Allows a texture to be used with image atomics. Requires [`Features::TEXTURE_ATOMIC`].
198 const STORAGE_ATOMIC = 1 << 16;
199 /// Specifies the contents of this texture will not be used in another pass to potentially reduce memory usage and bandwidth.
200 ///
201 /// No-op on platforms on platforms that do not benefit from transient textures.
202 /// Generally mobile and Apple chips care about this.
203 ///
204 /// Incompatible with ALL other usages except [`TextureUsages::RENDER_ATTACHMENT`] and requires it.
205 ///
206 /// Requires [`StoreOp::Discard`].
207 const TRANSIENT = 1 << 17;
208 }
209}
210
211bitflags::bitflags! {
212 /// Similar to `TextureUsages`, but used only for `CommandEncoder::transition_resources`.
213 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
214 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
215 #[cfg_attr(feature = "serde", serde(transparent))]
216 pub struct TextureUses: u16 {
217 /// The texture is in unknown state.
218 const UNINITIALIZED = 1 << 0;
219 /// Ready to present image to the surface.
220 const PRESENT = 1 << 1;
221 /// The source of a hardware copy.
222 /// cbindgen:ignore
223 const COPY_SRC = 1 << 2;
224 /// The destination of a hardware copy.
225 /// cbindgen:ignore
226 const COPY_DST = 1 << 3;
227 /// Read-only sampled or fetched resource.
228 const RESOURCE = 1 << 4;
229 /// The color target of a renderpass.
230 const COLOR_TARGET = 1 << 5;
231 /// Read-only depth stencil usage.
232 const DEPTH_STENCIL_READ = 1 << 6;
233 /// Read-write depth stencil usage
234 const DEPTH_STENCIL_WRITE = 1 << 7;
235 /// Read-only storage texture usage. Corresponds to a UAV in d3d, so is exclusive, despite being read only.
236 /// cbindgen:ignore
237 const STORAGE_READ_ONLY = 1 << 8;
238 /// Write-only storage texture usage.
239 /// cbindgen:ignore
240 const STORAGE_WRITE_ONLY = 1 << 9;
241 /// Read-write storage texture usage.
242 /// cbindgen:ignore
243 const STORAGE_READ_WRITE = 1 << 10;
244 /// Image atomic enabled storage.
245 /// cbindgen:ignore
246 const STORAGE_ATOMIC = 1 << 11;
247 /// Transient texture that may not have any backing memory. Not a resource state stored in the trackers, only used for passing down usages to create_texture.
248 const TRANSIENT = 1 << 12;
249 /// The combination of states that a texture may be in _at the same time_.
250 /// cbindgen:ignore
251 const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits() | Self::STORAGE_READ_ONLY.bits();
252 /// The combination of states that a texture must exclusively be in.
253 /// cbindgen:ignore
254 const EXCLUSIVE = Self::COPY_DST.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_WRITE_ONLY.bits() | Self::STORAGE_READ_WRITE.bits() | Self::STORAGE_ATOMIC.bits() | Self::PRESENT.bits();
255
256 /// Flag used by the wgpu-core texture tracker to say a texture is in different states for every sub-resource
257 const COMPLEX = 1 << 13;
258 /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource.
259 /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized.
260 const UNKNOWN = 1 << 14;
261 }
262}
263
264/// A texture transition for use with `CommandEncoder::transition_resources`.
265#[derive(Clone, Debug)]
266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
267pub struct TextureTransition<T> {
268 /// The texture to transition.
269 pub texture: T,
270 /// An optional selector to transition only part of the texture.
271 ///
272 /// If None, the entire texture will be transitioned.
273 pub selector: Option<TextureSelector>,
274 /// The new state to transition to.
275 pub state: TextureUses,
276}
277
278/// Specifies a particular set of subresources in a texture.
279#[derive(Clone, Debug, PartialEq, Eq)]
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281pub struct TextureSelector {
282 /// Range of mips to use.
283 pub mips: Range<u32>,
284 /// Range of layers to use.
285 pub layers: Range<u32>,
286}
287
288/// Specific type of a sample in a texture binding.
289///
290/// Corresponds to [WebGPU `GPUTextureSampleType`](
291/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturesampletype).
292#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
293#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
294pub enum TextureSampleType {
295 /// Sampling returns floats.
296 ///
297 /// Example WGSL syntax:
298 /// ```rust,ignore
299 /// @group(0) @binding(0)
300 /// var t: texture_2d<f32>;
301 /// ```
302 ///
303 /// Example GLSL syntax:
304 /// ```cpp,ignore
305 /// layout(binding = 0)
306 /// uniform texture2D t;
307 /// ```
308 Float {
309 /// If this is `false`, the texture can't be sampled with
310 /// a filtering sampler.
311 ///
312 /// Even if this is `true`, it's possible to sample with
313 /// a **non-filtering** sampler.
314 filterable: bool,
315 },
316 /// Sampling does the depth reference comparison.
317 ///
318 /// This is also compatible with a non-filtering sampler.
319 ///
320 /// Example WGSL syntax:
321 /// ```rust,ignore
322 /// @group(0) @binding(0)
323 /// var t: texture_depth_2d;
324 /// ```
325 ///
326 /// Example GLSL syntax:
327 /// ```cpp,ignore
328 /// layout(binding = 0)
329 /// uniform texture2DShadow t;
330 /// ```
331 Depth,
332 /// Sampling returns signed integers.
333 ///
334 /// Example WGSL syntax:
335 /// ```rust,ignore
336 /// @group(0) @binding(0)
337 /// var t: texture_2d<i32>;
338 /// ```
339 ///
340 /// Example GLSL syntax:
341 /// ```cpp,ignore
342 /// layout(binding = 0)
343 /// uniform itexture2D t;
344 /// ```
345 Sint,
346 /// Sampling returns unsigned integers.
347 ///
348 /// Example WGSL syntax:
349 /// ```rust,ignore
350 /// @group(0) @binding(0)
351 /// var t: texture_2d<u32>;
352 /// ```
353 ///
354 /// Example GLSL syntax:
355 /// ```cpp,ignore
356 /// layout(binding = 0)
357 /// uniform utexture2D t;
358 /// ```
359 Uint,
360}
361
362impl Default for TextureSampleType {
363 fn default() -> Self {
364 Self::Float { filterable: true }
365 }
366}
367
368/// Specific type of a sample in a texture binding.
369///
370/// For use in [`BindingType::StorageTexture`].
371///
372/// Corresponds to [WebGPU `GPUStorageTextureAccess`](
373/// https://gpuweb.github.io/gpuweb/#enumdef-gpustoragetextureaccess).
374#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
376#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
377pub enum StorageTextureAccess {
378 /// The texture can only be written in the shader and it:
379 /// - may or may not be annotated with `write` (WGSL).
380 /// - must be annotated with `writeonly` (GLSL).
381 ///
382 /// Example WGSL syntax:
383 /// ```rust,ignore
384 /// @group(0) @binding(0)
385 /// var my_storage_image: texture_storage_2d<r32float, write>;
386 /// ```
387 ///
388 /// Example GLSL syntax:
389 /// ```cpp,ignore
390 /// layout(set=0, binding=0, r32f) writeonly uniform image2D myStorageImage;
391 /// ```
392 WriteOnly,
393 /// The texture can only be read in the shader and it must be annotated with `read` (WGSL) or
394 /// `readonly` (GLSL).
395 ///
396 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
397 /// mode. This is a native-only extension.
398 ///
399 /// Example WGSL syntax:
400 /// ```rust,ignore
401 /// @group(0) @binding(0)
402 /// var my_storage_image: texture_storage_2d<r32float, read>;
403 /// ```
404 ///
405 /// Example GLSL syntax:
406 /// ```cpp,ignore
407 /// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
408 /// ```
409 ReadOnly,
410 /// The texture can be both read and written in the shader and must be annotated with
411 /// `read_write` in WGSL.
412 ///
413 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
414 /// mode. This is a nonstandard, native-only extension.
415 ///
416 /// Example WGSL syntax:
417 /// ```rust,ignore
418 /// @group(0) @binding(0)
419 /// var my_storage_image: texture_storage_2d<r32float, read_write>;
420 /// ```
421 ///
422 /// Example GLSL syntax:
423 /// ```cpp,ignore
424 /// layout(set=0, binding=0, r32f) uniform image2D myStorageImage;
425 /// ```
426 ReadWrite,
427 /// The texture can be both read and written in the shader via atomics and must be annotated
428 /// with `read_write` in WGSL.
429 ///
430 /// [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] must be enabled to use this access
431 /// mode. This is a nonstandard, native-only extension.
432 ///
433 /// Example WGSL syntax:
434 /// ```rust,ignore
435 /// @group(0) @binding(0)
436 /// var my_storage_image: texture_storage_2d<r32uint, atomic>;
437 /// ```
438 Atomic,
439}
440
441/// Describes a [`TextureView`].
442///
443/// For use with [`Texture::create_view()`].
444///
445/// Corresponds to [WebGPU `GPUTextureViewDescriptor`](
446/// https://gpuweb.github.io/gpuweb/#dictdef-gputextureviewdescriptor).
447///
448#[doc = link_to_wgpu_item!(struct TextureView)]
449#[doc = link_to_wgpu_docs!(["`Texture::create_view()`"]: "struct.Texture.html#method.create_view")]
450#[derive(Clone, Debug, Default, Eq, PartialEq)]
451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
452pub struct TextureViewDescriptor<L> {
453 /// Debug label of the texture view. This will show up in graphics debuggers for easy identification.
454 pub label: L,
455 /// Format of the texture view. Either must be the same as the texture format or in the list
456 /// of `view_formats` in the texture's descriptor.
457 pub format: Option<TextureFormat>,
458 /// The dimension of the texture view. For 1D textures, this must be `D1`. For 2D textures it must be one of
459 /// `D2`, `D2Array`, `Cube`, and `CubeArray`. For 3D textures it must be `D3`
460 pub dimension: Option<TextureViewDimension>,
461 /// The allowed usage(s) for the texture view. Must be a subset of the usage flags of the texture.
462 /// If not provided, defaults to the full set of usage flags of the texture.
463 pub usage: Option<TextureUsages>,
464 /// Aspect of the texture. Color textures must be [`TextureAspect::All`].
465 pub aspect: TextureAspect,
466 /// Base mip level.
467 pub base_mip_level: u32,
468 /// Mip level count.
469 /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
470 /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
471 pub mip_level_count: Option<u32>,
472 /// Base array layer.
473 pub base_array_layer: u32,
474 /// Layer count.
475 /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
476 /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
477 pub array_layer_count: Option<u32>,
478}
479
480impl<L> TextureViewDescriptor<L> {
481 /// Takes a closure and maps the label of the texture view descriptor into another.
482 #[must_use]
483 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureViewDescriptor<K> {
484 TextureViewDescriptor {
485 label: fun(&self.label),
486 format: self.format,
487 dimension: self.dimension,
488 usage: self.usage,
489 aspect: self.aspect,
490 base_mip_level: self.base_mip_level,
491 mip_level_count: self.mip_level_count,
492 base_array_layer: self.base_array_layer,
493 array_layer_count: self.array_layer_count,
494 }
495 }
496}
497
498/// Describes a [`Texture`](../wgpu/struct.Texture.html).
499///
500/// Corresponds to [WebGPU `GPUTextureDescriptor`](
501/// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor).
502#[repr(C)]
503#[derive(Clone, Debug, PartialEq, Eq, Hash)]
504#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
505pub struct TextureDescriptor<L, V> {
506 /// Debug label of the texture. This will show up in graphics debuggers for easy identification.
507 pub label: L,
508 /// Size of the texture. All components must be greater than zero. For a
509 /// regular 1D/2D texture, the unused sizes will be 1. For 2DArray textures,
510 /// Z is the number of 2D textures in that array.
511 pub size: Extent3d,
512 /// Mip count of texture. For a texture with no extra mips, this must be 1.
513 pub mip_level_count: u32,
514 /// Sample count of texture. If this is not 1, texture must have [`BindingType::Texture::multisampled`] set to true.
515 pub sample_count: u32,
516 /// Dimensions of the texture.
517 pub dimension: TextureDimension,
518 /// Format of the texture.
519 pub format: TextureFormat,
520 /// Allowed usages of the texture. If used in other ways, the operation will panic.
521 pub usage: TextureUsages,
522 /// Specifies what view formats will be allowed when calling `Texture::create_view` on this texture.
523 ///
524 /// View formats of the same format as the texture are always allowed.
525 ///
526 /// Note: currently, only the srgb-ness is allowed to change. (ex: `Rgba8Unorm` texture + `Rgba8UnormSrgb` view)
527 pub view_formats: V,
528}
529
530impl<L, V> TextureDescriptor<L, V> {
531 /// Takes a closure and maps the label of the texture descriptor into another.
532 #[must_use]
533 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> TextureDescriptor<K, V>
534 where
535 V: Clone,
536 {
537 TextureDescriptor {
538 label: fun(&self.label),
539 size: self.size,
540 mip_level_count: self.mip_level_count,
541 sample_count: self.sample_count,
542 dimension: self.dimension,
543 format: self.format,
544 usage: self.usage,
545 view_formats: self.view_formats.clone(),
546 }
547 }
548
549 /// Maps the label and view formats of the texture descriptor into another.
550 #[must_use]
551 pub fn map_label_and_view_formats<K, M>(
552 &self,
553 l_fun: impl FnOnce(&L) -> K,
554 v_fun: impl FnOnce(&V) -> M,
555 ) -> TextureDescriptor<K, M> {
556 TextureDescriptor {
557 label: l_fun(&self.label),
558 size: self.size,
559 mip_level_count: self.mip_level_count,
560 sample_count: self.sample_count,
561 dimension: self.dimension,
562 format: self.format,
563 usage: self.usage,
564 view_formats: v_fun(&self.view_formats),
565 }
566 }
567
568 /// Calculates the extent at a given mip level.
569 ///
570 /// If the given mip level is larger than possible, returns None.
571 ///
572 /// Treats the depth as part of the mipmaps. If calculating
573 /// for a 2DArray texture, which does not mipmap depth, set depth to 1.
574 ///
575 /// ```rust
576 /// # use wgpu_types as wgpu;
577 /// # type TextureDescriptor<'a> = wgpu::TextureDescriptor<(), &'a [wgpu::TextureFormat]>;
578 /// let desc = TextureDescriptor {
579 /// label: (),
580 /// size: wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 },
581 /// mip_level_count: 7,
582 /// sample_count: 1,
583 /// dimension: wgpu::TextureDimension::D3,
584 /// format: wgpu::TextureFormat::Rgba8Sint,
585 /// usage: wgpu::TextureUsages::empty(),
586 /// view_formats: &[],
587 /// };
588 ///
589 /// assert_eq!(desc.mip_level_size(0), Some(wgpu::Extent3d { width: 100, height: 60, depth_or_array_layers: 1 }));
590 /// assert_eq!(desc.mip_level_size(1), Some(wgpu::Extent3d { width: 50, height: 30, depth_or_array_layers: 1 }));
591 /// assert_eq!(desc.mip_level_size(2), Some(wgpu::Extent3d { width: 25, height: 15, depth_or_array_layers: 1 }));
592 /// assert_eq!(desc.mip_level_size(3), Some(wgpu::Extent3d { width: 12, height: 7, depth_or_array_layers: 1 }));
593 /// assert_eq!(desc.mip_level_size(4), Some(wgpu::Extent3d { width: 6, height: 3, depth_or_array_layers: 1 }));
594 /// assert_eq!(desc.mip_level_size(5), Some(wgpu::Extent3d { width: 3, height: 1, depth_or_array_layers: 1 }));
595 /// assert_eq!(desc.mip_level_size(6), Some(wgpu::Extent3d { width: 1, height: 1, depth_or_array_layers: 1 }));
596 /// assert_eq!(desc.mip_level_size(7), None);
597 /// ```
598 #[must_use]
599 pub fn mip_level_size(&self, level: u32) -> Option<Extent3d> {
600 if level >= self.mip_level_count {
601 return None;
602 }
603
604 Some(self.size.mip_level_size(level, self.dimension))
605 }
606
607 /// Computes the render extent of this texture.
608 ///
609 /// This is a low-level helper exported for use by wgpu-core.
610 ///
611 /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-compute-render-extent>
612 ///
613 /// # Panics
614 ///
615 /// If the mip level is out of range.
616 #[doc(hidden)]
617 #[must_use]
618 pub fn compute_render_extent(&self, mip_level: u32, plane: Option<u32>) -> Extent3d {
619 let Extent3d {
620 width,
621 height,
622 depth_or_array_layers: _,
623 } = self.mip_level_size(mip_level).expect("invalid mip level");
624
625 let (w_subsampling, h_subsampling) = self.format.subsampling_factors(plane);
626
627 let width = width / w_subsampling;
628 let height = height / h_subsampling;
629
630 Extent3d {
631 width,
632 height,
633 depth_or_array_layers: 1,
634 }
635 }
636
637 /// Returns the number of array layers.
638 ///
639 /// <https://gpuweb.github.io/gpuweb/#abstract-opdef-array-layer-count>
640 #[must_use]
641 pub fn array_layer_count(&self) -> u32 {
642 match self.dimension {
643 TextureDimension::D1 | TextureDimension::D3 => 1,
644 TextureDimension::D2 => self.size.depth_or_array_layers,
645 }
646 }
647}
648
649/// Describes a `Sampler`.
650///
651/// For use with `Device::create_sampler`.
652///
653/// Corresponds to [WebGPU `GPUSamplerDescriptor`](
654/// https://gpuweb.github.io/gpuweb/#dictdef-gpusamplerdescriptor).
655#[derive(Clone, Debug, PartialEq)]
656#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
657pub struct SamplerDescriptor<L> {
658 /// Debug label of the sampler. This will show up in graphics debuggers for easy identification.
659 pub label: L,
660 /// How to deal with out of bounds accesses in the u (i.e. x) direction
661 pub address_mode_u: AddressMode,
662 /// How to deal with out of bounds accesses in the v (i.e. y) direction
663 pub address_mode_v: AddressMode,
664 /// How to deal with out of bounds accesses in the w (i.e. z) direction
665 pub address_mode_w: AddressMode,
666 /// How to filter the texture when it needs to be magnified (made larger)
667 pub mag_filter: FilterMode,
668 /// How to filter the texture when it needs to be minified (made smaller)
669 pub min_filter: FilterMode,
670 /// How to filter between mip map levels
671 pub mipmap_filter: MipmapFilterMode,
672 /// Minimum level of detail (i.e. mip level) to use
673 pub lod_min_clamp: f32,
674 /// Maximum level of detail (i.e. mip level) to use
675 pub lod_max_clamp: f32,
676 /// If this is enabled, this is a comparison sampler using the given comparison function.
677 pub compare: Option<crate::CompareFunction>,
678 /// Must be at least 1. If this is not 1, all filter modes must be linear.
679 pub anisotropy_clamp: u16,
680 /// Border color to use when `address_mode` is [`AddressMode::ClampToBorder`]
681 pub border_color: Option<SamplerBorderColor>,
682}
683
684impl<L: Default> Default for SamplerDescriptor<L> {
685 fn default() -> Self {
686 Self {
687 label: Default::default(),
688 address_mode_u: Default::default(),
689 address_mode_v: Default::default(),
690 address_mode_w: Default::default(),
691 mag_filter: Default::default(),
692 min_filter: Default::default(),
693 mipmap_filter: Default::default(),
694 lod_min_clamp: 0.0,
695 lod_max_clamp: 32.0,
696 compare: None,
697 anisotropy_clamp: 1,
698 border_color: None,
699 }
700 }
701}
702
703impl<L> SamplerDescriptor<L> {
704 /// Takes a closure and maps the label of the sampler descriptor into another.
705 #[must_use]
706 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> SamplerDescriptor<K> {
707 SamplerDescriptor {
708 label: fun(&self.label),
709 address_mode_u: self.address_mode_u,
710 address_mode_v: self.address_mode_v,
711 address_mode_w: self.address_mode_w,
712 mag_filter: self.mag_filter,
713 min_filter: self.min_filter,
714 mipmap_filter: self.mipmap_filter,
715 lod_min_clamp: self.lod_min_clamp,
716 lod_max_clamp: self.lod_max_clamp,
717 compare: self.compare,
718 anisotropy_clamp: self.anisotropy_clamp,
719 border_color: self.border_color,
720 }
721 }
722}
723
724/// How edges should be handled in texture addressing.
725///
726/// Corresponds to [WebGPU `GPUAddressMode`](
727/// https://gpuweb.github.io/gpuweb/#enumdef-gpuaddressmode).
728#[repr(C)]
729#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
730#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
731#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
732pub enum AddressMode {
733 /// Clamp the value to the edge of the texture
734 ///
735 /// -0.25 -> 0.0
736 /// 1.25 -> 1.0
737 #[default]
738 ClampToEdge = 0,
739 /// Repeat the texture in a tiling fashion
740 ///
741 /// -0.25 -> 0.75
742 /// 1.25 -> 0.25
743 Repeat = 1,
744 /// Repeat the texture, mirroring it every repeat
745 ///
746 /// -0.25 -> 0.25
747 /// 1.25 -> 0.75
748 MirrorRepeat = 2,
749 /// Clamp the value to the border of the texture
750 /// Requires feature [`Features::ADDRESS_MODE_CLAMP_TO_BORDER`]
751 ///
752 /// -0.25 -> border
753 /// 1.25 -> border
754 ClampToBorder = 3,
755}
756
757/// Texel mixing mode when sampling between texels.
758///
759/// Corresponds to [WebGPU `GPUFilterMode`](
760/// https://gpuweb.github.io/gpuweb/#enumdef-gpufiltermode).
761#[repr(C)]
762#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
763#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
764#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
765pub enum FilterMode {
766 /// Nearest neighbor sampling.
767 ///
768 /// This creates a pixelated effect.
769 #[default]
770 Nearest = 0,
771 /// Linear Interpolation
772 ///
773 /// This makes textures smooth but blurry.
774 Linear = 1,
775}
776
777/// Texel mixing mode when sampling between texels.
778///
779/// Corresponds to [WebGPU `GPUMipmapFilterMode`](
780/// https://gpuweb.github.io/gpuweb/#enumdef-gpumipmapfiltermode).
781#[repr(C)]
782#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
783#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
784#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
785pub enum MipmapFilterMode {
786 /// Nearest neighbor sampling.
787 ///
788 /// Return the value of the texel nearest to the texture coordinates.
789 #[default]
790 Nearest = 0,
791 /// Linear Interpolation
792 ///
793 /// Select two texels in each dimension and return a linear interpolation between their values.
794 Linear = 1,
795}
796
797/// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`]
798#[repr(C)]
799#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
800#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
801pub enum SamplerBorderColor {
802 /// [0, 0, 0, 0]
803 TransparentBlack,
804 /// [0, 0, 0, 1]
805 OpaqueBlack,
806 /// [1, 1, 1, 1]
807 OpaqueWhite,
808
809 /// On the Metal backend, this is equivalent to `TransparentBlack` for
810 /// textures that have an alpha component, and equivalent to `OpaqueBlack`
811 /// for textures that do not have an alpha component. On other backends,
812 /// this is equivalent to `TransparentBlack`. Requires
813 /// [`Features::ADDRESS_MODE_CLAMP_TO_ZERO`]. Not supported on the web.
814 Zero,
815}
816
817/// Layout of a texture in a buffer's memory.
818///
819/// The bytes per row and rows per image can be hard to figure out so here are some examples:
820///
821/// | Resolution | Format | Bytes per block | Pixels per block | Bytes per row | Rows per image |
822/// |------------|--------|-----------------|------------------|----------------------------------------|------------------------------|
823/// | 256x256 | RGBA8 | 4 | 1 * 1 * 1 | 256 * 4 = Some(1024) | None |
824/// | 32x16x8 | RGBA8 | 4 | 1 * 1 * 1 | 32 * 4 = 128 padded to 256 = Some(256) | None |
825/// | 256x256 | BC3 | 16 | 4 * 4 * 1 | 16 * (256 / 4) = 1024 = Some(1024) | None |
826/// | 64x64x8 | BC3 | 16 | 4 * 4 * 1 | 16 * (64 / 4) = 256 = Some(256) | 64 / 4 = 16 = Some(16) |
827///
828/// Corresponds to [WebGPU `GPUTexelCopyBufferLayout`](
829/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagedatalayout).
830#[repr(C)]
831#[derive(Clone, Copy, Debug, Default)]
832#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
833pub struct TexelCopyBufferLayout {
834 /// Offset into the buffer that is the start of the texture. Must be a multiple of texture block size.
835 /// For non-compressed textures, this is 1.
836 pub offset: crate::BufferAddress,
837 /// Bytes per "row" in an image.
838 ///
839 /// A row is one row of pixels or of compressed blocks in the x direction.
840 ///
841 /// 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)
842 ///
843 /// Must be a multiple of 256 for [`CommandEncoder::copy_buffer_to_texture`][CEcbtt]
844 /// and [`CommandEncoder::copy_texture_to_buffer`][CEcttb]. You must manually pad the
845 /// buffer as if the image width is a multiple of 256. An image of size (500, 500) can be
846 /// written to a buffer of size (512, 500) with `bytes_per_row` of 512,
847 ///
848 /// [`Queue::write_texture`][Qwt] does not have this requirement.
849 ///
850 /// Must be a multiple of the texture block size. For non-compressed textures, this is 1.
851 ///
852 #[doc = link_to_wgpu_docs!(["CEcbtt"]: "struct.CommandEncoder.html#method.copy_buffer_to_texture")]
853 #[doc = link_to_wgpu_docs!(["CEcttb"]: "struct.CommandEncoder.html#method.copy_texture_to_buffer")]
854 #[doc = link_to_wgpu_docs!(["Qwt"]: "struct.Queue.html#method.write_texture")]
855 pub bytes_per_row: Option<u32>,
856 /// "Rows" that make up a single "image".
857 ///
858 /// A row is one row of pixels or of compressed blocks in the x direction.
859 ///
860 /// An image is one layer in the z direction of a 3D image or 2DArray texture.
861 ///
862 /// The amount of rows per image may be larger than the actual amount of rows of data.
863 ///
864 /// Required if there are multiple images (i.e. the depth is more than one).
865 pub rows_per_image: Option<u32>,
866}
867
868/// View of a buffer which can be used to copy to/from a texture.
869///
870/// Corresponds to [WebGPU `GPUTexelCopyBufferInfo`](
871/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
872#[repr(C)]
873#[derive(Copy, Clone, Debug)]
874#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
875pub struct TexelCopyBufferInfo<B> {
876 /// The buffer to be copied to/from.
877 pub buffer: B,
878 /// The layout of the texture data in this buffer.
879 pub layout: TexelCopyBufferLayout,
880}
881
882/// View of a texture which can be used to copy to/from a buffer/texture.
883///
884/// Corresponds to [WebGPU `GPUTexelCopyTextureInfo`](
885/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
886#[repr(C)]
887#[derive(Copy, Clone, Debug)]
888#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
889pub struct TexelCopyTextureInfo<T> {
890 /// The texture to be copied to/from.
891 pub texture: T,
892 /// The target mip level of the texture.
893 pub mip_level: u32,
894 /// The base texel of the texture in the selected `mip_level`. Together
895 /// with the `copy_size` argument to copy functions, defines the
896 /// sub-region of the texture to copy.
897 #[cfg_attr(feature = "serde", serde(default))]
898 pub origin: Origin3d,
899 /// The copy aspect.
900 #[cfg_attr(feature = "serde", serde(default))]
901 pub aspect: TextureAspect,
902}
903
904impl<T> TexelCopyTextureInfo<T> {
905 /// Adds color space and premultiplied alpha information to make this
906 /// descriptor tagged.
907 pub fn to_tagged(
908 self,
909 color_space: PredefinedColorSpace,
910 premultiplied_alpha: bool,
911 ) -> CopyExternalImageDestInfo<T> {
912 CopyExternalImageDestInfo {
913 texture: self.texture,
914 mip_level: self.mip_level,
915 origin: self.origin,
916 aspect: self.aspect,
917 color_space,
918 premultiplied_alpha,
919 }
920 }
921}
922
923/// Subresource range within an image
924#[repr(C)]
925#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
926#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
927#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
928pub struct ImageSubresourceRange {
929 /// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA].
930 ///
931 #[doc = link_to_wgpu_docs!(["TAA"]: "enum.TextureAspect.html#variant.All")]
932 pub aspect: TextureAspect,
933 /// Base mip level.
934 pub base_mip_level: u32,
935 /// Mip level count.
936 /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
937 /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
938 pub mip_level_count: Option<u32>,
939 /// Base array layer.
940 pub base_array_layer: u32,
941 /// Layer count.
942 /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
943 /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
944 pub array_layer_count: Option<u32>,
945}
946
947impl ImageSubresourceRange {
948 /// Returns if the given range represents a full resource, with a texture of the given
949 /// layer count and mip count.
950 ///
951 /// ```rust
952 /// # use wgpu_types as wgpu;
953 ///
954 /// let range_none = wgpu::ImageSubresourceRange {
955 /// aspect: wgpu::TextureAspect::All,
956 /// base_mip_level: 0,
957 /// mip_level_count: None,
958 /// base_array_layer: 0,
959 /// array_layer_count: None,
960 /// };
961 /// assert_eq!(range_none.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), true);
962 ///
963 /// let range_some = wgpu::ImageSubresourceRange {
964 /// aspect: wgpu::TextureAspect::All,
965 /// base_mip_level: 0,
966 /// mip_level_count: Some(5),
967 /// base_array_layer: 0,
968 /// array_layer_count: Some(10),
969 /// };
970 /// assert_eq!(range_some.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), true);
971 ///
972 /// let range_mixed = wgpu::ImageSubresourceRange {
973 /// aspect: wgpu::TextureAspect::StencilOnly,
974 /// base_mip_level: 0,
975 /// // Only partial resource
976 /// mip_level_count: Some(3),
977 /// base_array_layer: 0,
978 /// array_layer_count: None,
979 /// };
980 /// assert_eq!(range_mixed.is_full_resource(wgpu::TextureFormat::Stencil8, 5, 10), false);
981 /// ```
982 #[must_use]
983 pub fn is_full_resource(
984 &self,
985 format: TextureFormat,
986 mip_levels: u32,
987 array_layers: u32,
988 ) -> bool {
989 // Mip level count and array layer count need to deal with both the None and Some(count) case.
990 let mip_level_count = self.mip_level_count.unwrap_or(mip_levels);
991 let array_layer_count = self.array_layer_count.unwrap_or(array_layers);
992
993 let aspect_eq = Some(format) == format.aspect_specific_format(self.aspect);
994
995 let base_mip_level_eq = self.base_mip_level == 0;
996 let mip_level_count_eq = mip_level_count == mip_levels;
997
998 let base_array_layer_eq = self.base_array_layer == 0;
999 let array_layer_count_eq = array_layer_count == array_layers;
1000
1001 aspect_eq
1002 && base_mip_level_eq
1003 && mip_level_count_eq
1004 && base_array_layer_eq
1005 && array_layer_count_eq
1006 }
1007
1008 /// Returns the mip level range of a subresource range describes for a specific texture.
1009 #[must_use]
1010 pub fn mip_range(&self, mip_level_count: u32) -> Range<u32> {
1011 self.base_mip_level..match self.mip_level_count {
1012 Some(mip_level_count) => self.base_mip_level.saturating_add(mip_level_count),
1013 None => mip_level_count,
1014 }
1015 }
1016
1017 /// Returns the layer range of a subresource range describes for a specific texture.
1018 #[must_use]
1019 pub fn layer_range(&self, array_layer_count: u32) -> Range<u32> {
1020 self.base_array_layer..match self.array_layer_count {
1021 Some(array_layer_count) => self.base_array_layer.saturating_add(array_layer_count),
1022 None => array_layer_count,
1023 }
1024 }
1025}
1026
1027#[cfg(test)]
1028mod tests {
1029 use super::*;
1030 use crate::Extent3d;
1031
1032 #[test]
1033 fn test_physical_size() {
1034 let format = TextureFormat::Bc1RgbaUnormSrgb; // 4x4 blocks
1035 assert_eq!(
1036 Extent3d {
1037 width: 7,
1038 height: 7,
1039 depth_or_array_layers: 1
1040 }
1041 .physical_size(format),
1042 Extent3d {
1043 width: 8,
1044 height: 8,
1045 depth_or_array_layers: 1
1046 }
1047 );
1048 // Doesn't change, already aligned
1049 assert_eq!(
1050 Extent3d {
1051 width: 8,
1052 height: 8,
1053 depth_or_array_layers: 1
1054 }
1055 .physical_size(format),
1056 Extent3d {
1057 width: 8,
1058 height: 8,
1059 depth_or_array_layers: 1
1060 }
1061 );
1062 let format = TextureFormat::Astc {
1063 block: AstcBlock::B8x5,
1064 channel: AstcChannel::Unorm,
1065 }; // 8x5 blocks
1066 assert_eq!(
1067 Extent3d {
1068 width: 7,
1069 height: 7,
1070 depth_or_array_layers: 1
1071 }
1072 .physical_size(format),
1073 Extent3d {
1074 width: 8,
1075 height: 10,
1076 depth_or_array_layers: 1
1077 }
1078 );
1079 }
1080
1081 #[test]
1082 fn test_max_mips() {
1083 // 1D
1084 assert_eq!(
1085 Extent3d {
1086 width: 240,
1087 height: 1,
1088 depth_or_array_layers: 1
1089 }
1090 .max_mips(TextureDimension::D1),
1091 1
1092 );
1093 // 2D
1094 assert_eq!(
1095 Extent3d {
1096 width: 1,
1097 height: 1,
1098 depth_or_array_layers: 1
1099 }
1100 .max_mips(TextureDimension::D2),
1101 1
1102 );
1103 assert_eq!(
1104 Extent3d {
1105 width: 60,
1106 height: 60,
1107 depth_or_array_layers: 1
1108 }
1109 .max_mips(TextureDimension::D2),
1110 6
1111 );
1112 assert_eq!(
1113 Extent3d {
1114 width: 240,
1115 height: 1,
1116 depth_or_array_layers: 1000
1117 }
1118 .max_mips(TextureDimension::D2),
1119 8
1120 );
1121 // 3D
1122 assert_eq!(
1123 Extent3d {
1124 width: 16,
1125 height: 30,
1126 depth_or_array_layers: 60
1127 }
1128 .max_mips(TextureDimension::D3),
1129 6
1130 );
1131 }
1132}