Coverage Report

Created: 2026-10-28 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/avm/av2/common/tip.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
6
 * Clear License was not distributed with this source code in the LICENSE file,
7
 * you can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.
8
 * If the Alliance for Open Media Patent License 1.0 was not distributed with
9
 * this source code in the PATENTS file, you can obtain it at
10
 * aomedia.org/license/patent-license/.
11
 */
12
13
#include "av2/common/tip.h"
14
#include "config/avm_scale_rtcd.h"
15
#include "config/avm_dsp_rtcd.h"
16
#include "av2/common/reconinter.h"
17
18
// Percentage threshold of number of blocks with available motion
19
// projection in a frame to allow TIP mode
20
0
#define TIP_ENABLE_COUNT_THRESHOLD 60
21
22
static void tip_temporal_scale_motion_field(AV2_COMMON *cm,
23
0
                                            const int ref_frames_offset) {
24
0
  const int mvs_rows =
25
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_rows, TMVP_SHIFT_BITS);
26
0
  const int mvs_cols =
27
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, TMVP_SHIFT_BITS);
28
0
  for (int blk_row = 0; blk_row < mvs_rows; ++blk_row) {
29
0
    for (int blk_col = 0; blk_col < mvs_cols; ++blk_col) {
30
0
      TPL_MV_REF *tpl_mvs = cm->tpl_mvs_rows[blk_row] + blk_col;
31
0
      if (tpl_mvs->mfmv0.as_int != INVALID_MV) {
32
0
        int_mv this_refmv;
33
0
        get_mv_projection_clamp(&this_refmv.as_mv, tpl_mvs->mfmv0.as_mv,
34
0
                                ref_frames_offset, tpl_mvs->ref_frame_offset,
35
0
                                -REFMVS_LIMIT, REFMVS_LIMIT);
36
0
        tpl_mvs->mfmv0.as_int = this_refmv.as_int;
37
0
        tpl_mvs->ref_frame_offset = ref_frames_offset;
38
0
      } else {
39
0
        tpl_mvs->ref_frame_offset = ref_frames_offset;
40
0
      }
41
0
    }
42
0
  }
43
0
}
44
45
// Compute number of rows/columns/stride in TMVP unit (8x8)
46
static void compute_tmvp_mi_info(const AV2_COMMON *cm, int *mvs_rows,
47
                                 int *mvs_cols, int *mvs_stride,
48
0
                                 int *sb_tmvp_size) {
49
0
  *mvs_rows = ROUND_POWER_OF_TWO(cm->mi_params.mi_rows, TMVP_SHIFT_BITS);
50
0
  *mvs_cols = ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, TMVP_SHIFT_BITS);
51
0
  *mvs_stride = *mvs_cols;
52
53
0
  const SequenceHeader *const seq_params = &cm->seq_params;
54
0
  const int mf_sb_size_log2 =
55
0
      get_mf_sb_size_log2(block_size_high[seq_params->sb_size],
56
0
                          cm->mib_size_log2, cm->tmvp_sample_step);
57
58
0
  const int mf_sb_size = (1 << mf_sb_size_log2);
59
0
  *sb_tmvp_size = (mf_sb_size >> TMVP_MI_SZ_LOG2);
