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