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