Skip to main content

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