| 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 | |
| 10 | use crate::context::*; |
| 11 | use crate::mc::MotionVector; |
| 12 | use crate::partition::*; |
| 13 | use crate::predict::PredictionMode; |
| 14 | use crate::transform::*; |
| 15 | |
| 16 | use std::cmp; |
| 17 | use std::marker::PhantomData; |
| 18 | use std::ops::{Index, IndexMut}; |
| 19 | use std::slice; |
| 20 | |
| 21 | /// Tiled view of `FrameBlocks` |
| 22 | #[derive (Debug)] |
| 23 | pub struct TileBlocks<'a> { |
| 24 | data: *const Block, |
| 25 | x: usize, |
| 26 | y: usize, |
| 27 | cols: usize, |
| 28 | rows: usize, |
| 29 | frame_cols: usize, |
| 30 | frame_rows: usize, |
| 31 | phantom: PhantomData<&'a Block>, |
| 32 | } |
| 33 | |
| 34 | /// Mutable tiled view of `FrameBlocks` |
| 35 | #[derive (Debug)] |
| 36 | pub struct TileBlocksMut<'a> { |
| 37 | data: *mut Block, |
| 38 | // private to guarantee borrowing rules |
| 39 | x: usize, |
| 40 | y: usize, |
| 41 | cols: usize, |
| 42 | rows: usize, |
| 43 | frame_cols: usize, |
| 44 | frame_rows: usize, |
| 45 | phantom: PhantomData<&'a mut Block>, |
| 46 | } |
| 47 | |
| 48 | // common impl for TileBlocks and TileBlocksMut |
| 49 | macro_rules! tile_blocks_common { |
| 50 | // $name: TileBlocks or TileBlocksMut |
| 51 | // $opt_mut: nothing or mut |
| 52 | ($name:ident $(,$opt_mut:tt)?) => { |
| 53 | impl<'a> $name<'a> { |
| 54 | |
| 55 | #[inline(always)] |
| 56 | pub fn new( |
| 57 | frame_blocks: &'a $($opt_mut)? FrameBlocks, |
| 58 | x: usize, |
| 59 | y: usize, |
| 60 | cols: usize, |
| 61 | rows: usize, |
| 62 | ) -> Self { |
| 63 | Self { |
| 64 | data: & $($opt_mut)? frame_blocks[y][x], |
| 65 | x, |
| 66 | y, |
| 67 | cols, |
| 68 | rows, |
| 69 | frame_cols: frame_blocks.cols, |
| 70 | frame_rows: frame_blocks.rows, |
| 71 | phantom: PhantomData, |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | pub fn subregion( |
| 76 | &mut self, |
| 77 | x: usize, |
| 78 | y: usize, |
| 79 | cols: usize, |
| 80 | rows: usize, |
| 81 | ) -> TileBlocks<'_> { |
| 82 | TileBlocks { |
| 83 | data: &self[y][x], |
| 84 | x: self.x+x, |
| 85 | y: self.y+y, |
| 86 | cols: cmp::min(cols, self.cols - x), |
| 87 | rows: cmp::min(rows, self.rows - y), |
| 88 | frame_cols: self.frame_cols, |
| 89 | frame_rows: self.frame_rows, |
| 90 | phantom: PhantomData, |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | #[inline(always)] |
| 95 | pub const fn x(&self) -> usize { |
| 96 | self.x |
| 97 | } |
| 98 | |
| 99 | #[inline(always)] |
| 100 | pub const fn y(&self) -> usize { |
| 101 | self.y |
| 102 | } |
| 103 | |
| 104 | #[inline(always)] |
| 105 | pub const fn cols(&self) -> usize { |
| 106 | self.cols |
| 107 | } |
| 108 | |
| 109 | #[inline(always)] |
| 110 | pub const fn rows(&self) -> usize { |
| 111 | self.rows |
| 112 | } |
| 113 | |
| 114 | #[inline(always)] |
| 115 | pub const fn frame_cols(&self) -> usize { |
| 116 | self.frame_cols |
| 117 | } |
| 118 | |
| 119 | #[inline(always)] |
| 120 | pub const fn frame_rows(&self) -> usize { |
| 121 | self.frame_rows |
| 122 | } |
| 123 | |
| 124 | #[inline(always)] |
| 125 | pub fn above_of(&self, bo: TileBlockOffset) -> &Block { |
| 126 | &self[bo.0.y - 1][bo.0.x] |
| 127 | } |
| 128 | |
| 129 | #[inline(always)] |
| 130 | pub fn left_of(&self, bo: TileBlockOffset) -> &Block { |
| 131 | &self[bo.0.y][bo.0.x - 1] |
| 132 | } |
| 133 | |
| 134 | #[inline(always)] |
| 135 | pub fn above_left_of(&self, bo: TileBlockOffset) -> &Block { |
| 136 | &self[bo.0.y - 1][bo.0.x - 1] |
| 137 | } |
| 138 | |
| 139 | pub fn get_cdef(&self, sbo: TileSuperBlockOffset) -> u8 { |
| 140 | let bo = sbo.block_offset(0, 0).0; |
| 141 | self[bo.y][bo.x].cdef_index |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | unsafe impl Send for $name<'_> {} |
| 146 | unsafe impl Sync for $name<'_> {} |
| 147 | |
| 148 | impl Index<usize> for $name<'_> { |
| 149 | type Output = [Block]; |
| 150 | #[inline(always)] |
| 151 | fn index(&self, index: usize) -> &Self::Output { |
| 152 | assert!(index < self.rows); |
| 153 | // SAFETY: The above assert ensures we do not access OOB data. |
| 154 | unsafe { |
| 155 | let ptr = self.data.add(index * self.frame_cols); |
| 156 | slice::from_raw_parts(ptr, self.cols) |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | // for convenience, also index by TileBlockOffset |
| 162 | impl Index<TileBlockOffset> for $name<'_> { |
| 163 | type Output = Block; |
| 164 | #[inline(always)] |
| 165 | fn index(&self, bo: TileBlockOffset) -> &Self::Output { |
| 166 | &self[bo.0.y][bo.0.x] |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | tile_blocks_common!(TileBlocks); |
| 173 | tile_blocks_common!(TileBlocksMut, mut); |
| 174 | |
| 175 | impl TileBlocksMut<'_> { |
| 176 | #[inline (always)] |
| 177 | pub const fn as_const(&self) -> TileBlocks<'_> { |
| 178 | TileBlocks { |
| 179 | data: self.data, |
| 180 | x: self.x, |
| 181 | y: self.y, |
| 182 | cols: self.cols, |
| 183 | rows: self.rows, |
| 184 | frame_cols: self.frame_cols, |
| 185 | frame_rows: self.frame_rows, |
| 186 | phantom: PhantomData, |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | pub fn subregion_mut( |
| 191 | &mut self, x: usize, y: usize, cols: usize, rows: usize, |
| 192 | ) -> TileBlocksMut<'_> { |
| 193 | TileBlocksMut { |
| 194 | data: &mut self[y][x], |
| 195 | x: self.x + x, |
| 196 | y: self.y + y, |
| 197 | cols: cmp::min(cols, self.cols - x), |
| 198 | rows: cmp::min(rows, self.rows - y), |
| 199 | frame_cols: self.frame_cols, |
| 200 | frame_rows: self.frame_rows, |
| 201 | phantom: PhantomData, |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | #[inline (always)] |
| 206 | pub fn for_each<F>(&mut self, bo: TileBlockOffset, bsize: BlockSize, f: F) |
| 207 | where |
| 208 | F: Fn(&mut Block), |
| 209 | { |
| 210 | let mut bw = bsize.width_mi(); |
| 211 | let bh = bsize.height_mi(); |
| 212 | |
| 213 | if bo.0.x + bw >= self.cols { |
| 214 | bw = self.cols - bo.0.x; |
| 215 | } |
| 216 | for y in 0..bh { |
| 217 | if bo.0.y + y >= self.rows { |
| 218 | continue; |
| 219 | } |
| 220 | for block in self[bo.0.y + y][bo.0.x..bo.0.x + bw].iter_mut() { |
| 221 | f(block); |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | #[inline (always)] |
| 227 | pub fn set_mode( |
| 228 | &mut self, bo: TileBlockOffset, bsize: BlockSize, mode: PredictionMode, |
| 229 | ) { |
| 230 | self.for_each(bo, bsize, |block| block.mode = mode); |
| 231 | } |
| 232 | |
| 233 | #[inline (always)] |
| 234 | pub fn set_block_size(&mut self, bo: TileBlockOffset, bsize: BlockSize) { |
| 235 | let n4_w = bsize.width_mi() as u8; |
| 236 | let n4_h = bsize.height_mi() as u8; |
| 237 | self.for_each(bo, bsize, |block| { |
| 238 | block.bsize = bsize; |
| 239 | block.n4_w = n4_w; |
| 240 | block.n4_h = n4_h; |
| 241 | }); |
| 242 | } |
| 243 | |
| 244 | #[inline (always)] |
| 245 | pub fn set_tx_size( |
| 246 | &mut self, bo: TileBlockOffset, bsize: BlockSize, tx_size: TxSize, |
| 247 | ) { |
| 248 | self.for_each(bo, bsize, |block| block.txsize = tx_size); |
| 249 | } |
| 250 | |
| 251 | #[inline (always)] |
| 252 | pub fn set_skip( |
| 253 | &mut self, bo: TileBlockOffset, bsize: BlockSize, skip: bool, |
| 254 | ) { |
| 255 | self.for_each(bo, bsize, |block| block.skip = skip); |
| 256 | } |
| 257 | |
| 258 | #[inline (always)] |
| 259 | pub fn set_segmentation_idx( |
| 260 | &mut self, bo: TileBlockOffset, bsize: BlockSize, idx: u8, |
| 261 | ) { |
| 262 | self.for_each(bo, bsize, |block| block.segmentation_idx = idx); |
| 263 | } |
| 264 | |
| 265 | #[inline (always)] |
| 266 | pub fn set_ref_frames( |
| 267 | &mut self, bo: TileBlockOffset, bsize: BlockSize, r: [RefType; 2], |
| 268 | ) { |
| 269 | self.for_each(bo, bsize, |block| block.ref_frames = r); |
| 270 | } |
| 271 | |
| 272 | #[inline (always)] |
| 273 | pub fn set_motion_vectors( |
| 274 | &mut self, bo: TileBlockOffset, bsize: BlockSize, mvs: [MotionVector; 2], |
| 275 | ) { |
| 276 | self.for_each(bo, bsize, |block| block.mv = mvs); |
| 277 | } |
| 278 | |
| 279 | #[inline (always)] |
| 280 | pub fn set_cdef(&mut self, sbo: TileSuperBlockOffset, cdef_index: u8) { |
| 281 | let bo = sbo.block_offset(0, 0).0; |
| 282 | // Checkme: Is 16 still the right block unit for 128x128 superblocks? |
| 283 | let bw = cmp::min(bo.x + MIB_SIZE, self.cols); |
| 284 | let bh = cmp::min(bo.y + MIB_SIZE, self.rows); |
| 285 | for y in bo.y..bh { |
| 286 | for x in bo.x..bw { |
| 287 | self[y][x].cdef_index = cdef_index; |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | impl IndexMut<usize> for TileBlocksMut<'_> { |
| 294 | #[inline (always)] |
| 295 | fn index_mut(&mut self, index: usize) -> &mut Self::Output { |
| 296 | assert!(index < self.rows); |
| 297 | // SAFETY: The above assert ensures we do not access OOB data. |
| 298 | unsafe { |
| 299 | let ptr: *mut Block = self.data.add(count:index * self.frame_cols); |
| 300 | slice::from_raw_parts_mut(data:ptr, self.cols) |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | impl IndexMut<TileBlockOffset> for TileBlocksMut<'_> { |
| 306 | #[inline (always)] |
| 307 | fn index_mut(&mut self, bo: TileBlockOffset) -> &mut Self::Output { |
| 308 | &mut self[bo.0.y][bo.0.x] |
| 309 | } |
| 310 | } |
| 311 | |