/src/avm/av2/common/tile_common.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, Alliance for Open Media. All rights reserved |
3 | | * |
4 | | * This source code is subject to the terms of the BSD 3-Clause Clear License |
5 | | * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
6 | | * License was not distributed with this source code in the LICENSE file, you |
7 | | * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the |
8 | | * Alliance for Open Media Patent License 1.0 was not distributed with this |
9 | | * source code in the PATENTS file, you can obtain it at |
10 | | * aomedia.org/license/patent-license/. |
11 | | */ |
12 | | |
13 | | #include "av2/common/av2_common_int.h" |
14 | | #include "av2/common/resize.h" |
15 | | #include "av2/common/tile_common.h" |
16 | | #include "avm_dsp/avm_dsp_common.h" |
17 | | |
18 | 245k | void av2_tile_init(TileInfo *tile, const AV2_COMMON *cm, int row, int col) { |
19 | 245k | av2_tile_set_row(tile, cm, row); |
20 | 245k | av2_tile_set_col(tile, cm, col); |
21 | 245k | } |
22 | | |
23 | | static int get_max_tile_width(int seq_level_idx, int seq_tier, int sb_size_log2, |
24 | 44.1k | int sb_cols) { |
25 | 44.1k | if (seq_level_idx == SEQ_LEVEL_MAX) { |
26 | 1.35k | return sb_cols; |
27 | 1.35k | } |
28 | 42.8k | const int tier = (seq_tier > 0) ? 1 : 0; |
29 | 42.8k | const int scaling_factor = av2_tile_width_scaling_factor[tier][seq_level_idx]; |
30 | 42.8k | return (scaling_factor * MAX_TILE_WIDTH >> (sb_size_log2 + 2)); |
31 | 44.1k | } |
32 | | |
33 | | static int get_max_tile_area(int seq_level_idx, int seq_tier, int sb_size_log2, |
34 | 44.1k | int sb_cols, int sb_rows) { |
35 | 44.1k | if (seq_level_idx == SEQ_LEVEL_MAX) { |
36 | 1.35k | return sb_cols * sb_rows; |
37 | 1.35k | } |
38 | 42.8k | const int tier = (seq_tier > 0) ? 1 : 0; |
39 | 42.8k | const int scaling_factor = av2_tile_area_scaling_factor[tier][seq_level_idx]; |
40 | 42.8k | return (scaling_factor * MAX_TILE_AREA) >> (2 * sb_size_log2 + 2); |
41 | 44.1k | } |
42 | | |
43 | | void av2_get_tile_limits(CommonTileParams *const tiles, int cm_mi_rows, |
44 | | int cm_mi_cols, int mib_size_log2, |
45 | | int seq_mib_size_log2, int seq_level_idx, |
46 | 44.1k | int seq_tier) { |
47 | 44.1k | tiles->mib_size_log2 = mib_size_log2; |
48 | 44.1k | tiles->mi_rows = cm_mi_rows; |
49 | 44.1k | tiles->mi_cols = cm_mi_cols; |
50 | 44.1k | tiles->scale_sb = seq_mib_size_log2 - mib_size_log2; |
51 | 44.1k | assert(tiles->scale_sb <= 1); |
52 | 44.1k | const int mi_cols = ALIGN_POWER_OF_TWO(tiles->mi_cols, mib_size_log2); |
53 | 44.1k | const int mi_rows = ALIGN_POWER_OF_TWO(tiles->mi_rows, mib_size_log2); |
54 | 44.1k | const int sb_cols = mi_cols >> mib_size_log2; |
55 | 44.1k | const int sb_rows = mi_rows >> mib_size_log2; |
56 | 44.1k | tiles->sb_rows = sb_rows; |
57 | 44.1k | tiles->sb_cols = sb_cols; |
58 | | |
59 | 44.1k | const int sb_size_log2 = mib_size_log2 + MI_SIZE_LOG2; |
60 | 44.1k | tiles->max_width_sb = |
61 | 44.1k | get_max_tile_width(seq_level_idx, seq_tier, sb_size_log2, sb_cols); |
62 | 44.1k | const int max_tile_area_sb = get_max_tile_area( |
63 | 44.1k | seq_level_idx, seq_tier, sb_size_log2, sb_cols, sb_rows); |
64 | | |
65 | 44.1k | tiles->min_log2_cols = tile_log2(tiles->max_width_sb, sb_cols); |
66 | 44.1k | tiles->max_log2_cols = tile_log2(1, AVMMIN(sb_cols, MAX_TILE_COLS)); |
67 | 44.1k | tiles->max_log2_rows = tile_log2(1, AVMMIN(sb_rows, MAX_TILE_ROWS)); |
68 | 44.1k | tiles->min_log2 = tile_log2(max_tile_area_sb, sb_cols * sb_rows); |
69 | 44.1k | tiles->min_log2 = AVMMAX(tiles->min_log2, tiles->min_log2_cols); |
70 | 44.1k | } |
71 | | |
72 | | void av2_get_seq_tile_limits(TileInfoSyntax *const tiles, int frame_height, |
73 | | int frame_width, int mib_size_log2, |
74 | | int seq_mib_size_log2, int seq_level_idx, |
75 | 20.1k | int seq_tier) { |
76 | 20.1k | const int cm_mi_rows = ALIGN_POWER_OF_TWO(frame_height, 3) >> MI_SIZE_LOG2; |
77 | 20.1k | const int cm_mi_cols = ALIGN_POWER_OF_TWO(frame_width, 3) >> MI_SIZE_LOG2; |
78 | 20.1k | av2_get_tile_limits(&tiles->tile_info, cm_mi_rows, cm_mi_cols, mib_size_log2, |
79 | 20.1k | seq_mib_size_log2, seq_level_idx, seq_tier); |
80 | 20.1k | } |
81 | | |
82 | 44.1k | void av2_calculate_tile_cols(CommonTileParams *const tiles) { |
83 | 44.1k | const int mib_size_log2 = tiles->mib_size_log2; |
84 | 44.1k | int mi_cols = ALIGN_POWER_OF_TWO(tiles->mi_cols, mib_size_log2); |
85 | 44.1k | int mi_rows = ALIGN_POWER_OF_TWO(tiles->mi_rows, mib_size_log2); |
86 | 44.1k | int sb_cols = mi_cols >> mib_size_log2; |
87 | 44.1k | int sb_rows = mi_rows >> mib_size_log2; |
88 | 44.1k | int i; |
89 | | |
90 | | // This will be overridden if there is at least two columns of tiles |
91 | | // (otherwise there is no inner tile width) |
92 | 44.1k | tiles->min_inner_width = -1; |
93 | | |
94 | 44.1k | if (tiles->uniform_spacing) { |
95 | 21.6k | const int sb_size_scale = tiles->scale_sb; |
96 | 21.6k | const int seq_mib_size_log2 = mib_size_log2 + sb_size_scale; |
97 | | |
98 | | // Use sequence level sb_size to calculate the tile size. |
99 | 21.6k | const int seq_sb_cols = |
100 | 21.6k | ALIGN_POWER_OF_TWO(tiles->mi_cols, seq_mib_size_log2) >> |
101 | 21.6k | seq_mib_size_log2; |
102 | 21.6k | const int full_sb_cols = tiles->mi_cols >> seq_mib_size_log2; |
103 | 21.6k | const int base_size_sb = full_sb_cols >> tiles->log2_cols; |
104 | 21.6k | int extra_sbs = full_sb_cols - (base_size_sb << tiles->log2_cols); |
105 | 21.6k | if (base_size_sb == 0) extra_sbs += seq_sb_cols - full_sb_cols; |
106 | 21.6k | int start_sb; |
107 | 21.6k | const int size_sb = |
108 | 21.6k | full_sb_cols > 0 ? ((base_size_sb + (extra_sbs > 0)) << sb_size_scale) |
109 | 21.6k | : 1; |
110 | 21.6k | assert(size_sb > 0); |
111 | 21.6k | for (i = 0, start_sb = 0; |
112 | 108k | start_sb < seq_sb_cols && i < (1 << tiles->log2_cols); i++) { |
113 | 87.1k | tiles->col_start_sb[i] = (start_sb << sb_size_scale); |
114 | 87.1k | start_sb += base_size_sb + (extra_sbs > 0); |
115 | 87.1k | if (extra_sbs > 0) extra_sbs--; |
116 | 87.1k | } |
117 | 21.6k | tiles->cols = i; |
118 | 21.6k | tiles->log2_cols = tile_log2(1, tiles->cols); |
119 | 21.6k | tiles->col_start_sb[i] = sb_cols; |
120 | 21.6k | tiles->min_log2_rows = AVMMAX(tiles->min_log2 - tiles->log2_cols, 0); |
121 | 21.6k | tiles->max_height_sb = sb_rows >> tiles->min_log2_rows; |
122 | | |
123 | 21.6k | tiles->width = size_sb << mib_size_log2; |
124 | 21.6k | tiles->width = AVMMIN(tiles->width, tiles->mi_cols); |
125 | 21.6k | if (tiles->cols > 1) { |
126 | 6.12k | tiles->min_inner_width = tiles->width; |
127 | 6.12k | } |
128 | 22.4k | } else { |
129 | 22.4k | int max_tile_area_sb = (sb_rows * sb_cols); |
130 | 22.4k | int widest_tile_sb = 1; |
131 | 22.4k | int narrowest_inner_tile_sb = 65536; |
132 | 22.4k | tiles->log2_cols = tile_log2(1, tiles->cols); |
133 | 49.6k | for (i = 0; i < tiles->cols; i++) { |
134 | 27.2k | int size_sb = tiles->col_start_sb[i + 1] - tiles->col_start_sb[i]; |
135 | 27.2k | widest_tile_sb = AVMMAX(widest_tile_sb, size_sb); |
136 | | // ignore the rightmost tile in frame for determining the narrowest |
137 | 27.2k | if (i < tiles->cols - 1) |
138 | 4.77k | narrowest_inner_tile_sb = AVMMIN(narrowest_inner_tile_sb, size_sb); |
139 | 27.2k | } |
140 | 22.4k | if (tiles->min_log2) { |
141 | 43 | max_tile_area_sb >>= (tiles->min_log2 + 1); |
142 | 43 | } |
143 | 22.4k | tiles->max_height_sb = AVMMAX(max_tile_area_sb / widest_tile_sb, 1); |
144 | 22.4k | if (tiles->cols > 1) { |
145 | 1.06k | tiles->min_inner_width = narrowest_inner_tile_sb << mib_size_log2; |
146 | 1.06k | } |
147 | 22.4k | } |
148 | 44.1k | } |
149 | | |
150 | 44.1k | void av2_calculate_tile_rows(CommonTileParams *const tiles) { |
151 | 44.1k | const int mib_size_log2 = tiles->mib_size_log2; |
152 | 44.1k | int mi_rows = ALIGN_POWER_OF_TWO(tiles->mi_rows, mib_size_log2); |
153 | 44.1k | int sb_rows = mi_rows >> mib_size_log2; |
154 | 44.1k | int start_sb, size_sb, i; |
155 | | |
156 | 44.1k | if (tiles->uniform_spacing) { |
157 | 21.6k | const int sb_size_scale = tiles->scale_sb; |
158 | 21.6k | const int seq_mib_size_log2 = mib_size_log2 + sb_size_scale; |
159 | | |
160 | | // Use sequence level sb_size to calculate the tile size. |
161 | 21.6k | const int seq_sb_rows = |
162 | 21.6k | ALIGN_POWER_OF_TWO(tiles->mi_rows, seq_mib_size_log2) >> |
163 | 21.6k | seq_mib_size_log2; |
164 | 21.6k | const int full_sb_rows = tiles->mi_rows >> seq_mib_size_log2; |
165 | 21.6k | const int base_size_sb = full_sb_rows >> tiles->log2_rows; |
166 | 21.6k | int extra_sbs = full_sb_rows - (base_size_sb << tiles->log2_rows); |
167 | 21.6k | if (base_size_sb == 0) extra_sbs += seq_sb_rows - full_sb_rows; |
168 | 21.6k | size_sb = full_sb_rows > 0 |
169 | 21.6k | ? ((base_size_sb + (extra_sbs > 0)) << sb_size_scale) |
170 | 21.6k | : 1; |
171 | 21.6k | assert(size_sb > 0); |
172 | 21.6k | for (i = 0, start_sb = 0; |
173 | 109k | start_sb < seq_sb_rows && i < (1 << tiles->log2_rows); i++) { |
174 | 88.0k | tiles->row_start_sb[i] = (start_sb << sb_size_scale); |
175 | 88.0k | start_sb += base_size_sb + (extra_sbs > 0); |
176 | 88.0k | if (extra_sbs > 0) extra_sbs--; |
177 | 88.0k | } |
178 | 21.6k | tiles->rows = i; |
179 | 21.6k | tiles->log2_rows = tile_log2(1, tiles->rows); |
180 | 21.6k | tiles->row_start_sb[i] = sb_rows; |
181 | | |
182 | 21.6k | tiles->height = size_sb << mib_size_log2; |
183 | 21.6k | tiles->height = AVMMIN(tiles->height, tiles->mi_rows); |
184 | 22.4k | } else { |
185 | 22.4k | tiles->log2_rows = tile_log2(1, tiles->rows); |
186 | 22.4k | } |
187 | 44.1k | } |
188 | | |
189 | 302k | void av2_tile_set_row(TileInfo *tile, const AV2_COMMON *cm, int row) { |
190 | 302k | assert(row < cm->tiles.rows); |
191 | 302k | int mi_row_start = cm->tiles.row_start_sb[row] << cm->mib_size_log2; |
192 | 302k | int mi_row_end = cm->tiles.row_start_sb[row + 1] << cm->mib_size_log2; |
193 | 302k | tile->tile_row = row; |
194 | 302k | tile->mi_row_start = mi_row_start; |
195 | 302k | tile->mi_row_end = AVMMIN(mi_row_end, cm->mi_params.mi_rows); |
196 | 302k | assert(tile->mi_row_end > tile->mi_row_start); |
197 | 302k | } |
198 | | |
199 | 302k | void av2_tile_set_col(TileInfo *tile, const AV2_COMMON *cm, int col) { |
200 | 302k | assert(col < cm->tiles.cols); |
201 | 302k | int mi_col_start = cm->tiles.col_start_sb[col] << cm->mib_size_log2; |
202 | 302k | int mi_col_end = cm->tiles.col_start_sb[col + 1] << cm->mib_size_log2; |
203 | 302k | tile->tile_col = col; |
204 | 302k | tile->mi_col_start = mi_col_start; |
205 | 302k | tile->mi_col_end = AVMMIN(mi_col_end, cm->mi_params.mi_cols); |
206 | 302k | assert(tile->mi_col_end > tile->mi_col_start); |
207 | 302k | } |
208 | | |
209 | 0 | int av2_get_sb_rows_in_tile(AV2_COMMON *cm, TileInfo tile) { |
210 | 0 | int mi_rows_aligned_to_sb = ALIGN_POWER_OF_TWO( |
211 | 0 | tile.mi_row_end - tile.mi_row_start, cm->mib_size_log2); |
212 | 0 | int sb_rows = mi_rows_aligned_to_sb >> cm->mib_size_log2; |
213 | |
|
214 | 0 | return sb_rows; |
215 | 0 | } |
216 | | |
217 | 0 | int av2_get_sb_cols_in_tile(AV2_COMMON *cm, TileInfo tile) { |
218 | 0 | int mi_cols_aligned_to_sb = ALIGN_POWER_OF_TWO( |
219 | 0 | tile.mi_col_end - tile.mi_col_start, cm->mib_size_log2); |
220 | 0 | int sb_cols = mi_cols_aligned_to_sb >> cm->mib_size_log2; |
221 | |
|
222 | 0 | return sb_cols; |
223 | 0 | } |
224 | | |
225 | | AV2PixelRect av2_get_tile_rect(const TileInfo *tile_info, const AV2_COMMON *cm, |
226 | 133k | int is_uv) { |
227 | 133k | AV2PixelRect r; |
228 | | |
229 | | // Calculate position in the Y plane |
230 | 133k | r.left = tile_info->mi_col_start * MI_SIZE; |
231 | 133k | r.right = tile_info->mi_col_end * MI_SIZE; |
232 | 133k | r.top = tile_info->mi_row_start * MI_SIZE; |
233 | 133k | r.bottom = tile_info->mi_row_end * MI_SIZE; |
234 | | |
235 | 133k | const int frame_w = cm->mi_params.mi_cols * MI_SIZE; |
236 | 133k | const int frame_h = cm->mi_params.mi_rows * MI_SIZE; |
237 | | // Make sure we don't fall off the bottom-right of the frame. |
238 | 133k | r.right = AVMMIN(r.right, frame_w); |
239 | 133k | r.bottom = AVMMIN(r.bottom, frame_h); |
240 | | |
241 | | // Convert to coordinates in the appropriate plane |
242 | 133k | const int ss_x = is_uv && cm->seq_params.subsampling_x; |
243 | 133k | const int ss_y = is_uv && cm->seq_params.subsampling_y; |
244 | | |
245 | 133k | r.left = ROUND_POWER_OF_TWO(r.left, ss_x); |
246 | 133k | r.right = ROUND_POWER_OF_TWO(r.right, ss_x); |
247 | 133k | r.top = ROUND_POWER_OF_TWO(r.top, ss_y); |
248 | 133k | r.bottom = ROUND_POWER_OF_TWO(r.bottom, ss_y); |
249 | | |
250 | 133k | return r; |
251 | 133k | } |
252 | | |
253 | 0 | void av2_get_uniform_tile_size(const AV2_COMMON *cm, int *w, int *h) { |
254 | 0 | const CommonTileParams *const tiles = &cm->tiles; |
255 | 0 | if (tiles->uniform_spacing) { |
256 | 0 | *w = tiles->width; |
257 | 0 | *h = tiles->height; |
258 | 0 | } else { |
259 | 0 | for (int i = 0; i < tiles->cols; ++i) { |
260 | 0 | const int tile_width_sb = |
261 | 0 | tiles->col_start_sb[i + 1] - tiles->col_start_sb[i]; |
262 | 0 | const int tile_w = tile_width_sb * cm->mib_size; |
263 | 0 | assert(i == 0 || tile_w == *w); // ensure all tiles have same dimension |
264 | 0 | *w = tile_w; |
265 | 0 | } |
266 | |
|
267 | 0 | for (int i = 0; i < tiles->rows; ++i) { |
268 | 0 | const int tile_height_sb = |
269 | 0 | tiles->row_start_sb[i + 1] - tiles->row_start_sb[i]; |
270 | 0 | const int tile_h = tile_height_sb * cm->mib_size; |
271 | 0 | assert(i == 0 || tile_h == *h); // ensure all tiles have same dimension |
272 | 0 | *h = tile_h; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | 24.0k | int av2_is_min_tile_width_satisfied(const AV2_COMMON *cm) { |
278 | | // Disable check if there is a single tile col in the frame |
279 | 24.0k | if (cm->tiles.cols == 1) return 1; |
280 | | |
281 | 2.97k | return (cm->tiles.min_inner_width << MI_SIZE_LOG2) >= 64; |
282 | 24.0k | } |
283 | | |
284 | 34.9k | int get_tile_row_from_mi_row(const CommonTileParams *tiles, int mi_row) { |
285 | 34.9k | int row = 0; |
286 | 59.9k | for (row = 0; row < tiles->rows; ++row) { |
287 | 59.9k | if (mi_row >= (tiles->row_start_sb[row] << tiles->mib_size_log2) && |
288 | 59.9k | mi_row < (tiles->row_start_sb[row + 1] << tiles->mib_size_log2)) |
289 | 35.0k | break; |
290 | 59.9k | } |
291 | 34.9k | return row; |
292 | 34.9k | } |
293 | | |
294 | 35.0k | int get_tile_col_from_mi_col(const CommonTileParams *tiles, int mi_col) { |
295 | 35.0k | int col = 0; |
296 | 48.8k | for (col = 0; col < tiles->cols; ++col) { |
297 | 48.8k | if (mi_col >= (tiles->col_start_sb[col] << tiles->mib_size_log2) && |
298 | 48.8k | mi_col < (tiles->col_start_sb[col + 1] << tiles->mib_size_log2)) |
299 | 35.0k | break; |
300 | 48.8k | } |
301 | 35.0k | return col; |
302 | 35.0k | } |
303 | | |
304 | 1.03M | int is_vert_tile_boundary(CommonTileParams *const tiles, int mi_col) { |
305 | 1.91M | for (int col = 0; col < tiles->cols; ++col) { |
306 | 1.03M | const int mi_col_start = tiles->col_start_sb[col] << tiles->mib_size_log2; |
307 | 1.03M | if (mi_col == mi_col_start) |
308 | 145k | return 1; |
309 | 884k | else if (mi_col < mi_col_start) |
310 | 0 | return 0; |
311 | 1.03M | } |
312 | 884k | return 0; |
313 | 1.03M | } |
314 | | |
315 | 869k | int is_horz_tile_boundary(CommonTileParams *const tiles, int mi_row) { |
316 | 1.69M | for (int row = 0; row < tiles->rows; ++row) { |
317 | 869k | const int mi_row_start = tiles->row_start_sb[row] << tiles->mib_size_log2; |
318 | 869k | if (mi_row == mi_row_start) |
319 | 42.4k | return 1; |
320 | 826k | else if (mi_row < mi_row_start) |
321 | 0 | return 0; |
322 | 869k | } |
323 | 826k | return 0; |
324 | 869k | } |