Coverage Report

Created: 2026-10-28 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/avm/av2/common/blockd.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 <assert.h>
14
#include <math.h>
15
16
#include "avm_ports/system_state.h"
17
18
#include "av2/common/av2_common_int.h"
19
#include "av2/common/blockd.h"
20
#include "av2/common/enums.h"
21
22
3.54M
PREDICTION_MODE av2_get_joint_mode(const MB_MODE_INFO *mi) {
23
3.54M
  if (!mi) return DC_PRED;
24
3.08M
  if (is_inter_block(mi, SHARED_PART) || is_intrabc_block(mi, SHARED_PART))
25
12.9k
    return DC_PRED;
26
3.07M
  return mi->joint_y_mode_delta_angle;
27
3.08M
}
28
29
139k
void av2_reset_is_mi_coded_map(MACROBLOCKD *xd, int stride) {
30
139k
  av2_zero(xd->is_mi_coded);
31
139k
  xd->is_mi_coded_stride = stride;
32
139k
}
33
34
void av2_mark_block_as_coded(MACROBLOCKD *xd, BLOCK_SIZE bsize,
35
1.13M
                             BLOCK_SIZE sb_size) {
36
1.13M
  const int mi_row = xd->mi_row;
37
1.13M
  const int mi_col = xd->mi_col;
38
1.13M
  const int sb_mi_size = mi_size_wide[sb_size];
39
1.13M
  const int mi_row_offset = mi_row & (sb_mi_size - 1);
40
1.13M
  const int mi_col_offset = mi_col & (sb_mi_size - 1);
41
42
9.06M
  for (int r = 0; r < mi_size_high[bsize]; ++r)
43
97.6M
    for (int c = 0; c < mi_size_wide[bsize]; ++c) {
44
89.6M
      const int pos =
45
89.6M
          (mi_row_offset + r) * xd->is_mi_coded_stride + mi_col_offset + c;
46
89.6M
      switch (xd->tree_type) {
47
58.3M
        case SHARED_PART:
48
58.3M
          xd->is_mi_coded[0][pos] = 1;
49
58.3M
          xd->is_mi_coded[1][pos] = 1;
50
58.3M
          break;
51
15.8M
        case LUMA_PART: xd->is_mi_coded[0][pos] = 1; break;
52
15.6M
        case CHROMA_PART: xd->is_mi_coded[1][pos] = 1; break;
53
0
        default: assert(0 && "Invalid tree type");
54
89.6M
      }
55
89.6M
    }
56
1.13M
}
57
58
void av2_mark_block_as_not_coded(MACROBLOCKD *xd, int mi_row, int mi_col,
59
0
                                 BLOCK_SIZE bsize, BLOCK_SIZE sb_size) {
60
0
  const int sb_mi_size = mi_size_wide[sb_size];
61
0
  const int mi_row_offset = mi_row & (sb_mi_size - 1);
62
0
  const int mi_col_offset = mi_col & (sb_mi_size - 1);
63
64
0
  for (int r = 0; r < mi_size_high[bsize]; ++r) {
65
0
    const int pos =
66
0
        (mi_row_offset + r) * xd->is_mi_coded_stride + mi_col_offset;
67
0
    uint8_t *row_ptr_luma = &xd->is_mi_coded[0][pos];
68
0
    uint8_t *row_ptr_chroma = &xd->is_mi_coded[1][pos];
69
0
    switch (xd->tree_type) {
70
0
      case SHARED_PART:
71
0
        av2_zero_array(row_ptr_luma, mi_size_wide[bsize]);
72
0
        av2_zero_array(row_ptr_chroma, mi_size_wide[bsize]);
73
0
        break;
74
0
      case LUMA_PART: av2_zero_array(row_ptr_luma, mi_size_wide[bsize]); break;
75
0
      case CHROMA_PART:
76
0
        av2_zero_array(row_ptr_chroma, mi_size_wide[bsize]);
77
0
        break;
78
0
      default: assert(0 && "Invalid tree type");
79
0
    }
80
0
  }
81
0
}
82
83
void av2_mark_block_as_pseudo_coded(MACROBLOCKD *xd, int mi_row, int mi_col,
84
63.0k
                                    BLOCK_SIZE bsize, BLOCK_SIZE sb_size) {
85
63.0k
  const int sb_mi_size = mi_size_wide[sb_size];
86
63.0k
  const int mi_row_offset = mi_row & (sb_mi_size - 1);
87
63.0k
  const int mi_col_offset = mi_col & (sb_mi_size - 1);
88
89
629k
  for (int r = 0; r < mi_size_high[bsize]; ++r)
90
6.53M
    for (int c = 0; c < mi_size_wide[bsize]; ++c) {
91
5.96M
      const int pos =
92
5.96M
          (mi_row_offset + r) * xd->is_mi_coded_stride + mi_col_offset + c;
93
5.96M
      switch (xd->tree_type) {
94
3.69M
        case SHARED_PART:
95
3.69M
          xd->is_mi_coded[0][pos] = 2;
96
3.69M
          xd->is_mi_coded[1][pos] = 2;
97
3.69M
          break;
98
1.14M
        case LUMA_PART: xd->is_mi_coded[0][pos] = 2; break;
99
1.14M
        case CHROMA_PART: xd->is_mi_coded[1][pos] = 2; break;
100
0
        default: assert(0 && "Invalid tree type");
101
5.96M
      }
102
5.96M
    }
103
63.0k
}
104
105
2.15M
PARTITION_TREE *av2_alloc_ptree_node(PARTITION_TREE *parent, int index) {
106
2.15M
  PARTITION_TREE *ptree = NULL;
107
2.15M
  struct avm_internal_error_info error;
108
109
2.15M
  AVM_CHECK_MEM_ERROR(&error, ptree, avm_calloc(1, sizeof(*ptree)));
110
111
2.15M
  ptree->parent = parent;
112
2.15M
  ptree->index = index;
113
2.15M
  ptree->partition = PARTITION_INVALID;
114
2.15M
  ptree->is_settled = 0;
115
10.7M
  for (int i = 0; i < 4; ++i) ptree->sub_tree[i] = NULL;
116
117
2.15M
  return ptree;
118
2.15M
}
119
120
9.45M
void av2_free_ptree_recursive(PARTITION_TREE *ptree) {
121
9.45M
  if (ptree == NULL) return;
122
123
10.8M
  for (int i = 0; i < 4; ++i) {
124
8.66M
    av2_free_ptree_recursive(ptree->sub_tree[i]);
125
8.66M
    ptree->sub_tree[i] = NULL;
126
8.66M
  }
127
128
2.16M
  avm_free(ptree);
129
2.16M
}
130
131
186k
void av2_reset_ptree_in_sbi(SB_INFO *sbi, TREE_TYPE tree_type) {
132
186k
  const int idx = av2_get_sdp_idx(tree_type);
133
186k
  if (sbi->ptree_root[idx]) av2_free_ptree_recursive(sbi->ptree_root[idx]);
134
135
186k
  sbi->ptree_root[idx] = av2_alloc_ptree_node(NULL, 0);
136
186k
}
137
138
void av2_set_entropy_contexts(const MACROBLOCKD *xd,
139
                              struct macroblockd_plane *pd, int plane,
140
                              BLOCK_SIZE plane_bsize, TX_SIZE tx_size,
141
4.50M
                              int has_eob, int aoff, int loff) {
142
4.50M
  ENTROPY_CONTEXT *const a = pd->above_entropy_context + aoff;
143
4.50M
  ENTROPY_CONTEXT *const l = pd->left_entropy_context + loff;
144
4.50M
  const int txs_wide = tx_size_wide_unit[tx_size];
145
4.50M
  const int txs_high = tx_size_high_unit[tx_size];
146
147
  // above
148
4.50M
  if (has_eob && xd->mb_to_right_edge < 0) {
149
4.38k
    const int blocks_wide = max_block_wide(xd, plane_bsize, plane);
150
4.38k
    const int above_contexts = AVMMIN(txs_wide, blocks_wide - aoff);
151
4.38k
    memset(a, has_eob, sizeof(*a) * above_contexts);
152
4.38k
    memset(a + above_contexts, 0, sizeof(*a) * (txs_wide - above_contexts));
153
4.50M
  } else {
154
4.50M
    memset(a, has_eob, sizeof(*a) * txs_wide);
155
4.50M
  }
156
157
  // left
158
4.50M
  if (has_eob && xd->mb_to_bottom_edge < 0) {
159
5.99k
    const int blocks_high = max_block_high(xd, plane_bsize, plane);
160
5.99k
    const int left_contexts = AVMMIN(txs_high, blocks_high - loff);
161
5.99k
    memset(l, has_eob, sizeof(*l) * left_contexts);
162
5.99k
    memset(l + left_contexts, 0, sizeof(*l) * (txs_high - left_contexts));
163
4.50M
  } else {
164
4.50M
    memset(l, has_eob, sizeof(*l) * txs_high);
165
4.50M
  }
166
4.50M
}
167
168
void av2_reset_entropy_context(MACROBLOCKD *xd, BLOCK_SIZE bsize,
169
46.3k
                               const int num_planes) {
170
  // TODO(chiyotsai): This part is needed to avoid encoder/decoder mismatch.
171
  // Investigate why this is the case. It seems like on the decoder side, the
172
  // decoder is failing to clear the context after encoding a skip_txfm chroma
173
  // block.
174
46.3k
  const int plane_start = (xd->tree_type == CHROMA_PART);
175
46.3k
  int plane_end = 0;
176
46.3k
  switch (xd->tree_type) {
177
3.20k
    case LUMA_PART: plane_end = 1; break;
178
0
    case CHROMA_PART: plane_end = num_planes; break;
179
43.1k
    case SHARED_PART:
180
43.1k
      plane_end = 1 + (num_planes - 1) * xd->is_chroma_ref;
181
43.1k
      break;
182
0
    default: assert(0);
183
46.3k
  }
184
134k
  for (int i = plane_start; i < plane_end; ++i) {
185
88.4k
    struct macroblockd_plane *const pd = &xd->plane[i];
186
88.4k
    const BLOCK_SIZE plane_bsize = get_mb_plane_block_size(
187
88.4k
        xd, xd->mi[0], i, pd->subsampling_x, pd->subsampling_y);
188
88.4k
    (void)bsize;
189
88.4k
    const int txs_wide = mi_size_wide[plane_bsize];
190
88.4k
    const int txs_high = mi_size_high[plane_bsize];
191
88.4k
    memset(pd->above_entropy_context, 0, sizeof(ENTROPY_CONTEXT) * txs_wide);
192
88.4k
    memset(pd->left_entropy_context, 0, sizeof(ENTROPY_CONTEXT) * txs_high);
193
88.4k
  }
194
46.3k
}
195
196
// Resets the LR decoding state before decoding each coded tile and
197
// associated LR coefficients
198
void av2_reset_loop_restoration(MACROBLOCKD *xd, int plane_start, int plane_end,
199
29.3k
                                const int *num_filter_classes) {
200
114k
  for (int p = plane_start; p < plane_end; ++p) {
201
85.1k
    av2_reset_wienerns_bank(&xd->wienerns_info[p], xd->current_base_qindex,
202
85.1k
                            num_filter_classes[p], p != AVM_PLANE_Y);
203
85.1k
  }
204
29.3k
}
205
206
// Initialize bank
207
void av2_reset_wienerns_bank(WienerNonsepInfoBank *bank, int qindex,
208
85.1k
                             int num_classes, int chroma) {
209
424k
  for (int i = 0; i < LR_BANK_SIZE; ++i) {
210
338k
    set_default_wienerns(&bank->filter[i], qindex, num_classes, chroma);
211
338k
  }
212
213
94.8k
  for (int c_id = 0; c_id < num_classes; ++c_id) {
214
9.62k
    bank->bank_size_for_class[c_id] = 0;
215
9.62k
    bank->bank_ptr_for_class[c_id] = 0;
216
9.62k
  }
217
85.1k
}
218
219
// Add a new filter to bank
220
void av2_add_to_wienerns_bank(WienerNonsepInfoBank *bank,
221
                              const WienerNonsepInfo *info,
222
36.0k
                              int wiener_class_id) {
223
36.0k
  int c_id_begin = wiener_class_id;
224
36.0k
  int c_id_end = wiener_class_id + 1;
225
36.0k
  if (wiener_class_id == ALL_WIENERNS_CLASSES) {
226
0
    c_id_begin = 0;
227
0
    c_id_end = info->num_classes;
228
0
  }
229
72.0k
  for (int c_id = c_id_begin; c_id < c_id_end; ++c_id) {
230
36.0k
    if (bank->bank_size_for_class[c_id] < LR_BANK_SIZE) {
231
34.9k
      bank->bank_ptr_for_class[c_id] = bank->bank_size_for_class[c_id];
232
34.9k
      bank->bank_size_for_class[c_id]++;
233
34.9k
    } else {
234
1.04k
      bank->bank_ptr_for_class[c_id] =
235
1.04k
          (bank->bank_ptr_for_class[c_id] + 1) % LR_BANK_SIZE;
236
1.04k
    }
237
36.0k
    copy_nsfilter_taps_for_class(&bank->filter[bank->bank_ptr_for_class[c_id]],
238
36.0k
                                 info, c_id);
239
36.0k
  }
240
36.0k
}
241
242
// Returns the filter that is at slot ndx from last. When ndx is zero the last
243
// filter added is returned. When ndx is one the filter added before the last
244
// and so on.
245
WienerNonsepInfo *av2_ref_from_wienerns_bank(WienerNonsepInfoBank *bank,
246
0
                                             int ndx, int wiener_class_id) {
247
0
  assert(wiener_class_id != ALL_WIENERNS_CLASSES);
248
0
  if (bank->bank_size_for_class[wiener_class_id] == 0) {
249
0
    assert(ndx == 0);
250
0
    return &bank->filter[0];
251
0
  } else {
252
0
    assert(ndx < bank->bank_size_for_class[wiener_class_id]);
253
0
    const int ptr =
254
0
        bank->bank_ptr_for_class[wiener_class_id] - ndx +
255
0
        (bank->bank_ptr_for_class[wiener_class_id] < ndx ? LR_BANK_SIZE : 0);
256
0
    return &bank->filter[ptr];
257
0
  }
258
0
}
259
260
// Get a const reference to a filter given the index
261
const WienerNonsepInfo *av2_constref_from_wienerns_bank(
262
37.9k
    const WienerNonsepInfoBank *bank, int ndx, int wiener_class_id) {
263
37.9k
  assert(wiener_class_id != ALL_WIENERNS_CLASSES);
264
37.9k
  if (bank->bank_size_for_class[wiener_class_id] == 0) {
265
2.19k
    return &bank->filter[0];
266
35.7k
  } else {
267
35.7k
    assert(ndx < bank->bank_size_for_class[wiener_class_id]);
268
35.7k
    const int ptr =
269
35.7k
        bank->bank_ptr_for_class[wiener_class_id] - ndx +
270
35.7k
        (bank->bank_ptr_for_class[wiener_class_id] < ndx ? LR_BANK_SIZE : 0);
271
35.7k
    return &bank->filter[ptr];
272
35.7k
  }
273
37.9k
}
274
275
// Directly replace a filter in the bank at given index
276
void av2_upd_to_wienerns_bank(WienerNonsepInfoBank *bank, int ndx,
277
                              const WienerNonsepInfo *info,
278
0
                              int wiener_class_id) {
279
0
  copy_nsfilter_taps_for_class(
280
0
      av2_ref_from_wienerns_bank(bank, ndx, wiener_class_id), info,
281
0
      wiener_class_id);
282
0
}
283
284
105k
int16_t *nsfilter_taps(WienerNonsepInfo *nsinfo, int wiener_class_id) {
285
105k
  assert(wiener_class_id >= 0 && wiener_class_id < nsinfo->num_classes);
286
105k
  return nsinfo->allfiltertaps + wiener_class_id * WIENERNS_TAPS_MAX;
287
105k
}
288
289
const int16_t *const_nsfilter_taps(const WienerNonsepInfo *nsinfo,
290
293k
                                   int wiener_class_id) {
291
293k
  assert(wiener_class_id >= 0 && wiener_class_id < nsinfo->num_classes);
292
293k
  return nsinfo->allfiltertaps + wiener_class_id * WIENERNS_TAPS_MAX;
293
293k
}
294
295
void copy_nsfilter_taps_for_class(WienerNonsepInfo *to_info,
296
                                  const WienerNonsepInfo *from_info,
297
40.0k
                                  int wiener_class_id) {
298
40.0k
  assert(wiener_class_id >= 0 && wiener_class_id < to_info->num_classes);
299
40.0k
  assert(wiener_class_id >= 0 && wiener_class_id < from_info->num_classes);
300
40.0k
  const int offset = wiener_class_id * WIENERNS_TAPS_MAX;
301
40.0k
  memcpy(to_info->allfiltertaps + offset, from_info->allfiltertaps + offset,
302
40.0k
         WIENERNS_TAPS_MAX * sizeof(*to_info->allfiltertaps));
303
40.0k
  to_info->bank_ref_for_class[wiener_class_id] =
304
40.0k
      from_info->bank_ref_for_class[wiener_class_id];
305
40.0k
}
306
307
void copy_nsfilter_taps(WienerNonsepInfo *to_info,
308
249
                        const WienerNonsepInfo *from_info) {
309
249
  assert(to_info->num_classes == from_info->num_classes);
310
249
  memcpy(to_info->allfiltertaps, from_info->allfiltertaps,
311
249
         sizeof(to_info->allfiltertaps));
312
249
  memcpy(to_info->bank_ref_for_class, from_info->bank_ref_for_class,
313
249
         sizeof(to_info->bank_ref_for_class));
314
249
}
315
316
void av2_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y,
317
4.28k
                            const int num_planes) {
318
4.28k
  int i;
319
320
16.1k
  for (i = 0; i < num_planes; i++) {
321
11.8k
    xd->plane[i].plane_type = get_plane_type(i);
322
11.8k
    xd->plane[i].subsampling_x = i ? ss_x : 0;
323
11.8k
    xd->plane[i].subsampling_y = i ? ss_y : 0;
324
11.8k
  }
325
5.32k
  for (i = num_planes; i < MAX_MB_PLANE; i++) {
326
1.04k
    xd->plane[i].subsampling_x = 1;
327
1.04k
    xd->plane[i].subsampling_y = 1;
328
1.04k
  }
329
4.28k
}
330
331
10.0k
int max_dictionary_size(int nopcw) {
332
10.0k
  const int max_num_predictors =
333
10.0k
      num_dictionary_slots(WIENERNS_MAX_CLASSES, nopcw);
334
10.0k
  return max_num_predictors * MAX_NUM_DICTIONARY_TAPS;
335
10.0k
}
336
337
285
void allocate_frame_filter_dictionary(AV2_COMMON *cm) {
338
  // Use max_dictionary_size(0) below instead of max_dictionary_size(nopcw)
339
  // to always allocate for the largest possible dictionary size.
340
  // If nopcw is solely based on sequence level parameters, this
341
  // should not be strictly necessary, since reallocation should
342
  // happen with every new sequence parameter set. However the current
343
  // reference decoder does not appear to reallocate when the sequence
344
  // level parameters change. Hence this change is needed.
345
285
  const int nopcw = disable_pcwiener_filters_in_framefilters(&cm->seq_params);
346
285
  (void)nopcw;
347
285
  cm->frame_filter_dictionary =
348
285
      avm_calloc(max_dictionary_size(0), sizeof(*cm->frame_filter_dictionary));
349
285
  cm->translated_pcwiener_filters =
350
285
      avm_calloc(NUM_PC_WIENER_FILTERS * MAX_NUM_DICTIONARY_TAPS,
351
285
                 sizeof(*cm->translated_pcwiener_filters));
352
285
  cm->translation_done = 0;
353
285
  cm->frame_filter_dictionary_stride = MAX_NUM_DICTIONARY_TAPS;
354
285
  cm->num_ref_filters = avm_calloc(1, sizeof(*cm->num_ref_filters));
355
285
}
356
357
2.36k
void free_frame_filter_dictionary(AV2_COMMON *cm) {
358
2.36k
  avm_free(cm->frame_filter_dictionary);
359
2.36k
  avm_free(cm->translated_pcwiener_filters);
360
2.36k
  avm_free(cm->num_ref_filters);
361
2.36k
  cm->frame_filter_dictionary = NULL;
362
2.36k
  cm->translated_pcwiener_filters = NULL;
363
2.36k
  cm->num_ref_filters = NULL;
364
2.36k
  cm->translation_done = 0;
365
2.36k
  cm->frame_filter_dictionary_stride = 0;
366
2.36k
}
367
368
// TODO: Refactor so that this gets called only once during encoding/decoding.
369
// Useful when using pre-trained filters (with different config and precision)
370
// to predict transmitetd filters to reduce side-information.
371
285
void translate_pcwiener_filters_to_wienerns(AV2_COMMON *cm) {
372
285
  if (cm->translation_done) {
373
0
    return;
374
0
  }
375
285
  const int base_qindex = cm->quant_params.base_qindex;
376
285
  const int is_uv = 0;
377
285
  const WienernsFilterParameters *nsfilter_params =
378
285
      get_wienerns_parameters(base_qindex, is_uv);
379
285
  assert(nsfilter_params->ncoeffs <= MAX_NUM_DICTIONARY_TAPS);
380
285
  const int num_feat = nsfilter_params->ncoeffs;
381
285
  const int set_index = 0;  // get_filter_set_index(base_qindex, qindex_offset);
382
383
285
  const int num_pc_wiener_filters = NUM_PC_WIENER_FILTERS;
384
285
  const int(*wienerns_coeffs)[WIENERNS_COEFCFG_LEN] = nsfilter_params->coeffs;
385
285
  const int16_t(*pcwiener_filters_luma)[NUM_PC_WIENER_TAPS_LUMA] =
386
285
      get_filter_set(set_index);
387
285
  const int precision_diff =
388
285
      PC_WIENER_PREC_FILTER - nsfilter_params->nsfilter_config.prec_bits;
389
285
  assert(precision_diff >= 0);
390
391
18.5k
  for (int pc_wiener_cnt = 0; pc_wiener_cnt < num_pc_wiener_filters;
392
18.2k
       ++pc_wiener_cnt) {
393
18.2k
    int filter_index = pc_wiener_cnt;
394
18.2k
    const int16_t *pcwiener_filter = pcwiener_filters_luma[filter_index];
395
396
18.2k
    const int dict_index = pc_wiener_cnt;
397
398
18.2k
    assert(cm->translated_pcwiener_filters != NULL);
399
237k
    for (int i = 0; i < AVMMIN(num_feat, NUM_PC_WIENER_TAPS_LUMA - 1); ++i) {
400
218k
      const int16_t scaled_tap = ROUND_POWER_OF_TWO_SIGNED(
401
218k
          pcwiener_filter[i], precision_diff);  // Assuming no translation
402
      // pcwiener_filter[tap_translator[i]], precision_diff); // deprecated
403
218k
      cm->translated_pcwiener_filters[dict_index * MAX_NUM_DICTIONARY_TAPS +
404
218k
                                      i] =
405
218k
          clip_to_wienerns_range(scaled_tap,
406
218k
                                 wienerns_coeffs[i][WIENERNS_MIN_ID],
407
218k
                                 (1 << wienerns_coeffs[i][WIENERNS_BIT_ID]));
408
218k
    }
409
18.2k
  }
410
285
  cm->translation_done = 1;
411
285
}
412
413
static inline int num_sampled_pc_wiener_filters(int plane, int num_ref_filters,
414
19.5k
                                                int num_classes, int nopcw) {
415
19.5k
  if (plane != AVM_PLANE_Y) return 0;
416
17.8k
  if (nopcw) return 0;
417
17.7k
  return AVMMIN(
418
17.8k
      AVMMAX(max_num_base_filters(num_classes, 0) - num_ref_filters, 0),
419
17.8k
      NUM_PC_WIENER_FILTERS);
420
17.8k
}
421
422
void set_group_counts(int plane, int num_classes, int num_ref_frames,
423
9.76k
                      int *group_counts, int nopcw) {
424
9.76k
  int total_slots = num_dictionary_slots(num_classes, nopcw);
425
9.76k
  (void)total_slots;
426
9.76k
  group_counts[0] = num_classes;
427
9.76k
  total_slots -= group_counts[0];
428
9.76k
  assert(total_slots >= 0);
429
9.76k
  group_counts[1] = num_ref_frames;
430
9.76k
  total_slots -= group_counts[1];
431
9.76k
  assert(total_slots >= 0);
432
9.76k
  group_counts[2] =
433
9.76k
      num_sampled_pc_wiener_filters(plane, num_ref_frames, num_classes, nopcw);
434
9.76k
}
435
436
int set_frame_filter_dictionary(int plane, const AV2_COMMON *cm,
437
                                int num_classes,
438
                                int16_t *frame_filter_dictionary,
439
9.76k
                                int dict_stride) {
440
9.76k
  assert(frame_filter_dictionary != NULL);
441
9.76k
  assert(dict_stride > 0);
442
9.76k
  const int base_qindex = cm->quant_params.base_qindex;
443
9.76k
  const int is_uv = plane > 0;
444
9.76k
  const WienernsFilterParameters *nsfilter_params =
445
9.76k
      get_wienerns_parameters(base_qindex, is_uv);
446
447
9.76k
  const int nopcw = disable_pcwiener_filters_in_framefilters(&cm->seq_params);
448
9.76k
  if (!nopcw) assert(nsfilter_params->ncoeffs <= MAX_NUM_DICTIONARY_TAPS);
449
9.76k
  const int num_feat = nsfilter_params->ncoeffs;
450
451
9.76k
  memset(frame_filter_dictionary, 0,
452
9.76k
         max_dictionary_size(nopcw) * sizeof(*frame_filter_dictionary));
453
9.76k
  const int max_predictors = num_dictionary_slots(num_classes, nopcw);
454
455
  // Filters prior to ref_filter_offset are all zeros via calloc. --------------
456
9.76k
  const int ref_filter_offset = reference_filters_begin(num_classes);
457
  // ---------------------------------------------------------------------------
458
459
  // Copy available reference filters to the dictionary. -----------------------
460
9.76k
  int num_ref_filters = 0;
461
9.76k
  const int min_pc_wiener = plane == AVM_PLANE_Y ? (nopcw ? 0 : 16) : 0;
462
9.76k
  assert(min_pc_wiener <= NUM_PC_WIENER_FILTERS);
463
9.76k
  const int allowed_num_base_filters =
464
9.76k
      max_num_base_filters(num_classes, nopcw) - min_pc_wiener;
465
9.76k
  assert(allowed_num_base_filters >= 0);
466
9.76k
  assert(allowed_num_base_filters < max_predictors);
467
9.76k
  const int num_ref_frames = (frame_is_intra_only(cm) || frame_is_sframe(cm))
468
9.76k
                                 ? 0
469
9.76k
                                 : cm->ref_frames_info.num_total_refs;
470
9.76k
  for (int ref_idx = 0; ref_idx < num_ref_frames; ref_idx++) {
471
0
    const RefCntBuffer *ref_frame_buf = get_ref_frame_buf(cm, ref_idx);
472
0
    if (ref_frame_buf == NULL) {
473
0
      assert(0);
474
0
      continue;
475
0
    }
476
0
    if (ref_frame_buf->is_restricted) continue;
477
0
    int planes_to_check[2] = { plane, -1 };
478
0
    int num_planes_to_check = 1;
479
0
    const int mix_planes = 1;
480
0
    if (plane != AVM_PLANE_Y && mix_planes) {
481
0
      num_planes_to_check = 2;
482
0
      planes_to_check[1] = (plane == AVM_PLANE_U) ? AVM_PLANE_V : AVM_PLANE_U;
483
0
    }
484
0
    for (int chk = 0; chk < num_planes_to_check; ++chk) {
485
0
      const int p = planes_to_check[chk];
486
0
      RestorationInfo rsi = ref_frame_buf->rst_info[p];
487
0
      if (rsi.frame_filters_on) {
488
0
        for (int c_id = 0; c_id < rsi.num_filter_classes; ++c_id) {
489
0
          if (num_ref_filters >= allowed_num_base_filters) break;
490
491
0
          int16_t *match_filter =
492
0
              frame_filter_dictionary +
493
0
              (num_ref_filters + ref_filter_offset) * dict_stride;
494
0
          const int16_t *wienerns_filter =
495
0
              const_nsfilter_taps(&rsi.frame_filters, c_id);
496
0
          for (int i = 0; i < num_feat; ++i) {
497
0
            match_filter[i] = wienerns_filter[i];
498
0
          }
499
0
          ++num_ref_filters;
500
0
        }
501
0
      }
502
0
    }
503
0
  }
504
  // ---------------------------------------------------------------------------
505
506
  // Sample from the pc-wiener filters for the remaining allowed slots. --------
507
9.76k
  const int shuffled_index[] = { 16, 7,  58, 21, 12, 61, 26, 38, 18, 30, 50,
508
9.76k
                                 45, 23, 49, 43, 62, 42, 54, 27, 36, 17, 44,
509
9.76k
                                 32, 34, 4,  24, 52, 31, 37, 11, 33, 19, 35,
510
9.76k
                                 6,  22, 53, 63, 25, 41, 47, 1,  59, 0,  28,
511
9.76k
                                 40, 55, 48, 8,  5,  51, 9,  46, 56, 60, 15,
512
9.76k
                                 2,  13, 14, 57, 29, 3,  20, 39, 10 };
513
9.76k
  const int num_pc_wiener_filters =
514
9.76k
      num_sampled_pc_wiener_filters(plane, num_ref_filters, num_classes, nopcw);
515
9.76k
  assert(num_pc_wiener_filters >= 0 &&
516
9.76k
         num_pc_wiener_filters <= NUM_PC_WIENER_FILTERS);
517
518
9.76k
  assert(cm->translated_pcwiener_filters != NULL);
519
9.76k
  assert(cm->translation_done);
520
492k
  for (int pc_wiener_cnt = 0; pc_wiener_cnt < num_pc_wiener_filters;
521
482k
       ++pc_wiener_cnt) {
522
482k
    int filter_index = shuffled_index[pc_wiener_cnt];
523
482k
    assert(filter_index < NUM_PC_WIENER_FILTERS);
524
525
482k
    const int16_t *pcwiener_filter = cm->translated_pcwiener_filters +
526
482k
                                     filter_index * MAX_NUM_DICTIONARY_TAPS;
527
528
482k
    const int dict_index = ref_filter_offset + num_ref_filters + pc_wiener_cnt;
529
482k
    assert(dict_index < max_predictors);
530
482k
    if (dict_index >= max_predictors) {
531
0
      break;
532
0
    }
533
534
482k
    int16_t *match_filter = frame_filter_dictionary + dict_index * dict_stride;
535
8.20M
    for (int i = 0; i < num_feat; ++i) {
536
7.72M
      match_filter[i] = pcwiener_filter[i];
537
7.72M
    }
538
482k
  }
539
  // ---------------------------------------------------------------------------
540
541
  // One or more match filters are all zeros via calloc. -----------------------
542
  // ---------------------------------------------------------------------------
543
9.76k
  return num_ref_filters;
544
9.76k
}
545
546
void add_filter_to_dictionary(const WienerNonsepInfo *filter, int class_id,
547
                              const WienernsFilterParameters *nsfilter_params,
548
                              int16_t *frame_filter_dictionary, int dict_stride,
549
78.7k
                              int nopcw) {
550
78.7k
  (void)nopcw;
551
78.7k
  assert(frame_filter_dictionary != NULL);
552
78.7k
  assert(dict_stride > 0);
553
78.7k
  if (class_id == filter->num_classes - 1) return;
554
75.8k
  const int filter_index = prev_filters_begin(filter->num_classes) + class_id;
555
75.8k
  assert(filter_index < num_dictionary_slots(filter->num_classes, nopcw));
556
75.8k
  int16_t *match_filter = frame_filter_dictionary + filter_index * dict_stride;
557
75.8k
  const int16_t *wienerns_filter = const_nsfilter_taps(filter, class_id);
558
75.8k
  const int num_feat = nsfilter_params->ncoeffs;
559
1.28M
  for (int i = 0; i < num_feat; ++i) {
560
1.21M
    match_filter[i] = wienerns_filter[i];
561
1.21M
  }
562
75.8k
}
563
564
2.12k
void av2_alloc_txk_skip_array(CommonModeInfoParams *mi_params, AV2_COMMON *cm) {
565
  // Allocate based on the MIN_TX_SIZE, which is a 4x4 block.
566
2.12k
  (void)cm;
567
8.49k
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
568
6.36k
    int w = mi_params->mi_cols << MI_SIZE_LOG2;
569
6.36k
    int h = mi_params->mi_rows << MI_SIZE_LOG2;
570
6.36k
    w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
571
6.36k
    h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
572
6.36k
    int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
573
6.36k
    int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
574
6.36k
    mi_params->tx_skip[plane] = avm_calloc(rows * stride, sizeof(uint8_t));
575
6.36k
    mi_params->tx_skip_buf_size[plane] = rows * stride;
576
6.36k
    mi_params->tx_skip_stride[plane] = stride;
577
6.36k
  }
