1 // Copyright © 2024 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3
4 use crate::format::Format;
5 use crate::image::SampleLayout;
6 use crate::tiling::{gob_height, Tiling, GOB_DEPTH, GOB_WIDTH_B};
7 use crate::Minify;
8
9 pub mod units {
10 #[derive(Clone, Debug, Copy, PartialEq)]
11 pub struct Elements {}
12
13 #[derive(Clone, Debug, Copy, PartialEq)]
14 pub struct Pixels {}
15
16 #[derive(Clone, Debug, Copy, PartialEq)]
17 pub struct Samples {}
18
19 #[derive(Clone, Debug, Copy, PartialEq)]
20 pub struct Bytes {}
21
22 #[derive(Clone, Debug, Copy, PartialEq)]
23 pub struct Tiles {}
24
25 #[derive(Clone, Debug, Copy, PartialEq)]
26 pub struct GOBs {}
27 }
28
29 #[derive(Clone, Debug, Copy, PartialEq, Default)]
30 #[repr(C)]
31 pub struct Extent4D<U> {
32 pub width: u32,
33 pub height: u32,
34 pub depth: u32,
35 pub array_len: u32,
36 phantom: std::marker::PhantomData<U>,
37 }
38
39 impl<U> Extent4D<U> {
new( width: u32, height: u32, depth: u32, array_len: u32, ) -> Extent4D<U>40 pub fn new(
41 width: u32,
42 height: u32,
43 depth: u32,
44 array_len: u32,
45 ) -> Extent4D<U> {
46 Extent4D {
47 width,
48 height,
49 depth,
50 array_len,
51 phantom: std::marker::PhantomData,
52 }
53 }
54
align(self, alignment: &Self) -> Self55 pub fn align(self, alignment: &Self) -> Self {
56 Self {
57 width: self.width.next_multiple_of(alignment.width),
58 height: self.height.next_multiple_of(alignment.height),
59 depth: self.depth.next_multiple_of(alignment.depth),
60 array_len: self.array_len.next_multiple_of(alignment.array_len),
61 phantom: std::marker::PhantomData,
62 }
63 }
64
mul<V>(self, other: Extent4D<V>) -> Extent4D<V>65 fn mul<V>(self, other: Extent4D<V>) -> Extent4D<V> {
66 Extent4D {
67 width: self.width * other.width,
68 height: self.height * other.height,
69 depth: self.depth * other.depth,
70 array_len: self.array_len * other.array_len,
71 phantom: std::marker::PhantomData,
72 }
73 }
74
div_ceil<V>(self, other: Self) -> Extent4D<V>75 fn div_ceil<V>(self, other: Self) -> Extent4D<V> {
76 Extent4D {
77 width: self.width.div_ceil(other.width),
78 height: self.height.div_ceil(other.height),
79 depth: self.depth.div_ceil(other.depth),
80 array_len: self.array_len.div_ceil(other.array_len),
81 phantom: std::marker::PhantomData,
82 }
83 }
84
cast_units<V>(self) -> Extent4D<V>85 pub fn cast_units<V>(self) -> Extent4D<V> {
86 Extent4D {
87 width: self.width,
88 height: self.height,
89 depth: self.depth,
90 array_len: self.array_len,
91 phantom: std::marker::PhantomData,
92 }
93 }
94 }
95
96 impl Extent4D<units::Pixels> {
to_sa( self, sample_layout: SampleLayout, ) -> Extent4D<units::Samples>97 pub fn to_sa(
98 self,
99 sample_layout: SampleLayout,
100 ) -> Extent4D<units::Samples> {
101 self.mul(sample_layout.px_extent_sa())
102 }
103
to_el( self, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Elements>104 pub fn to_el(
105 self,
106 format: Format,
107 sample_layout: SampleLayout,
108 ) -> Extent4D<units::Elements> {
109 self.to_sa(sample_layout).div_ceil(format.el_extent_sa())
110 }
111
to_B( self, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Bytes>112 pub fn to_B(
113 self,
114 format: Format,
115 sample_layout: SampleLayout,
116 ) -> Extent4D<units::Bytes> {
117 self.to_el(format, sample_layout).to_B(format)
118 }
119
to_tl( self, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Tiles>120 pub fn to_tl(
121 self,
122 tiling: &Tiling,
123 format: Format,
124 sample_layout: SampleLayout,
125 ) -> Extent4D<units::Tiles> {
126 let tl_extent_B = tiling.extent_B();
127 self.to_B(format, sample_layout).div_ceil(tl_extent_B)
128 }
129 }
130
131 #[no_mangle]
nil_extent4d_px_to_el( extent_px: Extent4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Elements>132 pub extern "C" fn nil_extent4d_px_to_el(
133 extent_px: Extent4D<units::Pixels>,
134 format: Format,
135 sample_layout: SampleLayout,
136 ) -> Extent4D<units::Elements> {
137 extent_px.to_el(format, sample_layout)
138 }
139
140 #[no_mangle]
nil_extent4d_px_to_tl( extent_px: Extent4D<units::Pixels>, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Tiles>141 pub extern "C" fn nil_extent4d_px_to_tl(
142 extent_px: Extent4D<units::Pixels>,
143 tiling: &Tiling,
144 format: Format,
145 sample_layout: SampleLayout,
146 ) -> Extent4D<units::Tiles> {
147 extent_px.to_tl(tiling, format, sample_layout)
148 }
149
150 impl Extent4D<units::Samples> {
to_px(self, sample_layout: SampleLayout) -> Extent4D<units::Pixels>151 pub fn to_px(self, sample_layout: SampleLayout) -> Extent4D<units::Pixels> {
152 self.div_ceil(sample_layout.px_extent_sa())
153 }
154 }
155
156 impl Extent4D<units::Elements> {
to_B(self, format: Format) -> Extent4D<units::Bytes>157 pub fn to_B(self, format: Format) -> Extent4D<units::Bytes> {
158 Extent4D {
159 width: self.width * format.el_size_B(),
160 ..self.cast_units()
161 }
162 }
163
to_sa(self, format: Format) -> Extent4D<units::Samples>164 pub fn to_sa(self, format: Format) -> Extent4D<units::Samples> {
165 self.mul(format.el_extent_sa())
166 }
167 }
168
169 impl Extent4D<units::Bytes> {
size_B(&self) -> u64170 pub fn size_B(&self) -> u64 {
171 // size_B of something with layers doesn't make sense because we can't
172 // know the array stride based only on the other dimensions.
173 assert!(self.array_len == 1);
174 u64::from(self.width) * u64::from(self.height) * u64::from(self.depth)
175 }
176
to_GOB(self, gob_height_is_8: bool) -> Extent4D<units::GOBs>177 pub fn to_GOB(self, gob_height_is_8: bool) -> Extent4D<units::GOBs> {
178 let gob_extent_B = Extent4D {
179 width: GOB_WIDTH_B,
180 height: gob_height(gob_height_is_8),
181 depth: GOB_DEPTH,
182 array_len: 1,
183 phantom: std::marker::PhantomData,
184 };
185
186 self.div_ceil(gob_extent_B)
187 }
188 }
189
190 #[derive(Clone, Debug, Copy, PartialEq)]
191 #[repr(C)]
192 pub struct Offset4D<U> {
193 pub x: u32,
194 pub y: u32,
195 pub z: u32,
196 pub a: u32,
197 phantom: std::marker::PhantomData<U>,
198 }
199
200 impl<U> Offset4D<U> {
div_floor<V>(self, other: Extent4D<U>) -> Offset4D<V>201 fn div_floor<V>(self, other: Extent4D<U>) -> Offset4D<V> {
202 Offset4D {
203 x: self.x / other.width,
204 y: self.y / other.height,
205 z: self.z / other.depth,
206 a: self.a / other.array_len,
207 phantom: std::marker::PhantomData,
208 }
209 }
210
mul<V>(self, other: Extent4D<V>) -> Offset4D<V>211 fn mul<V>(self, other: Extent4D<V>) -> Offset4D<V> {
212 Offset4D {
213 x: self.x * other.width,
214 y: self.y * other.height,
215 z: self.z * other.depth,
216 a: self.a * other.array_len,
217 phantom: std::marker::PhantomData,
218 }
219 }
220
cast_units<V>(self) -> Offset4D<V>221 fn cast_units<V>(self) -> Offset4D<V> {
222 Offset4D {
223 x: self.x,
224 y: self.y,
225 z: self.z,
226 a: self.a,
227 phantom: std::marker::PhantomData,
228 }
229 }
230 }
231
232 impl Offset4D<units::Pixels> {
to_el( self, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Elements>233 pub fn to_el(
234 self,
235 format: Format,
236 sample_layout: SampleLayout,
237 ) -> Offset4D<units::Elements> {
238 self.mul(sample_layout.px_extent_sa())
239 .div_floor(format.el_extent_sa())
240 }
241
to_B( self, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Bytes>242 pub fn to_B(
243 self,
244 format: Format,
245 sample_layout: SampleLayout,
246 ) -> Offset4D<units::Bytes> {
247 self.to_el(format, sample_layout).to_B(format)
248 }
249
to_tl( self, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Tiles>250 pub fn to_tl(
251 self,
252 tiling: &Tiling,
253 format: Format,
254 sample_layout: SampleLayout,
255 ) -> Offset4D<units::Tiles> {
256 self.to_B(format, sample_layout)
257 .div_floor(tiling.extent_B())
258 }
259 }
260
261 #[no_mangle]
nil_offset4d_px_to_el( offset: Offset4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Elements>262 pub extern "C" fn nil_offset4d_px_to_el(
263 offset: Offset4D<units::Pixels>,
264 format: Format,
265 sample_layout: SampleLayout,
266 ) -> Offset4D<units::Elements> {
267 offset.to_el(format, sample_layout)
268 }
269
270 #[no_mangle]
nil_offset4d_px_to_tl( offset: Offset4D<units::Pixels>, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Tiles>271 pub extern "C" fn nil_offset4d_px_to_tl(
272 offset: Offset4D<units::Pixels>,
273 tiling: &Tiling,
274 format: Format,
275 sample_layout: SampleLayout,
276 ) -> Offset4D<units::Tiles> {
277 offset.to_tl(tiling, format, sample_layout)
278 }
279
280 impl Offset4D<units::Elements> {
to_B(self, format: Format) -> Offset4D<units::Bytes>281 pub fn to_B(self, format: Format) -> Offset4D<units::Bytes> {
282 Offset4D {
283 x: self.x * format.el_size_B(),
284 ..self.cast_units()
285 }
286 }
287 }
288
289 impl Minify<u32> for Extent4D<units::Pixels> {
minify(self, level: u32) -> Self290 fn minify(self, level: u32) -> Self {
291 Self {
292 width: self.width.minify(level),
293 height: self.height.minify(level),
294 depth: self.depth.minify(level),
295 ..self
296 }
297 }
298 }
299