Coverage Report

Created: 2026-10-17 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}