surpass/rasterizer/
pixel_segment.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cmp::Ordering;
6use std::{fmt, mem};
7
8use crate::{MAX_HEIGHT_SHIFT, MAX_WIDTH_SHIFT, PIXEL_WIDTH};
9
10// Tile coordinates are signed integers stored with a bias.
11// The value range goes from -1 to 2^bits - 2 inclusive.
12const TILE_BIAS: i16 = 1;
13
14pub const fn bit_field_lens<const TW: usize, const TH: usize>() -> [usize; 7] {
15    const fn log2_round_up(n: usize) -> usize {
16        if n.count_ones() == 1 {
17            n.trailing_zeros() as usize
18        } else {
19            mem::size_of::<usize>() * 8 - n.leading_zeros() as usize
20        }
21    }
22
23    let tile_width_shift = TW.trailing_zeros() as usize;
24    let tile_height_shift = TH.trailing_zeros() as usize;
25
26    let mut bit_field_lens = [
27        MAX_HEIGHT_SHIFT - tile_height_shift,
28        MAX_WIDTH_SHIFT - tile_width_shift,
29        0,
30        tile_width_shift,
31        tile_height_shift,
32        log2_round_up((PIXEL_WIDTH + 1) * 2),
33        log2_round_up((PIXEL_WIDTH + 1) * 2),
34    ];
35
36    let layer_id_len = mem::size_of::<PixelSegment<TW, TH>>() * 8
37        - bit_field_lens[0]
38        - bit_field_lens[1]
39        - bit_field_lens[3]
40        - bit_field_lens[4]
41        - bit_field_lens[5]
42        - bit_field_lens[6];
43
44    bit_field_lens[2] = layer_id_len;
45
46    bit_field_lens
47}
48
49const fn shift_left_for<const TW: usize, const TH: usize>(bit_field_index: usize) -> u32 {
50    let mut amount = 0;
51    let mut i = 0;
52
53    while i < bit_field_index {
54        amount += bit_field_lens::<TW, TH>()[i];
55        i += 1;
56    }
57
58    amount as u32
59}
60
61const fn shift_right_for<const TW: usize, const TH: usize>(bit_field_index: usize) -> u32 {
62    (mem::size_of::<PixelSegment<TW, TH>>() * 8 - bit_field_lens::<TW, TH>()[bit_field_index])
63        as u32
64}
65
66macro_rules! extract {
67    ( $tw:expr , $th:expr , $pixel_segment:expr , $bit_field_index:expr ) => {{
68        $pixel_segment << shift_left_for::<$tw, $th>($bit_field_index)
69            >> shift_right_for::<$tw, $th>($bit_field_index)
70    }};
71}
72
73#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
74pub struct PixelSegment<const TW: usize, const TH: usize>(u64);
75
76impl<const TW: usize, const TH: usize> PixelSegment<TW, TH> {
77    const BIT_FIELD_LENGTH: [usize; 7] = bit_field_lens::<TW, TH>();
78
79    #[inline]
80    pub fn new(
81        layer_id: u32,
82        tile_x: i16,
83        tile_y: i16,
84        local_x: u8,
85        local_y: u8,
86        double_area_multiplier: u8,
87        cover: i8,
88    ) -> Self {
89        let mut val = 0;
90
91        val |= ((1 << Self::BIT_FIELD_LENGTH[0]) - 1) & (tile_y + TILE_BIAS).max(0) as u64;
92
93        val <<= Self::BIT_FIELD_LENGTH[1];
94        val |= ((1 << Self::BIT_FIELD_LENGTH[1]) - 1) as u64 & (tile_x + TILE_BIAS).max(0) as u64;
95
96        val <<= Self::BIT_FIELD_LENGTH[2];
97        val |= ((1 << Self::BIT_FIELD_LENGTH[2]) - 1) as u64 & u64::from(layer_id);
98
99        val <<= Self::BIT_FIELD_LENGTH[3];
100        val |= ((1 << Self::BIT_FIELD_LENGTH[3]) - 1) as u64 & u64::from(local_x);
101
102        val <<= Self::BIT_FIELD_LENGTH[4];
103        val |= ((1 << Self::BIT_FIELD_LENGTH[4]) - 1) as u64 & u64::from(local_y);
104
105        val <<= Self::BIT_FIELD_LENGTH[5];
106        val |= ((1 << Self::BIT_FIELD_LENGTH[5]) - 1) as u64 & u64::from(double_area_multiplier);
107
108        val <<= Self::BIT_FIELD_LENGTH[6];
109        val |= ((1 << Self::BIT_FIELD_LENGTH[6]) - 1) as u64 & cover as u64;
110
111        Self(val)
112    }
113
114    #[inline]
115    pub fn layer_id(self) -> u32 {
116        extract!(TW, TH, self.0, 2) as u32
117    }
118
119    #[inline]
120    pub fn tile_x(self) -> i16 {
121        extract!(TW, TH, self.0, 1) as i16 - TILE_BIAS
122    }
123
124    #[inline]
125    pub fn tile_y(self) -> i16 {
126        extract!(TW, TH, self.0, 0) as i16 - TILE_BIAS
127    }
128
129    #[inline]
130    pub fn local_x(self) -> u8 {
131        extract!(TW, TH, self.0, 3) as u8
132    }
133
134    #[inline]
135    pub fn local_y(self) -> u8 {
136        extract!(TW, TH, self.0, 4) as u8
137    }
138
139    #[inline]
140    fn double_area_multiplier(self) -> u8 {
141        extract!(TW, TH, self.0, 5) as u8
142    }
143
144    #[inline]
145    pub fn double_area(self) -> i16 {
146        i16::from(self.double_area_multiplier()) * i16::from(self.cover())
147    }
148
149    #[inline]
150    pub fn cover(self) -> i8 {
151        extract!(TW, TH, self.0 as i64, 6) as i8
152    }
153}
154
155impl<const TW: usize, const TH: usize> fmt::Debug for PixelSegment<TW, TH> {
156    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        let unpacked: PixelSegmentUnpacked = (*self).into();
158        f.debug_struct("PixelSegment")
159            .field("layer_id", &unpacked.layer_id)
160            .field("tile_x", &unpacked.tile_x)
161            .field("tile_y", &unpacked.tile_y)
162            .field("local_x", &unpacked.local_x)
163            .field("local_y", &unpacked.local_y)
164            .field("double_area", &unpacked.double_area)
165            .field("cover", &unpacked.cover)
166            .finish()
167    }
168}
169
170impl<const TW: usize, const TH: usize> From<&PixelSegment<TW, TH>> for u64 {
171    fn from(segment: &PixelSegment<TW, TH>) -> Self {
172        segment.0
173    }
174}
175
176#[inline]
177pub fn search_last_by_key<F, K, const TW: usize, const TH: usize>(
178    segments: &[PixelSegment<TW, TH>],
179    key: K,
180    mut f: F,
181) -> Result<usize, usize>
182where
183    F: FnMut(&PixelSegment<TW, TH>) -> K,
184    K: Ord,
185{
186    let mut len = segments.len();
187    if len == 0 {
188        return Err(0);
189    }
190
191    let mut start = 0;
192    while len > 1 {
193        let half = len / 2;
194        let mid = start + half;
195        (start, len) = match f(&segments[mid]).cmp(&key) {
196            Ordering::Greater => (start, half),
197            _ => (mid, len - half),
198        };
199    }
200
201    match f(&segments[start]).cmp(&key) {
202        Ordering::Less => Err(start + 1),
203        Ordering::Equal => Ok(start),
204        Ordering::Greater => Err(start),
205    }
206}
207
208#[derive(Debug)]
209pub struct PixelSegmentUnpacked {
210    pub layer_id: u32,
211    pub tile_x: i16,
212    pub tile_y: i16,
213    pub local_x: u8,
214    pub local_y: u8,
215    pub double_area: i16,
216    pub cover: i8,
217}
218
219impl<const TW: usize, const TH: usize> From<PixelSegment<TW, TH>> for PixelSegmentUnpacked {
220    fn from(value: PixelSegment<TW, TH>) -> Self {
221        PixelSegmentUnpacked {
222            layer_id: value.layer_id(),
223            tile_x: value.tile_x(),
224            tile_y: value.tile_y(),
225            local_x: value.local_x(),
226            local_y: value.local_y(),
227            double_area: value.double_area(),
228            cover: value.cover(),
229        }
230    }
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236
237    use crate::{LAYER_LIMIT, PIXEL_DOUBLE_WIDTH, TILE_HEIGHT, TILE_WIDTH};
238
239    #[test]
240    fn pixel_segment() {
241        let layer_id = 3;
242        let tile_x = 4;
243        let tile_y = 5;
244        let local_x = 6;
245        let local_y = 7;
246        let double_area_multiplier = 8;
247        let cover = 9;
248
249        let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
250            layer_id,
251            tile_x,
252            tile_y,
253            local_x,
254            local_y,
255            double_area_multiplier,
256            cover,
257        );
258
259        assert_eq!(pixel_segment.layer_id(), layer_id);
260        assert_eq!(pixel_segment.tile_x(), tile_x);
261        assert_eq!(pixel_segment.tile_y(), tile_y);
262        assert_eq!(pixel_segment.local_x(), local_x);
263        assert_eq!(pixel_segment.local_y(), local_y);
264        assert_eq!(
265            pixel_segment.double_area(),
266            i16::from(double_area_multiplier) * i16::from(cover)
267        );
268        assert_eq!(pixel_segment.cover(), cover);
269    }
270
271    #[test]
272    fn pixel_segment_max() {
273        let layer_id = LAYER_LIMIT as u32;
274        let tile_x = (1 << (bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[1] - 1)) - 1;
275        let tile_y = (1 << (bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[0] - 1)) - 1;
276        let local_x = (1 << bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[4]) - 1;
277        let local_y = (1 << bit_field_lens::<TILE_WIDTH, TILE_HEIGHT>()[3]) - 1;
278        let double_area_multiplier = PIXEL_DOUBLE_WIDTH as u8;
279        let cover = PIXEL_WIDTH as i8;
280
281        let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
282            layer_id,
283            tile_x,
284            tile_y,
285            local_x,
286            local_y,
287            double_area_multiplier,
288            cover,
289        );
290
291        assert_eq!(pixel_segment.layer_id(), layer_id);
292        assert_eq!(pixel_segment.tile_x(), tile_x);
293        assert_eq!(pixel_segment.tile_y(), tile_y);
294        assert_eq!(pixel_segment.local_x(), local_x);
295        assert_eq!(pixel_segment.local_y(), local_y);
296        assert_eq!(
297            pixel_segment.double_area(),
298            i16::from(double_area_multiplier) * i16::from(cover)
299        );
300        assert_eq!(pixel_segment.cover(), cover);
301    }
302
303    #[test]
304    fn pixel_segment_min() {
305        let layer_id = 0;
306        let tile_x = -1;
307        let tile_y = -1;
308        let local_x = 0;
309        let local_y = 0;
310        let double_area_multiplier = 0;
311        let cover = -(PIXEL_WIDTH as i8);
312
313        let pixel_segment = PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(
314            layer_id,
315            tile_x,
316            tile_y,
317            local_x,
318            local_y,
319            double_area_multiplier,
320            cover,
321        );
322
323        assert_eq!(pixel_segment.layer_id(), layer_id);
324        assert_eq!(pixel_segment.tile_x(), -1);
325        assert_eq!(pixel_segment.tile_y(), -1);
326        assert_eq!(pixel_segment.local_x(), local_x);
327        assert_eq!(pixel_segment.local_y(), local_y);
328        assert_eq!(
329            pixel_segment.double_area(),
330            i16::from(double_area_multiplier) * i16::from(cover)
331        );
332        assert_eq!(pixel_segment.cover(), cover);
333    }
334
335    #[test]
336    fn pixel_segment_clipping() {
337        let tile_x = -2;
338        let tile_y = -2;
339
340        let pixel_segment =
341            PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(0, tile_x, tile_y, 0, 0, 0, 0);
342
343        assert_eq!(pixel_segment.tile_x(), -1, "negative tile coord clipped to -1");
344        assert_eq!(pixel_segment.tile_y(), -1, "negative tile coord clipped to -1");
345
346        let tile_x = i16::MIN;
347        let tile_y = i16::MIN;
348
349        let pixel_segment =
350            PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(0, tile_x, tile_y, 0, 0, 0, 0);
351
352        assert_eq!(pixel_segment.tile_x(), -1, "negative tile coord clipped to -1");
353        assert_eq!(pixel_segment.tile_y(), -1, "negative tile coord clipped to -1");
354    }
355
356    #[test]
357    fn search_last_by_key_test() {
358        let size = 50;
359        let segments: Vec<_> = (0..(size * 2))
360            .map(|i| PixelSegment::<TILE_WIDTH, TILE_HEIGHT>::new(i / 2, 0, 0, 0, 0, 0, 0))
361            .collect();
362        for i in 0..size {
363            assert_eq!(
364                Ok((i * 2 + 1) as usize),
365                search_last_by_key(segments.as_slice(), i, |ps| ps.layer_id())
366            );
367        }
368    }
369}