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}