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}
218