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