578
#ifndef NDEBUG
579
  av2_reset_txk_skip_array(cm);
580
#endif  // NDEBUG
581
2.12k
}
582
583
void av2_set_txk_skip_array_stride(CommonModeInfoParams *mi_params,
584
140
                                   AV2_COMMON *cm) {
585
140
  (void)cm;
586
560
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
587
420
    int w = mi_params->mi_cols << MI_SIZE_LOG2;
588
420
    int h = mi_params->mi_rows << MI_SIZE_LOG2;
589
420
    w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
590
420
    h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
591
420
    int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
592
420
    int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
593
420
    if (rows * stride > (int)mi_params->tx_skip_buf_size[plane]) {
594
0
      avm_free(mi_params->tx_skip[plane]);
595
0
      mi_params->tx_skip[plane] = avm_calloc(rows * stride, sizeof(uint8_t));
596
0
      mi_params->tx_skip_buf_size[plane] = rows * stride;
597
0
    }
598
420
    mi_params->tx_skip_stride[plane] = stride;
599
420
  }
600
140
}
601
602
4.48k
void av2_dealloc_txk_skip_array(CommonModeInfoParams *mi_params) {
603
17.9k
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
604
13.4k
    avm_free(mi_params->tx_skip[plane]);
605
13.4k
    mi_params->tx_skip[plane] = NULL;
606
13.4k
  }
