• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::{GOBType, Tiling};
7 use crate::Minify;
8 
9 use std::ops::Add;
10 
11 pub mod units {
12     #[derive(Clone, Debug, Copy, PartialEq)]
13     pub struct Elements {}
14 
15     #[derive(Clone, Debug, Copy, PartialEq)]
16     pub struct Pixels {}
17 
18     #[derive(Clone, Debug, Copy, PartialEq)]
19     pub struct Samples {}
20 
21     #[derive(Clone, Debug, Copy, PartialEq)]
22     pub struct Bytes {}
23 
24     #[derive(Clone, Debug, Copy, PartialEq)]
25     pub struct Tiles {}
26 
27     #[derive(Clone, Debug, Copy, PartialEq)]
28     pub struct GOBs {}
29 }
30 
31 #[derive(Clone, Debug, Copy, PartialEq, Default)]
32 #[repr(C)]
33 pub struct Extent4D<U> {
34     pub width: u32,
35     pub height: u32,
36     pub depth: u32,
37     pub array_len: u32,
38     phantom: std::marker::PhantomData<U>,
39 }
40 
41 impl<U> Extent4D<U> {
new( width: u32, height: u32, depth: u32, array_len: u32, ) -> Extent4D<U>42     pub const fn new(
43         width: u32,
44         height: u32,
45         depth: u32,
46         array_len: u32,
47     ) -> Extent4D<U> {
48         Extent4D {
49             width,
50             height,
51             depth,
52             array_len,
53             phantom: std::marker::PhantomData,
54         }
55     }
56 
align(self, alignment: &Self) -> Self57     pub fn align(self, alignment: &Self) -> Self {
58         Self {
59             width: self.width.next_multiple_of(alignment.width),
60             height: self.height.next_multiple_of(alignment.height),
61             depth: self.depth.next_multiple_of(alignment.depth),
62             array_len: self.array_len.next_multiple_of(alignment.array_len),
63             phantom: std::marker::PhantomData,
64         }
65     }
66 
67     #[allow(dead_code)]
is_aligned_to(&self, alignment: Extent4D<U>) -> bool68     pub fn is_aligned_to(&self, alignment: Extent4D<U>) -> bool {
69         (self.width % alignment.width) == 0
70             && (self.height % alignment.height) == 0
71             && (self.depth % alignment.depth) == 0
72             && (self.array_len % alignment.array_len) == 0
73     }
74 
mul<V>(self, other: Extent4D<V>) -> Extent4D<V>75     fn mul<V>(self, other: Extent4D<V>) -> Extent4D<V> {
76         Extent4D {
77             width: self.width * other.width,
78             height: self.height * other.height,
79             depth: self.depth * other.depth,
80             array_len: self.array_len * other.array_len,
81             phantom: std::marker::PhantomData,
82         }
83     }
84 
div_ceil<V>(self, other: Self) -> Extent4D<V>85     fn div_ceil<V>(self, other: Self) -> Extent4D<V> {
86         Extent4D {
87             width: self.width.div_ceil(other.width),
88             height: self.height.div_ceil(other.height),
89             depth: self.depth.div_ceil(other.depth),
90             array_len: self.array_len.div_ceil(other.array_len),
91             phantom: std::marker::PhantomData,
92         }
93     }
94 
cast_units<V>(self) -> Extent4D<V>95     pub fn cast_units<V>(self) -> Extent4D<V> {
96         Extent4D {
97             width: self.width,
98             height: self.height,
99             depth: self.depth,
100             array_len: self.array_len,
101             phantom: std::marker::PhantomData,
102         }
103     }
104 }
105 
106 impl Extent4D<units::Pixels> {
to_sa( self, sample_layout: SampleLayout, ) -> Extent4D<units::Samples>107     pub fn to_sa(
108         self,
109         sample_layout: SampleLayout,
110     ) -> Extent4D<units::Samples> {
111         self.mul(sample_layout.px_extent_sa())
112     }
113 
to_el( self, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Elements>114     pub fn to_el(
115         self,
116         format: Format,
117         sample_layout: SampleLayout,
118     ) -> Extent4D<units::Elements> {
119         self.to_sa(sample_layout).div_ceil(format.el_extent_sa())
120     }
121 
to_B( self, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Bytes>122     pub fn to_B(
123         self,
124         format: Format,
125         sample_layout: SampleLayout,
126     ) -> Extent4D<units::Bytes> {
127         self.to_el(format, sample_layout).to_B(format)
128     }
129 
to_tl( self, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Tiles>130     pub fn to_tl(
131         self,
132         tiling: &Tiling,
133         format: Format,
134         sample_layout: SampleLayout,
135     ) -> Extent4D<units::Tiles> {
136         let tl_extent_B = tiling.extent_B();
137         self.to_B(format, sample_layout).div_ceil(tl_extent_B)
138     }
139 }
140 
141 #[no_mangle]
nil_extent4d_px_to_el( extent_px: Extent4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Elements>142 pub extern "C" fn nil_extent4d_px_to_el(
143     extent_px: Extent4D<units::Pixels>,
144     format: Format,
145     sample_layout: SampleLayout,
146 ) -> Extent4D<units::Elements> {
147     extent_px.to_el(format, sample_layout)
148 }
149 
150 #[no_mangle]
nil_extent4d_px_to_tl( extent_px: Extent4D<units::Pixels>, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Tiles>151 pub extern "C" fn nil_extent4d_px_to_tl(
152     extent_px: Extent4D<units::Pixels>,
153     tiling: &Tiling,
154     format: Format,
155     sample_layout: SampleLayout,
156 ) -> Extent4D<units::Tiles> {
157     extent_px.to_tl(tiling, format, sample_layout)
158 }
159 
160 #[no_mangle]
nil_extent4d_px_to_B( extent_px: Extent4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Extent4D<units::Bytes>161 pub extern "C" fn nil_extent4d_px_to_B(
162     extent_px: Extent4D<units::Pixels>,
163     format: Format,
164     sample_layout: SampleLayout,
165 ) -> Extent4D<units::Bytes> {
166     extent_px.to_B(format, sample_layout)
167 }
168 
169 impl Extent4D<units::Samples> {
to_px(self, sample_layout: SampleLayout) -> Extent4D<units::Pixels>170     pub fn to_px(self, sample_layout: SampleLayout) -> Extent4D<units::Pixels> {
171         self.div_ceil(sample_layout.px_extent_sa())
172     }
173 }
174 
175 impl Extent4D<units::Elements> {
to_B(self, format: Format) -> Extent4D<units::Bytes>176     pub fn to_B(self, format: Format) -> Extent4D<units::Bytes> {
177         Extent4D {
178             width: self.width * format.el_size_B(),
179             ..self.cast_units()
180         }
181     }
182 
to_sa(self, format: Format) -> Extent4D<units::Samples>183     pub fn to_sa(self, format: Format) -> Extent4D<units::Samples> {
184         self.mul(format.el_extent_sa())
185     }
186 }
187 
188 impl Extent4D<units::Bytes> {
size_B(&self) -> u64189     pub fn size_B(&self) -> u64 {
190         // size_B of something with layers doesn't make sense because we can't
191         // know the array stride based only on the other dimensions.
192         assert!(self.array_len == 1);
193         u64::from(self.width) * u64::from(self.height) * u64::from(self.depth)
194     }
195 
to_GOB(self, gob_type: GOBType) -> Extent4D<units::GOBs>196     pub fn to_GOB(self, gob_type: GOBType) -> Extent4D<units::GOBs> {
197         self.div_ceil(gob_type.extent_B())
198     }
199 }
200 
201 #[derive(Clone, Debug, Copy, PartialEq)]
202 #[repr(C)]
203 pub struct Offset4D<U> {
204     pub x: u32,
205     pub y: u32,
206     pub z: u32,
207     pub a: u32,
208     phantom: std::marker::PhantomData<U>,
209 }
210 
211 impl<U> Offset4D<U> {
new(x: u32, y: u32, z: u32, a: u32) -> Offset4D<U>212     pub const fn new(x: u32, y: u32, z: u32, a: u32) -> Offset4D<U> {
213         Offset4D {
214             x,
215             y,
216             z,
217             a,
218             phantom: std::marker::PhantomData,
219         }
220     }
221 
222     #[allow(dead_code)]
is_aligned_to(&self, alignment: Extent4D<U>) -> bool223     pub fn is_aligned_to(&self, alignment: Extent4D<U>) -> bool {
224         (self.x % alignment.width) == 0
225             && (self.y % alignment.height) == 0
226             && (self.z % alignment.depth) == 0
227             && (self.a % alignment.array_len) == 0
228     }
229 
div_floor<V>(self, other: Extent4D<U>) -> Offset4D<V>230     fn div_floor<V>(self, other: Extent4D<U>) -> Offset4D<V> {
231         Offset4D {
232             x: self.x / other.width,
233             y: self.y / other.height,
234             z: self.z / other.depth,
235             a: self.a / other.array_len,
236             phantom: std::marker::PhantomData,
237         }
238     }
239 
mul<V>(self, other: Extent4D<V>) -> Offset4D<V>240     fn mul<V>(self, other: Extent4D<V>) -> Offset4D<V> {
241         Offset4D {
242             x: self.x * other.width,
243             y: self.y * other.height,
244             z: self.z * other.depth,
245             a: self.a * other.array_len,
246             phantom: std::marker::PhantomData,
247         }
248     }
249 
cast_units<V>(self) -> Offset4D<V>250     fn cast_units<V>(self) -> Offset4D<V> {
251         Offset4D {
252             x: self.x,
253             y: self.y,
254             z: self.z,
255             a: self.a,
256             phantom: std::marker::PhantomData,
257         }
258     }
259 }
260 
261 impl<U> Add<Extent4D<U>> for Offset4D<U> {
262     type Output = Offset4D<U>;
263 
add(self, rhs: Extent4D<U>) -> Offset4D<U>264     fn add(self, rhs: Extent4D<U>) -> Offset4D<U> {
265         Self {
266             x: self.x + rhs.width,
267             y: self.y + rhs.height,
268             z: self.z + rhs.depth,
269             a: self.a + rhs.array_len,
270             phantom: std::marker::PhantomData,
271         }
272     }
273 }
274 
275 impl Offset4D<units::Pixels> {
to_el( self, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Elements>276     pub fn to_el(
277         self,
278         format: Format,
279         sample_layout: SampleLayout,
280     ) -> Offset4D<units::Elements> {
281         self.mul(sample_layout.px_extent_sa())
282             .div_floor(format.el_extent_sa())
283     }
284 
to_B( self, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Bytes>285     pub fn to_B(
286         self,
287         format: Format,
288         sample_layout: SampleLayout,
289     ) -> Offset4D<units::Bytes> {
290         self.to_el(format, sample_layout).to_B(format)
291     }
292 
to_tl( self, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Tiles>293     pub fn to_tl(
294         self,
295         tiling: &Tiling,
296         format: Format,
297         sample_layout: SampleLayout,
298     ) -> Offset4D<units::Tiles> {
299         self.to_B(format, sample_layout)
300             .div_floor(tiling.extent_B())
301     }
302 }
303 
304 #[no_mangle]
nil_offset4d_px_to_el( offset: Offset4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Elements>305 pub extern "C" fn nil_offset4d_px_to_el(
306     offset: Offset4D<units::Pixels>,
307     format: Format,
308     sample_layout: SampleLayout,
309 ) -> Offset4D<units::Elements> {
310     offset.to_el(format, sample_layout)
311 }
312 
313 #[no_mangle]
nil_offset4d_px_to_tl( offset: Offset4D<units::Pixels>, tiling: &Tiling, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Tiles>314 pub extern "C" fn nil_offset4d_px_to_tl(
315     offset: Offset4D<units::Pixels>,
316     tiling: &Tiling,
317     format: Format,
318     sample_layout: SampleLayout,
319 ) -> Offset4D<units::Tiles> {
320     offset.to_tl(tiling, format, sample_layout)
321 }
322 
323 #[no_mangle]
nil_offset4d_px_to_B( offset: Offset4D<units::Pixels>, format: Format, sample_layout: SampleLayout, ) -> Offset4D<units::Bytes>324 pub extern "C" fn nil_offset4d_px_to_B(
325     offset: Offset4D<units::Pixels>,
326     format: Format,
327     sample_layout: SampleLayout,
328 ) -> Offset4D<units::Bytes> {
329     offset.to_B(format, sample_layout)
330 }
331 
332 impl Offset4D<units::Elements> {
to_B(self, format: Format) -> Offset4D<units::Bytes>333     pub fn to_B(self, format: Format) -> Offset4D<units::Bytes> {
334         Offset4D {
335             x: self.x * format.el_size_B(),
336             ..self.cast_units()
337         }
338     }
339 }
340 
341 impl Minify<u32> for Extent4D<units::Pixels> {
minify(self, level: u32) -> Self342     fn minify(self, level: u32) -> Self {
343         Self {
344             width: self.width.minify(level),
345             height: self.height.minify(level),
346             depth: self.depth.minify(level),
347             ..self
348         }
349     }
350 }
351