wgpu_types/
texture.rs

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