wgpu_types/
origin_extent.rs

1#[cfg(any(feature = "serde", test))]
2use serde::{Deserialize, Serialize};
3
4use crate::TextureDimension;
5
6/// Origin of a copy from a 2D image.
7///
8/// Corresponds to [WebGPU `GPUOrigin2D`](
9/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin2ddict).
10#[repr(C)]
11#[derive(Clone, Copy, PartialEq, Eq, Hash)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
14pub struct Origin2d {
15    #[allow(missing_docs)]
16    pub x: u32,
17    #[allow(missing_docs)]
18    pub y: u32,
19}
20
21impl Origin2d {
22    /// Zero origin.
23    pub const ZERO: Self = Self { x: 0, y: 0 };
24
25    /// Adds the third dimension to this origin
26    #[must_use]
27    pub fn to_3d(self, z: u32) -> Origin3d {
28        Origin3d {
29            x: self.x,
30            y: self.y,
31            z,
32        }
33    }
34}
35
36impl core::fmt::Debug for Origin2d {
37    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38        (self.x, self.y).fmt(f)
39    }
40}
41
42/// Origin of a copy to/from a texture.
43///
44/// Corresponds to [WebGPU `GPUOrigin3D`](
45/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin3ddict).
46#[repr(C)]
47#[derive(Clone, Copy, PartialEq, Eq, Hash)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
50pub struct Origin3d {
51    /// X position of the origin
52    pub x: u32,
53    /// Y position of the origin
54    pub y: u32,
55    /// Z position of the origin
56    pub z: u32,
57}
58
59impl Origin3d {
60    /// Zero origin.
61    pub const ZERO: Self = Self { x: 0, y: 0, z: 0 };
62
63    /// Removes the third dimension from this origin
64    #[must_use]
65    pub fn to_2d(self) -> Origin2d {
66        Origin2d {
67            x: self.x,
68            y: self.y,
69        }
70    }
71}
72
73impl Default for Origin3d {
74    fn default() -> Self {
75        Self::ZERO
76    }
77}
78
79impl core::fmt::Debug for Origin3d {
80    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81        (self.x, self.y, self.z).fmt(f)
82    }
83}
84
85/// Extent of a texture related operation.
86///
87/// Corresponds to [WebGPU `GPUExtent3D`](
88/// https://gpuweb.github.io/gpuweb/#dictdef-gpuextent3ddict).
89#[repr(C)]
90#[derive(Clone, Copy, PartialEq, Eq, Hash)]
91#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
93pub struct Extent3d {
94    /// Width of the extent
95    pub width: u32,
96    /// Height of the extent
97    pub height: u32,
98    /// The depth of the extent or the number of array layers
99    #[cfg_attr(feature = "serde", serde(default = "default_depth"))]
100    pub depth_or_array_layers: u32,
101}
102
103impl core::fmt::Debug for Extent3d {
104    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105        (self.width, self.height, self.depth_or_array_layers).fmt(f)
106    }
107}
108
109#[cfg(feature = "serde")]
110fn default_depth() -> u32 {
111    1
112}
113
114impl Default for Extent3d {
115    fn default() -> Self {
116        Self {
117            width: 1,
118            height: 1,
119            depth_or_array_layers: 1,
120        }
121    }
122}
123
124impl Extent3d {
125    /// Calculates the [physical size] backing a texture of the given
126    /// format and extent.  This includes padding to the block width
127    /// and height of the format.
128    ///
129    /// This is the texture extent that you must upload at when uploading to _mipmaps_ of compressed textures.
130    ///
131    /// [physical size]: https://gpuweb.github.io/gpuweb/#physical-miplevel-specific-texture-extent
132    #[must_use]
133    pub fn physical_size(&self, format: crate::TextureFormat) -> Self {
134        let (block_width, block_height) = format.block_dimensions();
135
136        let width = self.width.div_ceil(block_width) * block_width;
137        let height = self.height.div_ceil(block_height) * block_height;
138
139        Self {
140            width,
141            height,
142            depth_or_array_layers: self.depth_or_array_layers,
143        }
144    }
145
146    /// Calculates the maximum possible count of mipmaps.
147    ///
148    /// Treats the depth as part of the mipmaps. If calculating
149    /// for a 2DArray texture, which does not mipmap depth, set depth to 1.
150    #[must_use]
151    pub fn max_mips(&self, dim: TextureDimension) -> u32 {
152        match dim {
153            TextureDimension::D1 => 1,
154            TextureDimension::D2 => {
155                let max_dim = self.width.max(self.height);
156                32 - max_dim.leading_zeros()
157            }
158            TextureDimension::D3 => {
159                let max_dim = self.width.max(self.height.max(self.depth_or_array_layers));
160                32 - max_dim.leading_zeros()
161            }
162        }
163    }
164
165    /// Calculates the extent at a given mip level.
166    ///
167    /// This is a low-level helper for internal use.
168    ///
169    /// It does *not* account for memory size being a multiple of block size.
170    ///
171    /// TODO(<https://github.com/gfx-rs/wgpu/issues/8491>): It also does not
172    /// consider whether an even dimension is required due to chroma
173    /// subsampling, but it probably should.
174    ///
175    /// <https://gpuweb.github.io/gpuweb/#logical-miplevel-specific-texture-extent>
176    #[doc(hidden)]
177    #[must_use]
178    pub fn mip_level_size(&self, level: u32, dim: TextureDimension) -> Self {
179        Self {
180            width: u32::max(1, self.width >> level),
181            height: match dim {
182                TextureDimension::D1 => 1,
183                _ => u32::max(1, self.height >> level),
184            },
185            depth_or_array_layers: match dim {
186                TextureDimension::D1 => 1,
187                TextureDimension::D2 => self.depth_or_array_layers,
188                TextureDimension::D3 => u32::max(1, self.depth_or_array_layers >> level),
189            },
190        }
191    }
192}