607
4.48k
}
608
609
0
void av2_reset_txk_skip_array(AV2_COMMON *cm) {
610
  // Allocate based on the MIN_TX_SIZE, which is a 4x4 block.
611
0
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
612
0
    int h = cm->mi_params.mi_rows << MI_SIZE_LOG2;
613
0
    h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
614
0
    h >>= ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
615
0
    int stride = cm->mi_params.tx_skip_stride[plane];
616
0
    int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
617
0
    memset(cm->mi_params.tx_skip[plane], ILLEGAL_TXK_SKIP_VALUE, rows * stride);
618
0
  }
619
0
}
620
621
6.67k
void av2_reset_txk_skip_array_using_mi_params(CommonModeInfoParams *mi_params) {
622
26.7k
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
623
20.0k
    memset(mi_params->tx_skip[plane], ILLEGAL_TXK_SKIP_VALUE,
624
20.0k
           mi_params->tx_skip_buf_size[plane]);
625
20.0k
  }
626
6.67k
}
627
628
void av2_init_txk_skip_array(const AV2_COMMON *cm, int mi_row, int mi_col,
629
                             BLOCK_SIZE bsize, uint8_t value,
630
                             TREE_TYPE tree_type,
631
                             const CHROMA_REF_INFO *chroma_ref_info,
632
1.18M
                             int plane_start, int plane_end) {
633
1.18M
  const bool is_chroma_ref = tree_type == SHARED_PART
634
1.18M
                                 ? chroma_ref_info->is_chroma_ref
635
1.18M
                             : tree_type == LUMA_PART ? 0
636
507k
                                                      : 1;
637
3.69M
  for (int plane = plane_start; plane < plane_end; plane++) {
638
2.59M
    if (plane && !is_chroma_ref) {
639
82.8k
      break;
640
82.8k
    }
641
2.51M
    const int plane_mi_row =
642
2.51M
        plane ? chroma_ref_info->mi_row_chroma_base : mi_row;
643
2.51M
    const int plane_mi_col =
644
2.51M
        plane ? chroma_ref_info->mi_col_chroma_base : mi_col;
645
2.51M
    const BLOCK_SIZE bsize_base = (tree_type == SHARED_PART && plane)
646
2.51M
                                      ? chroma_ref_info->bsize_base
647
2.51M
                                      : bsize;
648
2.51M
    int stride = cm->mi_params.tx_skip_stride[plane];
649
2.51M
    int x = (plane_mi_col << MI_SIZE_LOG2) >>
650
2.51M
            ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
651
2.51M
    int y = (plane_mi_row << MI_SIZE_LOG2) >>
652
2.51M
            ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
653
2.51M
    int row = y >> MIN_TX_SIZE_LOG2;
654
2.51M
    int col = x >> MIN_TX_SIZE_LOG2;
655
2.51M
    int blk_w = block_size_wide[bsize_base] >>
656
2.51M
                ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
657
2.51M
    int blk_h = block_size_high[bsize_base] >>
658
2.51M
                ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
659
2.51M
    blk_w >>= MIN_TX_SIZE_LOG2;
660
2.51M
    blk_h >>= MIN_TX_SIZE_LOG2;
661
662
2.51M
    if (plane && (blk_w == 0 || blk_h == 0) && is_chroma_ref) {
663
450
      blk_w = blk_w == 0 ? 1 : blk_w;
664
450
      blk_h = blk_h == 0 ? 1 : blk_h;
665
450
    }
666
667
15.4M
    for (int r = 0; r < blk_h; r++) {
668
127M
      for (int c = 0; c < blk_w; c++) {
669
114M
        uint32_t idx = (row + r) * stride + col + c;
670
114M
        assert(idx < cm->mi_params.tx_skip_buf_size[plane]);
671
114M
        cm->mi_params.tx_skip[plane][idx] = value;
672
114M
      }
673
12.9M
    }
674
2.51M
  }
675
1.18M
}
676
677
void av2_update_txk_skip_array(const AV2_COMMON *cm, int mi_row, int mi_col,
678
                               TREE_TYPE tree_type,
679
                               const CHROMA_REF_INFO *chroma_ref_info,
680
                               int plane, int blk_row, int blk_col,
681
2.56M
                               TX_SIZE tx_size) {
682
2.56M
  blk_row *= 4;
683
2.56M
  blk_col *= 4;
684
2.56M
  mi_row = (tree_type == SHARED_PART && plane)
685
2.56M
               ? chroma_ref_info->mi_row_chroma_base
686
2.56M
               : mi_row;
687
2.56M
  mi_col = (tree_type == SHARED_PART && plane)
688
2.56M
               ? chroma_ref_info->mi_col_chroma_base
689
2.56M
               : mi_col;
690
2.56M
  int stride = cm->mi_params.tx_skip_stride[plane];
691
2.56M
  int tx_w = tx_size_wide[tx_size];
692
2.56M
  int tx_h = tx_size_high[tx_size];
693
2.56M
  int cols = tx_w >> MIN_TX_SIZE_LOG2;
694
2.56M
  int rows = tx_h >> MIN_TX_SIZE_LOG2;
695
2.56M
  int x = (mi_col << MI_SIZE_LOG2) >>
696
2.56M
          ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
697
2.56M
  int y = (mi_row << MI_SIZE_LOG2) >>
698
2.56M
          ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
699
2.56M
  x = (x + blk_col) >> MIN_TX_SIZE_LOG2;
700
2.56M
  y = (y + blk_row) >> MIN_TX_SIZE_LOG2;
701
13.4M
  for (int r = 0; r < rows; r++) {
702
10.8M
    uint32_t idx = (y + r) * stride + x;
703
10.8M
    assert(idx < cm->mi_params.tx_skip_buf_size[plane]);
704
10.8M
    static_assert(sizeof(uint8_t) == sizeof(cm->mi_params.tx_skip[plane][idx]),
705
10.8M
                  "");
706
10.8M
    memset(&cm->mi_params.tx_skip[plane][idx], 1,
707
10.8M
           cols * sizeof(cm->mi_params.tx_skip[plane][idx]));
708
10.8M
  }
709
2.56M
}
710
711
uint8_t av2_get_txk_skip(const AV2_COMMON *cm, int mi_row, int mi_col,
712
                         TREE_TYPE tree_type,
713
                         const CHROMA_REF_INFO *chroma_ref_info, int plane,
714
0
                         int blk_row, int blk_col) {
715
0
  blk_row *= 4;
716
0
  blk_col *= 4;
717
0
  mi_row = (tree_type == SHARED_PART && plane)
718
0
               ? chroma_ref_info->mi_row_chroma_base
719
0
               : mi_row;
720
0
  mi_col = (tree_type == SHARED_PART && plane)
721
0
               ? chroma_ref_info->mi_col_chroma_base
722
0
               : mi_col;
723
0
  int stride = cm->mi_params.tx_skip_stride[plane];
724
0
  int x = (mi_col << MI_SIZE_LOG2) >>
725
0
          ((plane == 0) ? 0 : cm->seq_params.subsampling_x);
726
0
  int y = (mi_row << MI_SIZE_LOG2) >>
727
0
          ((plane == 0) ? 0 : cm->seq_params.subsampling_y);
728
0
  x = (x + blk_col) >> MIN_TX_SIZE_LOG2;
729
0
  y = (y + blk_row) >> MIN_TX_SIZE_LOG2;
730
0
  uint32_t idx = y * stride + x;
731
0
  assert(idx < cm->mi_params.tx_skip_buf_size[plane]);
732
0
  assert(cm->mi_params.tx_skip[plane][idx] != ILLEGAL_TXK_SKIP_VALUE);
733
0
  return cm->mi_params.tx_skip[plane][idx];
734
0
}
735
736
void av2_alloc_class_id_array(CommonModeInfoParams *mi_params, AV2_COMMON *cm,
737
2.12k
                              int height) {
738
2.12k
  (void)cm;
739
8.49k
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
740
6.36k
    int w = (mi_params->mi_cols << MI_SIZE_LOG2);
741
6.36k
    int h = height;
742
6.36k
    w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
743
6.36k
    h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
744
6.36k
    int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
745
6.36k
    int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
746
6.36k
    mi_params->wiener_class_id[plane] =
747
6.36k
        avm_calloc(rows * stride, sizeof(uint8_t));
748
6.36k
    mi_params->wiener_class_id_buf_size[plane] = rows * stride;
749
6.36k
    mi_params->wiener_class_id_stride[plane] = stride;
750
6.36k
  }
