rav1e/tiling/
tile.rs

1// Copyright (c) 2019-2022, The rav1e contributors. All rights reserved
2//
3// This source code is subject to the terms of the BSD 2 Clause License and
4// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
5// was not distributed with this source code in the LICENSE file, you can
6// obtain it at www.aomedia.org/license/software. If the Alliance for Open
7// Media Patent License 1.0 was not distributed with this source code in the
8// PATENTS file, you can obtain it at www.aomedia.org/license/patent.
9
10use super::*;
11
12use crate::context::*;
13use crate::frame::*;
14use crate::util::*;
15
16/// Rectangle of a tile, in pixels
17///
18/// This is similar to Rect, but with unsigned (x, y) for convenience.
19#[derive(Debug, Clone, Copy)]
20pub struct TileRect {
21  pub x: usize,
22  pub y: usize,
23  pub width: usize,
24  pub height: usize,
25}
26
27impl TileRect {
28  #[inline(always)]
29  pub const fn decimated(&self, xdec: usize, ydec: usize) -> Self {
30    Self {
31      x: self.x >> xdec,
32      y: self.y >> ydec,
33      width: self.width >> xdec,
34      height: self.height >> ydec,
35    }
36  }
37
38  #[inline(always)]
39  pub const fn to_frame_plane_offset(
40    &self, tile_po: PlaneOffset,
41  ) -> PlaneOffset {
42    PlaneOffset {
43      x: self.x as isize + tile_po.x,
44      y: self.y as isize + tile_po.y,
45    }
46  }
47
48  #[inline(always)]
49  pub fn to_frame_block_offset(
50    &self, tile_bo: TileBlockOffset, xdec: usize, ydec: usize,
51  ) -> PlaneBlockOffset {
52    debug_assert!(self.x % (MI_SIZE >> xdec) == 0);
53    debug_assert!(self.y % (MI_SIZE >> ydec) == 0);
54    let bx = self.x >> (MI_SIZE_LOG2 - xdec);
55    let by = self.y >> (MI_SIZE_LOG2 - ydec);
56    PlaneBlockOffset(BlockOffset { x: bx + tile_bo.0.x, y: by + tile_bo.0.y })
57  }
58
59  #[inline(always)]
60  pub fn to_frame_super_block_offset(
61    &self, tile_sbo: TileSuperBlockOffset, sb_size_log2: usize, xdec: usize,
62    ydec: usize,
63  ) -> PlaneSuperBlockOffset {
64    debug_assert!(sb_size_log2 == 6 || sb_size_log2 == 7);
65    debug_assert!(self.x % (1 << (sb_size_log2 - xdec)) == 0);
66    debug_assert!(self.y % (1 << (sb_size_log2 - ydec)) == 0);
67    let sbx = self.x >> (sb_size_log2 - xdec);
68    let sby = self.y >> (sb_size_log2 - ydec);
69    PlaneSuperBlockOffset(SuperBlockOffset {
70      x: sbx + tile_sbo.0.x,
71      y: sby + tile_sbo.0.y,
72    })
73  }
74}
75
76impl From<TileRect> for Rect {
77  #[inline(always)]
78  fn from(tile_rect: TileRect) -> Rect {
79    Rect {
80      x: tile_rect.x as isize,
81      y: tile_rect.y as isize,
82      width: tile_rect.width,
83      height: tile_rect.height,
84    }
85  }
86}
87
88/// Tiled view of a frame
89#[derive(Debug)]
90pub struct Tile<'a, T: Pixel> {
91  pub planes: [PlaneRegion<'a, T>; MAX_PLANES],
92}
93
94/// Mutable tiled view of a frame
95#[derive(Debug)]
96pub struct TileMut<'a, T: Pixel> {
97  pub planes: [PlaneRegionMut<'a, T>; MAX_PLANES],
98}
99
100// common impl for Tile and TileMut
101macro_rules! tile_common {
102  // $name: Tile or TileMut
103  // $pr_type: PlaneRegion or PlaneRegionMut
104  // $iter: iter or iter_mut
105  //opt_mut: nothing or mut
106  ($name:ident, $pr_type:ident, $iter:ident $(,$opt_mut:tt)?) => {
107    impl<'a, T: Pixel> $name<'a, T> {
108
109      #[inline(always)]
110      pub fn new(
111        frame: &'a $($opt_mut)? Frame<T>,
112        luma_rect: TileRect,
113      ) -> Self {
114        let mut planes_iter = frame.planes.$iter();
115        Self {
116          planes: [
117            {
118              let plane = planes_iter.next().unwrap();
119              $pr_type::new(plane, luma_rect.into())
120            },
121            {
122              let plane = planes_iter.next().unwrap();
123              let rect = luma_rect.decimated(plane.cfg.xdec, plane.cfg.ydec);
124              $pr_type::new(plane, rect.into())
125            },
126            {
127              let plane = planes_iter.next().unwrap();
128              let rect = luma_rect.decimated(plane.cfg.xdec, plane.cfg.ydec);
129              $pr_type::new(plane, rect.into())
130            },
131          ],
132        }
133      }
134
135      /// Return a view to a subregion of a Tile
136      ///
137      /// The subregion must be included in (i.e. must not exceed) this Tile.
138      ///
139      /// It is described by an `Area`, relative to the luma plane of
140      /// this region.
141      ///
142      /// # Panics
143      ///
144      /// - If the requested dimensions are larger than the plane size
145      #[inline(always)]
146      pub fn subregion(&self, area: Area) -> Tile<'_, T> {
147        let tile_rect = area.to_rect(
148          0,
149          0,
150          self.planes[0].rect().width,
151          self.planes[0].rect().height,
152        );
153        Tile {
154          planes: {
155            let sub_plane = |pli: usize| {
156              let plane = &self.planes[pli];
157              let &PlaneConfig { xdec, ydec, .. } = plane.plane_cfg;
158              let rect = tile_rect.decimated(xdec, ydec);
159              if !plane.is_null() {
160                assert!(rect.x >= 0 && rect.x as usize <= plane.rect().width);
161                assert!(rect.y >= 0 && rect.y as usize <= plane.rect().height);
162                assert!(rect.x as usize + rect.width <=
163                        plane.rect().x as usize + plane.rect().width);
164                assert!(rect.y as usize + rect.height <=
165                        plane.rect().y as usize + plane.rect().height);
166              }
167              plane.subregion(rect.to_area())
168            };
169            [sub_plane(0), sub_plane(1), sub_plane(2)]
170          },
171        }
172      }
173
174      // Return an equivalent Tile with origin homed to 0,0.  Data
175      // pointer is not moved (0,0 points to the same pixel previously
176      // pointed to by old x,y).
177      #[inline(always)]
178      pub fn home(&self) -> Self {
179        Self {
180          planes: [
181            self.planes[0].home(),
182            self.planes[1].home(),
183            self.planes[2].home(),
184          ],
185        }
186      }
187
188      // Return a copy of this tile's contents in a new backing frame.
189      #[inline(always)]
190      pub(crate) fn scratch_copy(&self) -> Frame<T> {
191        Frame {
192          planes: [
193            self.planes[0].scratch_copy(),
194            self.planes[1].scratch_copy(),
195            self.planes[2].scratch_copy(),
196          ],
197        }
198      }
199    }
200  }
201}
202
203tile_common!(Tile, PlaneRegion, iter);
204tile_common!(TileMut, PlaneRegionMut, iter_mut, mut);
205
206impl<'a, T: Pixel> TileMut<'a, T> {
207  #[inline(always)]
208  pub fn as_const(&self) -> Tile<'_, T> {
209    Tile {
210      planes: [
211        self.planes[0].as_const(),
212        self.planes[1].as_const(),
213        self.planes[2].as_const(),
214      ],
215    }
216  }
217}