60
0
}
61
62
0
static void tip_fill_motion_field_holes(AV2_COMMON *cm) {
63
0
  int mvs_rows = 0;
64
0
  int mvs_cols = 0;
65
0
  int mvs_stride = 0;
66
0
  int sb_tmvp_size = 0;
67
0
  assert(cm->tmvp_sample_step > 0);
68
0
  int sample = cm->tmvp_sample_step;
69
70
0
  compute_tmvp_mi_info(cm, &mvs_rows, &mvs_cols, &mvs_stride, &sb_tmvp_size);
71
72
0
  const int dirs[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
73
0
  for (int sb_row = 0; sb_row < mvs_rows; sb_row += sb_tmvp_size) {
74
0
    const int start_row = sb_row;
75
0
    const int end_row = AVMMIN(sb_row + sb_tmvp_size, mvs_rows);
76
0
    for (int sb_col = 0; sb_col < mvs_cols; sb_col += sb_tmvp_size) {
77
0
      const int start_col = sb_col;
78
0
      const int end_col = AVMMIN(sb_col + sb_tmvp_size, mvs_cols);
79
0
      for (int row = start_row; row < end_row; row += sample) {
80
0
        for (int col = start_col; col < end_col; col += sample) {
81
0
          const TPL_MV_REF *cur_tpl_mvs = cm->tpl_mvs_rows[row] + col;
82
0
          if (cur_tpl_mvs->mfmv0.as_int != INVALID_MV) {
83
0
            for (int dir = 0; dir < 4; ++dir) {
84
0
              const int neighbor_row = row + dirs[dir][0] * sample;
85
0
              const int neighbor_col = col + dirs[dir][1] * sample;
86
0
              if (neighbor_row >= start_row && neighbor_row < end_row &&
87
0
                  neighbor_col >= start_col && neighbor_col < end_col &&
88
0
                  cm->tpl_mvs_rows[neighbor_row][neighbor_col].mfmv0.as_int ==
89
0
                      INVALID_MV) {
90
0
                cm->tpl_mvs_rows[neighbor_row][neighbor_col].mfmv0.as_int =
91
0
                    cur_tpl_mvs->mfmv0.as_int;
92
0
                cm->tpl_mvs_rows[neighbor_row][neighbor_col].ref_frame_offset =
93
0
                    cur_tpl_mvs->ref_frame_offset;
94
0
              }
95
0
            }
96
0
          }
97
0
        }
98
0
      }
99
0
    }
100
0
  }
101
0
}
102
103
0
static void tip_blk_average_filter_mv(AV2_COMMON *cm) {
104
0
  int mvs_rows = 0;
105
0
  int mvs_cols = 0;
106
0
  int mvs_stride = 0;
107
0
  int sb_tmvp_size = 0;
108
0
  assert(cm->tmvp_sample_step > 0);
109
0
  int sample = cm->tmvp_sample_step;
110
111
0
  compute_tmvp_mi_info(cm, &mvs_rows, &mvs_cols, &mvs_stride, &sb_tmvp_size);
112
113
0
#define DIV_SHIFT_BITS 16
114
  // Avoid the division operation. Maximum 5 MVs would be used for MV smoothing.
115
  // weight_div_mult[i] where i is the number of MVs are available.
116
  // The value of weight_div_mult[i] is to implement 1/i without division with
117
  // the shift of (weight_div_mult[i] >> 16)
118
0
  const int weight_div_mult[6] = { 0, 65536, 32768, 21845, 16384, 13107 };
119
0
  const int sb_stride = MAX_SB_TMVP_SIZE;
120
0
  int_mv tpl_mfs[MAX_SB_TMVP_SIZE * MAX_SB_TMVP_SIZE];
121
0
  for (int sb_row = 0; sb_row < mvs_rows; sb_row += sb_tmvp_size) {
122
0
    const int start_row = sb_row;
123
0
    const int end_row = AVMMIN(sb_row + sb_tmvp_size, mvs_rows);
124
0
    for (int sb_col = 0; sb_col < mvs_cols; sb_col += sb_tmvp_size) {
125
0
      const int start_col = sb_col;
126
0
      const int end_col = AVMMIN(sb_col + sb_tmvp_size, mvs_cols);
127
0
      for (int row = start_row; row < end_row; row += sample) {
128
0
        const int i0 = row - sample;
129
0
        const int i1 = row + sample;
130
0
        for (int col = start_col; col < end_col; col += sample) {
131
0
          const int j0 = col - sample;
132
0
          const int j1 = col + sample;
133
0
          int weights = 0;
134
0
          int sum_mv_row = 0;
135
0
          int sum_mv_col = 0;
136
0
          if (cm->tpl_mvs_rows[row][col].mfmv0.as_int != INVALID_MV) {
137
0
            weights++;
138
0
            sum_mv_row += cm->tpl_mvs_rows[row][col].mfmv0.as_mv.row;
139
0
            sum_mv_col += cm->tpl_mvs_rows[row][col].mfmv0.as_mv.col;
140
0
          }
141
142
0
          if (i0 >= start_row) {
143
0
            if (cm->tpl_mvs_rows[i0][col].mfmv0.as_int != INVALID_MV) {
144
0
              weights++;
145
0
              sum_mv_row += cm->tpl_mvs_rows[i0][col].mfmv0.as_mv.row;
146
0
              sum_mv_col += cm->tpl_mvs_rows[i0][col].mfmv0.as_mv.col;
147
0
            }
148
0
          }
149
150
0
          if (i1 < end_row) {
151
0
            if (cm->tpl_mvs_rows[i1][col].mfmv0.as_int != INVALID_MV) {
152
0
              weights++;
153
0
              sum_mv_row += cm->tpl_mvs_rows[i1][col].mfmv0.as_mv.row;
154
0
              sum_mv_col += cm->tpl_mvs_rows[i1][col].mfmv0.as_mv.col;
155
0
            }
156
0
          }
157
158
0
          if (j0 >= start_col) {
159
0
            if (cm->tpl_mvs_rows[row][j0].mfmv0.as_int != INVALID_MV) {
160
0
              weights++;
161
0
              sum_mv_row += cm->tpl_mvs_rows[row][j0].mfmv0.as_mv.row;
162
0
              sum_mv_col += cm->tpl_mvs_rows[row][j0].mfmv0.as_mv.col;
163
0
            }
164
0
          }
165
166
0
          if (j1 < end_col) {
167
0
            if (cm->tpl_mvs_rows[row][j1].mfmv0.as_int != INVALID_MV) {
168
0
              weights++;
169
0
              sum_mv_row += cm->tpl_mvs_rows[row][j1].mfmv0.as_mv.row;
170
0
              sum_mv_col += cm->tpl_mvs_rows[row][j1].mfmv0.as_mv.col;
171
0
            }
172
0
          }
173
174
0
          const int blk_pos_in_sb = (row - sb_row) * sb_stride + (col - sb_col);
175
0
          if (weights) {
176
0
            const int scale_factor = weight_div_mult[weights];
177
0
            const int64_t scale_mv_row = (int64_t)sum_mv_row * scale_factor;
178
0
            const int64_t scale_mv_col = (int64_t)sum_mv_col * scale_factor;
179
0
            tpl_mfs[blk_pos_in_sb].as_mv.row =
180
0
                (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED_64(scale_mv_row,
181
0
                                                                DIV_SHIFT_BITS);
182
0
            tpl_mfs[blk_pos_in_sb].as_mv.col =
183
0
                (MV_COMP_DATA_TYPE)ROUND_POWER_OF_TWO_SIGNED_64(scale_mv_col,
184
0
                                                                DIV_SHIFT_BITS);
185
0
          } else {
186
0
            tpl_mfs[blk_pos_in_sb].as_int = INVALID_MV;
187
0
          }
188
0
        }
189
0
      }
190
191
0
      for (int row = start_row; row < end_row; row += sample) {
192
0
        for (int col = start_col; col < end_col; col += sample) {
193
0
          const int blk_pos_in_sb = (row - sb_row) * sb_stride + (col - sb_col);
194
0
          cm->tpl_mvs_rows[row][col].mfmv0.as_int =
195
0
              tpl_mfs[blk_pos_in_sb].as_int;
196
0
        }
197
0
      }
198
0
    }
199
0
  }
200
0
}
201
202
0
static void tip_config_tip_parameter(AV2_COMMON *cm) {
203
0
  TIP *tip_ref = &cm->tip_ref;
204
0
  const OrderHintInfo *const order_hint_info = &cm->seq_params.order_hint_info;
205
0
  const int cur_order_hint = cm->cur_frame->display_order_hint;
206
207
0
  MV_REFERENCE_FRAME nearest_rf[2] = { tip_ref->ref_frame[0],
208
0
                                       tip_ref->ref_frame[1] };
209
210
0
  RefCntBuffer *ref0_frame_buf = get_ref_frame_buf(cm, nearest_rf[0]);
211
0
  const int ref0_frame_order_hint = ref0_frame_buf->display_order_hint;
212
0
  const int cur_to_ref0_offset =
213
0
      get_relative_dist(order_hint_info, cur_order_hint, ref0_frame_order_hint);
214
215
0
  RefCntBuffer *ref1_frame_buf = get_ref_frame_buf(cm, nearest_rf[1]);
216
0
  const int ref1_frame_order_hint = ref1_frame_buf->display_order_hint;
217
0
  const int cur_to_ref1_offset =
218
0
      get_relative_dist(order_hint_info, cur_order_hint, ref1_frame_order_hint);
219
220
0
  int ref_frames_offset = 0;
221
0
  if (cm->has_both_sides_refs) {
222
0
    ref_frames_offset = get_relative_dist(
223
0
        order_hint_info, ref1_frame_order_hint, ref0_frame_order_hint);
224
0
  } else {
225
0
    ref_frames_offset = get_relative_dist(
226
0
        order_hint_info, ref0_frame_order_hint, ref1_frame_order_hint);
227
0
  }
228
0
  tip_ref->ref_frame_buffer[0] = ref0_frame_buf;
229
0
  tip_ref->ref_frame_buffer[1] = ref1_frame_buf;
230
0
  tip_ref->ref_scale_factor[0] = get_ref_scale_factors_const(cm, nearest_rf[0]);
231
0
  tip_ref->ref_scale_factor[1] = get_ref_scale_factors_const(cm, nearest_rf[1]);
232
0
  tip_ref->ref_frames_offset_sf[0] =
233
0
      tip_derive_scale_factor(cur_to_ref0_offset, ref_frames_offset);
234
0
  tip_ref->ref_frames_offset_sf[1] =
235
0
      tip_derive_scale_factor(cur_to_ref1_offset, ref_frames_offset);
236
0
  tip_ref->ref_frames_offset = AVMMIN(ref_frames_offset, MAX_FRAME_DISTANCE);
237
0
  tip_ref->ref_offset[0] = cur_to_ref0_offset;
238
0
  tip_ref->ref_offset[1] = cur_to_ref1_offset;
239
0
  tip_ref->ref_order_hint[0] = ref0_frame_order_hint;
240
0
  tip_ref->ref_order_hint[1] = ref1_frame_order_hint;
241
0
}
242
243
0
void av2_setup_tip_motion_field(AV2_COMMON *cm) {
244
0
  if (cm->features.tip_frame_mode) {
245
0
    tip_config_tip_parameter(cm);
246
0
    tip_temporal_scale_motion_field(cm, cm->tip_ref.ref_frames_offset);
247
0
    if (cm->features.allow_tip_hole_fill) {
248
0
      tip_fill_motion_field_holes(cm);
249
0
      tip_blk_average_filter_mv(cm);
250
0
    }
251
0
    av2_fill_tpl_mvs_sample_gap(cm);
252
253
0
    cm->features.use_optflow_tip =
254
0
        cm->features.tip_frame_mode && cm->has_both_sides_refs;
255
0
  }
256
0
}
257
258
0
static void enc_check_enable_tip_mode(AV2_COMMON *cm) {
259
0
  const TPL_MV_REF *tpl_mvs_base = cm->tpl_mvs;
260
0
  const int mvs_rows =
261
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_rows, TMVP_SHIFT_BITS);
262
0
  const int mvs_cols =
263
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, TMVP_SHIFT_BITS);
264
0
  const int mvs_stride = mvs_cols;
265
266
0
  assert(cm->tmvp_sample_step > 0);
267
0
  const int sample = cm->tmvp_sample_step;
268
269
0
  int count = 0;
270
0
  for (int blk_row = 0; blk_row < mvs_rows; blk_row += sample) {
271
0
    for (int blk_col = 0; blk_col < mvs_cols; blk_col += sample) {
272
0
      const int tpl_offset = blk_row * mvs_stride + blk_col;
273
0
      const TPL_MV_REF *tpl_mvs = tpl_mvs_base + tpl_offset;
274
0
      if (tpl_mvs->mfmv0.as_int != INVALID_MV) {
275
0
        ++count;
276
0
      }
277
0
    }
278
0
  }
279
280
0
  count *= sample * sample;
281
282
  // Percentage of number of blocks with available motion field
283
0
  const int percent = (count * 100) / (mvs_rows * mvs_cols);
284
0
  if (percent < TIP_ENABLE_COUNT_THRESHOLD) {
285
0
    cm->features.tip_frame_mode = TIP_FRAME_DISABLED;
286
0
  } else {
287
0
    cm->features.tip_frame_mode = TIP_FRAME_AS_REF;
288
0
  }
289
0
}
290
291
0
static void enc_decide_tip_mode(AV2_COMMON *cm) {
292
0
  TIP *tip_ref = &cm->tip_ref;
293
0
  if (cm->current_frame.frame_type == KEY_FRAME ||
294
0
      cm->current_frame.frame_type == INTRA_ONLY_FRAME ||
295
0
      cm->current_frame.frame_type == S_FRAME) {
296
0
    cm->features.tip_frame_mode = TIP_FRAME_DISABLED;
297
0
    tip_ref->ref_frame[0] = NONE_FRAME;
298
0
    tip_ref->ref_frame[1] = NONE_FRAME;
299
0
    return;
300
0
  }
301
302
0
  MV_REFERENCE_FRAME nearest_rf[2] = { tip_ref->ref_frame[0],
303
0
                                       tip_ref->ref_frame[1] };
304
305
0
  const int tip_mode_allowed = nearest_rf[0] != NONE_FRAME &&
306
0
                               nearest_rf[1] != NONE_FRAME &&
307
0
                               is_ref_motion_field_eligible_by_frame_size(
308
0
                                   cm, get_ref_frame_buf(cm, nearest_rf[0])) &&
309
0
                               is_ref_motion_field_eligible_by_frame_size(
310
0
                                   cm, get_ref_frame_buf(cm, nearest_rf[1]));
311
312
0
  if (tip_mode_allowed && (is_ref_motion_field_eligible_by_frame_type(
313
0
                               get_ref_frame_buf(cm, nearest_rf[0])) ||
314
0
                           is_ref_motion_field_eligible_by_frame_type(
315
0
                               get_ref_frame_buf(cm, nearest_rf[1])))) {
316
0
    enc_check_enable_tip_mode(cm);
317
318
0
    if (cm->features.tip_frame_mode) {
319
0
      cm->features.allow_tip_hole_fill = cm->seq_params.enable_tip_hole_fill;
320
0
    }
321
0
  } else {
322
0
    cm->features.tip_frame_mode = TIP_FRAME_DISABLED;
323
0
    cm->features.allow_tip_hole_fill = false;
324
0
    tip_ref->ref_frame[0] = NONE_FRAME;
325
0
    tip_ref->ref_frame[1] = NONE_FRAME;
326
0
  }
327
0
}
328
329
0
void av2_enc_setup_tip_motion_field(AV2_COMMON *cm) {
330
0
  enc_decide_tip_mode(cm);
331
0
  av2_setup_tip_motion_field(cm);
332
0
}
333
334
MAKE_BFP_SAD_WRAPPER_COMMON(avm_highbd_sad8x8)
335
MAKE_BFP_SAD_WRAPPER_COMMON(avm_highbd_sad16x8)
336
MAKE_BFP_SAD_WRAPPER_COMMON(avm_highbd_sad8x16)
337
MAKE_BFP_SAD_WRAPPER_COMMON(avm_highbd_sad16x16)
338
339
unsigned int get_highbd_sad(const uint16_t *src_ptr, int source_stride,
340
                            const uint16_t *ref_ptr, int ref_stride, int bd,
341
0
                            int bw, int bh) {
342
0
  if (bd == 8) {
343
0
    if (bw == 8 && bh == 8)
344
0
      return avm_highbd_sad8x8_8(src_ptr, source_stride, ref_ptr, ref_stride);
345
0
    else if (bw == 16 && bh == 8)
346
0
      return avm_highbd_sad16x8_8(src_ptr, source_stride, ref_ptr, ref_stride);
347
0
    else if (bw == 8 && bh == 16)
348
0
      return avm_highbd_sad8x16_8(src_ptr, source_stride, ref_ptr, ref_stride);
349
0
    else if (bw == 16 && bh == 16)
350
0
      return avm_highbd_sad16x16_8(src_ptr, source_stride, ref_ptr, ref_stride);
351
0
    else if (bw == 12 && bh == 12)
352
0
      return avm_highbd_sad12x12(src_ptr, source_stride, ref_ptr, ref_stride);
353
0
    else if (bw == 20 && bh == 12)
354
0
      return avm_highbd_sad20x12(src_ptr, source_stride, ref_ptr, ref_stride);
355
0
    else if (bw == 12 && bh == 20)
356
0
      return avm_highbd_sad12x20(src_ptr, source_stride, ref_ptr, ref_stride);
357
0
    else if (bw == 20 && bh == 20)
358
0
      return avm_highbd_sad20x20(src_ptr, source_stride, ref_ptr, ref_stride);
359
0
    else {
360
0
      assert(0);
361
0
      return 0;
362
0
    }
363
0
  } else if (bd == 10) {
364
0
    if (bw == 8 && bh == 8)
365
0
      return avm_highbd_sad8x8_10(src_ptr, source_stride, ref_ptr, ref_stride);
366
0
    else if (bw == 16 && bh == 8)
367
0
      return avm_highbd_sad16x8_10(src_ptr, source_stride, ref_ptr, ref_stride);
368
0
    else if (bw == 8 && bh == 16)
369
0
      return avm_highbd_sad8x16_10(src_ptr, source_stride, ref_ptr, ref_stride);
370
0
    else if (bw == 16 && bh == 16)
371
0
      return avm_highbd_sad16x16_10(src_ptr, source_stride, ref_ptr,
372
0
                                    ref_stride);
373
0
    else {
374
0
      assert(0);
375
0
      return 0;
376
0
    }
377
0
  } else if (bd == 12) {
378
0
    if (bw == 8 && bh == 8)
379
0
      return avm_highbd_sad8x8_12(src_ptr, source_stride, ref_ptr, ref_stride);
380
0
    else if (bw == 16 && bh == 8)
381
0
      return avm_highbd_sad16x8_12(src_ptr, source_stride, ref_ptr, ref_stride);
382
0
    else if (bw == 8 && bh == 16)
383
0
      return avm_highbd_sad8x16_12(src_ptr, source_stride, ref_ptr, ref_stride);
384
0
    else if (bw == 16 && bh == 16)
385
0
      return avm_highbd_sad16x16_12(src_ptr, source_stride, ref_ptr,
386
0
                                    ref_stride);
387
0
    else {
388
0
      assert(0);
389
0
      return 0;
390
0
    }
391
0
  } else {
392
0
    assert(0);
393
0
    return 0;
394
0
  }
395
0
}
396
// Build an 8x8 block in the TIP frame
397
static AVM_INLINE void tip_build_inter_predictors_8x8(
398
    const AV2_COMMON *cm, MACROBLOCKD *xd, int plane, BLOCK_SIZE unit_bsize,
399
    const MV mv[2], int mi_x, int mi_y, uint16_t **mc_buf,
400
    CONV_BUF_TYPE *tmp_conv_dst, CalcSubpelParamsFunc calc_subpel_params_func,
401
    uint16_t *dst, int dst_stride, uint16_t *dst0_16_refinemv,
402
0
    uint16_t *dst1_16_refinemv, ReferenceArea ref_area[2]) {
403
  // TODO(any): currently this only works for y plane
404
0
  assert(plane == 0);
405
406
0
  int bw = block_size_wide[unit_bsize];
407
0
  int bh = block_size_high[unit_bsize];
408
409
0
  const int bd = cm->seq_params.bit_depth;
410
411
0
  const int ss_x = plane ? cm->seq_params.subsampling_x : 0;
412
0
  const int ss_y = plane ? cm->seq_params.subsampling_y : 0;
413
0
  const int comp_pixel_x = (mi_x >> ss_x);
414
0
  const int comp_pixel_y = (mi_y >> ss_y);
415
0
  const int comp_bw = bw >> ss_x;
416
0
  const int comp_bh = bh >> ss_y;
417
418
0
  MB_MODE_INFO mbmi_buf;
419
0
  av2_zero(mbmi_buf);
420
0
  MB_MODE_INFO *mbmi = &mbmi_buf;
421
422
0
  int_mv mv_refined[2 * 4];
423
0
  memset(mv_refined, 0, 2 * 4 * sizeof(int_mv));
424
425
0
  CONV_BUF_TYPE *org_buf = xd->tmp_conv_dst;
426
0
  xd->tmp_conv_dst = tmp_conv_dst;
427
428
0
  mbmi->mv[0].as_mv = mv[0];
429
0
  mbmi->mv[1].as_mv = mv[1];
430
0
  mbmi->ref_frame[0] = TIP_FRAME;
431
0
  mbmi->ref_frame[1] = NONE_FRAME;
432
0
  mbmi->interp_fltr = cm->tip_interp_filter;
433
0
  mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
434
0
  mbmi->use_intrabc[0] = 0;
435
0
  mbmi->motion_mode = SIMPLE_TRANSLATION;
436
0
  mbmi->sb_type[PLANE_TYPE_Y] = unit_bsize;
437
0
  mbmi->interinter_comp.type = COMPOUND_AVERAGE;
438
0
  mbmi->max_mv_precision = MV_PRECISION_ONE_EIGHTH_PEL;
439
0
  mbmi->pb_mv_precision = MV_PRECISION_ONE_EIGHTH_PEL;
440
0
  mbmi->morph_pred = 0;
441
442
0
  uint16_t *refinemv_ref0 = NULL;
443
0
  uint16_t *refinemv_ref1 = NULL;
444
445
0
  MV best_mv_ref[2] = { { mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col },
446
0
                        { mbmi->mv[1].as_mv.row, mbmi->mv[1].as_mv.col } };
447
448
0
  int apply_refinemv = (is_refinemv_allowed_tip_blocks(cm, mbmi) && plane == 0);
449
0
  assert(IMPLIES(bw > 16, !apply_refinemv));
450
451
0
  if (apply_refinemv) {
452
0
    uint16_t *dst_ref0 = NULL, *dst_ref1 = NULL;
453
0
    dst_ref0 = &dst0_16_refinemv[0];
454
0
    dst_ref1 = &dst1_16_refinemv[0];
455
0
    mbmi->refinemv_flag = 1;
456
457
0
    apply_mv_refinement(cm, xd, plane, mbmi, bw, bh, mi_x, mi_y, mc_buf, mv,
458
0
                        calc_subpel_params_func, comp_pixel_x, comp_pixel_y,
459
0
                        dst_ref0, dst_ref1, &refinemv_ref0, &refinemv_ref1,
460
0
                        best_mv_ref, bw, bh, ref_area);
461
0
    REFINEMV_SUBMB_INFO *refinemv_subinfo = &xd->refinemv_subinfo[0];
462
0
    fill_subblock_refine_mv(refinemv_subinfo, bw, bh, best_mv_ref[0],
463
0
                            best_mv_ref[1]);
464
0
  }
465
466
0
  if (plane == 0) {
467
0
    mv_refined[0].as_mv = convert_mv_to_1_16th_pel(&best_mv_ref[0]);
468
0
    mv_refined[1].as_mv = convert_mv_to_1_16th_pel(&best_mv_ref[1]);
469
0
  }
470
471
  // Arrays to hold optical flow offsets.
472
0
  int vxy_bufs[4 * 4] = { 0 };
473
0
  int *vx0 = vxy_bufs;
474
0
  int *vx1 = vxy_bufs + (4 * 1);
475
0
  int *vy0 = vxy_bufs + (4 * 2);
476
0
  int *vy1 = vxy_bufs + (4 * 3);
477
478
  // Pointers to gradient and dst buffers
479
0
  int16_t *gx0 = xd->opfl_gxy_bufs,
480
0
          *gy0 = xd->opfl_gxy_bufs + (MAX_SB_SQUARE * 1),
481
0
          *gx1 = xd->opfl_gxy_bufs + (MAX_SB_SQUARE * 2),
482
0
          *gy1 = xd->opfl_gxy_bufs + (MAX_SB_SQUARE * 3);
483
0
  uint16_t *dst0 = NULL, *dst1 = NULL;
484
485
0
  dst0 = xd->opfl_dst_bufs;
486
0
  dst1 = xd->opfl_dst_bufs + MAX_SB_SQUARE;
487
0
  int do_pred = 1;
488
0
  int opfl_dst_stride = bw;
489
0
  if (refinemv_ref0 != NULL && refinemv_ref1 != NULL) {
490
0
    dst0 = refinemv_ref0;
491
0
    dst1 = refinemv_ref1;
492
0
    opfl_dst_stride = REFINEMV_SUBBLOCK_WIDTH +
493
0
                      2 * (SUBBLK_REF_EXT_LINES + SMVR_SEARCH_EXT_LINES);
494
0
    do_pred = 0;
495
0
  }
496
497
0
  int do_opfl =
498
0
      is_optflow_refinement_enabled(cm, xd, mbmi, plane, 1 /* tip_ref_frame */);
499
0
  assert(IMPLIES(bw > 8, !do_opfl));
500
501
0
  const unsigned int sad_thres =
502
0
      cm->features.tip_frame_mode == TIP_FRAME_AS_OUTPUT ? 15 : 6;
503
504
0
  const int use_4x4 = 0;
505
0
  if (do_opfl) {
506
0
    if (do_pred) {
507
0
      assert(opfl_dst_stride == bw);
508
0
      InterPredParams params0, params1;
509
0
      av2_opfl_build_inter_predictor(cm, xd, plane, mbmi, bw, bh, mi_x, mi_y,
510
0
                                     mc_buf, &params0, calc_subpel_params_func,
511
0
                                     0, dst0, &best_mv_ref[0], bw, bh);
512
0
      av2_opfl_build_inter_predictor(cm, xd, plane, mbmi, bw, bh, mi_x, mi_y,
513
0
                                     mc_buf, &params1, calc_subpel_params_func,
514
0
                                     1, dst1, &best_mv_ref[1], bw, bh);
515
0
    }
516
0
    const unsigned int sad = get_highbd_sad(dst0, opfl_dst_stride, dst1,
517
0
                                            opfl_dst_stride, bd, bw, bh);
518
0
    if (sad < sad_thres) {
519
0
      do_opfl = 0;
520
0
    }
521
0
  }
522
523
0
  if (do_opfl) {
524
    // Initialize refined mv
525
0
    const MV mv0 = best_mv_ref[0];
526
0
    const MV mv1 = best_mv_ref[1];
527
528
0
    for (int mvi = 0; mvi < 4; mvi++) {
529
0
      mv_refined[mvi * 2].as_mv = mv0;
530
0
      mv_refined[mvi * 2 + 1].as_mv = mv1;
531
0
    }
532
    // Refine MV using optical flow. The final output MV will be in 1/16
533
    // precision.
534
0
    av2_get_optflow_based_mv(cm, xd, plane, mbmi, mv_refined, bw, bh, mi_x,
535
0
                             mi_y, 0 /* build_for_decode */, mc_buf,
536
0
                             calc_subpel_params_func, gx0, gy0, gx1, gy1, vx0,
537
0
                             vy0, vx1, vy1, dst0, dst1, opfl_dst_stride, 0,
538
0
                             use_4x4, best_mv_ref, bw, bh);
539
0
    xd->opfl_vxy_bufs[0] = *vx0;
540
0
    xd->opfl_vxy_bufs[N_OF_OFFSETS * 1] = *vx1;
541
0
    xd->opfl_vxy_bufs[N_OF_OFFSETS * 2] = *vy0;
542
0
    xd->opfl_vxy_bufs[N_OF_OFFSETS * 3] = *vy1;
543
0
  }
544
545
0
  if (plane == 0) {
546
0
    xd->mv_refined[0] = mv_refined[0];
547
0
    xd->mv_refined[1] = mv_refined[1];
548
0
  }
549
550
0
  BacpBlockData bacp_block_data[2 * N_OF_OFFSETS];
551
0
  const struct scale_factors *const sf0 = cm->tip_ref.ref_scale_factor[0];
552
0
  const struct scale_factors *const sf1 = cm->tip_ref.ref_scale_factor[1];
553
0
  uint8_t use_bacp = cm->features.enable_imp_msk_bld && !av2_is_scaled(sf0) &&
554
0
                     !av2_is_scaled(sf1);
555
556
0
  for (int ref = 0; ref < 2; ++ref) {
557
0
    const struct scale_factors *const sf = cm->tip_ref.ref_scale_factor[ref];
558
0
    struct buf_2d *const pred_buf = &xd->plane[plane].pre[ref];
559
560
0
    InterPredParams inter_pred_params;
561
0
    av2_init_inter_params(&inter_pred_params, comp_bw, comp_bh, comp_pixel_y,
562
0
                          comp_pixel_x, ss_x, ss_y, bd, 0, sf, pred_buf,
563
0
                          cm->tip_interp_filter);
564
565
0
    if (apply_refinemv || do_opfl) {
566
0
      inter_pred_params.use_ref_padding = 1;
567
0
      inter_pred_params.ref_area = &ref_area[ref];
568
0
    }
569
570
0
    inter_pred_params.comp_mode = UNIFORM_COMP;
571
572
0
    inter_pred_params.border_data.enable_bacp = use_bacp;
573
0
    inter_pred_params.border_data.bacp_block_data =
574
0
        &bacp_block_data[0];  // Always point to the first ref
575
0
    inter_pred_params.sb_type = mbmi->sb_type[PLANE_TYPE_Y];
576
0
    inter_pred_params.mask_comp = mbmi->interinter_comp;
577
578
0
    inter_pred_params.conv_params =
579
0
        get_conv_params_no_round(ref, plane, tmp_conv_dst, MAX_SB_SIZE, 1, bd);
580
581
0
    if (do_opfl) {
582
0
      av2_opfl_rebuild_inter_predictor(
583
0
          dst, dst_stride, plane, mv_refined, &inter_pred_params, xd, mi_x,
584
0
          mi_y, 0 /* build_for_decode */, cm, bw, ref, mc_buf,
585
0
          calc_subpel_params_func, use_4x4, mbmi, bh, mv, 0);
586
0
    } else {
587
0
      const MV mv_1_16th_pel = convert_mv_to_1_16th_pel(&best_mv_ref[ref]);
588
0
      av2_build_one_inter_predictor(dst, dst_stride, &mv_1_16th_pel,
589
0
                                    &inter_pred_params, xd, mi_x, mi_y, ref,
590
0
                                    mc_buf, calc_subpel_params_func);
591
0
    }
592
0
  }
593
594
0
  xd->tmp_conv_dst = org_buf;
595
0
}
596
597
static AVM_INLINE void tip_build_inter_predictors_8x8_and_bigger(
598
    const AV2_COMMON *cm, MACROBLOCKD *xd, int plane, TIP_PLANE *tip_plane,
599
    const MV mv[2], int bw, int bh, int mi_x, int mi_y, uint16_t **mc_buf,
600
0
    CONV_BUF_TYPE *tmp_conv_dst, CalcSubpelParamsFunc calc_subpel_params_func) {
601
0
  TIP_PLANE *const tip = &tip_plane[plane];
602
0
  struct buf_2d *const dst_buf = &tip->dst;
603
0
  uint16_t *const dst = dst_buf->buf;
604
605
0
  BLOCK_SIZE unit_bsize = get_tip_bsize_from_bw_bh(bw, bh);
606
0
  int unit_bw = block_size_wide[unit_bsize];
607
0
  int unit_bh = block_size_high[unit_bsize];
608
0
  xd->tree_type = SHARED_PART;
609
0
  const int width = (cm->mi_params.mi_cols << MI_SIZE_LOG2);
610
0
  const int height = (cm->mi_params.mi_rows << MI_SIZE_LOG2);
611
0
  xd->mb_to_top_edge = -GET_MV_SUBPEL(mi_y);
612
0
  xd->mb_to_bottom_edge = GET_MV_SUBPEL(height - bh - mi_y);
613
0
  xd->mb_to_left_edge = -GET_MV_SUBPEL(mi_x);
614
0
  xd->mb_to_right_edge = GET_MV_SUBPEL(width - bw - mi_x);
615
0
  const int ss_x = plane ? cm->seq_params.subsampling_x : 0;
616
0
  const int ss_y = plane ? cm->seq_params.subsampling_y : 0;
617
0
  const int comp_pixel_x = (mi_x >> ss_x);
618
0
  const int comp_pixel_y = (mi_y >> ss_y);
619
0
  const int comp_bw = bw >> ss_x;
620
0
  const int comp_bh = bh >> ss_y;
621
622
0
  const int has_both_sides_refs = cm->has_both_sides_refs;
623
0
  const int tip_wtd_index = cm->tip_global_wtd_index;
624
0
  const int8_t tip_weight = tip_weighting_factors[tip_wtd_index];
625
0
  const int is_compound = tip_weight != TIP_SINGLE_WTD;
626
627
0
  uint16_t
628
0
      dst0_16_refinemv[2 *
629
0
                       (REFINEMV_SUBBLOCK_WIDTH +
630
0
                        2 * (SUBBLK_REF_EXT_LINES + SMVR_SEARCH_EXT_LINES)) *
631
0
                       (REFINEMV_SUBBLOCK_HEIGHT +
632
0
                        2 * (SUBBLK_REF_EXT_LINES + SMVR_SEARCH_EXT_LINES))];
633
0
  uint16_t
634
0
      dst1_16_refinemv[2 *
635
0
                       (REFINEMV_SUBBLOCK_WIDTH +
636
0
                        2 * (SUBBLK_REF_EXT_LINES + SMVR_SEARCH_EXT_LINES)) *
637
0
                       (REFINEMV_SUBBLOCK_HEIGHT +
638
0
                        2 * (SUBBLK_REF_EXT_LINES + SMVR_SEARCH_EXT_LINES))];
639
640
0
  const int apply_refinemv =
641
0
      (cm->seq_params.enable_refinemv && cm->seq_params.enable_tip_refinemv &&
642
0
       plane == 0 && has_both_sides_refs && is_compound &&
643
0
       tip_weight == TIP_EQUAL_WTD);
644
645
0
  ReferenceArea ref_area[2];
646
0
  const int do_opfl = cm->features.opfl_refine_type != REFINE_NONE &&
647
0
                      cm->seq_params.enable_tip_refinemv &&
648
0
                      cm->features.use_optflow_tip && plane == 0;
649
0
  int is_tip_mv_refine_disabled_for_unit_size_16x16 =
650
0
      is_tip_mv_refinement_disabled_for_unit_size_16x16(
651
0
          unit_bh, cm->seq_params.enable_tip_refinemv,
652
0
          cm->features.tip_frame_mode);
653
0
  const int do_ref_area_pad = cm->seq_params.enable_tip_refinemv &&
654
0
                              cm->has_both_sides_refs &&
655
0
                              !is_tip_mv_refine_disabled_for_unit_size_16x16;
656
0
  if (do_ref_area_pad) {
657
0
    MB_MODE_INFO *mbmi = avm_calloc(1, sizeof(*mbmi));
658
0
    mbmi->mv[0].as_mv = mv[0];
659
0
    mbmi->mv[1].as_mv = mv[1];
660
0
    mbmi->ref_frame[0] = TIP_FRAME;
661
0
    mbmi->ref_frame[1] = NONE_FRAME;
662
0
    mbmi->interp_fltr = EIGHTTAP_REGULAR;
663
0
    mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
664
0
    mbmi->use_intrabc[0] = 0;
665
0
    mbmi->morph_pred = 0;
666
0
    mbmi->motion_mode = SIMPLE_TRANSLATION;
667
0
    mbmi->sb_type[PLANE_TYPE_Y] = unit_bsize;
668
0
    mbmi->interinter_comp.type = COMPOUND_AVERAGE;
669
0
    mbmi->max_mv_precision = MV_PRECISION_ONE_EIGHTH_PEL;
670
0
    mbmi->pb_mv_precision = MV_PRECISION_ONE_EIGHTH_PEL;
671
0
    const int mi_row = -xd->mb_to_top_edge >> MI_SUBPEL_SIZE_LOG2;
672
0
    const int mi_col = -xd->mb_to_left_edge >> MI_SUBPEL_SIZE_LOG2;
673
0
    mbmi->chroma_ref_info.mi_row_chroma_base = mi_row;
674
0
    mbmi->chroma_ref_info.mi_col_chroma_base = mi_col;
675
0
    av2_get_reference_area_with_padding(cm, xd, plane, mbmi, mv, comp_bw,
676
0
                                        comp_bh, mi_x, mi_y, ref_area, comp_bw,
677
0
                                        comp_bh);
678
0
    avm_free(mbmi);
679
0
  }
680
681
0
  int dst_stride = dst_buf->stride;
682
0
  if (plane == 0 && !is_tip_mv_refine_disabled_for_unit_size_16x16 &&
683
0
      is_any_mv_refinement_allowed_in_tip(cm) && is_compound &&
684
0
      tip_weight == TIP_EQUAL_WTD && (do_opfl || apply_refinemv)) {
685
0
    if (bw != unit_bw || bh != unit_bh) {
686
0
      for (int h = 0; h < bh; h += unit_bh) {
687
0
        for (int w = 0; w < bw; w += unit_bw) {
688
0
          dst_buf->buf = dst + h * dst_stride + w;
689
0
          tip_build_inter_predictors_8x8_and_bigger(
690
0
              cm, xd, plane, tip_plane, mv, unit_bw, unit_bh, mi_x + w,
691
0
              mi_y + h, mc_buf, tmp_conv_dst, calc_subpel_params_func);
692
0
        }
693
0
      }
694
0
      dst_buf->buf = dst;
695
0
      return;
696
0
    }
697
0
    tip_build_inter_predictors_8x8(
698
0
        cm, xd, plane, unit_bsize, mv, mi_x, mi_y, mc_buf, tmp_conv_dst,
699
0
        calc_subpel_params_func, dst, dst_stride, dst0_16_refinemv,
700
0
        dst1_16_refinemv, ref_area);
701
0
    return;
702
0
  }
703
704
0
  const int bd = cm->seq_params.bit_depth;
705
706
0
  if (plane == 0) {
707
0
    xd->mv_refined[0].as_mv = convert_mv_to_1_16th_pel(&mv[0]);
708
0
    xd->mv_refined[1].as_mv = convert_mv_to_1_16th_pel(&mv[1]);
709
0
  }
710
711
0
  BacpBlockData bacp_block_data[2 * N_OF_OFFSETS];
712
0
  const struct scale_factors *const sf0 = cm->tip_ref.ref_scale_factor[0];
713
0
  const struct scale_factors *const sf1 = cm->tip_ref.ref_scale_factor[1];
714
0
  uint8_t use_bacp = is_compound && tip_weight == TIP_EQUAL_WTD &&
715
0
                     cm->features.enable_imp_msk_bld && !av2_is_scaled(sf0) &&
716
0
                     !av2_is_scaled(sf1);
717
718
0
  for (int ref = 0; ref < 1 + is_compound; ++ref) {
719
0
    const struct scale_factors *const sf = cm->tip_ref.ref_scale_factor[ref];
720
0
    struct buf_2d *const pred_buf = &xd->plane[plane].pre[ref];
721
722
0
    InterPredParams inter_pred_params;
723
0
    av2_init_inter_params(&inter_pred_params, comp_bw, comp_bh, comp_pixel_y,
724
0
                          comp_pixel_x, ss_x, ss_y, bd, 0, sf, pred_buf,
725
0
                          cm->tip_interp_filter);
726
727
0
    if (is_compound) {
728
0
      inter_pred_params.comp_mode = UNIFORM_COMP;
729
0
    }
730
731
0
    inter_pred_params.border_data.enable_bacp = use_bacp;
732
0
    inter_pred_params.border_data.bacp_block_data =
733
0
        &bacp_block_data[0];  // Always point to the first ref
734
0
    inter_pred_params.sb_type = unit_bsize;
735
0
    if (is_compound) {
736
0
      inter_pred_params.mask_comp.type = COMPOUND_AVERAGE;
737
0
    }
738
739
0
    inter_pred_params.conv_params = get_conv_params_no_round(
740
0
        ref, plane, tmp_conv_dst, MAX_SB_SIZE, is_compound, bd);
741
742
0
    set_tip_interp_weight_factor(cm, ref, &inter_pred_params);
743
744
0
    if (do_ref_area_pad) {
745
0
      inter_pred_params.use_ref_padding = 1;
746
0
      inter_pred_params.ref_area = &ref_area[ref];
747
0
    }
748
749
0
    const MV mv_1_16th_pel =
750
0
        plane ? xd->mv_refined[ref].as_mv : convert_mv_to_1_16th_pel(&mv[ref]);
751
752
0
    av2_build_one_inter_predictor(dst, dst_buf->stride, &mv_1_16th_pel,
753
0
                                  &inter_pred_params, xd, mi_x, mi_y, ref,
754
0
                                  mc_buf, calc_subpel_params_func);
755
0
  }
756
0
}
757
758
static AVM_INLINE void tip_component_build_inter_predictors(
759
    const AV2_COMMON *cm, MACROBLOCKD *xd, int plane, TIP_PLANE *tip_plane,
760
    const MV mv[2], int bw, int bh, int mi_x, int mi_y, uint16_t **mc_buf,
761
0
    CONV_BUF_TYPE *tmp_conv_dst, CalcSubpelParamsFunc calc_subpel_params_func) {
762
0
  tip_build_inter_predictors_8x8_and_bigger(
763
0
      cm, xd, plane, tip_plane, mv, bw, bh, mi_x, mi_y, mc_buf, tmp_conv_dst,
764
0
      calc_subpel_params_func);
765
0
}
766
767
static INLINE void tip_setup_pred_plane(struct buf_2d *dst, uint16_t *src,
768
                                        int width, int height, int crop_width,
769
                                        int crop_height, int stride,
770
                                        int tpl_row, int tpl_col,
771
                                        const struct scale_factors *scale,
772
0
                                        int subsampling_x, int subsampling_y) {
773
0
  const int x = tpl_col >> subsampling_x;
774
0
  const int y = tpl_row >> subsampling_y;
775
0
  dst->buf = src + scaled_buffer_offset(x, y, stride, scale);
776
0
  dst->buf0 = src;
777
0
  dst->width = width;
778
0
  dst->height = height;
779
0
  dst->crop_width = crop_width;
780
0
  dst->crop_height = crop_height;
781
0
  dst->stride = stride;
782
0
}
783
784
static AVM_INLINE void tip_component_setup_dst_planes(
785
    AV2_COMMON *const cm, TIP_PLANE *const tip_plane, const int plane,
786
0
    const int tpl_row, const int tpl_col) {
787
0
  const YV12_BUFFER_CONFIG *src = &cm->tip_ref.tip_frame->buf;
788
0
  TIP_PLANE *const pd = &tip_plane[plane];
789
0
  int is_uv = 0;
790
0
  int subsampling_x = 0;
791
0
  int subsampling_y = 0;
792
0
  if (plane > 0) {
793
0
    is_uv = 1;
794
0
    subsampling_x = cm->seq_params.subsampling_x;
795
0
    subsampling_y = cm->seq_params.subsampling_y;
796
0
  }
797
0
  tip_setup_pred_plane(&pd->dst, src->buffers[plane], src->widths[is_uv],
798
0
                       src->heights[is_uv], src->crop_widths[is_uv],
799
0
                       src->crop_heights[is_uv], src->strides[is_uv], tpl_row,
800
0
                       tpl_col, NULL, subsampling_x, subsampling_y);
801
0
}
802
803
void av2_tip_setup_tip_frame_row(AV2_COMMON *cm, MACROBLOCKD *xd, int blk_row,
804
                                 int blk_col_start, int blk_row_end,
805
                                 int blk_col_end, int mvs_stride,
806
                                 int unit_blk_size, int max_allow_blk_size,
807
                                 uint16_t **mc_buf, CONV_BUF_TYPE *tmp_conv_dst,
808
                                 CalcSubpelParamsFunc calc_subpel_params_func,
809
0
                                 int copy_refined_mvs) {
810
0
  TIP *tip_ref = &cm->tip_ref;
811
0
  const TPL_MV_REF *tpl_mvs_base = cm->tpl_mvs;
812
0
  int enable_tip_refinemv = cm->seq_params.enable_tip_refinemv;
813
814
0
  MV zero_mv[2];
815
0
  memset(zero_mv, 0, sizeof(zero_mv));
816
817
0
  const int step = (unit_blk_size >> TMVP_MI_SZ_LOG2);
818
0
  for (int blk_col = blk_col_start; blk_col < blk_col_end; blk_col += step) {
819
0
    const int tpl_offset = blk_row * mvs_stride;
820
0
    const TPL_MV_REF *tpl_mvs = tpl_mvs_base + tpl_offset;
821
0
    const int tpl_row = blk_row << TMVP_MI_SZ_LOG2;
822
0
    const int tpl_col = blk_col << TMVP_MI_SZ_LOG2;
823
824
0
    int blk_width = unit_blk_size;
825
0
    int blk_height = unit_blk_size;
826
0
    if (is_tip_mv_refinement_disabled_for_unit_size_16x16(
827
0
            unit_blk_size, enable_tip_refinemv, cm->features.tip_frame_mode)) {
828
0
      blk_width = get_tip_block_width_with_same_mv(
829
0
          cm, tpl_mvs, unit_blk_size, blk_col, blk_col_end, max_allow_blk_size);
830
0
    }
831
832
0
    tpl_mvs = tpl_mvs + blk_col;
833
0
    MV mv[2];
834
0
    if (tpl_mvs->mfmv0.as_int != 0 && tpl_mvs->mfmv0.as_int != INVALID_MV) {
835
0
      tip_get_mv_projection(&mv[0], tpl_mvs->mfmv0.as_mv,
836
0
                            tip_ref->ref_frames_offset_sf[0]);
837
0
      tip_get_mv_projection(&mv[1], tpl_mvs->mfmv0.as_mv,
838
0
                            tip_ref->ref_frames_offset_sf[1]);
839
0
      mv[0].row = (MV_COMP_DATA_TYPE)clamp(
840
0
          mv[0].row + cm->tip_global_motion.as_mv.row, MV_LOW + 1, MV_UPP - 1);
841
0
      mv[0].col = (MV_COMP_DATA_TYPE)clamp(
842
0
          mv[0].col + cm->tip_global_motion.as_mv.col, MV_LOW + 1, MV_UPP - 1);
843
0
      mv[1].row = (MV_COMP_DATA_TYPE)clamp(
844
0
          mv[1].row + cm->tip_global_motion.as_mv.row, MV_LOW + 1, MV_UPP - 1);
845
0
      mv[1].col = (MV_COMP_DATA_TYPE)clamp(
846
0
          mv[1].col + cm->tip_global_motion.as_mv.col, MV_LOW + 1, MV_UPP - 1);
847
0
    } else {
848
0
      mv[0] = cm->tip_global_motion.as_mv;
849
0
      mv[1] = cm->tip_global_motion.as_mv;
850
0
    }
851
852
0
    for (int plane = 0; plane < av2_num_planes(cm); plane++) {
853
0
      if (plane == 0 && copy_refined_mvs) {
854
0
        REFINEMV_SUBMB_INFO *refinemv_subinfo = &xd->refinemv_subinfo[0];
855
0
        fill_subblock_refine_mv(refinemv_subinfo, blk_width, blk_height, mv[0],
856
0
                                mv[1]);
857
0
        xd->opfl_vxy_bufs[0] = 0;
858
0
        xd->opfl_vxy_bufs[N_OF_OFFSETS * 1] = 0;
859
0
        xd->opfl_vxy_bufs[N_OF_OFFSETS * 2] = 0;
860
0
        xd->opfl_vxy_bufs[N_OF_OFFSETS * 3] = 0;
861
0
      }
862
863
0
      setup_pred_planes_for_tip(&cm->tip_ref, xd, plane, plane + 1,
864
0
                                tpl_col >> MI_SIZE_LOG2,
865
0
                                tpl_row >> MI_SIZE_LOG2);
866
867
0
      tip_component_setup_dst_planes(cm, xd->tip_plane, plane, tpl_row,
868
0
                                     tpl_col);
869
0
      tip_component_build_inter_predictors(
870
0
          cm, xd, plane, xd->tip_plane, mv, blk_width, blk_height, tpl_col,
871
0
          tpl_row, mc_buf, tmp_conv_dst, calc_subpel_params_func);
872
873
0
      if (plane == 0 && copy_refined_mvs) {
874
0
        MB_MODE_INFO mbmi;
875
0
        av2_zero(mbmi);
876
0
        mbmi.sb_type[PLANE_TYPE_Y] =
877
0
            get_tip_bsize_from_bw_bh(blk_width, blk_height);
878
0
        mbmi.ref_frame[0] = TIP_FRAME;
879
0
        mbmi.ref_frame[1] = NONE_FRAME;
880
0
        mbmi.mode = NEWMV;
881
0
        mbmi.skip_mode = 0;
882
0
        mbmi.motion_mode = SIMPLE_TRANSLATION;
883
0
        mbmi.interinter_comp.type = COMPOUND_AVERAGE;
884
0
        mbmi.cwp_idx = 0;
885
0
        mbmi.refinemv_flag = 0;
886
887
        // Save the MVs before refinement into the TMVP list.
888
0
        mbmi.mv[0].as_mv = cm->tip_global_motion.as_mv;
889
0
        mbmi.mv[1].as_mv = cm->tip_global_motion.as_mv;
890
891
0
        const int x_inside_boundary =
892
0
            AVMMIN(blk_width >> MI_SIZE_LOG2, (blk_col_end - blk_col)
893
0
                                                  << TMVP_SHIFT_BITS);
894
0
        const int y_inside_boundary =
895
0
            AVMMIN(step << TMVP_SHIFT_BITS, (blk_row_end - blk_row)
896
0
                                                << TMVP_SHIFT_BITS);
897
0
        if (cm->seq_params.order_hint_info.enable_ref_frame_mvs) {
898
0
          if (enable_refined_mvs_in_tmvp(cm, xd, &mbmi)) {
899
0
            av2_copy_frame_refined_mvs(cm, xd, &mbmi,
900
0
                                       blk_row << TMVP_SHIFT_BITS,
901
0
                                       blk_col << TMVP_SHIFT_BITS,
902
0
                                       x_inside_boundary, y_inside_boundary);
903
0
          } else {
904
0
            av2_copy_frame_mvs(cm, xd, &mbmi, blk_row << TMVP_SHIFT_BITS,
905
0
                               blk_col << TMVP_SHIFT_BITS, x_inside_boundary,
906
0
                               y_inside_boundary);
907
0
          }
908
0
        }
909
0
      }
910
0
    }
911
0
    blk_col += (blk_width >> TMVP_MI_SZ_LOG2) - step;
912
0
  }
913
0
}
914
915
// Frame processing for TIP
916
static void tip_setup_tip_frame_plane(
917
    AV2_COMMON *cm, MACROBLOCKD *xd, int blk_row_start, int blk_col_start,
918
    int blk_row_end, int blk_col_end, int mvs_stride, int unit_blk_size,
919
    int max_allow_blk_size, uint16_t **mc_buf, CONV_BUF_TYPE *tmp_conv_dst,
920
0
    CalcSubpelParamsFunc calc_subpel_params_func, int copy_refined_mvs) {
921
0
  const int step = (unit_blk_size >> TMVP_MI_SZ_LOG2);
922
0
  for (int blk_row = blk_row_start; blk_row < blk_row_end; blk_row += step) {
923
0
    av2_tip_setup_tip_frame_row(cm, xd, blk_row, blk_col_start, blk_row_end,
924
0
                                blk_col_end, mvs_stride, unit_blk_size,
925
0
                                max_allow_blk_size, mc_buf, tmp_conv_dst,
926
0
                                calc_subpel_params_func, copy_refined_mvs);
927
0
  }
928
0
}
929
930
static AVM_INLINE void tip_setup_tip_frame_planes(
931
    AV2_COMMON *cm, MACROBLOCKD *xd, int blk_row_start, int blk_col_start,
932
    int blk_row_end, int blk_col_end, int mvs_stride, uint16_t **mc_buf,
933
    CONV_BUF_TYPE *tmp_conv_dst, CalcSubpelParamsFunc calc_subpel_params_func,
934
0
    int copy_refined_mvs) {
935
0
  int unit_blk_size = (get_unit_bsize_for_tip_frame(
936
0
                           cm->features.tip_frame_mode, cm->tip_interp_filter,
937
0
                           cm->seq_params.enable_tip_refinemv) == BLOCK_16X16)
938
0
                          ? 16
939
0
                          : 8;
940
0
  tip_setup_tip_frame_plane(cm, xd, blk_row_start, blk_col_start, blk_row_end,
941
0
                            blk_col_end, mvs_stride, unit_blk_size,
942
0
                            MAX_BLOCK_SIZE_WITH_SAME_MV, mc_buf, tmp_conv_dst,
943
0
                            calc_subpel_params_func, copy_refined_mvs);
944
945
0
  avm_extend_frame_borders(&cm->tip_ref.tip_frame->buf, av2_num_planes(cm),
946
0
                           cm->decoding);
947
0
}
948
949
void av2_setup_tip_frame(AV2_COMMON *cm, MACROBLOCKD *xd, uint16_t **mc_buf,
950
                         CONV_BUF_TYPE *tmp_conv_dst,
951
                         CalcSubpelParamsFunc calc_subpel_params_func,
952
0
                         int copy_refined_mvs) {
953
0
  const int mvs_rows =
954
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_rows, TMVP_SHIFT_BITS);
955
0
  const int mvs_cols =
956
0
      ROUND_POWER_OF_TWO(cm->mi_params.mi_cols, TMVP_SHIFT_BITS);
957
0
  tip_setup_tip_frame_planes(cm, xd, 0, 0, mvs_rows, mvs_cols, mvs_cols, mc_buf,
958
0
                             tmp_conv_dst, calc_subpel_params_func,
959
0
                             copy_refined_mvs);
960
0
}