751
2.12k
}
752
753
void av2_set_class_id_array_stride(CommonModeInfoParams *mi_params,
754
140
                                   AV2_COMMON *cm, int height) {
755
140
  (void)cm;
756
560
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
757
420
    int w = (mi_params->mi_cols << MI_SIZE_LOG2);
758
420
    int h = height;
759
420
    w = ((w + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
760
420
    h = ((h + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2;
761
420
    int stride = (w + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
762
420
    int rows = (h + MIN_TX_SIZE - 1) >> MIN_TX_SIZE_LOG2;
763
420
    if (rows * stride > (int)mi_params->wiener_class_id_buf_size[plane]) {
764
0
      avm_free(mi_params->wiener_class_id[plane]);
765
0
      mi_params->wiener_class_id[plane] =
766
0
          avm_calloc(rows * stride, sizeof(uint8_t));
767
0
      mi_params->wiener_class_id_buf_size[plane] = rows * stride;
768
0
    }
769
420
    mi_params->wiener_class_id_stride[plane] = stride;
770
420
  }
771
140
}
772
773
4.48k
void av2_dealloc_class_id_array(CommonModeInfoParams *mi_params) {
774
17.9k
  for (int plane = 0; plane < MAX_MB_PLANE; plane++) {
775
13.4k
    avm_free(mi_params->wiener_class_id[plane]);
776
    mi_params->wiener_class_id[plane] = NULL;
777
13.4k
  }
778
4.48k
}