Coverage Report

Created: 2026-08-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/mode_decision.c
Line
Count
Source
1
/*
2
* Copyright(c) 2019 Intel Corporation
3
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
4
*
5
* This source code is subject to the terms of the BSD 3-Clause Clear License and
6
* the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear License
7
* was not distributed with this source code in the LICENSE file, you can
8
* obtain it at https://www.aomedia.org/license. If the Alliance for Open
9
* Media Patent License 1.0 was not distributed with this source code in the
10
* PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
11
*/
12
13
/***************************************
14
* Includes
15
***************************************/
16
#include <stdbool.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <limits.h>
20
21
#include "common_utils.h"
22
#include "enc_dec_process.h"
23
#include "definitions.h"
24
#include "sequence_control_set.h"
25
#include "mode_decision.h"
26
#include "md_process.h"
27
#include "motion_estimation.h"
28
29
#include "av1me.h"
30
#include "hash.h"
31
#include "enc_inter_prediction.h"
32
#include "rd_cost.h"
33
#include "aom_dsp_rtcd.h"
34
#include "svt_log.h"
35
#include "resize.h"
36
#include "mcomp.h"
37
#include "ac_bias.h"
38
#include "src_ops_process.h"
39
#include "utility.h"
40
#include "adaptive_mv_pred.h"
41
#include "av1me.h"
42
static const uint32_t intra_luma_to_chroma[INTRA_MODES] = {
43
    UV_DC_PRED, // Average of above and left pixels
44
    UV_V_PRED, // Vertical
45
    UV_H_PRED, // Horizontal
46
    UV_D45_PRED, // Directional 45  degree
47
    UV_D135_PRED, // Directional 135 degree
48
    UV_D113_PRED, // Directional 113 degree
49
    UV_D157_PRED, // Directional 157 degree
50
    UV_D203_PRED, // Directional 203 degree
51
    UV_D67_PRED, // Directional 67  degree
52
    UV_SMOOTH_PRED, // Combination of horizontal and vertical interpolation
53
    UV_SMOOTH_V_PRED, // Vertical interpolation
54
    UV_SMOOTH_H_PRED, // Horizontal interpolation
55
    UV_PAETH_PRED, // Predict from the direction of smallest gradient
56
};
57
58
void calc_target_weighted_pred(PictureControlSet* pcs, ModeDecisionContext* ctx, const Av1Common* cm,
59
                               const MacroBlockD* xd, int mi_row, int mi_col, const uint8_t* above, int above_stride,
60
                               const uint8_t* left, int left_stride);
61
#define INC_MD_CAND_CNT(cnt, max_can_count)                  \
62
314k
    MULTI_LINE_MACRO_BEGIN                                   \
63
314k
    if (cnt + 1 < max_can_count)                             \
64
314k
        cnt++;                                               \
65
314k
    else                                                     \
66
18.4E
        SVT_ERROR("Mode decision candidate count exceeded"); \
67
314k
    MULTI_LINE_MACRO_END
68
69
0
#define SUPERRES_INVALID_STATE 0x7fffffff
70
71
2.96M
bool svt_av1_is_lossless_segment(PictureControlSet* pcs, int8_t segment_id) {
72
#if !CONFIG_ENABLE_LOSSLESS
73
    (void)pcs;
74
    (void)segment_id;
75
    return false;
76
#else
77
2.96M
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
78
2.96M
    if (frm_hdr->segmentation_params.segmentation_enabled) {
79
0
        return pcs->lossless[segment_id];
80
2.96M
    } else {
81
2.96M
        return pcs->lossless[0];
82
2.96M
    }
83
2.96M
#endif
84
2.96M
}
85
86
0
static bool check_mv_validity(int16_t x_mv, int16_t y_mv, uint8_t need_shift) {
87
0
    Mv mv;
88
    //go to 1/8th if input is 1/4pel
89
0
    mv.y = y_mv << need_shift;
90
0
    mv.x = x_mv << need_shift;
91
    /* AV1 limits
92
      -16384 < MV_x_in_1/8 or MV_y_in_1/8 < 16384
93
      which means in full pel:
94
      -2048 < MV_x_in_full_pel or MV_y_in_full_pel < 2048
95
    */
96
0
    if (!is_mv_valid(mv)) {
97
0
        return false;
98
0
    }
99
0
    return true;
100
0
}
101
102
int svt_is_interintra_allowed(uint8_t enable_inter_intra, BlockSize bsize, PredictionMode mode,
103
0
                              const MvReferenceFrame ref_frame[2]) {
104
0
    return enable_inter_intra && svt_aom_is_interintra_allowed_bsize((const BlockSize)bsize) &&
105
0
        svt_aom_is_interintra_allowed_mode(mode) && svt_aom_is_interintra_allowed_ref(ref_frame);
106
0
}
107
108
0
int svt_aom_filter_intra_allowed_bsize(BlockSize bs) {
109
0
    if (!CONFIG_ENABLE_FILTER_INTRA) {
110
0
        return 0; // filter_intra off -> const-folds, cascades DCE
111
0
    }
112
0
    return block_size_wide[bs] <= 32 && block_size_high[bs] <= 32;
113
0
}
114
115
315k
int svt_aom_filter_intra_allowed(uint8_t enable_filter_intra, BlockSize bsize, uint8_t palette_size, uint32_t mode) {
116
315k
    if (!CONFIG_ENABLE_FILTER_INTRA) {
117
0
        return 0; // filter_intra off
118
0
    }
119
315k
    return enable_filter_intra && mode == DC_PRED && palette_size == 0 && svt_aom_filter_intra_allowed_bsize(bsize);
120
315k
}
121
122
#if CONFIG_ENABLE_INTER_COMPOUND
123
// returns the max inter-inter compound type based on settings and block size
124
0
static MD_COMP_TYPE get_tot_comp_types_bsize(MD_COMP_TYPE tot_comp_types, BlockSize bsize) {
125
0
    return (svt_aom_get_wedge_params_bits(bsize) == 0) ? MIN(tot_comp_types, MD_COMP_WEDGE) : tot_comp_types;
126
0
}
127
#endif
128
129
/*
130
Get the ME offset for a given block (the offset used to locate the PA MVs from the parent PCS).
131
*/
132
uint32_t svt_aom_get_me_block_offset(const uint32_t org_x, const uint32_t org_y, const BlockSize bsize,
133
157k
                                     const uint8_t enable_me_8x8, const uint8_t enable_me_16x16) {
134
157k
    const int      bwidth     = block_size_wide[bsize];
135
157k
    const int      bheight    = block_size_high[bsize];
136
157k
    const uint32_t max_length = MAX(bwidth, bheight);
137
138
157k
    uint32_t me_idx = 0;
139
157k
    switch (max_length) {
140
0
    case 4:
141
153k
    case 8:
142
153k
        me_idx++;
143
153k
        if (org_x & 8) { // (org_x % 16) / 8
144
74.3k
            me_idx += 1;
145
74.3k
        }
146
153k
        if (org_y & 8) { // (org_y % 16) / 8
147
74.3k
            me_idx += 2;
148
74.3k
        }
149
153k
        AOM_FALLTHROUGH_INTENDED;
150
154k
    case 16:
151
154k
        me_idx++;
152
154k
        if (org_x & 16) { // (org_x % 32) / 16
153
73.1k
            me_idx += 5;
154
73.1k
        }
155
154k
        if (org_y & 16) { // (org_y % 32) / 16
156
73.0k
            me_idx += 10;
157
73.0k
        }
158
154k
        AOM_FALLTHROUGH_INTENDED;
159
155k
    case 32:
160
155k
        me_idx++;
161
155k
        if (org_x & 32) { // (org_x % 64) / 32
162
72.3k
            me_idx += 21;
163
72.3k
        }
164
155k
        if (org_y & 32) { // (org_y % 64) / 32
165
71.4k
            me_idx += 42;
166
71.4k
        }
167
155k
        break;
168
2.46k
    default:
169
        // me_idx = 0;
170
2.46k
        break;
171
157k
    }
172
173
157k
    uint32_t me_block_offset = me_idx_85[me_idx]; // convert idx to me_idx
174
175
157k
    if (!enable_me_8x8) {
176
157k
        if (me_block_offset >= MAX_SB64_PU_COUNT_NO_8X8) {
177
153k
            me_block_offset = me_idx_85_8x8_to_16x16_conversion[me_block_offset - MAX_SB64_PU_COUNT_NO_8X8];
178
153k
        }
179
157k
        assert(me_block_offset < 21);
180
157k
        if (!enable_me_16x16) {
181
0
            if (me_block_offset >= MAX_SB64_PU_COUNT_WO_16X16) {
182
0
                assert(me_block_offset < 21);
183
0
                me_block_offset = me_idx_16x16_to_parent_32x32_conversion[me_block_offset - MAX_SB64_PU_COUNT_WO_16X16];
184
0
            }
185
0
        }
186
157k
    }
187
188
157k
    return me_block_offset;
189
157k
}
190
191
//Given one reference frame identified by the pair (list_index,ref_index)
192
//indicate if ME data is valid
193
uint8_t svt_aom_is_me_data_present(uint32_t me_block_offset, uint32_t me_cand_offset, const MeSbResults* me_results,
194
0
                                   uint8_t list_idx, uint8_t ref_idx) {
195
0
    uint8_t            total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
196
0
    const MeCandidate* me_block_results = &me_results->me_candidate_array[me_cand_offset];
197
0
    for (uint32_t me_cand_i = 0; me_cand_i < total_me_cnt; ++me_cand_i) {
198
0
        const MeCandidate* me_cand = &me_block_results[me_cand_i];
199
0
        assert(me_cand->direction <= 2);
200
0
        if (me_cand->direction == 0 || me_cand->direction == 2) {
201
0
            if (list_idx == me_cand->ref0_list && ref_idx == me_cand->ref_idx_l0) {
202
0
                return 1;
203
0
            }
204
0
        }
205
0
        if (me_cand->direction == 1 || me_cand->direction == 2) {
206
0
            if (list_idx == me_cand->ref1_list && ref_idx == me_cand->ref_idx_l1) {
207
0
                return 1;
208
0
            }
209
0
        }
210
0
    }
211
0
    return 0;
212
0
}
213
214
/********************************************
215
* Constants
216
********************************************/
217
// 1 - Regular uni-pred ,
218
// 2 - Regular uni-pred + Wedge compound Inter Intra
219
// 3 - Regular uni-pred + Wedge compound Inter Intra + Smooth compound Inter Intra
220
221
#if CONFIG_ENABLE_OBMC
222
0
static bool warped_motion_mode_allowed(PictureControlSet* pcs, ModeDecisionContext* ctx) {
223
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
224
0
    return frm_hdr->allow_warped_motion && has_overlappable_candidates(ctx->blk_ptr) && ctx->blk_geom->bwidth >= 8 &&
225
0
        ctx->blk_geom->bheight >= 8 && ctx->wm_ctrls.enabled;
226
0
}
227
#endif
228
MotionMode svt_aom_obmc_motion_mode_allowed(
229
    const PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
230
    uint8_t          situation, // 0: candidate(s) preparation, 1: data preparation, 2: simple translation face-off
231
0
    MvReferenceFrame rf0, MvReferenceFrame rf1, PredictionMode mode) {
232
0
    if (!CONFIG_ENABLE_OBMC && !CONFIG_ENABLE_WARP) {
233
0
        return SIMPLE_TRANSLATION; // OBMC/warp off -> const-folds, cascades DCE
234
0
    }
235
0
    if (ctx->obmc_ctrls.trans_face_off && !situation) {
236
0
        return SIMPLE_TRANSLATION;
237
0
    }
238
    // check if should cap the max block size for obmc
239
240
0
    if (block_size_wide[bsize] > ctx->obmc_ctrls.max_blk_size ||
241
0
        block_size_high[bsize] > ctx->obmc_ctrls.max_blk_size) {
242
0
        return SIMPLE_TRANSLATION;
243
0
    }
244
0
    if (!ctx->obmc_ctrls.enabled) {
245
0
        return SIMPLE_TRANSLATION;
246
0
    }
247
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
248
249
0
    if (!frm_hdr->is_motion_mode_switchable) {
250
0
        return SIMPLE_TRANSLATION;
251
0
    }
252
253
0
    if (frm_hdr->force_integer_mv == 0) {
254
0
        const TransformationType gm_type = pcs->ppcs->global_motion[rf0].wmtype;
255
0
        if (is_global_mv_block(mode, bsize, gm_type)) {
256
0
            return SIMPLE_TRANSLATION;
257
0
        }
258
0
    }
259
0
    if (is_motion_variation_allowed_bsize(bsize) && is_inter_singleref_mode(mode) && rf1 != INTRA_FRAME &&
260
0
        !(rf1 > INTRA_FRAME)) // is_motion_variation_allowed_compound
261
0
    {
262
0
        if (!has_overlappable_candidates(ctx->blk_ptr)) { // check_num_overlappable_neighbors
263
0
            return SIMPLE_TRANSLATION;
264
0
        }
265
266
0
        return OBMC_CAUSAL;
267
0
    } else {
268
0
        return SIMPLE_TRANSLATION;
269
0
    }
270
0
}
271
272
//static uint32_t  AntiContouringIntraMode[11] = { EB_INTRA_PLANAR, EB_INTRA_DC, EB_INTRA_HORIZONTAL, EB_INTRA_VERTICAL,
273
//EB_INTRA_MODE_2, EB_INTRA_MODE_6, EB_INTRA_MODE_14, EB_INTRA_MODE_18, EB_INTRA_MODE_22, EB_INTRA_MODE_30, EB_INTRA_MODE_34 };
274
0
int32_t svt_aom_have_newmv_in_inter_mode(PredictionMode mode) {
275
0
    return (mode == NEWMV || mode == NEW_NEWMV || mode == NEAREST_NEWMV || mode == NEW_NEARESTMV ||
276
0
            mode == NEAR_NEWMV || mode == NEW_NEARMV);
277
0
}
278
279
static MvReferenceFrame to_ref_frame[2][4] = {{LAST_FRAME, LAST2_FRAME, LAST3_FRAME, GOLDEN_FRAME},
280
                                              {BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME, INVALID_REF}};
281
282
0
MvReferenceFrame svt_get_ref_frame_type(uint8_t list, uint8_t ref_idx) {
283
0
    return to_ref_frame[list][ref_idx];
284
0
};
285
286
0
uint8_t svt_aom_get_max_drl_index(uint8_t refmvCnt, PredictionMode mode) {
287
0
    uint8_t max_drl = 0;
288
289
0
    if (mode == NEWMV || mode == NEW_NEWMV) {
290
0
        if (refmvCnt < 2) {
291
0
            max_drl = 1;
292
0
        } else if (refmvCnt == 2) {
293
0
            max_drl = 2;
294
0
        } else {
295
0
            max_drl = 3;
296
0
        }
297
0
    }
298
299
0
    if (mode == NEARMV || mode == NEAR_NEARMV || mode == NEAR_NEWMV || mode == NEW_NEARMV) {
300
0
        if (refmvCnt < 3) {
301
0
            max_drl = 1;
302
0
        } else if (refmvCnt == 3) {
303
0
            max_drl = 2;
304
0
        } else {
305
0
            max_drl = 3;
306
0
        }
307
0
    }
308
309
0
    return max_drl;
310
0
}
311
312
0
#define MV_COST_WEIGHT 108
313
314
static int64_t pick_interintra_wedge(PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
315
                                     const uint8_t* const p0, const uint8_t* const p1, uint8_t* src_buf,
316
0
                                     uint32_t src_stride, int8_t* wedge_index_out) {
317
0
    assert(svt_aom_is_interintra_wedge_used(bsize));
318
    // assert(cpi->common.seq_params.enable_interintra_compound);
319
320
0
    const int bw = block_size_wide[bsize];
321
0
    const int bh = block_size_high[bsize];
322
0
    DECLARE_ALIGNED(32, int16_t, residual1[MAX_INTERINTRA_SB_SQUARE]); // src - pred1
323
0
    DECLARE_ALIGNED(32, int16_t, diff10[MAX_INTERINTRA_SB_SQUARE]); // pred1 - pred0
324
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
325
0
    if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
326
0
        svt_aom_highbd_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw, EB_TEN_BIT);
327
0
        svt_aom_highbd_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw, EB_TEN_BIT);
328
329
0
    } else
330
0
#endif
331
0
    {
332
0
        svt_aom_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw);
333
0
        svt_aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw);
334
0
    }
335
336
0
    int8_t  wedge_index = -1;
337
0
    int64_t rd          = pick_wedge_fixed_sign(pcs, ctx, bsize, residual1, diff10, 0, &wedge_index);
338
0
    *wedge_index_out    = wedge_index;
339
340
0
    return rd;
341
0
}
342
343
0
static void inter_intra_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand) {
344
0
    SequenceControlSet* scs = pcs->scs;
345
0
    DECLARE_ALIGNED(16, uint8_t, tmp_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
346
0
    DECLARE_ALIGNED(16, uint8_t, ii_pred_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
347
    // get inter pred for ref0
348
0
    EbPictureBufferDesc* src_pic = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? pcs->input_frame16bit : pcs->ppcs->enhanced_pic;
349
0
    uint16_t* src_buf_hbd = (uint16_t*)src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
350
0
    uint8_t*  src_buf     = src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
351
352
0
    uint8_t  bit_depth   = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? EB_TEN_BIT : EB_EIGHT_BIT;
353
0
    uint32_t full_lambda = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_lambda_md[EB_10_BIT_MD]
354
0
                                                             : ctx->full_lambda_md[EB_8_BIT_MD];
355
356
0
    uint32_t            bwidth  = ctx->blk_geom->bwidth;
357
0
    uint32_t            bheight = ctx->blk_geom->bheight;
358
0
    EbPictureBufferDesc pred_desc;
359
0
    pred_desc.border   = 0;
360
0
    pred_desc.y_stride = bwidth;
361
362
0
    EbPictureBufferDesc* ref_pic_list0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
363
0
    EbPictureBufferDesc* ref_pic_list1 = NULL;
364
365
    // Use scaled references if resolution of the reference is different from that of the input
366
    // Only have one ref
367
0
    if (ref_pic_list0 != NULL) {
368
0
        uint8_t list_idx0  = get_list_idx(cand->block_mi.ref_frame[0]);
369
0
        int8_t  ref_idx_l0 = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
370
0
        svt_aom_use_scaled_rec_refs_if_needed(
371
0
            pcs,
372
0
            pcs->ppcs->enhanced_pic,
373
0
            (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx0][ref_idx_l0]->object_ptr,
374
0
            &ref_pic_list0,
375
0
            SVT_EFFECTIVE_HBD_MD(ctx->hbd_md));
376
0
    }
377
0
    pred_desc.y_buffer = tmp_buf;
378
379
    //we call the regular inter prediction path here (no compound)
380
0
    cand->block_mi.interp_filters     = 0;
381
0
    cand->block_mi.is_interintra_used = 0;
382
0
    svt_aom_inter_prediction(scs,
383
0
                             pcs,
384
0
                             &cand->block_mi,
385
0
                             &cand->wm_params_l0,
386
0
                             &cand->wm_params_l1,
387
0
                             ctx->blk_ptr,
388
0
                             ctx->blk_geom->bsize,
389
0
                             ctx->shape,
390
0
                             false, // use_precomputed_obmc
391
0
                             false, // use_precomputed_ii - ii not performed here
392
0
                             ctx,
393
0
                             NULL,
394
0
                             NULL,
395
0
                             NULL,
396
0
                             ref_pic_list0,
397
0
                             ref_pic_list1,
398
0
                             ctx->blk_org_x,
399
0
                             ctx->blk_org_y,
400
0
                             &pred_desc, //output
401
0
                             0, //output org_x,
402
0
                             0, //output org_y,
403
0
                             PICTURE_BUFFER_DESC_LUMA_MASK,
404
0
                             SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? EB_TEN_BIT : EB_EIGHT_BIT,
405
0
                             0); // is_16bit_pipeline
406
407
0
    assert(svt_aom_is_interintra_wedge_used(ctx->blk_geom->bsize)); //if not I need to add nowedge path!!
408
409
0
    int64_t        best_interintra_rd   = INT64_MAX;
410
0
    InterIntraMode best_interintra_mode = INTERINTRA_MODES;
411
0
    for (int j = 0; j < INTERINTRA_MODES; ++j) {
412
        // if ((!cpi->oxcf.enable_smooth_intra || cpi->sf.disable_smooth_intra) &&
413
        //     (InterIntraMode)j == II_SMOOTH_PRED)
414
        //   continue;
415
0
        InterIntraMode interintra_mode = (InterIntraMode)j;
416
        // rmode = interintra_mode_cost[mbmi->interintra_mode];
417
0
        const int bsize_group = eb_size_group_lookup[ctx->blk_geom->bsize];
418
0
        const int rmode       = ctx->md_rate_est_ctx->inter_intra_mode_fac_bits[bsize_group][interintra_mode];
419
        // av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw);
420
0
        if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
421
0
            svt_aom_combine_interintra_highbd(interintra_mode, // mode,
422
0
                                              0, // use_wedge_interintra,
423
0
                                              0, // cand->interintra_wedge_index,
424
0
                                              0, // int wedge_sign,
425
0
                                              ctx->blk_geom->bsize,
426
0
                                              ctx->blk_geom->bsize, // plane_bsize,
427
0
                                              ii_pred_buf,
428
0
                                              bwidth, /*uint8_t *comppred, int compstride,*/
429
0
                                              tmp_buf,
430
0
                                              bwidth, /*const uint8_t *interpred, int interstride,*/
431
0
                                              ctx->intrapred_buf[j],
432
0
                                              bwidth /*const uint8_t *intrapred,   int intrastride*/,
433
0
                                              bit_depth);
434
0
        } else {
435
0
            svt_aom_combine_interintra(interintra_mode, //mode,
436
0
                                       0, //use_wedge_interintra,
437
0
                                       0, //cand->interintra_wedge_index,
438
0
                                       0, //int wedge_sign,
439
0
                                       ctx->blk_geom->bsize,
440
0
                                       ctx->blk_geom->bsize, // plane_bsize,
441
0
                                       ii_pred_buf,
442
0
                                       bwidth, /*uint8_t *comppred, int compstride,*/
443
0
                                       tmp_buf,
444
0
                                       bwidth, /*const uint8_t *interpred, int interstride,*/
445
0
                                       ctx->intrapred_buf[j],
446
0
                                       bwidth /*const uint8_t *intrapred,   int intrastride*/);
447
0
        }
448
0
        int64_t rd;
449
0
        if (ctx->inter_intra_comp_ctrls.use_rd_model) {
450
0
            int     rate_sum;
451
0
            int64_t dist_sum;
452
0
            model_rd_for_sb_with_curvfit(pcs,
453
0
                                         ctx,
454
0
                                         ctx->blk_geom->bsize,
455
0
                                         bwidth,
456
0
                                         bheight,
457
0
                                         SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? (uint8_t*)src_buf_hbd : src_buf,
458
0
                                         src_pic->y_stride,
459
0
                                         ii_pred_buf,
460
0
                                         bwidth,
461
0
                                         0,
462
0
                                         0,
463
0
                                         0,
464
0
                                         0,
465
0
                                         &rate_sum,
466
0
                                         &dist_sum,
467
0
                                         NULL,
468
0
                                         NULL,
469
0
                                         NULL);
470
471
0
            rd = RDCOST(full_lambda, rate_sum + rmode, dist_sum);
472
0
        } else {
473
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
474
0
            if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
475
0
                rd = svt_aom_highbd_sse((uint8_t*)src_buf_hbd, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
476
0
            } else
477
0
#endif
478
0
            {
479
0
                rd = svt_aom_sse(src_buf, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
480
0
            }
481
0
        }
482
0
        if (rd < best_interintra_rd) {
483
0
            best_interintra_rd             = rd;
484
0
            cand->block_mi.interintra_mode = best_interintra_mode = interintra_mode;
485
0
        }
486
0
    }
487
    // To test: Enable wedge search if source variance and edge strength are above the thresholds.
488
    //CHKN need to re-do intra pred using the winner, or have a separate intra serch for wedge
489
0
    int64_t       best_interintra_rd_wedge = INT64_MAX;
490
0
    const uint8_t ii_wedge_mode            = ctx->shape == PART_N ? ctx->inter_intra_comp_ctrls.wedge_mode_sq
491
0
                                                                  : ctx->inter_intra_comp_ctrls.wedge_mode_nsq;
492
0
    if (ii_wedge_mode) {
493
0
        best_interintra_rd_wedge = pick_interintra_wedge(
494
0
            pcs,
495
0
            ctx,
496
0
            ctx->blk_geom->bsize,
497
0
            ctx->intrapred_buf[best_interintra_mode],
498
0
            tmp_buf,
499
0
            SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? (uint8_t*)src_buf_hbd : src_buf,
500
0
            src_pic->y_stride,
501
0
            &cand->block_mi.interintra_wedge_index);
502
0
    }
503
504
    // for ii_wedge_mode 1, always inject wedge as a separate candidate; for wedge mode 2 only inject
505
    // if wedge is better than non-wedge
506
0
    if (ii_wedge_mode == 1 || best_interintra_rd_wedge < best_interintra_rd) {
507
0
        cand->block_mi.use_wedge_interintra = 1;
508
0
    } else {
509
0
        cand->block_mi.use_wedge_interintra = 0;
510
0
    }
511
0
}
512
513
static COMPOUND_TYPE to_av1_compound_lut[] = {COMPOUND_AVERAGE, COMPOUND_DISTWTD, COMPOUND_DIFFWTD, COMPOUND_WEDGE};
514
515
static void determine_compound_mode(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
516
0
                                    MD_COMP_TYPE cur_type) {
517
#if !CONFIG_ENABLE_INTER_COMPOUND
518
    (void)pcs;
519
    (void)ctx;
520
#endif
521
0
    BlockModeInfo* block_mi        = &cand->block_mi;
522
0
    block_mi->interinter_comp.type = to_av1_compound_lut[cur_type];
523
0
    switch (cur_type) {
524
0
    case MD_COMP_AVG:
525
0
        block_mi->comp_group_idx = 0;
526
0
        block_mi->compound_idx   = 1;
527
0
        break;
528
0
    case MD_COMP_DIST:
529
0
        block_mi->comp_group_idx = 0;
530
0
        block_mi->compound_idx   = 0;
531
0
        break;
532
0
    case MD_COMP_DIFF0:
533
0
        block_mi->comp_group_idx            = 1;
534
0
        block_mi->compound_idx              = 1;
535
0
        block_mi->interinter_comp.mask_type = 55;
536
0
#if CONFIG_ENABLE_INTER_COMPOUND
537
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
538
0
#endif
539
0
        break;
540
0
    case MD_COMP_WEDGE:
541
0
        block_mi->comp_group_idx = 1;
542
0
        block_mi->compound_idx   = 1;
543
0
#if CONFIG_ENABLE_INTER_COMPOUND
544
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
545
0
#endif
546
0
        break;
547
0
    default:
548
0
        SVT_ERROR("not used comp type\n");
549
0
        assert(0);
550
0
        break;
551
0
    }
552
0
}
553
554
void svt_aom_choose_best_av1_mv_pred(ModeDecisionContext* ctx, MvReferenceFrame ref_frame,
555
                                     PredictionMode mode, // NEW or NEW_NEW
556
                                     Mv mv0, Mv mv1,
557
                                     uint8_t* bestDrlIndex, // output
558
                                     Mv       best_pred_mv[2] // output
559
0
) {
560
0
    if (ctx->shut_fast_rate) {
561
0
        return;
562
0
    }
563
0
    if (ctx->approx_inter_rate > 1) {
564
0
        *bestDrlIndex   = 0;
565
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
566
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
567
0
        return;
568
0
    }
569
0
    int16_t mv0x = mv0.x;
570
0
    int16_t mv0y = mv0.y;
571
0
    int16_t mv1x = mv1.x;
572
0
    int16_t mv1y = mv1.y;
573
574
0
    uint8_t is_compound = is_inter_compound_mode(mode);
575
576
0
    struct MdRateEstimationContext* md_rate_est_ctx = ctx->md_rate_est_ctx;
577
0
    BlkStruct*                      blk_ptr         = ctx->blk_ptr;
578
0
    uint8_t                         max_drl_index;
579
0
    Mv                              nearestmv[2] = {{{0}}, {{0}}};
580
0
    Mv                              nearmv[2];
581
0
    Mv                              ref_mv[2];
582
0
    Mv                              mv;
583
584
0
    max_drl_index = svt_aom_get_max_drl_index(blk_ptr->av1xd->ref_mv_count[ref_frame], mode);
585
    // max_drl_index = 1;
586
587
0
    if (max_drl_index == 1) {
588
0
        *bestDrlIndex = 0;
589
590
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
591
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
592
0
    } else {
593
0
        uint8_t  drli;
594
0
        uint32_t best_mv_cost = 0xFFFFFFFF;
595
0
        for (drli = 0; drli < max_drl_index; drli++) {
596
0
            svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_frame, is_compound, mode, drli, nearestmv, nearmv, ref_mv);
597
598
            //compute the rate for this drli Cand
599
0
            mv.y             = mv0y;
600
0
            mv.x             = mv0x;
601
0
            uint32_t mv_rate = 0;
602
0
            if (ctx->approx_inter_rate) {
603
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost_light(mv, ref_mv[0]);
604
0
            } else {
605
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost(
606
0
                    mv, ref_mv[0], md_rate_est_ctx->nmv_vec_cost, md_rate_est_ctx->nmvcoststack, MV_COST_WEIGHT);
607
0
            }
608
609
0
            if (is_compound) {
610
0
                mv.y = mv1y;
611
0
                mv.x = mv1x;
612
0
                if (ctx->approx_inter_rate) {
613
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost_light(mv, ref_mv[1]);
614
0
                } else {
615
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost(
616
0
                        mv, ref_mv[1], md_rate_est_ctx->nmv_vec_cost, md_rate_est_ctx->nmvcoststack, MV_COST_WEIGHT);
617
0
                }
618
0
            }
619
620
0
            const int32_t new_mv = (mode == NEWMV || mode == NEW_NEWMV);
621
0
            if (new_mv) {
622
0
                int32_t idx;
623
0
                for (idx = 0; idx < 2; ++idx) {
624
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame] > idx + 1) {
625
0
                        uint8_t drl_1_ctx = av1_drl_ctx(&(ctx->ref_mv_stack[ref_frame][0]), idx);
626
0
                        mv_rate += ctx->md_rate_est_ctx->drl_mode_fac_bits[drl_1_ctx][drli != idx];
627
0
                        if (drli == idx) {
628
0
                            break;
629
0
                        }
630
0
                    }
631
0
                }
632
0
            }
633
634
0
            if (mv_rate < best_mv_cost) {
635
0
                best_mv_cost    = mv_rate;
636
0
                *bestDrlIndex   = drli;
637
0
                best_pred_mv[0] = ref_mv[0];
638
0
                best_pred_mv[1] = ref_mv[1];
639
0
            }
640
0
        }
641
0
    }
642
0
}
643
644
0
static void mode_decision_cand_bf_dctor(EbPtr p) {
645
    // pred/rec_coeff/quant are borrowed from the MD-context pools; residual/recon are
646
    // shared (temp_*). Nothing is owned by the candidate buffer itself.
647
0
    (void)p;
648
0
}
649
650
3.04k
static void mode_decision_scratch_cand_bf_dctor(EbPtr p) {
651
3.04k
    ModeDecisionCandidateBuffer* obj = (ModeDecisionCandidateBuffer*)p;
652
3.04k
    EB_DELETE(obj->pred);
653
3.04k
    EB_DELETE(obj->residual);
654
3.04k
    EB_DELETE(obj->rec_coeff);
655
3.04k
    EB_DELETE(obj->recon);
656
3.04k
    EB_DELETE(obj->quant);
657
3.04k
}
658
659
/***************************************
660
* Mode Decision Candidate Ctor
661
***************************************/
662
EbErrorType svt_aom_mode_decision_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, EbPictureBufferDesc* pred,
663
                                               EbPictureBufferDesc* rec_coeff, EbPictureBufferDesc* quant,
664
                                               EbPictureBufferDesc* temp_residual, EbPictureBufferDesc* temp_recon_ptr,
665
15.2k
                                               uint64_t* fast_cost, uint64_t* full_cost, uint64_t* full_cost_ssim) {
666
15.2k
    buffer_ptr->dctor = mode_decision_cand_bf_dctor;
667
668
    // Candidate Ptr
669
15.2k
    buffer_ptr->cand = NULL;
670
671
    // Video Buffers — pred/rec_coeff/quant borrowed from MD-context pools; residual/recon
672
    // shared with the MD context.
673
15.2k
    buffer_ptr->pred      = pred;
674
15.2k
    buffer_ptr->residual  = temp_residual;
675
15.2k
    buffer_ptr->rec_coeff = rec_coeff;
676
15.2k
    buffer_ptr->quant     = quant;
677
15.2k
    buffer_ptr->recon     = temp_recon_ptr;
678
679
    // Costs
680
15.2k
    buffer_ptr->fast_cost      = fast_cost;
681
15.2k
    buffer_ptr->full_cost      = full_cost;
682
15.2k
    buffer_ptr->full_cost_ssim = full_cost_ssim;
683
15.2k
    return EB_ErrorNone;
684
15.2k
}
685
686
EbErrorType svt_aom_mode_decision_scratch_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, uint8_t sb_size,
687
3.04k
                                                       EbBitDepth max_bitdepth) {
688
3.04k
    EbPictureBufferDescInitData picture_buffer_desc_init_data;
689
3.04k
    EbPictureBufferDescInitData double_width_picture_buffer_desc_init_data;
690
3.04k
    EbPictureBufferDescInitData thirty_two_width_picture_buffer_desc_init_data;
691
692
3.04k
    buffer_ptr->dctor = mode_decision_scratch_cand_bf_dctor;
693
694
    // Init Picture Data
695
3.04k
    picture_buffer_desc_init_data.max_width                           = sb_size;
696
3.04k
    picture_buffer_desc_init_data.max_height                          = sb_size;
697
3.04k
    picture_buffer_desc_init_data.bit_depth                           = max_bitdepth;
698
3.04k
    picture_buffer_desc_init_data.color_format                        = EB_YUV420;
699
3.04k
    picture_buffer_desc_init_data.buffer_enable_mask                  = PICTURE_BUFFER_DESC_FULL_MASK;
700
3.04k
    picture_buffer_desc_init_data.border                              = 0;
701
3.04k
    picture_buffer_desc_init_data.split_mode                          = false;
702
3.04k
    picture_buffer_desc_init_data.is_16bit_pipeline                   = max_bitdepth > EB_EIGHT_BIT;
703
3.04k
    double_width_picture_buffer_desc_init_data.max_width              = sb_size;
704
3.04k
    double_width_picture_buffer_desc_init_data.max_height             = sb_size;
705
3.04k
    double_width_picture_buffer_desc_init_data.bit_depth              = EB_SIXTEEN_BIT;
706
3.04k
    double_width_picture_buffer_desc_init_data.color_format           = EB_YUV420;
707
3.04k
    double_width_picture_buffer_desc_init_data.buffer_enable_mask     = PICTURE_BUFFER_DESC_FULL_MASK;
708
3.04k
    double_width_picture_buffer_desc_init_data.border                 = 0;
709
3.04k
    double_width_picture_buffer_desc_init_data.split_mode             = false;
710
3.04k
    double_width_picture_buffer_desc_init_data.is_16bit_pipeline      = true;
711
3.04k
    thirty_two_width_picture_buffer_desc_init_data.max_width          = sb_size;
712
3.04k
    thirty_two_width_picture_buffer_desc_init_data.max_height         = sb_size;
713
3.04k
    thirty_two_width_picture_buffer_desc_init_data.bit_depth          = EB_THIRTYTWO_BIT;
714
3.04k
    thirty_two_width_picture_buffer_desc_init_data.color_format       = EB_YUV420;
715
3.04k
    thirty_two_width_picture_buffer_desc_init_data.buffer_enable_mask = PICTURE_BUFFER_DESC_FULL_MASK;
716
3.04k
    thirty_two_width_picture_buffer_desc_init_data.border             = 0;
717
3.04k
    thirty_two_width_picture_buffer_desc_init_data.split_mode         = false;
718
3.04k
    thirty_two_width_picture_buffer_desc_init_data.is_16bit_pipeline  = true;
719
720
    // Candidate Ptr
721
3.04k
    buffer_ptr->cand = NULL;
722
723
    // Video Buffers
724
3.04k
    EB_NEW(buffer_ptr->pred, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
725
3.04k
    EB_NEW(buffer_ptr->residual, svt_picture_buffer_desc_ctor, (EbPtr)&double_width_picture_buffer_desc_init_data);
726
3.04k
    EB_NEW(buffer_ptr->rec_coeff, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
727
3.04k
    EB_NEW(buffer_ptr->quant, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
728
729
3.04k
    EB_NEW(buffer_ptr->recon, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
730
3.04k
    return EB_ErrorNone;
731
3.04k
}
732
733
/***************************************
734
* return true if the MV candidate is already injected
735
***************************************/
736
0
static bool mv_is_already_injected(ModeDecisionContext* ctx, Mv mv0, Mv mv1, uint8_t ref_type) {
737
0
    MvReferenceFrame rf[2];
738
0
    av1_set_ref_frame(rf, ref_type);
739
740
    // Unipred Candidate
741
0
    if (rf[1] <= INTRA_FRAME) {
742
        // First check the validity of the candidate MV, and exit if invalid MV
743
0
        if (ctx->corrupted_mv_check && !check_mv_validity(mv0.x, mv0.y, 0)) {
744
0
            return true;
745
0
        }
746
747
0
        for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
748
0
            if (ctx->injected_ref_types[cand_idx] == ref_type && ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int) {
749
0
                return true;
750
0
            }
751
0
        }
752
0
    } else { // Bipred Candidate
753
        // First check the validity of the candidate MV, and exit if invalid MV
754
0
        if (ctx->corrupted_mv_check && (!check_mv_validity(mv0.x, mv0.y, 0) || !check_mv_validity(mv1.x, mv1.y, 0))) {
755
0
            return true;
756
0
        }
757
758
0
        RedundantCandCtrls* redund_ctrls = &ctx->cand_reduction_ctrls.redundant_cand_ctrls;
759
0
        if (redund_ctrls->score_th) {
760
0
            uint8_t is_high_mag = (ABS(mv0.x) > redund_ctrls->mag_th) && (ABS(mv0.y) > redund_ctrls->mag_th) &&
761
0
                (ABS(mv1.x) > redund_ctrls->mag_th) && (ABS(mv1.y) > redund_ctrls->mag_th);
762
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
763
0
                if (ctx->injected_ref_types[cand_idx] == ref_type) {
764
0
                    int score = ABS(ctx->injected_mvs[cand_idx][0].x - mv0.x) +
765
0
                        ABS(ctx->injected_mvs[cand_idx][0].y - mv0.y) + ABS(ctx->injected_mvs[cand_idx][1].x - mv1.x) +
766
0
                        ABS(ctx->injected_mvs[cand_idx][1].y - mv1.y);
767
768
0
                    if (score == 0 || (score < redund_ctrls->score_th && is_high_mag)) {
769
0
                        return true;
770
0
                    }
771
0
                }
772
0
            }
773
0
        } else {
774
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
775
0
                if (ctx->injected_ref_types[cand_idx] == ref_type &&
776
0
                    ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int &&
777
0
                    ctx->injected_mvs[cand_idx][1].as_int == mv1.as_int) {
778
0
                    return true;
779
0
                }
780
0
            }
781
0
        }
782
0
    }
783
0
    return false;
784
0
}
785
786
bool svt_aom_is_valid_unipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx,
787
0
                                  uint8_t ref_idx) {
788
0
    if (!ctx->ref_pruning_ctrls.enabled) {
789
0
        return true;
790
0
    }
791
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx][ref_idx].do_ref &&
792
0
        (ref_idx || !ctx->ref_pruning_ctrls.closest_refs[inter_cand_group])) {
793
0
        return false;
794
0
    } else {
795
0
        return true;
796
0
    }
797
0
}
798
799
// Determine if the MV-to-MVP difference satisfies the mv_diff restriction
800
0
static bool is_valid_mv_diff(Mv best_pred_mv[2], Mv mv0, Mv mv1, uint8_t is_compound) {
801
0
    const uint8_t mv_diff_max_bit = MV_IN_USE_BITS;
802
803
0
    if (abs(mv0.x - best_pred_mv[0].x) > (1 << mv_diff_max_bit) ||
804
0
        abs(mv0.y - best_pred_mv[0].y) > (1 << mv_diff_max_bit)) {
805
0
        return false;
806
0
    }
807
808
0
    if (is_compound) {
809
0
        if (abs(mv1.x - best_pred_mv[1].x) > (1 << mv_diff_max_bit) ||
810
0
            abs(mv1.y - best_pred_mv[1].y) > (1 << mv_diff_max_bit)) {
811
0
            return false;
812
0
        }
813
0
    }
814
0
    return true;
815
0
}
816
817
static bool is_valid_bipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx_0,
818
0
                                uint8_t ref_idx_0, uint8_t list_idx_1, uint8_t ref_idx_1) {
819
0
    if (!ctx->ref_pruning_ctrls.enabled) {
820
0
        return true;
821
0
    }
822
    // Both ref should be 1 for bipred refs to be valid: if 1 is not best_refs then there is a chance to exit the injection
823
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx_0][ref_idx_0].do_ref ||
824
0
        !ctx->ref_filtering_res[inter_cand_group][list_idx_1][ref_idx_1].do_ref) {
825
        // Check whether we should check the closest, if no then there no need to move forward and return false
826
0
        if (!ctx->ref_pruning_ctrls.closest_refs[inter_cand_group]) {
827
0
            return false;
828
0
        }
829
830
        // Else check if ref are LAST and BWD, if not then return false
831
0
        if (ref_idx_0 || ref_idx_1) {
832
0
            return false;
833
0
        }
834
0
    }
835
0
    return true;
836
0
}
837
838
0
#define BIPRED_3x3_REFINMENT_POSITIONS 8
839
840
static int8_t allow_refinement_flag[BIPRED_3x3_REFINMENT_POSITIONS] = {1, 0, 1, 0, 1, 0, 1, 0};
841
static int8_t bipred_3x3_x_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {-1, -1, 0, 1, 1, 1, 0, -1};
842
static int8_t bipred_3x3_y_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {0, 1, 1, 1, 0, -1, -1, -1};
843
844
157k
static INLINE uint8_t is_dc_only_safe(PictureControlSet* pcs, ModeDecisionContext* ctx) {
845
    // Early exit if pruning not enabled, SB-128, NSQ, or 4x4 (no variance available)
846
157k
    if (!ctx->intra_ctrls.prune_using_edge_info || pcs->scs->super_block_size == 128 || ctx->shape != PART_N ||
847
157k
        ctx->blk_geom->sq_size == 4) {
848
0
        return 0;
849
0
    }
850
851
    // Block variance lookup
852
157k
    int            blk_idx;
853
157k
    int            sub_idx[4];
854
157k
    const Position blk_org = {.x = ctx->blk_org_x - ctx->sb_origin_x, .y = ctx->blk_org_y - ctx->sb_origin_y};
855
157k
    svt_aom_get_blk_var_map(ctx->blk_geom->sq_size, blk_org.x, blk_org.y, &blk_idx, sub_idx);
856
857
157k
    uint16_t* sb_var  = pcs->ppcs->variance[ctx->sb_index];
858
157k
    uint32_t  blk_var = sb_var[blk_idx];
859
860
    // For 8x8, we do not have 4x4 sub-variance, skip spread check
861
157k
    if (ctx->blk_geom->sq_size == 8) {
862
153k
        return (blk_var < 2000);
863
153k
    }
864
865
    // For 16x16 and above, compute spread from sub-blocks
866
4.21k
    uint32_t min_var = UINT32_MAX;
867
4.21k
    uint32_t max_var = 0;
868
869
20.7k
    for (int i = 0; i < 4; i++) {
870
16.5k
        uint32_t v = sb_var[sub_idx[i]];
871
16.5k
        min_var    = MIN(min_var, v);
872
16.5k
        max_var    = MAX(max_var, v);
873
16.5k
    }
874
875
4.21k
    uint32_t spread_var = max_var - min_var;
876
877
4.21k
    return (blk_var < 2000 && spread_var < 4000);
878
157k
}
879
880
// Inject inter-intra, WM, OBMC for unipred simple-trans candidate
881
//
882
// total_cand_count is the index to ctx->fast_cand_array for the next candidate injected (which is the
883
// same as the number of candidates injected so far).  It is assumed the simple-trans candidate to base
884
// the other candidtes on is the previously injected candidate (at index total_cand_count - 1).
885
//
886
// enable_ii, enable_wm, and enable_obmc allow the caller to disable some modes explicitly; if enabled, the
887
// mode will be injected if the block size/candidate type supports the mode. The enable signals are left as
888
// arguments because some candidates do not inject all modes (e.g. unipred does not inject WM/OBMC).
889
static void inj_non_simple_modes(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* total_cand_count,
890
0
                                 const bool enable_ii, const bool enable_wm, const bool enable_obmc) {
891
    // index of simple translation candidate (to be used to copy cand info for other modes)
892
    // assumes the simple trans cand is the previously injected candidate
893
0
    const uint32_t                     simple_trans_cand_idx = *total_cand_count - 1;
894
0
    const ModeDecisionCandidate* const simple_trans_cand     = &ctx->fast_cand_array[simple_trans_cand_idx];
895
896
    // The candidate count to be used to track number of inj cands, and the index of fast_cand_array for new candidates
897
0
    uint32_t cand_count = *total_cand_count;
898
899
0
    assert(simple_trans_cand->block_mi.ref_frame[1] == NONE_FRAME);
900
0
    const uint8_t list_idx = get_list_idx(simple_trans_cand->block_mi.ref_frame[0]);
901
0
    const uint8_t ref_idx  = get_ref_frame_idx(simple_trans_cand->block_mi.ref_frame[0]);
902
903
    // INJECT INTER-INTRA
904
0
    const uint8_t is_ii_allowed = svt_aom_is_valid_unipred_ref(ctx, INTER_INTRA_GROUP, list_idx, ref_idx) &&
905
0
        svt_is_interintra_allowed(ctx->inter_intra_comp_ctrls.enabled,
906
0
                                  ctx->blk_geom->bsize,
907
0
                                  simple_trans_cand->block_mi.mode,
908
0
                                  simple_trans_cand->block_mi.ref_frame);
909
0
    if (enable_ii && is_ii_allowed) {
910
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
911
0
        memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
912
913
0
        inter_intra_search(pcs, ctx, cand);
914
0
        cand->block_mi.is_interintra_used = 1;
915
0
        cand->block_mi.ref_frame[1]       = INTRA_FRAME;
916
0
        const InterIntraMode ii_mode      = cand->block_mi.interintra_mode;
917
0
        INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
918
919
        // if ii_wedge_mode is 1, then inject wedge/non-wedge as separate candidates; OW, only inject the best (above)
920
0
        const uint8_t ii_wedge_mode = ctx->shape == PART_N ? ctx->inter_intra_comp_ctrls.wedge_mode_sq
921
0
                                                           : ctx->inter_intra_comp_ctrls.wedge_mode_nsq;
922
0
        if (ii_wedge_mode == 1) {
923
0
            cand = &ctx->fast_cand_array[cand_count];
924
0
            memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
925
926
0
            cand->block_mi.is_interintra_used   = 1;
927
0
            cand->block_mi.ref_frame[1]         = INTRA_FRAME;
928
0
            cand->block_mi.interintra_mode      = ii_mode;
929
0
            cand->block_mi.use_wedge_interintra = 0;
930
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
931
0
        }
932
0
    }
933
934
0
#if CONFIG_ENABLE_OBMC
935
    // INJECT WARP
936
0
    const uint8_t is_warp_allowed = warped_motion_mode_allowed(pcs, ctx) &&
937
0
        svt_aom_is_valid_unipred_ref(ctx, WARP_GROUP, list_idx, ref_idx);
938
0
    if (enable_wm && is_warp_allowed) {
939
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
940
0
        memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
941
942
0
        cand->block_mi.is_interintra_used = 0;
943
0
        cand->block_mi.motion_mode        = WARPED_CAUSAL;
944
0
        cand->wm_params_l0.wmtype         = AFFINE;
945
946
0
        uint8_t motion_mode_valid = 1;
947
0
        if (cand->block_mi.mode == NEWMV && ctx->wm_ctrls.refinement_iterations && ctx->wm_ctrls.refine_level == 0) {
948
            // Perform refinement; if refinement is off, then MV is valid, since it's been checked above
949
0
            motion_mode_valid = svt_aom_wm_motion_refinement(pcs, ctx, cand, 0);
950
0
        }
951
952
0
        if (motion_mode_valid) {
953
0
            motion_mode_valid = svt_aom_warped_motion_parameters(ctx,
954
0
                                                                 cand->block_mi.mv[0],
955
0
                                                                 ctx->blk_geom,
956
0
                                                                 cand->block_mi.ref_frame[0],
957
0
                                                                 &cand->wm_params_l0,
958
0
                                                                 &cand->block_mi.num_proj_ref,
959
0
                                                                 ctx->wm_ctrls.lower_band_th,
960
0
                                                                 ctx->wm_ctrls.upper_band_th,
961
0
                                                                 0);
962
0
        }
963
964
0
        if (motion_mode_valid) {
965
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
966
0
        }
967
0
    }
968
969
    // INJECT OBMC
970
0
    const uint8_t is_obmc_allowed = svt_aom_is_valid_unipred_ref(ctx, OBMC_GROUP, list_idx, ref_idx) &&
971
0
        (svt_aom_obmc_motion_mode_allowed(pcs,
972
0
                                          ctx,
973
0
                                          ctx->blk_geom->bsize,
974
0
                                          0,
975
0
                                          simple_trans_cand->block_mi.ref_frame[0],
976
0
                                          simple_trans_cand->block_mi.ref_frame[1],
977
0
                                          simple_trans_cand->block_mi.mode) == OBMC_CAUSAL);
978
0
    if (enable_obmc && is_obmc_allowed) {
979
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
980
0
        memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
981
982
0
        cand->block_mi.is_interintra_used = 0;
983
0
        cand->block_mi.motion_mode        = OBMC_CAUSAL;
984
985
0
        uint8_t motion_mode_valid = 1;
986
0
        if (cand->block_mi.mode == NEWMV && ctx->obmc_ctrls.refine_level == 0) {
987
0
            assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
988
0
            motion_mode_valid = svt_aom_obmc_motion_refinement(pcs, ctx, cand, ctx->obmc_ctrls.refine_level);
989
0
        }
990
991
0
        if (motion_mode_valid) {
992
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
993
0
        }
994
0
    }
995
#else
996
    UNUSED(enable_wm);
997
    UNUSED(enable_obmc);
998
#endif // CONFIG_ENABLE_OBMC
999
1000
0
    *total_cand_count = cand_count;
1001
0
}
1002
1003
#if CONFIG_ENABLE_INTER_COMPOUND
1004
// Determines if inter MVP compound modes should be skipped based on info from neighbouring blocks/ref frame types.
1005
0
static bool skip_compound_on_ref_types(ModeDecisionContext* ctx, MvReferenceFrame rf[2]) {
1006
0
    if (!ctx->inter_comp_ctrls.skip_on_ref_info) {
1007
0
        return false;
1008
0
    }
1009
1010
0
    MacroBlockD* xd = ctx->blk_ptr->av1xd;
1011
1012
    // If both references are from the same list, skip compound
1013
0
    const uint8_t list_idx_0 = get_list_idx(rf[0]);
1014
0
    const uint8_t list_idx_1 = get_list_idx(rf[1]);
1015
0
    if (list_idx_0 == list_idx_1) {
1016
0
        return true;
1017
0
    }
1018
1019
    // Skip compound unless neighbours selected the ref frames
1020
0
    bool skip_comp = true;
1021
0
    if (!xd->left_available && !xd->up_available) {
1022
0
        return false;
1023
0
    }
1024
1025
0
    if (xd->left_available) {
1026
0
        const BlockModeInfo* const left_mi = &xd->left_mbmi->block_mi;
1027
0
        if ((is_inter_singleref_mode(left_mi->mode) &&
1028
0
             (left_mi->ref_frame[0] == rf[0] || left_mi->ref_frame[0] == rf[1])) ||
1029
0
            (is_inter_compound_mode(left_mi->mode) &&
1030
0
             (left_mi->ref_frame[0] == rf[0] && left_mi->ref_frame[1] == rf[1]))) {
1031
0
            return false;
1032
0
        }
1033
0
    }
1034
0
    if (xd->up_available) {
1035
0
        const BlockModeInfo* const above_mi = &xd->above_mbmi->block_mi;
1036
0
        if ((is_inter_singleref_mode(above_mi->mode) &&
1037
0
             (above_mi->ref_frame[0] == rf[0] || above_mi->ref_frame[0] == rf[1])) ||
1038
0
            (is_inter_compound_mode(above_mi->mode) &&
1039
0
             (above_mi->ref_frame[0] == rf[0] && above_mi->ref_frame[1] == rf[1]))) {
1040
0
            return false;
1041
0
        }
1042
0
    }
1043
1044
0
    return skip_comp;
1045
0
}
1046
#endif
1047
1048
// Inject inter-inter compound types (DIST, DIFF, WEDGE) for a bipred AVG candidate
1049
//
1050
// total_cand_count is the index to ctx->fast_cand_array for the next candidate injected (which is the
1051
// same as the number of candidates injected so far).  It is assumed the AVG candidate to base
1052
// the other candidtes on is the previously injected candidate (at index total_cand_count - 1).
1053
0
static void inj_comp_modes(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* total_cand_count) {
1054
#if !CONFIG_ENABLE_INTER_COMPOUND
1055
    // Inter compound disabled (RTC / MINIMAL): nothing to inject here. Compiling the body out lets LTO
1056
    // cascade-DCE svt_aom_calc_pred_masked_compound + the wedge/diff mask builders.
1057
    (void)pcs;
1058
    (void)ctx;
1059
    (void)total_cand_count;
1060
#else
1061
    // index of MD_COMP_AVG candidate (to be used to copy cand info for other modes)
1062
    // assumes the avg cand is the previously injected candidate
1063
0
    const uint32_t         avg_cand_idx = *total_cand_count - 1;
1064
0
    ModeDecisionCandidate* avg_cand     = &ctx->fast_cand_array[avg_cand_idx];
1065
1066
    // Get allowable compound types based on settings and block size
1067
0
    MD_COMP_TYPE tot_comp_types = get_tot_comp_types_bsize(ctx->inter_comp_ctrls.tot_comp_types, ctx->blk_geom->bsize);
1068
0
    if (tot_comp_types == MD_COMP_DIST) {
1069
0
        return;
1070
0
    }
1071
1072
    // Distortion-based ref pruning for compound types
1073
0
    const uint8_t ref_idx_0  = get_ref_frame_idx(avg_cand->block_mi.ref_frame[0]);
1074
0
    const uint8_t ref_idx_1  = get_ref_frame_idx(avg_cand->block_mi.ref_frame[1]);
1075
0
    const uint8_t list_idx_0 = get_list_idx(avg_cand->block_mi.ref_frame[0]);
1076
0
    const uint8_t list_idx_1 = get_list_idx(avg_cand->block_mi.ref_frame[1]);
1077
0
    if (!is_valid_bipred_ref(ctx, INTER_COMP_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
1078
0
        return;
1079
0
    }
1080
1081
    // Skip compound on neighbour info
1082
0
    if (skip_compound_on_ref_types(ctx, avg_cand->block_mi.ref_frame)) {
1083
0
        return;
1084
0
    }
1085
1086
    // Skip compound on MV length
1087
0
    if (ctx->inter_comp_ctrls.max_mv_length) {
1088
0
        const uint16_t max_mv_length = ctx->inter_comp_ctrls.max_mv_length;
1089
0
        if (abs(avg_cand->block_mi.mv[0].x) > max_mv_length || abs(avg_cand->block_mi.mv[0].y) > max_mv_length ||
1090
0
            abs(avg_cand->block_mi.mv[1].x) > max_mv_length || abs(avg_cand->block_mi.mv[1].y) > max_mv_length) {
1091
0
            return;
1092
0
        }
1093
0
    }
1094
    // If compound modes are to be tested for this block, generate the buffers that will be used in the DIFF/WEDGE search.
1095
    // Even if DIFF/WEDGE are not used, still call the function because it is needed for pred0_to_pred1_mult to work.
1096
0
    if (tot_comp_types > MD_COMP_DIST) {
1097
0
        if (svt_aom_calc_pred_masked_compound(pcs, ctx, avg_cand)) {
1098
0
            return;
1099
0
        }
1100
0
    }
1101
1102
    // The candidate count to be used to track number of inj cands, and the index of fast_cand_array for new candidates
1103
0
    uint32_t cand_count = *total_cand_count;
1104
0
    for (MD_COMP_TYPE cur_type = MD_COMP_DIST; cur_type < tot_comp_types; cur_type++) {
1105
0
        if (ctx->inter_comp_ctrls.no_sym_dist && cur_type == MD_COMP_DIST && ref_idx_0 == 0 && ref_idx_1 == 0) {
1106
0
            continue;
1107
0
        }
1108
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
1109
0
        memcpy(cand, &ctx->fast_cand_array[avg_cand_idx], sizeof(ModeDecisionCandidate));
1110
0
        cand->skip_mode_allowed = false;
1111
0
        determine_compound_mode(pcs, ctx, cand, cur_type);
1112
0
        INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
1113
0
    }
1114
0
    *total_cand_count = cand_count;
1115
0
#endif // !CONFIG_ENABLE_INTER_COMPOUND
1116
0
}
1117
1118
static void unipred_3x3_candidates_injection(PictureControlSet* pcs, ModeDecisionContext* ctx,
1119
0
                                             uint32_t* candidate_total_cnt) {
1120
0
    uint32_t               cand_total_cnt          = (*candidate_total_cnt);
1121
0
    const uint8_t          allow_high_precision_mv = pcs->ppcs->frm_hdr.allow_high_precision_mv;
1122
0
    MeSbResults*           me_results              = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1123
0
    const uint8_t          total_me_cnt            = me_results->total_me_candidate_index[ctx->me_block_offset];
1124
0
    const MeCandidate*     me_block_results        = &me_results->me_candidate_array[ctx->me_cand_offset];
1125
0
    ModeDecisionCandidate* cand_array              = ctx->fast_cand_array;
1126
1127
    // (8 Best_L0 neighbors)
1128
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
1129
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
1130
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
1131
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
1132
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
1133
0
        if (inter_direction == BI_PRED) {
1134
0
            continue;
1135
0
        }
1136
0
        assert(inter_direction == 0 || inter_direction == 1);
1137
0
        const uint8_t list_idx = inter_direction;
1138
0
        const uint8_t ref_idx  = list_idx == REF_LIST_0 ? list0_ref_index : list1_ref_index;
1139
0
        if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, UNI_3x3_GROUP), list_idx, ref_idx)) {
1140
0
            continue;
1141
0
        }
1142
0
        for (int unipred_index = 0; unipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++unipred_index) {
1143
            /**************
1144
            NEWMV L0
1145
            ************* */
1146
0
            if (ctx->unipred3x3_injection >= 2) {
1147
0
                if (allow_refinement_flag[unipred_index] == 0) {
1148
0
                    continue;
1149
0
                }
1150
0
            }
1151
0
            Mv to_inj_mv = ctx->sb_me_mv[list_idx][ref_idx];
1152
0
            to_inj_mv.x += (bipred_3x3_x_pos[unipred_index] << !allow_high_precision_mv);
1153
0
            to_inj_mv.y += (bipred_3x3_y_pos[unipred_index] << !allow_high_precision_mv);
1154
0
            const uint8_t    to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
1155
0
            MvReferenceFrame rf[2]              = {to_inject_ref_type, NONE_FRAME};
1156
0
            if ((ctx->injected_mv_count == 0 ||
1157
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false)) {
1158
0
                uint8_t drl_index       = 0;
1159
0
                Mv      best_pred_mv[2] = {{{0}}, {{0}}};
1160
0
                svt_aom_choose_best_av1_mv_pred(
1161
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
1162
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
1163
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1164
0
                    cand->block_mi.use_intrabc        = 0;
1165
0
                    cand->skip_mode_allowed           = false;
1166
0
                    cand->block_mi.mode               = NEWMV;
1167
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1168
0
                    cand->block_mi.is_interintra_used = 0;
1169
0
                    cand->drl_index                   = drl_index;
1170
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1171
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1172
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1173
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1174
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
1175
1176
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1177
1178
0
                    const bool enable_ii = true;
1179
                    // OBMC and WM perform a refinement search around the ME MV, so they are not injected as unipred3x3 candidates,
1180
                    // since this is effectively a refinement search
1181
0
                    const bool enable_obmc = false;
1182
0
                    const bool enable_warp = false;
1183
0
                    inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
1184
1185
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1186
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1187
0
                    ++ctx->injected_mv_count;
1188
0
                }
1189
0
            }
1190
0
        }
1191
0
    }
1192
1193
    // update the total number of candidates injected
1194
0
    (*candidate_total_cnt) = cand_total_cnt;
1195
1196
0
    return;
1197
0
}
1198
1199
static void bipred_3x3_candidates_injection(PictureControlSet* pcs, ModeDecisionContext* ctx,
1200
0
                                            uint32_t* candidate_total_cnt) {
1201
0
    uint32_t               cand_total_cnt          = (*candidate_total_cnt);
1202
0
    const uint8_t          allow_high_precision_mv = pcs->ppcs->frm_hdr.allow_high_precision_mv;
1203
0
    const MeSbResults*     me_results              = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1204
0
    const uint8_t          total_me_cnt            = me_results->total_me_candidate_index[ctx->me_block_offset];
1205
0
    const MeCandidate*     me_block_results        = &me_results->me_candidate_array[ctx->me_cand_offset];
1206
0
    ModeDecisionCandidate* cand_array              = ctx->fast_cand_array;
1207
0
    Mv                     best_pred_mv[2]         = {{{0}}, {{0}}};
1208
1209
    /**************
1210
    NEW_NEWMV
1211
    ************* */
1212
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
1213
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
1214
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
1215
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
1216
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
1217
0
        if (inter_direction < BI_PRED) {
1218
0
            continue;
1219
0
        }
1220
0
        assert(inter_direction == BI_PRED);
1221
1222
0
        const uint8_t ref0_list = me_block_results_ptr->ref0_list;
1223
0
        const uint8_t ref1_list = me_block_results_ptr->ref1_list;
1224
0
        if (!is_valid_bipred_ref(ctx, BI_3x3_GROUP, ref0_list, list0_ref_index, ref1_list, list1_ref_index)) {
1225
0
            continue;
1226
0
        }
1227
1228
0
        int8_t best_list = -1;
1229
        // 64-bit: (cost0 - cost1) * 100 can overflow int
1230
0
        int64_t diff = ((int64_t)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index] -
1231
0
                        (int64_t)ctx->post_subpel_me_mv_cost[ref1_list][list1_ref_index]) *
1232
0
            100;
1233
1234
0
        if (ctx->bipred3x3_ctrls.use_l0_l1_dev != (uint8_t)~0) {
1235
0
            if (llabs(diff) > ((int64_t)ctx->bipred3x3_ctrls.use_l0_l1_dev *
1236
0
                               (int)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index])) {
1237
0
                return;
1238
0
            }
1239
0
        }
1240
1241
        // Best list in terms of distortion reduction
1242
0
        if (ctx->bipred3x3_ctrls.use_best_list) {
1243
0
            best_list = ref0_list;
1244
0
            if (diff > 0) {
1245
0
                best_list = ref1_list;
1246
0
            }
1247
0
        }
1248
1249
0
        MvReferenceFrame rf[2]              = {svt_get_ref_frame_type(ref0_list, list0_ref_index),
1250
0
                                               svt_get_ref_frame_type(ref1_list, list1_ref_index)};
1251
0
        const uint8_t    to_inject_ref_type = av1_ref_frame_type(rf);
1252
0
        if (best_list == -1 || best_list == ref0_list) {
1253
            // (Best_L0, 8 Best_L1 neighbors)
1254
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1255
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1256
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1257
0
                        continue;
1258
0
                    }
1259
0
                }
1260
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1261
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1262
0
                to_inj_mv1.x += (bipred_3x3_x_pos[bipred_index] * (1 << !allow_high_precision_mv));
1263
0
                to_inj_mv1.y += (bipred_3x3_y_pos[bipred_index] * (1 << !allow_high_precision_mv));
1264
0
                if ((ctx->injected_mv_count == 0 ||
1265
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1266
0
                    uint8_t drl_index = 0;
1267
0
                    svt_aom_choose_best_av1_mv_pred(
1268
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1269
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1270
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1271
0
                        cand->block_mi.use_intrabc        = 0;
1272
0
                        cand->skip_mode_allowed           = false;
1273
0
                        cand->drl_index                   = drl_index;
1274
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1275
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1276
0
                        cand->block_mi.mode               = NEW_NEWMV;
1277
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1278
0
                        cand->block_mi.is_interintra_used = 0;
1279
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1280
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1281
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1282
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1283
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1284
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1285
1286
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1287
0
                            ctx->cmp_store.pred0_cnt = 0;
1288
0
                            ctx->cmp_store.pred1_cnt = 0;
1289
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1290
0
                        }
1291
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1292
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1293
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1294
0
                        ++ctx->injected_mv_count;
1295
0
                    }
1296
0
                }
1297
0
            }
1298
0
        }
1299
0
        if (best_list == -1 || best_list == ref1_list) {
1300
            // (8 Best_L0 neighbors, Best_L1) :
1301
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1302
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1303
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1304
0
                        continue;
1305
0
                    }
1306
0
                }
1307
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1308
0
                to_inj_mv0.x += (bipred_3x3_x_pos[bipred_index] * (1 << !allow_high_precision_mv));
1309
0
                to_inj_mv0.y += (bipred_3x3_y_pos[bipred_index] * (1 << !allow_high_precision_mv));
1310
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1311
0
                if ((ctx->injected_mv_count == 0 ||
1312
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1313
0
                    uint8_t drl_index = 0;
1314
0
                    svt_aom_choose_best_av1_mv_pred(
1315
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1316
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1317
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1318
0
                        cand->block_mi.use_intrabc        = 0;
1319
0
                        cand->skip_mode_allowed           = false;
1320
0
                        cand->drl_index                   = drl_index;
1321
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1322
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1323
0
                        cand->block_mi.mode               = NEW_NEWMV;
1324
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1325
0
                        cand->block_mi.is_interintra_used = 0;
1326
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1327
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1328
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1329
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1330
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1331
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1332
1333
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1334
0
                            ctx->cmp_store.pred0_cnt = 0;
1335
0
                            ctx->cmp_store.pred1_cnt = 0;
1336
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1337
0
                        }
1338
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1339
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1340
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1341
0
                        ++ctx->injected_mv_count;
1342
0
                    }
1343
0
                }
1344
0
            }
1345
0
        }
1346
0
    }
1347
1348
    // update the total number of candidates injected
1349
0
    (*candidate_total_cnt) = cand_total_cnt;
1350
1351
0
    return;
1352
0
}
1353
1354
/*********************************************************************
1355
**********************************************************************
1356
        Upto 12 inter Candidated injected
1357
        Min 6 inter Candidated injected
1358
UniPred L0 : NEARST         + upto 3x NEAR
1359
UniPred L1 : NEARST         + upto 3x NEAR
1360
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1361
**********************************************************************
1362
**********************************************************************/
1363
static void inject_mvp_candidates_ii_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candTotCnt,
1364
0
                                               const bool allow_bipred) {
1365
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1366
0
    uint32_t               cand_idx   = *candTotCnt;
1367
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1368
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1369
1370
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1
1371
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1372
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1373
0
        MvReferenceFrame rf[2];
1374
0
        av1_set_ref_frame(rf, ref_pair);
1375
1376
        //single ref/list
1377
0
        if (rf[1] == NONE_FRAME) {
1378
0
            MvReferenceFrame frame_type = rf[0];
1379
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1380
0
            if (ctx->cand_reduction_ctrls.lpd1_mvp_best_me_list) {
1381
0
                const MeSbResults* me_results           = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1382
0
                const uint8_t      total_me_cnt         = me_results->total_me_candidate_index[ctx->me_block_offset];
1383
0
                const MeCandidate* me_block_results     = &me_results->me_candidate_array[ctx->me_cand_offset];
1384
0
                const MeCandidate* me_block_results_ptr = &me_block_results[0];
1385
0
                const uint8_t      inter_direction      = me_block_results_ptr->direction;
1386
0
                if (total_me_cnt && list_idx != inter_direction) {
1387
0
                    continue;
1388
0
                }
1389
0
            }
1390
            //NEAREST
1391
            // Don't check if MV is already injected b/c NEAREST is the first INTER MV injected
1392
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1393
1394
0
            ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1395
0
            cand->block_mi.mode               = NEARESTMV;
1396
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1397
0
            cand->skip_mode_allowed           = false;
1398
0
            cand->drl_index                   = 0;
1399
0
            cand->block_mi.ref_frame[0]       = rf[0];
1400
0
            cand->block_mi.ref_frame[1]       = rf[1];
1401
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1402
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1403
0
            cand->block_mi.use_intrabc        = 0;
1404
0
            cand->block_mi.is_interintra_used = 0;
1405
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1406
1407
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1408
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1409
0
            ++ctx->injected_mv_count;
1410
            //NEAR
1411
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1412
0
            uint8_t       cap_max_drl_index = 0;
1413
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1414
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1415
0
            }
1416
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1417
0
                to_inj_mv.as_int = ctx->ref_mv_stack[frame_type][1 + drli].this_mv.as_int;
1418
1419
0
                if ((ctx->injected_mv_count == 0 ||
1420
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1421
0
                    cand                              = &cand_array[cand_idx];
1422
0
                    cand->block_mi.mode               = NEARMV;
1423
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1424
0
                    cand->skip_mode_allowed           = false;
1425
0
                    cand->drl_index                   = drli;
1426
0
                    cand->block_mi.use_intrabc        = 0;
1427
0
                    cand->block_mi.is_interintra_used = 0;
1428
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1429
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1430
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1431
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1432
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1433
1434
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1435
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1436
0
                    ++ctx->injected_mv_count;
1437
0
                }
1438
0
            }
1439
0
        } else if (allow_bipred) {
1440
            //NEAREST_NEAREST
1441
            // Don't check if MV is already injected b/c NEAREST_NEAREST is the first bipred INTER candidate injected
1442
0
            Mv         to_inj_mv0   = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1443
0
            Mv         to_inj_mv1   = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1444
0
            const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1445
0
                frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1446
0
                (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1447
0
            ModeDecisionCandidate* cand         = &cand_array[cand_idx];
1448
0
            cand->block_mi.mode                 = NEAREST_NEARESTMV;
1449
0
            cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1450
0
            cand->skip_mode_allowed             = is_skip_mode;
1451
0
            cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1452
0
            cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1453
0
            cand->drl_index                     = 0;
1454
0
            cand->block_mi.use_intrabc          = 0;
1455
0
            cand->block_mi.is_interintra_used   = 0;
1456
0
            cand->block_mi.ref_frame[0]         = rf[0];
1457
0
            cand->block_mi.ref_frame[1]         = rf[1];
1458
0
            cand->block_mi.comp_group_idx       = 0;
1459
0
            cand->block_mi.compound_idx         = 1;
1460
0
            cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1461
1462
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1463
1464
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1465
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1466
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1467
0
            ++ctx->injected_mv_count;
1468
1469
            //NEAR_NEAR
1470
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1471
0
            uint8_t       cap_max_drl_index = 0;
1472
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1473
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1474
0
            }
1475
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1476
0
                to_inj_mv0.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].this_mv.as_int;
1477
0
                to_inj_mv1.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].comp_mv.as_int;
1478
0
                if ((ctx->injected_mv_count == 0 ||
1479
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1480
0
                    cand                                = &cand_array[cand_idx];
1481
0
                    cand->block_mi.mode                 = NEAR_NEARMV;
1482
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1483
0
                    cand->skip_mode_allowed             = false;
1484
0
                    cand->block_mi.use_intrabc          = 0;
1485
0
                    cand->block_mi.is_interintra_used   = 0;
1486
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1487
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1488
0
                    cand->drl_index                     = drli;
1489
0
                    cand->block_mi.ref_frame[0]         = rf[0];
1490
0
                    cand->block_mi.ref_frame[1]         = rf[1];
1491
0
                    cand->block_mi.comp_group_idx       = 0;
1492
0
                    cand->block_mi.compound_idx         = 1;
1493
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1494
1495
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1496
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1497
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1498
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1499
0
                    ++ctx->injected_mv_count;
1500
0
                }
1501
0
            }
1502
0
        }
1503
0
    }
1504
    //update tot Candidate count
1505
0
    *candTotCnt = cand_idx;
1506
0
}
1507
1508
/*********************************************************************
1509
**********************************************************************
1510
        Upto 12 inter Candidated injected
1511
        Min 6 inter Candidated injected
1512
UniPred L0 : NEARST         + upto 3x NEAR
1513
UniPred L1 : NEARST         + upto 3x NEAR
1514
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1515
**********************************************************************
1516
**********************************************************************/
1517
static void inject_mvp_candidates_ii(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* cand_total_cnt,
1518
0
                                     const bool allow_bipred) {
1519
0
    BlkStruct*             blk_ptr    = ctx->blk_ptr;
1520
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1521
0
    uint32_t               cand_idx   = *cand_total_cnt;
1522
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1523
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
1524
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1525
1526
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1  (4)compound Uni-Dir List0-List0  (5)compound Uni-Dir List1-List1
1527
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1528
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1529
0
        MvReferenceFrame rf[2];
1530
0
        av1_set_ref_frame(rf, ref_pair);
1531
        //single ref/list
1532
0
        if (rf[1] == NONE_FRAME) {
1533
0
            MvReferenceFrame frame_type = rf[0];
1534
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1535
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
1536
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1537
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEAR_GROUP), list_idx, ref_idx)) {
1538
0
                continue;
1539
0
            }
1540
            //NEAREST
1541
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1542
0
            if ((ctx->injected_mv_count == 0 ||
1543
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1544
0
                assert(list_idx == 0 || list_idx == 1);
1545
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1546
0
                cand->block_mi.mode               = NEARESTMV;
1547
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1548
0
                cand->block_mi.use_intrabc        = 0;
1549
0
                cand->skip_mode_allowed           = false;
1550
0
                cand->drl_index                   = 0;
1551
0
                cand->block_mi.ref_frame[0]       = rf[0];
1552
0
                cand->block_mi.ref_frame[1]       = rf[1];
1553
0
                cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1554
0
                cand->block_mi.is_interintra_used = 0;
1555
0
                cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1556
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1557
1558
0
                const bool enable_ii   = true;
1559
0
                const bool enable_obmc = true;
1560
0
                const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1561
0
                inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1562
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1563
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1564
0
                ++ctx->injected_mv_count;
1565
0
            }
1566
1567
            //NEAR
1568
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1569
0
            uint8_t       cap_max_drl_index = 0;
1570
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1571
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1572
0
            }
1573
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1574
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, frame_type, 0, NEARMV, drli, nearestmv, nearmv, ref_mv);
1575
1576
0
                to_inj_mv.as_int = nearmv[0].as_int;
1577
0
                if ((ctx->injected_mv_count == 0 ||
1578
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1579
0
                    assert(list_idx == 0 || list_idx == 1);
1580
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1581
0
                    cand->block_mi.mode               = NEARMV;
1582
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1583
0
                    cand->block_mi.use_intrabc        = 0;
1584
0
                    cand->skip_mode_allowed           = false;
1585
0
                    cand->drl_index                   = drli;
1586
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1587
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1588
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1589
0
                    cand->block_mi.is_interintra_used = 0;
1590
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1591
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1592
1593
0
                    const bool enable_ii   = true;
1594
0
                    const bool enable_obmc = true;
1595
0
                    const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1596
0
                    inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1597
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1598
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1599
0
                    ++ctx->injected_mv_count;
1600
0
                }
1601
0
            }
1602
0
        } else if (allow_bipred) {
1603
0
            const uint8_t ref_idx_0 = get_ref_frame_idx(rf[0]);
1604
0
            const uint8_t ref_idx_1 = get_ref_frame_idx(rf[1]);
1605
1606
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1607
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1608
1609
0
            ctx->cmp_store.pred0_cnt = 0;
1610
0
            ctx->cmp_store.pred1_cnt = 0;
1611
1612
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1613
0
            if (!is_valid_bipred_ref(ctx, NRST_NEAR_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
1614
0
                continue;
1615
0
            }
1616
1617
            //NEAREST_NEAREST
1618
0
            Mv to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1619
0
            Mv to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1620
0
            if ((ctx->injected_mv_count == 0 ||
1621
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1622
0
                const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1623
0
                    frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1624
0
                    (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1625
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1626
0
                cand->block_mi.mode               = NEAREST_NEARESTMV;
1627
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1628
0
                cand->block_mi.is_interintra_used = 0;
1629
0
                cand->block_mi.use_intrabc        = 0;
1630
0
                cand->skip_mode_allowed           = /*cur_type == MD_COMP_AVG &&*/ is_skip_mode ? true : false;
1631
0
                cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1632
0
                cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1633
0
                cand->drl_index                   = 0;
1634
0
                cand->block_mi.ref_frame[0]       = rf[0];
1635
0
                cand->block_mi.ref_frame[1]       = rf[1];
1636
0
                determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1637
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1638
1639
0
                if (ctx->inter_comp_ctrls.do_nearest_nearest) {
1640
                    // Don't reset ctx->cmp_store.pred0_cnt for MVP
1641
0
                    inj_comp_modes(pcs, ctx, &cand_idx);
1642
0
                }
1643
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1644
0
                ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1645
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1646
0
                ++ctx->injected_mv_count;
1647
0
            }
1648
1649
            //NEAR_NEAR
1650
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1651
0
            uint8_t       cap_max_drl_index = 0;
1652
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1653
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1654
0
            }
1655
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1656
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_pair, 1, NEAR_NEARMV, drli, nearestmv, nearmv, ref_mv);
1657
1658
0
                to_inj_mv0.as_int = nearmv[0].as_int;
1659
0
                to_inj_mv1.as_int = nearmv[1].as_int;
1660
0
                if ((ctx->injected_mv_count == 0 ||
1661
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1662
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1663
0
                    cand->block_mi.mode               = NEAR_NEARMV;
1664
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1665
0
                    cand->block_mi.is_interintra_used = 0;
1666
0
                    cand->block_mi.use_intrabc        = 0;
1667
0
                    cand->skip_mode_allowed           = false;
1668
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1669
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1670
0
                    cand->drl_index                   = drli;
1671
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1672
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1673
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1674
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1675
1676
0
                    if (ctx->inter_comp_ctrls.do_near_near) {
1677
                        // Don't reset ctx->cmp_store.pred0_cnt for MVP
1678
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1679
0
                    }
1680
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1681
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1682
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1683
0
                    ++ctx->injected_mv_count;
1684
0
                }
1685
0
            }
1686
0
        }
1687
0
    }
1688
    //update tot Candidate count
1689
0
    *cand_total_cnt = cand_idx;
1690
0
}
1691
1692
static void inject_new_nearest_new_comb_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
1693
0
                                                   uint32_t* cand_tot_cnt) {
1694
0
    uint32_t               cand_idx   = *cand_tot_cnt;
1695
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1696
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1697
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1698
1699
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1  (4)compound Uni-Dir List0-List0  (5)compound Uni-Dir List1-List1
1700
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1701
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1702
0
        MvReferenceFrame rf[2];
1703
0
        av1_set_ref_frame(rf, ref_pair);
1704
0
        if (rf[1] != NONE_FRAME) {
1705
0
            const uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
1706
0
            const uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
1707
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1708
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1709
0
            if (!svt_aom_is_valid_unipred_ref(
1710
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_0, ref_idx_0) ||
1711
0
                !svt_aom_is_valid_unipred_ref(
1712
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_1, ref_idx_1)) {
1713
0
                continue;
1714
0
            }
1715
1716
0
            {
1717
                //NEAREST_NEWMV
1718
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1719
0
                Mv                 to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1720
0
                Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1721
0
                bool               inj_mv =
1722
0
                    (ctx->injected_mv_count == 0 || !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1723
0
                    svt_aom_is_me_data_present(
1724
0
                        ctx->me_block_offset, ctx->me_cand_offset, me_results, get_list_idx(rf[1]), ref_idx_1);
1725
0
                if (inj_mv) {
1726
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1727
0
                                                ctx->blk_ptr,
1728
0
                                                ref_pair,
1729
0
                                                1, // is_compound
1730
0
                                                NEAREST_NEWMV,
1731
0
                                                0, //not needed drli,
1732
0
                                                nearestmv,
1733
0
                                                nearmv,
1734
0
                                                ref_mv);
1735
1736
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1737
0
                    cand->block_mi.mode               = NEAREST_NEWMV;
1738
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1739
0
                    cand->block_mi.is_interintra_used = 0;
1740
0
                    cand->block_mi.use_intrabc        = 0;
1741
0
                    cand->skip_mode_allowed           = false;
1742
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1743
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1744
0
                    cand->drl_index                   = 0;
1745
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1746
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1747
0
                    cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1748
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1749
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1750
1751
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1752
0
                        ctx->cmp_store.pred0_cnt = 0;
1753
0
                        ctx->cmp_store.pred1_cnt = 0;
1754
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1755
0
                    }
1756
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1757
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1758
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1759
0
                    ++ctx->injected_mv_count;
1760
0
                }
1761
0
            }
1762
1763
0
            {
1764
                //NEW_NEARESTMV
1765
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1766
0
                Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1767
0
                Mv                 to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1768
0
                bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1769
0
                               !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1770
0
                    svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1771
0
                if (inj_mv) {
1772
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1773
0
                                                ctx->blk_ptr,
1774
0
                                                ref_pair,
1775
0
                                                1, // is_compound
1776
0
                                                NEW_NEARESTMV,
1777
0
                                                0, //not needed drli,
1778
0
                                                nearestmv,
1779
0
                                                nearmv,
1780
0
                                                ref_mv);
1781
1782
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1783
0
                    cand->block_mi.mode               = NEW_NEARESTMV;
1784
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1785
0
                    cand->block_mi.is_interintra_used = 0;
1786
0
                    cand->block_mi.use_intrabc        = 0;
1787
0
                    cand->skip_mode_allowed           = false;
1788
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1789
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1790
0
                    cand->drl_index                   = 0;
1791
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1792
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1793
0
                    cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1794
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1795
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1796
1797
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1798
0
                        ctx->cmp_store.pred0_cnt = 0;
1799
0
                        ctx->cmp_store.pred1_cnt = 0;
1800
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1801
0
                    }
1802
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1803
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1804
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1805
0
                    ++ctx->injected_mv_count;
1806
0
                }
1807
0
            }
1808
            // For level 2, only inject NEAREST_NEW/NEW_NEAREST candidates
1809
0
            if (ctx->new_nearest_near_comb_injection >= 2) {
1810
0
                continue;
1811
0
            }
1812
1813
            //NEW_NEARMV
1814
0
            {
1815
0
                const uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEW_NEARMV);
1816
1817
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1818
0
                    svt_aom_get_av1_mv_pred_drl(
1819
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEW_NEARMV, drli, nearestmv, nearmv, ref_mv);
1820
1821
                    //NEW_NEARMV
1822
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1823
0
                    Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1824
0
                    Mv                 to_inj_mv1 = {.as_int = nearmv[1].as_int};
1825
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1826
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1827
0
                        svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1828
0
                    if (inj_mv) {
1829
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1830
0
                        cand->block_mi.mode               = NEW_NEARMV;
1831
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1832
0
                        cand->block_mi.is_interintra_used = 0;
1833
0
                        cand->block_mi.use_intrabc        = 0;
1834
0
                        cand->skip_mode_allowed           = false;
1835
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1836
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1837
0
                        cand->drl_index                   = drli;
1838
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1839
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1840
0
                        cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1841
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1842
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1843
1844
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1845
0
                            ctx->cmp_store.pred0_cnt = 0;
1846
0
                            ctx->cmp_store.pred1_cnt = 0;
1847
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1848
0
                        }
1849
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1850
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1851
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1852
0
                        ++ctx->injected_mv_count;
1853
0
                    }
1854
0
                }
1855
0
            }
1856
            //NEAR_NEWMV
1857
0
            {
1858
0
                uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEWMV);
1859
1860
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1861
0
                    svt_aom_get_av1_mv_pred_drl(
1862
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEAR_NEWMV, drli, nearestmv, nearmv, ref_mv);
1863
1864
                    //NEAR_NEWMV
1865
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1866
0
                    Mv                 to_inj_mv0 = {.as_int = nearmv[0].as_int};
1867
0
                    Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1868
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1869
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1870
0
                        svt_aom_is_me_data_present(
1871
0
                                      ctx->me_block_offset, ctx->me_cand_offset, me_results, list_idx_1, ref_idx_1);
1872
1873
0
                    if (inj_mv) {
1874
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1875
0
                        cand->block_mi.mode               = NEAR_NEWMV;
1876
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1877
0
                        cand->block_mi.is_interintra_used = 0;
1878
0
                        cand->block_mi.use_intrabc        = 0;
1879
0
                        cand->skip_mode_allowed           = false;
1880
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1881
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1882
0
                        cand->drl_index                   = drli;
1883
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1884
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1885
0
                        cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1886
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1887
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1888
1889
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1890
0
                            ctx->cmp_store.pred0_cnt = 0;
1891
0
                            ctx->cmp_store.pred1_cnt = 0;
1892
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1893
0
                        }
1894
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1895
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1896
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1897
0
                        ++ctx->injected_mv_count;
1898
0
                    }
1899
0
                }
1900
0
            }
1901
0
        }
1902
0
    }
1903
    //update tot Candidate count
1904
0
    *cand_tot_cnt = cand_idx;
1905
0
}
1906
1907
// Refine the WM MV (8 bit search).  Return true if search found a valid MV; false otherwise
1908
uint8_t svt_aom_wm_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
1909
0
                                     const bool shut_approx) {
1910
0
    PictureParentControlSet* ppcs         = pcs->ppcs;
1911
0
    const Mv                 neighbors[9] = {
1912
0
        {{0, 0}}, {{-1, 0}}, {{0, 1}}, {{1, 0}}, {{0, -1}}, {{1, -1}}, {{1, 1}}, {{-1, 1}}, {{-1, -1}}};
1913
1914
    // Set info used to get MV cost
1915
0
    int*        mvjcost       = ctx->md_rate_est_ctx->nmv_vec_cost;
1916
0
    const int** mvcost        = ctx->md_rate_est_ctx->nmvcoststack;
1917
0
    uint32_t    full_lambda   = ctx->full_lambda_md[EB_8_BIT_MD]; // 8bit only
1918
0
    int         error_per_bit = full_lambda >> RD_EPB_SHIFT;
1919
0
    error_per_bit += (error_per_bit == 0);
1920
0
    EbPictureBufferDesc*    input_pic          = ppcs->enhanced_pic; // 10BIT not supported
1921
0
    uint32_t                input_origin_index = (ctx->blk_org_y) * input_pic->y_stride + (ctx->blk_org_x);
1922
0
    const AomVarianceFnPtr* fn_ptr             = &svt_aom_mefn_ptr[ctx->blk_geom->bsize];
1923
0
    unsigned int            sse;
1924
0
    uint8_t*                src_y = input_pic->y_buffer + input_origin_index;
1925
1926
0
    int mv_prec_shift = ppcs->frm_hdr.allow_high_precision_mv ? 0 : 1;
1927
0
    int best_cost     = INT_MAX;
1928
    // local WM always uses one ref - MV for ref0 stored in idx0
1929
0
    assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1930
0
    Mv       search_centre_mv = {.as_int = cand->block_mi.mv[0].as_int};
1931
0
    Mv       best_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1932
0
    Mv       prev_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1933
0
    const Mv ref_mv           = {.as_int = cand->pred_mv[0].as_int};
1934
1935
0
    int      max_iterations  = ctx->wm_ctrls.refinement_iterations;
1936
0
    int      tot_checked_pos = 0;
1937
0
    uint32_t mv_record[256];
1938
0
    for (int iter = 0; iter < max_iterations; iter++) {
1939
        // search the (0,0) offset position only for the first search iteration
1940
0
        for (int i = (iter ? 1 : 0); i < (ctx->wm_ctrls.refine_diag ? 9 : 5); i++) {
1941
0
            const Mv test_mv = (Mv){{search_centre_mv.x + (neighbors[i].x * (1 << mv_prec_shift)),
1942
0
                                     search_centre_mv.y + (neighbors[i].y * (1 << mv_prec_shift))}};
1943
1944
            // Don't re-test previously tested positions
1945
0
            if (iter) {
1946
0
                if (prev_mv.as_int == test_mv.as_int) {
1947
0
                    continue;
1948
0
                }
1949
0
                int match_found = 0;
1950
0
                for (int j = 0; j < tot_checked_pos; j++) {
1951
0
                    if (test_mv.as_int == mv_record[j]) {
1952
0
                        match_found = 1;
1953
0
                    }
1954
0
                }
1955
0
                if (match_found) {
1956
0
                    continue;
1957
0
                }
1958
0
            }
1959
0
            mv_record[tot_checked_pos++] = test_mv.as_int;
1960
0
            uint8_t local_warp_valid     = svt_aom_warped_motion_parameters(ctx,
1961
0
                                                                        test_mv,
1962
0
                                                                        ctx->blk_geom,
1963
0
                                                                        cand->block_mi.ref_frame[0],
1964
0
                                                                        &cand->wm_params_l0,
1965
0
                                                                        &cand->block_mi.num_proj_ref,
1966
0
                                                                        ctx->wm_ctrls.lower_band_th,
1967
0
                                                                        ctx->wm_ctrls.upper_band_th,
1968
0
                                                                        shut_approx);
1969
0
            if (!local_warp_valid) {
1970
0
                continue;
1971
0
            }
1972
0
            assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1973
0
            EbPictureBufferDesc* ref_pic_0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
1974
0
            EbPictureBufferDesc* ref_pic_1 = NULL; // will stay NULL b/c this is unipred candidate
1975
1976
            // update MV to be testing MV before calling prediction function
1977
0
            cand->block_mi.mv[0].as_int = test_mv.as_int;
1978
0
            svt_aom_inter_prediction(pcs->scs,
1979
0
                                     pcs,
1980
0
                                     &cand->block_mi,
1981
0
                                     &cand->wm_params_l0,
1982
0
                                     &cand->wm_params_l1,
1983
0
                                     ctx->blk_ptr,
1984
0
                                     ctx->blk_geom->bsize,
1985
0
                                     ctx->shape,
1986
                                     // If using 8bit MD for HBD content, can't use pre-computed OBMC/II to
1987
                                     // generate conformant recon
1988
0
                                     true, //use_precomputed_obmc - not used here
1989
0
                                     true, //use_precomputed_ii - not used here
1990
0
                                     ctx,
1991
0
                                     ctx->recon_neigh_y,
1992
0
                                     ctx->recon_neigh_cb,
1993
0
                                     ctx->recon_neigh_cr,
1994
0
                                     ref_pic_0,
1995
0
                                     ref_pic_1, // this is NULL
1996
0
                                     ctx->blk_org_x,
1997
0
                                     ctx->blk_org_y,
1998
0
                                     ctx->scratch_prediction_ptr,
1999
0
                                     0,
2000
0
                                     0,
2001
0
                                     PICTURE_BUFFER_DESC_LUMA_MASK,
2002
0
                                     EB_EIGHT_BIT,
2003
0
                                     0); // is_16bit_pipeline
2004
2005
0
            int var = fn_ptr->vf(ctx->scratch_prediction_ptr->y_buffer,
2006
0
                                 ctx->scratch_prediction_ptr->y_stride,
2007
0
                                 src_y,
2008
0
                                 input_pic->y_stride,
2009
0
                                 &sse);
2010
0
            if (ctx->approx_inter_rate) {
2011
0
                var += svt_aom_mv_err_cost_light(test_mv, ref_mv);
2012
0
            } else {
2013
0
                var += svt_aom_mv_err_cost(test_mv, ref_mv, mvjcost, mvcost, error_per_bit);
2014
0
            }
2015
2016
0
            if (var < best_cost) {
2017
0
                best_mv.as_int = test_mv.as_int;
2018
0
                best_cost      = var;
2019
0
            }
2020
0
        }
2021
0
        prev_mv.as_int          = search_centre_mv.as_int;
2022
0
        search_centre_mv.as_int = best_mv.as_int;
2023
0
        if (prev_mv.as_int == best_mv.as_int) {
2024
0
            break;
2025
0
        }
2026
0
    }
2027
0
    cand->block_mi.mv[0].as_int = best_mv.as_int;
2028
2029
    // Derive pred MV for best WM position
2030
0
    Mv best_pred_mv[2] = {{{0}}, {{0}}};
2031
0
    svt_aom_choose_best_av1_mv_pred(ctx,
2032
0
                                    cand->block_mi.ref_frame[0], // WM only allowed for unipred cands
2033
0
                                    cand->block_mi.mode,
2034
0
                                    cand->block_mi.mv[0],
2035
0
                                    (Mv){{0}},
2036
0
                                    &cand->drl_index,
2037
0
                                    best_pred_mv);
2038
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2039
2040
    // Check that final chosen MV is valid
2041
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, best_mv, best_mv, 0)) {
2042
0
        return 1;
2043
0
    }
2044
2045
0
    return 0;
2046
0
}
2047
2048
static INLINE void setup_pred_plane(Buf2D* dst, BlockSize bsize, uint8_t* src, int width, int height, int stride,
2049
0
                                    int mi_row, int mi_col, int subsampling_x, int subsampling_y) {
2050
    // Offset the buffer pointer
2051
0
    if (subsampling_y && (mi_row & 0x01) && (mi_size_high[bsize] == 1)) {
2052
0
        mi_row -= 1;
2053
0
    }
2054
0
    if (subsampling_x && (mi_col & 0x01) && (mi_size_wide[bsize] == 1)) {
2055
0
        mi_col -= 1;
2056
0
    }
2057
2058
0
    const int x = (MI_SIZE * mi_col) >> subsampling_x;
2059
0
    const int y = (MI_SIZE * mi_row) >> subsampling_y;
2060
0
    dst->buf    = src + (y * stride + x); // scaled_buffer_offset(x, y, stride, scale);
2061
0
    dst->buf0   = src;
2062
0
    dst->width  = width;
2063
0
    dst->height = height;
2064
0
    dst->stride = stride;
2065
0
}
2066
2067
void svt_av1_setup_pred_block(BlockSize bsize, Buf2D dst[MAX_PLANES], const Yv12BufferConfig* src, int mi_row,
2068
0
                              int mi_col) {
2069
0
    dst[0].buf    = src->y_buffer;
2070
0
    dst[0].stride = src->y_stride;
2071
0
    dst[1].buf    = src->u_buffer;
2072
0
    dst[2].buf    = src->v_buffer;
2073
0
    dst[1].stride = dst[2].stride = src->uv_stride;
2074
2075
0
    setup_pred_plane(
2076
0
        dst, bsize, dst[0].buf, src->y_crop_width, src->y_crop_height, dst[0].stride, mi_row, mi_col, 0, 0);
2077
0
}
2078
2079
static int sad_per_bit_lut_8[QINDEX_RANGE];
2080
static int sad_per_bit_lut_10[QINDEX_RANGE];
2081
2082
// Get the sad per bit for the relevant qindex and bit depth
2083
0
int svt_aom_get_sad_per_bit(int qidx, EbBitDepth is_hbd) {
2084
0
    return is_hbd ? sad_per_bit_lut_10[qidx] : sad_per_bit_lut_8[qidx];
2085
0
}
2086
2087
2
static void init_me_luts_bd(int* bit16lut, int range, EbBitDepth bit_depth) {
2088
2
    int i;
2089
    // Initialize the sad lut tables using a formulaic calculation for now.
2090
    // This is to make it easier to resolve the impact of experimental changes
2091
    // to the quantizer tables.
2092
514
    for (i = 0; i < range; i++) {
2093
512
        const double q = svt_av1_convert_qindex_to_q(i, bit_depth);
2094
512
        bit16lut[i]    = (int)(0.0418 * q + 2.4107);
2095
512
    }
2096
2
}
2097
2098
1
void svt_av1_init_me_luts(void) {
2099
1
    init_me_luts_bd(sad_per_bit_lut_8, QINDEX_RANGE, EB_EIGHT_BIT);
2100
1
    init_me_luts_bd(sad_per_bit_lut_10, QINDEX_RANGE, EB_TEN_BIT);
2101
1
}
2102
2103
#if CONFIG_ENABLE_OBMC
2104
static void single_motion_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2105
                                 Mv best_pred_mv, IntraBcContext* x, BlockSize bsize, Mv* ref_mv, int* rate_mv,
2106
0
                                 int refine_level) {
2107
0
    bool do_full_refine = 0;
2108
0
    bool do_frac_refine = 0;
2109
0
    switch (refine_level) {
2110
0
    case 0:
2111
0
    case 1:
2112
0
    case 3:
2113
0
        do_full_refine = 1;
2114
0
        do_frac_refine = 1;
2115
0
        break;
2116
0
    case 2:
2117
0
    case 4:
2118
0
        do_full_refine = 0;
2119
0
        do_frac_refine = 1;
2120
0
        break;
2121
0
    default:
2122
0
        break;
2123
0
    }
2124
0
    const Av1Common* const cm      = pcs->ppcs->av1_cm;
2125
0
    FrameHeader*           frm_hdr = &pcs->ppcs->frm_hdr;
2126
    // single_motion_search supports 8bit path only
2127
0
    uint32_t full_lambda = ctx->full_lambda_md[EB_8_BIT_MD];
2128
2129
0
    x->xd            = ctx->blk_ptr->av1xd;
2130
0
    const int mi_row = -x->xd->mb_to_top_edge / (8 * MI_SIZE);
2131
0
    const int mi_col = -x->xd->mb_to_left_edge / (8 * MI_SIZE);
2132
2133
0
    x->nmv_vec_cost  = ctx->md_rate_est_ctx->nmv_vec_cost;
2134
0
    x->mv_cost_stack = ctx->md_rate_est_ctx->nmvcoststack;
2135
    // Set up limit values for MV components.
2136
    // Mv beyond the range do not produce new/different prediction block.
2137
0
    const int mi_width   = mi_size_wide[bsize];
2138
0
    const int mi_height  = mi_size_high[bsize];
2139
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
2140
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
2141
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
2142
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
2143
    //set search paramters
2144
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
2145
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
2146
0
    x->errorperbit += (x->errorperbit == 0);
2147
0
    if (do_full_refine) {
2148
0
        int      sadpb         = x->sadperbit16;
2149
0
        MvLimits tmp_mv_limits = x->mv_limits;
2150
2151
        // Note: MV limits are modified here. Always restore the original values
2152
        // after full-pixel motion search.
2153
0
        svt_av1_set_mv_search_range(&x->mv_limits, *ref_mv);
2154
2155
0
        Mv mvp_full = best_pred_mv; // mbmi->mv[0].as_mv;
2156
2157
        // TODO: should use get_fullmv_from_mv instead of shifting
2158
0
        mvp_full.x >>= 3;
2159
0
        mvp_full.y >>= 3;
2160
2161
0
        x->best_mv.as_int = x->second_best_mv.as_int = INVALID_MV; //D
2162
2163
0
        switch (cand->block_mi.motion_mode) {
2164
0
        case OBMC_CAUSAL:
2165
0
            svt_av1_obmc_full_pixel_search(
2166
0
                ctx, x, mvp_full, sadpb, &svt_aom_mefn_ptr[bsize], *ref_mv, &(x->best_mv), 0);
2167
0
            break;
2168
0
        default:
2169
0
            assert(0 && "Invalid motion mode!\n");
2170
0
        }
2171
2172
0
        x->mv_limits = tmp_mv_limits;
2173
0
    } else { // round-up the default
2174
0
        x->best_mv.x = best_pred_mv.x >> 3;
2175
0
        x->best_mv.y = best_pred_mv.y >> 3;
2176
0
    }
2177
2178
0
    if (do_frac_refine) {
2179
0
        int          dis; /* TODO: use dis in distortion calculation later. */
2180
0
        unsigned int sse1; //unused
2181
0
        switch (cand->block_mi.motion_mode) {
2182
0
        case OBMC_CAUSAL:
2183
0
            svt_av1_find_best_obmc_sub_pixel_tree_up(ctx,
2184
0
                                                     x,
2185
0
                                                     cm,
2186
0
                                                     mi_row,
2187
0
                                                     mi_col,
2188
0
                                                     &x->best_mv,
2189
0
                                                     *ref_mv,
2190
0
                                                     frm_hdr->allow_high_precision_mv,
2191
0
                                                     x->errorperbit,
2192
0
                                                     &svt_aom_mefn_ptr[bsize],
2193
0
                                                     0, // mv.subpel_force_stop
2194
0
                                                     2, //  mv.subpel_iters_per_step
2195
0
                                                     x->nmv_vec_cost,
2196
0
                                                     x->mv_cost_stack,
2197
0
                                                     &dis,
2198
0
                                                     &sse1,
2199
0
                                                     0,
2200
0
                                                     USE_8_TAPS);
2201
2202
0
            break;
2203
0
        default:
2204
0
            assert(0 && "Invalid motion mode!\n");
2205
0
        }
2206
0
    } else {
2207
0
        x->best_mv.x *= 8;
2208
0
        x->best_mv.y *= 8;
2209
0
    }
2210
0
    if (ctx->approx_inter_rate) {
2211
0
        *rate_mv = svt_av1_mv_bit_cost_light(x->best_mv, *ref_mv);
2212
0
    } else {
2213
0
        *rate_mv = svt_av1_mv_bit_cost(x->best_mv, *ref_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT);
2214
0
    }
2215
0
}
2216
2217
// Refine the OBMC MV (8 bit search). Return true if search found a valid MV; false otherwise
2218
uint8_t svt_aom_obmc_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2219
0
                                       int refine_level) {
2220
0
    if (block_size_wide[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine ||
2221
0
        block_size_high[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine) {
2222
0
        return 1;
2223
0
    }
2224
2225
0
    if (ctx->obmc_weighted_pred_ready == false) {
2226
0
        int mi_row = ctx->blk_org_y >> 2;
2227
0
        int mi_col = ctx->blk_org_x >> 2;
2228
2229
0
        DECLARE_ALIGNED(16, uint8_t, dst_buf1_8b[4 * MAX_PLANES * MAX_SB_SQUARE]);
2230
2231
0
        uint8_t* dst_buf2_8b = dst_buf1_8b + 2 * MAX_PLANES * MAX_SB_SQUARE;
2232
0
        if (ctx->obmc_is_luma_neigh_10bit) {
2233
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_0,
2234
0
                              ctx->blk_geom->bwidth,
2235
0
                              dst_buf1_8b,
2236
0
                              ctx->blk_geom->bwidth,
2237
0
                              NULL,
2238
0
                              ctx->blk_geom->bwidth,
2239
0
                              ctx->blk_geom->bwidth,
2240
0
                              ctx->blk_geom->bheight);
2241
2242
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_1,
2243
0
                              ctx->blk_geom->bwidth,
2244
0
                              dst_buf2_8b,
2245
0
                              ctx->blk_geom->bwidth,
2246
0
                              NULL,
2247
0
                              ctx->blk_geom->bwidth,
2248
0
                              ctx->blk_geom->bwidth,
2249
0
                              ctx->blk_geom->bheight);
2250
0
        }
2251
2252
0
        calc_target_weighted_pred(pcs,
2253
0
                                  ctx,
2254
0
                                  pcs->ppcs->av1_cm,
2255
0
                                  ctx->blk_ptr->av1xd,
2256
0
                                  mi_row,
2257
0
                                  mi_col,
2258
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf1_8b : ctx->obmc_buff_0,
2259
0
                                  ctx->blk_geom->bwidth,
2260
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf2_8b : ctx->obmc_buff_1,
2261
0
                                  ctx->blk_geom->bwidth);
2262
2263
0
        ctx->obmc_weighted_pred_ready = true;
2264
0
    }
2265
0
    Mv              best_pred_mv[2] = {{{0}}, {{0}}};
2266
0
    IntraBcContext  x_st;
2267
0
    IntraBcContext* x = &x_st;
2268
2269
0
    MacroBlockD* xd;
2270
0
    xd = x->xd       = ctx->blk_ptr->av1xd;
2271
0
    const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE);
2272
0
    const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE);
2273
2274
0
    {
2275
0
        assert(cand->block_mi.ref_frame[1] == NONE_FRAME); // OBMC only allowed for unipred cands
2276
0
        uint8_t ref_idx  = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
2277
0
        uint8_t list_idx = get_list_idx(cand->block_mi.ref_frame[0]);
2278
2279
0
        assert(list_idx < MAX_NUM_OF_REF_PIC_LIST);
2280
0
        EbPictureBufferDesc* reference_picture =
2281
0
            ((EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr)->reference_picture;
2282
2283
0
        svt_aom_use_scaled_rec_refs_if_needed(pcs,
2284
0
                                              pcs->ppcs->enhanced_pic,
2285
0
                                              (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr,
2286
0
                                              &reference_picture,
2287
0
                                              EB_8_BIT_MD);
2288
0
        Yv12BufferConfig ref_buf;
2289
0
        svt_aom_link_eb_to_aom_buffer_desc_8bit(reference_picture, &ref_buf);
2290
2291
0
        Buf2D yv12_mb[MAX_PLANES];
2292
0
        svt_av1_setup_pred_block(ctx->blk_geom->bsize, yv12_mb, &ref_buf, mi_row, mi_col);
2293
0
        for (int i = 0; i < 1; ++i) {
2294
0
            x->xdplane[i].pre[0] = yv12_mb[i]; //ref in ME
2295
0
        }
2296
2297
0
        x->plane[0].src.buf  = 0; // x->xdplane[0].pre[0];
2298
0
        x->plane[0].src.buf0 = 0;
2299
0
    }
2300
2301
0
    Mv  best_mv = {.as_int = cand->block_mi.mv[0].as_int};
2302
0
    int tmp_rate_mv;
2303
2304
0
    Mv ref_mv = {.as_int = cand->pred_mv[0].as_int};
2305
2306
0
    single_motion_search(pcs, ctx, cand, best_mv, x, ctx->blk_geom->bsize, &ref_mv, &tmp_rate_mv, refine_level);
2307
0
    cand->block_mi.mv[0].as_int = x->best_mv.as_int;
2308
0
    svt_aom_choose_best_av1_mv_pred(ctx,
2309
0
                                    cand->block_mi.ref_frame[0], // OBMC only allowed for unipred candidtes
2310
0
                                    cand->block_mi.mode,
2311
0
                                    cand->block_mi.mv[0],
2312
0
                                    (Mv){{0}},
2313
0
                                    &cand->drl_index,
2314
0
                                    best_pred_mv);
2315
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2316
    // Check that final chosen MV is valid
2317
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, cand->block_mi.mv[0], cand->block_mi.mv[0], 0)) {
2318
0
        return 1;
2319
0
    }
2320
2321
0
    return 0;
2322
0
}
2323
#endif // CONFIG_ENABLE_OBMC
2324
2325
/*
2326
   inject ME candidates for Light PD0
2327
*/
2328
static void inject_new_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2329
0
                                      const bool allow_bipred) {
2330
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2331
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2332
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2333
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2334
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2335
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2336
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2337
2338
0
    const uint8_t max_refs = pcs->ppcs->pa_me_data->max_refs;
2339
0
    const uint8_t max_l0   = pcs->ppcs->pa_me_data->max_l0;
2340
2341
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2342
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2343
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2344
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2345
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2346
2347
0
        if (ctx->pd0_ctrls.pd0_level == PD0_LVL_6 && inter_direction == BI_PRED) {
2348
0
            continue;
2349
0
        }
2350
2351
        /**************
2352
            NEWMV
2353
        ************* */
2354
0
        if (inter_direction < BI_PRED) {
2355
0
            const uint8_t list_idx = inter_direction;
2356
0
            const uint8_t ref_idx  = inter_direction ? list1_ref_index : list0_ref_index;
2357
0
            const int16_t to_inject_mv_x =
2358
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].x) * 8;
2359
0
            const int16_t to_inject_mv_y =
2360
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].y) * 8;
2361
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2362
2363
0
            ModeDecisionCandidate* cand = &cand_array[cand_total_cnt];
2364
0
            cand->block_mi.mode         = NEWMV;
2365
0
            cand->block_mi.mv[0]        = (Mv){{to_inject_mv_x, to_inject_mv_y}};
2366
0
            cand->block_mi.ref_frame[0] = to_inject_ref_type;
2367
0
            cand->block_mi.ref_frame[1] = NONE_FRAME;
2368
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2369
0
            if (cand_total_cnt > 2) {
2370
0
                break;
2371
0
            }
2372
0
        } else if (allow_bipred) {
2373
0
            assert(inter_direction == BI_PRED);
2374
            /**************
2375
               NEW_NEWMV
2376
            ************* */
2377
0
            const uint32_t ref0_offset = me_block_offset * max_refs +
2378
0
                (me_block_results_ptr->ref0_list > 0 ? max_l0 : 0) + list0_ref_index;
2379
0
            const uint32_t ref1_offset = me_block_offset * max_refs +
2380
0
                (me_block_results_ptr->ref1_list > 0 ? max_l0 : 0) + list1_ref_index;
2381
0
            const int16_t to_inject_mv_x_l0 = (me_results->me_mv_array[ref0_offset].x) * 8;
2382
0
            const int16_t to_inject_mv_y_l0 = (me_results->me_mv_array[ref0_offset].y) * 8;
2383
0
            const int16_t to_inject_mv_x_l1 = (me_results->me_mv_array[ref1_offset].x) * 8;
2384
0
            const int16_t to_inject_mv_y_l1 = (me_results->me_mv_array[ref1_offset].y) * 8;
2385
2386
0
            MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2387
0
                                      svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2388
2389
            // Inject AVG candidate only
2390
0
            ModeDecisionCandidate* cand   = &cand_array[cand_total_cnt];
2391
0
            cand->block_mi.mv[REF_LIST_0] = (Mv){{to_inject_mv_x_l0, to_inject_mv_y_l0}};
2392
0
            cand->block_mi.mv[REF_LIST_1] = (Mv){{to_inject_mv_x_l1, to_inject_mv_y_l1}};
2393
0
            cand->block_mi.mode           = NEW_NEWMV;
2394
0
            cand->block_mi.ref_frame[0]   = rf[0];
2395
0
            cand->block_mi.ref_frame[1]   = rf[1];
2396
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2397
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2398
0
            if (cand_total_cnt > 2) {
2399
0
                break;
2400
0
            }
2401
0
        }
2402
0
    }
2403
    // update the total number of candidates injected
2404
0
    (*candidate_total_cnt) = cand_total_cnt;
2405
0
}
2406
2407
static void inject_new_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2408
0
                                            uint32_t* candidate_total_cnt, const bool allow_bipred) {
2409
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2410
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2411
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2412
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2413
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2414
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2415
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2416
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2417
2418
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2419
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2420
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2421
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2422
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2423
2424
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates >= 2) {
2425
0
            if ((total_me_cnt > 1) && (inter_direction != 2)) {
2426
0
                continue;
2427
0
            }
2428
0
        } else if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2429
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2430
0
                continue;
2431
0
            }
2432
0
        }
2433
2434
        /**************
2435
            NEWMV
2436
        ************* */
2437
0
        if (inter_direction < BI_PRED) {
2438
0
            const uint8_t list_idx           = inter_direction;
2439
0
            const uint8_t ref_idx            = inter_direction ? list1_ref_index : list0_ref_index;
2440
0
            Mv            to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2441
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2442
0
            if (ctx->injected_mv_count == 0 ||
2443
0
                mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false) {
2444
0
                uint8_t drl_index = 0;
2445
0
                svt_aom_choose_best_av1_mv_pred(
2446
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2447
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2448
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2449
0
                    cand->block_mi.use_intrabc        = 0;
2450
0
                    cand->block_mi.is_interintra_used = 0;
2451
0
                    cand->skip_mode_allowed           = false;
2452
0
                    cand->block_mi.mode               = NEWMV;
2453
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2454
0
                    cand->drl_index                   = drl_index;
2455
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2456
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2457
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2458
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2459
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2460
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2461
                    // Add the injected MV to the list of injected MVs
2462
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2463
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2464
0
                    ++ctx->injected_mv_count;
2465
0
                }
2466
0
            }
2467
0
        } else if (allow_bipred && inter_direction == 2 &&
2468
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2469
            /**************
2470
               NEW_NEWMV
2471
            ************* */
2472
0
            Mv               to_inj_mv0 = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2473
0
            Mv               to_inj_mv1 = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2474
0
            MvReferenceFrame rf[2]      = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2475
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2476
0
            uint8_t          to_inject_ref_type = av1_ref_frame_type(rf);
2477
0
            if ((ctx->injected_mv_count == 0 ||
2478
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2479
0
                uint8_t drl_index = 0;
2480
0
                svt_aom_choose_best_av1_mv_pred(
2481
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2482
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2483
0
                    ModeDecisionCandidate* cand         = &cand_array[cand_total_cnt];
2484
0
                    cand->block_mi.use_intrabc          = 0;
2485
0
                    cand->block_mi.is_interintra_used   = 0;
2486
0
                    cand->skip_mode_allowed             = false;
2487
0
                    cand->drl_index                     = drl_index;
2488
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
2489
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
2490
0
                    cand->block_mi.mode                 = NEW_NEWMV;
2491
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
2492
0
                    cand->block_mi.ref_frame[0]         = rf[0];
2493
0
                    cand->block_mi.ref_frame[1]         = rf[1];
2494
0
                    cand->pred_mv[0].as_int             = best_pred_mv[0].as_int;
2495
0
                    cand->pred_mv[1].as_int             = best_pred_mv[1].as_int;
2496
0
                    cand->block_mi.comp_group_idx       = 0;
2497
0
                    cand->block_mi.compound_idx         = 1;
2498
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
2499
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2500
2501
                    // Add the injected MV to the list of injected MVs
2502
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2503
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2504
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2505
0
                    ++ctx->injected_mv_count;
2506
0
                }
2507
0
            }
2508
0
        }
2509
0
    }
2510
    // update the total number of candidates injected
2511
0
    (*candidate_total_cnt) = cand_total_cnt;
2512
0
}
2513
2514
static void inject_new_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2515
0
                                  const bool allow_bipred) {
2516
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2517
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2518
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2519
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2520
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2521
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2522
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2523
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2524
2525
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2526
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2527
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2528
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2529
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2530
2531
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2532
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2533
0
                continue;
2534
0
            }
2535
0
        }
2536
2537
        /**************
2538
            NEWMV unipred
2539
        ************* */
2540
0
        if (inter_direction < BI_PRED) {
2541
0
            const uint8_t list_idx = inter_direction;
2542
0
            const uint8_t ref_idx  = list_idx == REF_LIST_0 ? list0_ref_index : list1_ref_index;
2543
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, PA_ME_GROUP), list_idx, ref_idx)) {
2544
0
                continue;
2545
0
            }
2546
0
            Mv      to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2547
0
            uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2548
0
            if ((ctx->injected_mv_count == 0 ||
2549
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false)) {
2550
0
                uint8_t drl_index = 0;
2551
0
                svt_aom_choose_best_av1_mv_pred(
2552
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2553
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2554
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2555
0
                    cand->block_mi.use_intrabc        = 0;
2556
0
                    cand->skip_mode_allowed           = false;
2557
0
                    cand->block_mi.mode               = NEWMV;
2558
0
                    cand->drl_index                   = drl_index;
2559
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2560
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2561
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2562
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2563
0
                    cand->block_mi.is_interintra_used = 0;
2564
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2565
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2566
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2567
2568
0
                    const bool enable_ii   = true;
2569
0
                    const bool enable_obmc = true;
2570
0
                    const bool enable_warp = true;
2571
0
                    inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2572
2573
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2574
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2575
0
                    ++ctx->injected_mv_count;
2576
0
                }
2577
0
            }
2578
0
        } else if (allow_bipred &&
2579
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2580
0
            assert(inter_direction == BI_PRED);
2581
            /**************
2582
               NEW_NEWMV
2583
            ************* */
2584
0
            if (!is_valid_bipred_ref(ctx,
2585
0
                                     PA_ME_GROUP,
2586
0
                                     me_block_results_ptr->ref0_list,
2587
0
                                     list0_ref_index,
2588
0
                                     me_block_results_ptr->ref1_list,
2589
0
                                     list1_ref_index)) {
2590
0
                continue;
2591
0
            }
2592
0
            Mv      to_inj_mv0         = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2593
0
            Mv      to_inj_mv1         = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2594
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(
2595
0
                (const MvReferenceFrame[]){svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2596
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)});
2597
0
            if ((ctx->injected_mv_count == 0 ||
2598
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2599
0
                uint8_t drl_index = 0;
2600
0
                svt_aom_choose_best_av1_mv_pred(
2601
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2602
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2603
0
                    MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2604
0
                                              svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2605
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2606
0
                    cand->block_mi.use_intrabc        = 0;
2607
0
                    cand->skip_mode_allowed           = false;
2608
0
                    cand->drl_index                   = drl_index;
2609
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2610
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2611
0
                    cand->block_mi.mode               = NEW_NEWMV;
2612
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2613
0
                    cand->block_mi.is_interintra_used = 0;
2614
0
                    cand->block_mi.ref_frame[0]       = rf[0];
2615
0
                    cand->block_mi.ref_frame[1]       = rf[1];
2616
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2617
0
                    cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2618
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2619
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2620
2621
0
                    if (ctx->inter_comp_ctrls.do_me) {
2622
0
                        ctx->cmp_store.pred0_cnt = 0;
2623
0
                        ctx->cmp_store.pred1_cnt = 0;
2624
0
                        inj_comp_modes(pcs, ctx, &cand_total_cnt);
2625
0
                    }
2626
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2627
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2628
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2629
0
                    ++ctx->injected_mv_count;
2630
0
                }
2631
0
            }
2632
0
        }
2633
0
    }
2634
    // update the total number of candidates injected
2635
0
    (*candidate_total_cnt) = cand_total_cnt;
2636
0
}
2637
2638
static void inject_global_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2639
0
                                     const bool allow_bipred) {
2640
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
2641
0
    uint32_t               cand_total_cnt = (*candidate_total_cnt);
2642
0
    uint32_t               mi_row         = ctx->blk_org_y >> MI_SIZE_LOG2;
2643
0
    uint32_t               mi_col         = ctx->blk_org_x >> MI_SIZE_LOG2;
2644
2645
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2646
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2647
0
        MvReferenceFrame rf[2];
2648
0
        av1_set_ref_frame(rf, ref_pair);
2649
2650
        //single ref/list
2651
0
        if (rf[1] == NONE_FRAME) {
2652
0
            MvReferenceFrame frame_type = rf[0];
2653
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2654
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2655
2656
0
            if (!svt_aom_is_valid_unipred_ref(ctx, GLOBAL_GROUP, list_idx, ref_idx)) {
2657
0
                continue;
2658
0
            }
2659
            // Get gm params
2660
0
            WarpedMotionParams* gm_params = &pcs->ppcs->global_motion[frame_type];
2661
0
            if (pcs->ppcs->gm_ctrls.skip_identity && gm_params->wmtype == IDENTITY) {
2662
0
                continue;
2663
0
            }
2664
0
            Mv to_inj_mv = svt_aom_gm_get_motion_vector_enc(gm_params,
2665
0
                                                            pcs->ppcs->frm_hdr.allow_high_precision_mv,
2666
0
                                                            ctx->blk_geom->bsize,
2667
0
                                                            mi_col,
2668
0
                                                            mi_row,
2669
0
                                                            0 /* force_integer_mv */);
2670
2671
0
            assert(list_idx == 0 || list_idx == 1);
2672
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2673
0
            cand->block_mi.mode               = GLOBALMV;
2674
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2675
0
            cand->block_mi.is_interintra_used = 0;
2676
0
            cand->wm_params_l0                = *gm_params;
2677
0
            cand->wm_params_l1                = *gm_params;
2678
0
            cand->block_mi.use_intrabc        = 0;
2679
0
            cand->skip_mode_allowed           = false;
2680
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2681
0
            cand->drl_index                   = 0;
2682
0
            cand->block_mi.ref_frame[0]       = rf[0];
2683
0
            cand->block_mi.ref_frame[1]       = rf[1];
2684
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2685
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2686
2687
0
            const bool enable_ii   = true;
2688
0
            const bool enable_obmc = false;
2689
0
            const bool enable_warp = false;
2690
0
            inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2691
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2692
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2693
0
            ++ctx->injected_mv_count;
2694
0
        } else if (allow_bipred) {
2695
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2696
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2697
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2698
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2699
2700
0
            if (!is_valid_bipred_ref(ctx, GLOBAL_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
2701
0
                return;
2702
0
            }
2703
            // Get gm params
2704
0
            WarpedMotionParams* gm_params_0 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_0, ref_idx_0)];
2705
2706
0
            WarpedMotionParams* gm_params_1 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_1, ref_idx_1)];
2707
2708
0
            if (pcs->ppcs->gm_ctrls.skip_identity &&
2709
0
                (gm_params_0->wmtype == IDENTITY || gm_params_1->wmtype == IDENTITY)) {
2710
0
                continue;
2711
0
            }
2712
0
            Mv to_inj_mv0 = svt_aom_gm_get_motion_vector_enc(gm_params_0,
2713
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2714
0
                                                             ctx->blk_geom->bsize,
2715
0
                                                             mi_col,
2716
0
                                                             mi_row,
2717
0
                                                             0 /* force_integer_mv */);
2718
2719
0
            Mv      to_inj_mv1         = svt_aom_gm_get_motion_vector_enc(gm_params_1,
2720
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2721
0
                                                             ctx->blk_geom->bsize,
2722
0
                                                             mi_col,
2723
0
                                                             mi_row,
2724
0
                                                             0 /* force_integer_mv */);
2725
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(rf);
2726
2727
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2728
0
            cand->block_mi.use_intrabc        = 0;
2729
0
            cand->skip_mode_allowed           = false;
2730
0
            cand->block_mi.mode               = GLOBAL_GLOBALMV;
2731
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2732
0
            cand->wm_params_l0                = *gm_params_0;
2733
0
            cand->wm_params_l1                = *gm_params_1;
2734
0
            cand->block_mi.is_interintra_used = 0;
2735
0
            cand->drl_index                   = 0;
2736
0
            cand->block_mi.ref_frame[0]       = rf[0];
2737
0
            cand->block_mi.ref_frame[1]       = rf[1];
2738
0
            cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2739
0
            cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2740
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2741
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2742
2743
0
            if (ctx->inter_comp_ctrls.do_global) {
2744
0
                ctx->cmp_store.pred0_cnt = 0;
2745
0
                ctx->cmp_store.pred1_cnt = 0;
2746
0
                inj_comp_modes(pcs, ctx, &cand_total_cnt);
2747
0
            }
2748
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2749
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2750
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2751
0
            ++ctx->injected_mv_count;
2752
0
        }
2753
0
    }
2754
    // update the total number of candidates injected
2755
0
    (*candidate_total_cnt) = cand_total_cnt;
2756
0
}
2757
2758
static void inject_pme_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2759
0
                                  const bool allow_bipred) {
2760
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
2761
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
2762
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
2763
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2764
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2765
0
        MvReferenceFrame rf[2];
2766
0
        av1_set_ref_frame(rf, ref_pair);
2767
2768
        //single ref/list
2769
0
        if (rf[1] == NONE_FRAME) {
2770
0
            MvReferenceFrame frame_type = rf[0];
2771
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2772
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2773
2774
0
            if (ctx->valid_pme_mv[list_idx][ref_idx]) {
2775
0
                Mv to_inj_mv = ctx->best_pme_mv[list_idx][ref_idx];
2776
0
                if ((ctx->injected_mv_count == 0 ||
2777
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
2778
0
                    uint8_t drl_index = 0;
2779
0
                    svt_aom_choose_best_av1_mv_pred(
2780
0
                        ctx, frame_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2781
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2782
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2783
0
                        cand->block_mi.use_intrabc        = 0;
2784
0
                        cand->skip_mode_allowed           = false;
2785
0
                        cand->block_mi.mode               = NEWMV;
2786
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2787
0
                        cand->block_mi.is_interintra_used = 0;
2788
0
                        cand->drl_index                   = drl_index;
2789
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2790
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2791
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2792
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2793
0
                        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2794
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2795
2796
0
                        const bool enable_ii   = true;
2797
0
                        const bool enable_obmc = true;
2798
0
                        const bool enable_warp = true;
2799
0
                        inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2800
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2801
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2802
0
                        ++ctx->injected_mv_count;
2803
0
                    }
2804
0
                }
2805
0
            }
2806
0
        } else if (allow_bipred) {
2807
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2808
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2809
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2810
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2811
2812
0
            if (ctx->valid_pme_mv[list_idx_0][ref_idx_0] && ctx->valid_pme_mv[list_idx_1][ref_idx_1]) {
2813
0
                Mv            to_inj_mv0         = ctx->best_pme_mv[list_idx_0][ref_idx_0];
2814
0
                Mv            to_inj_mv1         = ctx->best_pme_mv[list_idx_1][ref_idx_1];
2815
0
                const uint8_t to_inject_ref_type = av1_ref_frame_type((const MvReferenceFrame[]){
2816
0
                    svt_get_ref_frame_type(list_idx_0, ref_idx_0),
2817
0
                    svt_get_ref_frame_type(list_idx_1, ref_idx_1),
2818
0
                });
2819
0
                if ((ctx->injected_mv_count == 0 ||
2820
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2821
0
                    uint8_t drl_index = 0;
2822
0
                    svt_aom_choose_best_av1_mv_pred(
2823
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2824
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2825
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2826
0
                        cand->block_mi.use_intrabc        = 0;
2827
0
                        cand->skip_mode_allowed           = false;
2828
0
                        cand->drl_index                   = drl_index;
2829
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2830
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2831
0
                        cand->block_mi.mode               = NEW_NEWMV;
2832
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2833
0
                        cand->block_mi.is_interintra_used = 0;
2834
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2835
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2836
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2837
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2838
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2839
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2840
2841
0
                        if (ctx->inter_comp_ctrls.do_pme) {
2842
0
                            ctx->cmp_store.pred0_cnt = 0;
2843
0
                            ctx->cmp_store.pred1_cnt = 0;
2844
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
2845
0
                        }
2846
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2847
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2848
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2849
0
                        ++ctx->injected_mv_count;
2850
0
                    }
2851
0
                }
2852
0
            }
2853
0
        }
2854
0
    }
2855
0
    (*candidate_total_cnt) = cand_total_cnt;
2856
0
}
2857
2858
static void inject_inter_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
2859
0
                                        uint32_t* candidate_total_cnt) {
2860
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2861
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2862
    // See AV1 spec 5.11.25
2863
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2864
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2865
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2866
2867
0
    inject_new_candidates_pd0(pcs, ctx, candidate_total_cnt, allow_bipred);
2868
0
}
2869
2870
static void inject_inter_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2871
0
                                              uint32_t* cand_total_cnt) {
2872
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2873
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2874
    // See AV1 spec 5.11.25
2875
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2876
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2877
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2878
    // Needed in case WM/OBMC is on at the frame level (even though not used in light-PD1 path)
2879
0
    if (frm_hdr->is_motion_mode_switchable) {
2880
0
        const uint16_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2881
0
        const uint16_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2882
0
        svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2883
0
    } else {
2884
        // Overlappable neighbours only needed for non-"SIMPLE_TRANSLATION" candidates
2885
0
        ctx->blk_ptr->overlappable_neighbors = 0;
2886
0
    }
2887
0
    svt_aom_init_wm_samples(pcs, ctx);
2888
    // Inject MVP candidates
2889
0
    if (ctx->new_nearest_injection &&
2890
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2891
0
        inject_mvp_candidates_ii_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2892
0
    }
2893
2894
    // Inject ME candidates
2895
0
    if (ctx->inject_new_me) {
2896
0
        inject_new_candidates_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2897
0
    }
2898
0
}
2899
2900
static void svt_aom_inject_inter_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
2901
0
                                            uint32_t* cand_total_cnt) {
2902
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2903
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2904
    // See AV1 spec 5.11.25
2905
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2906
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2907
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2908
2909
0
    const uint32_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2910
0
    const uint32_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2911
2912
0
    svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2913
0
    svt_aom_init_wm_samples(pcs, ctx);
2914
0
#if CONFIG_ENABLE_OBMC
2915
0
    if (ctx->obmc_ctrls.enabled && ctx->obmc_ctrls.refine_level == 0) {
2916
0
        const uint8_t is_obmc_allowed = svt_aom_obmc_motion_mode_allowed(
2917
0
                                            pcs, ctx, ctx->blk_geom->bsize, 1, LAST_FRAME, -1, NEWMV) == OBMC_CAUSAL;
2918
0
        if (is_obmc_allowed) {
2919
0
            svt_aom_precompute_obmc_data(pcs, ctx, PICTURE_BUFFER_DESC_LUMA_MASK);
2920
0
        }
2921
0
    }
2922
0
#endif
2923
    /**************
2924
         MVP
2925
    ************* */
2926
0
    if (ctx->new_nearest_injection &&
2927
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2928
0
        inject_mvp_candidates_ii(pcs, ctx, cand_total_cnt, allow_bipred);
2929
0
    }
2930
    //----------------------
2931
    //    NEAREST_NEWMV, NEW_NEARESTMV, NEAR_NEWMV, NEW_NEARMV.
2932
    //----------------------
2933
0
    if (ctx->new_nearest_near_comb_injection && allow_bipred) {
2934
0
        inject_new_nearest_new_comb_candidates(pcs, ctx, cand_total_cnt);
2935
0
    }
2936
0
    if (ctx->inject_new_me) {
2937
0
        inject_new_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2938
0
    }
2939
0
    if (ctx->global_mv_injection) {
2940
0
        inject_global_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2941
0
    }
2942
0
    if (ctx->bipred3x3_ctrls.enabled && allow_bipred) {
2943
0
        bipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2944
0
    }
2945
2946
0
    if (ctx->unipred3x3_injection) {
2947
0
        unipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2948
0
    }
2949
2950
    // determine when to inject pme candidates based on size and resolution of block
2951
0
    if (ctx->inject_new_pme && ctx->updated_enable_pme) {
2952
0
        inject_pme_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2953
0
    }
2954
0
}
2955
2956
static const TxType g_intra_mode_to_tx_type[INTRA_MODES] = {
2957
    DCT_DCT, // DC
2958
    ADST_DCT, // V
2959
    DCT_ADST, // H
2960
    DCT_DCT, // D45
2961
    ADST_ADST, // D135
2962
    ADST_DCT, // D117
2963
    DCT_ADST, // D153
2964
    DCT_ADST, // D207
2965
    ADST_DCT, // D63
2966
    ADST_ADST, // SMOOTH
2967
    ADST_DCT, // SMOOTH_V
2968
    DCT_ADST, // SMOOTH_H
2969
    ADST_ADST, // PAETH
2970
};
2971
2972
static INLINE TxType intra_mode_to_tx_type(PredictionMode pred_mode, UvPredictionMode pred_mode_uv,
2973
157k
                                           PlaneType plane_type) {
2974
157k
    const PredictionMode mode = (plane_type == PLANE_TYPE_Y) ? pred_mode : get_uv_mode(pred_mode_uv);
2975
157k
    assert(mode < INTRA_MODES);
2976
157k
    return g_intra_mode_to_tx_type[mode];
2977
157k
}
2978
2979
/* For intra prediction, the chroma transform type may not follow the luma type.
2980
This function will return the intra chroma TX type to be used, which is based on TX size and chroma mode.
2981
Refer to section 5.11.40 of the AV1 spec (compute_tx_type). */
2982
157k
TxType svt_aom_get_intra_uv_tx_type(UvPredictionMode pred_mode_uv, TxSize tx_size, int32_t reduced_tx_set) {
2983
157k
    if (txsize_sqr_up_map[tx_size] > TX_32X32) {
2984
0
        return DCT_DCT;
2985
0
    }
2986
2987
    // In intra mode, uv planes don't share the same prediction mode as y
2988
    // plane, so the tx_type should not be shared. Pass DC_PRED as luma mode because the argument
2989
    // will not be used.
2990
157k
    TxType tx_type = intra_mode_to_tx_type(DC_PRED, pred_mode_uv, PLANE_TYPE_UV);
2991
157k
    assert(tx_type < TX_TYPES);
2992
157k
    const TxSetType tx_set_type = get_ext_tx_set_type(tx_size, /*is_inter*/ 0, reduced_tx_set);
2993
157k
    return !av1_ext_tx_used[tx_set_type][tx_type] ? DCT_DCT : tx_type;
2994
157k
}
2995
2996
// Values are now correlated to quantizer.
2997
0
static INLINE int mv_check_bounds(const MvLimits* mv_limits, const Mv mv) {
2998
0
    return (mv.y >> 3) < mv_limits->row_min || (mv.y >> 3) > mv_limits->row_max || (mv.x >> 3) < mv_limits->col_min ||
2999
0
        (mv.x >> 3) > mv_limits->col_max;
3000
0
}
3001
3002
0
static void assert_release(int statement) {
3003
0
    if (statement == 0) {
3004
0
        SVT_LOG("ASSERT_ERRRR\n");
3005
0
    }
3006
0
}
3007
3008
static void intra_bc_search(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3009
0
                            BlkStruct* blk_ptr, Mv* dv_cand, uint8_t* num_dv_cand) {
3010
0
    IntraBcContext  x_st;
3011
0
    IntraBcContext* x           = &x_st;
3012
0
    uint32_t        full_lambda = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_lambda_md[EB_10_BIT_MD]
3013
0
                                                                    : ctx->full_lambda_md[EB_8_BIT_MD];
3014
3015
0
    x->approx_inter_rate = ctx->approx_inter_rate;
3016
0
    x->xd                = blk_ptr->av1xd;
3017
0
    x->nmv_vec_cost      = ctx->md_rate_est_ctx->nmv_vec_cost;
3018
0
    x->mv_cost_stack     = ctx->md_rate_est_ctx->nmvcoststack;
3019
0
    BlockSize bsize      = ctx->blk_geom->bsize;
3020
0
    assert(bsize < BLOCK_SIZES_ALL);
3021
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
3022
0
    const Av1Common* const cm         = pcs->ppcs->av1_cm;
3023
0
    MvReferenceFrame       ref_frame  = INTRA_FRAME;
3024
0
    const int              num_planes = 3;
3025
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
3026
0
    const TileInfo*        tile       = &xd->tile;
3027
0
    const int              mi_row     = -xd->mb_to_top_edge / (8 * MI_SIZE);
3028
0
    const int              mi_col     = -xd->mb_to_left_edge / (8 * MI_SIZE);
3029
0
    const int              w          = block_size_wide[bsize];
3030
0
    const int              h          = block_size_high[bsize];
3031
0
    const int              sb_row     = mi_row >> scs->seq_header.sb_size_log2;
3032
0
    const int              sb_col     = mi_col >> scs->seq_header.sb_size_log2;
3033
3034
    // Set up limit values for MV components.
3035
    // Mv beyond the range do not produce new/different prediction block.
3036
0
    const int mi_width   = mi_size_wide[bsize];
3037
0
    const int mi_height  = mi_size_high[bsize];
3038
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
3039
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
3040
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
3041
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
3042
    //set search paramters
3043
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
3044
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
3045
0
    x->errorperbit += (x->errorperbit == 0);
3046
    //temp buffer for hash me
3047
0
    for (int i = 0; i < 2; i++) {
3048
0
        EB_MALLOC_ARRAY_NO_CHECK(x->hash_value_buffer[i], AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
3049
0
    }
3050
3051
0
    Mv nearestmv, nearmv;
3052
0
    svt_av1_find_best_ref_mvs_from_stack(ctx->ref_mv_stack /*mbmi_ext*/, xd, ref_frame, &nearestmv, &nearmv);
3053
0
    if (nearestmv.as_int == INVALID_MV) {
3054
0
        nearestmv.as_int = 0;
3055
0
    }
3056
0
    if (nearmv.as_int == INVALID_MV) {
3057
0
        nearmv.as_int = 0;
3058
0
    }
3059
0
    Mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
3060
0
    if (dv_ref.as_int == 0) {
3061
0
        svt_aom_find_ref_dv(&dv_ref, tile, scs->seq_header.sb_mi_size, mi_row, mi_col);
3062
0
    }
3063
    // Ref DV should not have sub-pel.
3064
0
    assert((dv_ref.x & 7) == 0);
3065
0
    assert((dv_ref.y & 7) == 0);
3066
0
    ctx->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;
3067
3068
    /* pointer to current frame */
3069
0
    Yv12BufferConfig cur_buf;
3070
0
    svt_aom_link_eb_to_aom_buffer_desc_8bit(pcs->ppcs->enhanced_pic, &cur_buf);
3071
0
    struct Buf2D yv12_mb[MAX_PLANES];
3072
0
    svt_av1_setup_pred_block(bsize, yv12_mb, &cur_buf, mi_row, mi_col);
3073
0
    for (int i = 0; i < num_planes; ++i) {
3074
0
        x->xdplane[i].pre[0] = yv12_mb[i]; // ref in ME
3075
0
    }
3076
    // setup src for DV search same as ref
3077
0
    x->plane[0].src = x->xdplane[0].pre[0];
3078
3079
0
    enum IntrabcMotionDirection max_dir = pcs->ppcs->intrabc_ctrls.search_dir ? IBC_MOTION_LEFT : IBC_MOTION_DIRECTIONS;
3080
3081
0
    for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE; dir < max_dir; ++dir) {
3082
0
        const MvLimits tmp_mv_limits = x->mv_limits;
3083
3084
0
        switch (dir) {
3085
0
        case IBC_MOTION_ABOVE:
3086
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3087
0
            x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w;
3088
0
            x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE;
3089
0
            x->mv_limits.row_max = (sb_row * scs->seq_header.sb_mi_size - mi_row) * MI_SIZE - h;
3090
0
            break;
3091
0
        case IBC_MOTION_LEFT:
3092
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3093
0
            x->mv_limits.col_max = (sb_col * scs->seq_header.sb_mi_size - mi_col) * MI_SIZE - w;
3094
            // TODO: Minimize the overlap between above and
3095
            // left areas.
3096
0
            x->mv_limits.row_min     = (tile->mi_row_start - mi_row) * MI_SIZE;
3097
0
            int bottom_coded_mi_edge = AOMMIN((sb_row + 1) * scs->seq_header.sb_mi_size, tile->mi_row_end);
3098
0
            x->mv_limits.row_max     = (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
3099
0
            break;
3100
0
        default:
3101
0
            assert(0);
3102
0
        }
3103
0
        assert_release(x->mv_limits.col_min >= tmp_mv_limits.col_min);
3104
0
        assert_release(x->mv_limits.col_max <= tmp_mv_limits.col_max);
3105
0
        assert_release(x->mv_limits.row_min >= tmp_mv_limits.row_min);
3106
0
        assert_release(x->mv_limits.row_max <= tmp_mv_limits.row_max);
3107
3108
0
        svt_av1_set_mv_search_range(&x->mv_limits, dv_ref);
3109
3110
0
        if (x->mv_limits.col_max < x->mv_limits.col_min || x->mv_limits.row_max < x->mv_limits.row_min) {
3111
0
            x->mv_limits = tmp_mv_limits;
3112
0
            continue;
3113
0
        }
3114
0
        Mv mvp_full = dv_ref;
3115
0
        mvp_full.x >>= 3;
3116
0
        mvp_full.y >>= 3;
3117
0
        x->best_mv.as_int = 0;
3118
3119
        // Hash Search
3120
0
        const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
3121
3122
0
        int best_hash_cost = INT_MAX;
3123
0
        Mv  best_hash_mv   = {{0, 0}};
3124
3125
0
        svt_av1_intrabc_hash_search(
3126
0
            pcs, x, bsize, mi_col * MI_SIZE, mi_row * MI_SIZE, dv_ref, 1, fn_ptr, &best_hash_cost, &best_hash_mv);
3127
3128
        // Hash produced a candidate
3129
0
        if (best_hash_cost < INT_MAX) {
3130
0
            Mv dv;
3131
0
            dv.x = best_hash_mv.x * 8;
3132
0
            dv.y = best_hash_mv.y * 8;
3133
3134
0
            dv_cand[*num_dv_cand] = dv;
3135
0
            (*num_dv_cand)++;
3136
3137
0
            x->best_mv = best_hash_mv;
3138
0
        }
3139
        // Full-pixel fallback if hash didn't produce a candidate
3140
0
        else {
3141
0
            svt_av1_full_pixel_search(pcs, x, bsize, &mvp_full, 0, x->sadperbit16, NULL, dv_ref);
3142
3143
0
            Mv dv = {{x->best_mv.x * 8, x->best_mv.y * 8}};
3144
3145
0
            if (!mv_check_bounds(&x->mv_limits, dv) &&
3146
0
                svt_aom_is_dv_valid(dv, xd, mi_row, mi_col, bsize, scs->seq_header.sb_size_log2)) {
3147
0
                dv_cand[*num_dv_cand] = dv;
3148
0
                (*num_dv_cand)++;
3149
0
            }
3150
0
        }
3151
3152
0
        x->mv_limits = tmp_mv_limits;
3153
0
    }
3154
3155
0
    for (int i = 0; i < 2; i++) {
3156
0
        EB_FREE_ARRAY(x->hash_value_buffer[i]);
3157
0
    }
3158
0
}
3159
3160
static void inject_intra_bc_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3161
0
                                       BlkStruct* blk_ptr, uint32_t* cand_cnt) {
3162
0
    Mv      dv_cand[2];
3163
0
    uint8_t num_dv_cand = 0;
3164
3165
    //perform dv-pred + search up to 2 dv(s)
3166
0
    intra_bc_search(pcs, ctx, scs, blk_ptr, dv_cand, &num_dv_cand);
3167
3168
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
3169
3170
0
    for (uint32_t dv_i = 0; dv_i < num_dv_cand; dv_i++) {
3171
0
        ModeDecisionCandidate* cand               = &cand_array[*cand_cnt];
3172
0
        cand->palette_info                        = NULL;
3173
0
        cand->block_mi.use_intrabc                = 1;
3174
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3175
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3176
0
        cand->block_mi.uv_mode                    = UV_DC_PRED;
3177
0
        cand->block_mi.cfl_alpha_signs            = 0;
3178
0
        cand->block_mi.cfl_alpha_idx              = 0;
3179
0
        cand->transform_type[0]                   = DCT_DCT;
3180
0
        cand->transform_type_uv                   = DCT_DCT;
3181
0
        cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3182
0
        cand->block_mi.ref_frame[1]               = NONE_FRAME;
3183
0
        cand->block_mi.mode                       = DC_PRED;
3184
0
        cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3185
        //inter ralated
3186
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3187
0
        cand->block_mi.is_interintra_used = 0;
3188
0
        cand->skip_mode_allowed           = false;
3189
0
        cand->block_mi.mv[0].as_int       = dv_cand[dv_i].as_int;
3190
0
        cand->pred_mv[0].as_int           = ctx->ref_mv_stack[INTRA_FRAME][0].this_mv.as_int;
3191
0
        cand->drl_index                   = 0;
3192
0
        cand->block_mi.interp_filters     = av1_broadcast_interp_filter(BILINEAR);
3193
0
        INC_MD_CAND_CNT((*cand_cnt), pcs->ppcs->max_can_count);
3194
0
    }
3195
0
}
3196
3197
static void inject_intra_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
3198
156k
                                        uint32_t* candidate_total_cnt) {
3199
156k
    uint32_t               cand_total_cnt     = 0;
3200
156k
    ModeDecisionCandidate* cand               = &ctx->fast_cand_array[cand_total_cnt];
3201
156k
    cand->skip_mode_allowed                   = false;
3202
156k
    cand->palette_info                        = NULL;
3203
156k
    cand->block_mi.use_intrabc                = 0;
3204
156k
    cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3205
156k
    cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3206
156k
    cand->block_mi.uv_mode                    = UV_DC_PRED;
3207
156k
    cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3208
156k
    cand->block_mi.cfl_alpha_signs            = 0;
3209
156k
    cand->block_mi.cfl_alpha_idx              = 0;
3210
156k
    cand->transform_type[0]                   = DCT_DCT;
3211
156k
    cand->transform_type_uv                   = DCT_DCT;
3212
156k
    cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3213
156k
    cand->block_mi.ref_frame[1]               = NONE_FRAME;
3214
156k
    cand->block_mi.mode                       = DC_PRED;
3215
156k
    cand->block_mi.motion_mode                = SIMPLE_TRANSLATION;
3216
156k
    cand->block_mi.is_interintra_used         = 0;
3217
156k
    cand->block_mi.tx_depth                   = 0;
3218
156k
    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3219
    // update the total number of candidates injected
3220
156k
    (*candidate_total_cnt) = cand_total_cnt;
3221
156k
    return;
3222
156k
}
3223
3224
static void inject_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const bool dc_cand_only_flag,
3225
157k
                                    uint32_t* candidate_total_cnt) {
3226
157k
    FrameHeader*           frm_hdr          = &pcs->ppcs->frm_hdr;
3227
157k
    PredictionMode         intra_mode_start = DC_PRED;
3228
18.4E
    PredictionMode         intra_mode_end   = dc_cand_only_flag ? DC_PRED : ctx->intra_ctrls.intra_mode_end;
3229
157k
    uint32_t               cand_total_cnt   = *candidate_total_cnt;
3230
157k
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
3231
18.4E
    const bool    use_angle_delta = ctx->intra_ctrls.angular_pred_level ? av1_use_angle_delta(ctx->blk_geom->bsize) : 0;
3232
157k
    const uint8_t disable_angle_prediction                = (ctx->intra_ctrls.angular_pred_level == 0);
3233
157k
    uint8_t       directional_mode_skip_mask[INTRA_MODES] = {0};
3234
157k
    if (ctx->intra_ctrls.angular_pred_level >= 4) {
3235
1.73M
        for (uint8_t i = D45_PRED; i < INTRA_MODE_END; i++) {
3236
1.57M
            directional_mode_skip_mask[i] = 1;
3237
1.57M
        }
3238
157k
    }
3239
157k
    const TxSize tx_size_uv = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3240
3241
315k
    for (PredictionMode intra_mode = intra_mode_start; intra_mode <= intra_mode_end; ++intra_mode) {
3242
157k
        if (av1_is_directional_mode(intra_mode) &&
3243
0
            (disable_angle_prediction || directional_mode_skip_mask[intra_mode])) {
3244
0
            continue;
3245
0
        }
3246
3247
157k
        const uint8_t angle_delta_count = av1_is_directional_mode(intra_mode) &&
3248
0
                ctx->intra_ctrls.angular_pred_level <= 2 && use_angle_delta
3249
157k
            ? 7
3250
157k
            : 1;
3251
3252
315k
        for (uint8_t angle_delta_counter = 0; angle_delta_counter < angle_delta_count; ++angle_delta_counter) {
3253
157k
            int32_t angle_delta = CLIP((angle_delta_count == 1 ? 0 : angle_delta_counter - MAX_ANGLE_DELTA),
3254
157k
                                       -MAX_ANGLE_DELTA,
3255
157k
                                       MAX_ANGLE_DELTA);
3256
157k
            if ((ctx->intra_ctrls.angular_pred_level >= 2 &&
3257
157k
                 (angle_delta == -1 || angle_delta == 1 || angle_delta == -2 || angle_delta == 2)) ||
3258
157k
                (ctx->intra_ctrls.angular_pred_level >= 3 && angle_delta != 0)) {
3259
0
                continue;
3260
0
            }
3261
157k
            ModeDecisionCandidate* cand               = &cand_array[cand_total_cnt];
3262
157k
            cand->skip_mode_allowed                   = false;
3263
157k
            cand->palette_info                        = NULL;
3264
157k
            cand->block_mi.mode                       = intra_mode;
3265
157k
            cand->block_mi.use_intrabc                = 0;
3266
157k
            cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3267
157k
            cand->block_mi.angle_delta[PLANE_TYPE_Y]  = angle_delta;
3268
157k
            cand->block_mi.uv_mode                    = ctx->ind_uv_avail ? ctx->best_uv_mode[intra_mode]
3269
157k
                                                                          : intra_luma_to_chroma[intra_mode];
3270
157k
            cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[intra_mode]
3271
157k
                                                                          : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3272
157k
            cand->block_mi.cfl_alpha_signs            = 0;
3273
157k
            cand->block_mi.cfl_alpha_idx              = 0;
3274
157k
            cand->transform_type[0]                   = DCT_DCT;
3275
157k
            cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3276
157k
                cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3277
3278
157k
            if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3279
0
                continue;
3280
0
            }
3281
157k
            cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3282
157k
            cand->block_mi.ref_frame[1]       = NONE_FRAME;
3283
157k
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3284
157k
            cand->block_mi.is_interintra_used = 0;
3285
157k
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3286
157k
        }
3287
157k
    }
3288
3289
    // update the total number of candidates injected
3290
157k
    (*candidate_total_cnt) = cand_total_cnt;
3291
3292
157k
    return;
3293
157k
}
3294
3295
static void inject_filter_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
3296
0
                                           uint32_t* candidate_total_cnt) {
3297
0
    FilterIntraMode intra_mode_start = FILTER_DC_PRED;
3298
0
    FilterIntraMode intra_mode_end   = ctx->intra_ctrls.intra_mode_end == PAETH_PRED ? FILTER_PAETH_PRED
3299
0
          : ctx->intra_ctrls.intra_mode_end >= D157_PRED                             ? FILTER_D157_PRED
3300
0
          : ctx->intra_ctrls.intra_mode_end >= H_PRED                                ? FILTER_H_PRED
3301
0
          : ctx->intra_ctrls.intra_mode_end >= V_PRED                                ? FILTER_V_PRED
3302
0
                                                                                     : FILTER_DC_PRED;
3303
0
    intra_mode_end                   = MIN(intra_mode_end, ctx->filter_intra_ctrls.max_filter_intra_mode);
3304
3305
0
    const TxSize           tx_size_uv     = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3306
0
    uint32_t               cand_total_cnt = *candidate_total_cnt;
3307
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
3308
0
    FrameHeader*           frm_hdr        = &pcs->ppcs->frm_hdr;
3309
3310
0
    for (FilterIntraMode filter_intra_mode = intra_mode_start; filter_intra_mode <= intra_mode_end;
3311
0
         filter_intra_mode++) {
3312
0
        ModeDecisionCandidate* cand              = &cand_array[cand_total_cnt];
3313
0
        cand->skip_mode_allowed                  = false;
3314
0
        cand->block_mi.mode                      = DC_PRED;
3315
0
        cand->block_mi.use_intrabc               = 0;
3316
0
        cand->block_mi.filter_intra_mode         = filter_intra_mode;
3317
0
        cand->palette_info                       = NULL;
3318
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3319
3320
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[fimode_to_intramode[filter_intra_mode]]
3321
0
                                                   : intra_luma_to_chroma[fimode_to_intramode[filter_intra_mode]];
3322
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail
3323
0
            ? ctx->best_uv_angle[fimode_to_intramode[filter_intra_mode]]
3324
0
            : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3325
3326
0
        cand->block_mi.cfl_alpha_signs = 0;
3327
0
        cand->block_mi.cfl_alpha_idx   = 0;
3328
0
        cand->transform_type[0]        = DCT_DCT;
3329
0
        cand->transform_type_uv        = svt_aom_get_intra_uv_tx_type(
3330
0
            cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3331
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3332
0
            continue;
3333
0
        }
3334
0
        cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3335
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3336
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3337
0
        cand->block_mi.is_interintra_used = 0;
3338
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3339
0
    }
3340
3341
    // update the total number of candidates injected
3342
0
    (*candidate_total_cnt) = cand_total_cnt;
3343
3344
0
    return;
3345
0
}
3346
3347
static void inject_zz_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3348
0
                                       uint32_t* candidate_total_cnt) {
3349
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3350
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3351
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3352
0
    cand_array[cand_total_cnt].drl_index   = 0;
3353
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3354
0
                                    svt_get_ref_frame_type(REF_LIST_0, 0),
3355
0
                                    NEWMV,
3356
0
                                    (Mv){{0}},
3357
0
                                    (Mv){{0}},
3358
0
                                    &cand_array[cand_total_cnt].drl_index,
3359
0
                                    best_pred_mv);
3360
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3361
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3362
0
        cand->block_mi.use_intrabc        = 0;
3363
0
        cand->skip_mode_allowed           = false;
3364
0
        cand->block_mi.mode               = NEWMV;
3365
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3366
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3367
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_0, 0);
3368
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3369
0
        cand->transform_type[0]           = DCT_DCT;
3370
0
        cand->transform_type_uv           = DCT_DCT;
3371
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3372
0
        cand->block_mi.is_interintra_used = 0;
3373
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3374
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_0, 0)].num;
3375
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3376
        // update the total number of candidates injected
3377
0
        (*candidate_total_cnt) = cand_total_cnt;
3378
0
    }
3379
0
}
3380
3381
1.10M
int svt_av1_allow_palette(int allow_palette, BlockSize bsize) {
3382
#if !CONFIG_ENABLE_PALETTE
3383
    (void)allow_palette;
3384
    (void)bsize;
3385
    return 0;
3386
#else
3387
1.10M
    assert(bsize < BLOCK_SIZES_ALL);
3388
1.10M
    return allow_palette && block_size_wide[bsize] <= 64 && block_size_high[bsize] <= 64 && bsize >= BLOCK_8X8;
3389
1.10M
#endif
3390
1.10M
}
3391
3392
void search_palette_luma(PictureControlSet* pcs, ModeDecisionContext* ctx, PaletteInfo* palette_cand,
3393
                         uint8_t* palette_size_array, uint32_t* tot_palette_cands);
3394
3395
#if FTR_RTC_INTER_PALETTE
3396
// Per-pixel ME-residual floor at or below which an inter block is treated as unchanged content and
3397
// the palette search is skipped: palette cannot beat a ~0-bit zero-MV skip there.
3398
0
#define RTC_INTER_PALETTE_RES_FLOOR 4
3399
#endif
3400
3401
0
static void inject_palette_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt) {
3402
0
#if FTR_RTC_INTER_PALETTE
3403
    // Skip the palette search on inter blocks where inter prediction is essentially perfect; if
3404
    // neither ME nor PME distortion is available the search still runs. Returning with no candidates
3405
    // injected also clears eval_intrabc in generate_md_stage_0_cand when intrabc_ctrls.palette_hint
3406
    // is set - inert on this path (intrabc_level is 0 in RTC, and intra-BC only exists on intra
3407
    // frames), but relevant if palette_hint ever extends to inter frames.
3408
0
    if (pcs->slice_type != I_SLICE) {
3409
0
        uint32_t best_me = (uint32_t)~0;
3410
0
        if (ctx->md_me_dist != (uint32_t)~0) {
3411
0
            best_me = ctx->md_me_dist;
3412
0
        }
3413
0
        if (ctx->md_pme_dist != (uint32_t)~0 && ctx->md_pme_dist < best_me) {
3414
0
            best_me = ctx->md_pme_dist;
3415
0
        }
3416
0
        if (best_me != (uint32_t)~0) {
3417
0
            const uint32_t per_pix = best_me / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight);
3418
0
            if (per_pix <= RTC_INTER_PALETTE_RES_FLOOR) {
3419
0
                return;
3420
0
            }
3421
0
        }
3422
0
    }
3423
0
#endif
3424
0
    uint32_t               can_total_cnt      = *candidate_total_cnt;
3425
0
    ModeDecisionCandidate* cand_array         = ctx->fast_cand_array;
3426
0
    const TxSize           tx_size_uv         = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3427
0
    uint32_t               tot_palette_cands  = 0;
3428
0
    PaletteInfo*           palette_cand_array = ctx->palette_cand_array;
3429
    // MD palette search
3430
0
    uint8_t* palette_size_array_0 = ctx->palette_size_array_0;
3431
3432
0
    search_palette_luma(pcs, ctx, palette_cand_array, palette_size_array_0, &tot_palette_cands);
3433
3434
0
    for (uint32_t cand_i = 0; cand_i < tot_palette_cands; ++cand_i) {
3435
0
        ModeDecisionCandidate* cand       = &cand_array[can_total_cnt];
3436
0
        cand->block_mi.is_interintra_used = 0;
3437
0
        cand->palette_size[0]             = palette_size_array_0[cand_i];
3438
        // Palette is not supported for chroma
3439
0
        cand->palette_size[1] = 0;
3440
0
        cand->palette_info    = &palette_cand_array[cand_i];
3441
0
        assert(palette_size_array_0[cand_i] < 9);
3442
        //to re check these fields
3443
0
        cand->skip_mode_allowed    = false;
3444
0
        cand->block_mi.mode        = DC_PRED;
3445
0
        cand->block_mi.use_intrabc = 0;
3446
3447
0
        cand->block_mi.filter_intra_mode         = FILTER_INTRA_MODES;
3448
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3449
        // Palette is not supported for chroma mode, so we can set the intra chroma mode to anything. To use palette
3450
        // for chroma, we must force DC_PRED to be used for the intra chroma mode
3451
0
        assert(cand_array[can_total_cnt].palette_size[1] == 0);
3452
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[DC_PRED] : intra_luma_to_chroma[DC_PRED];
3453
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[DC_PRED]
3454
0
                                                                      : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3455
0
        cand->block_mi.cfl_alpha_signs            = 0;
3456
0
        cand->block_mi.cfl_alpha_idx              = 0;
3457
0
        cand->transform_type[0]                   = DCT_DCT;
3458
0
        cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3459
0
            cand->block_mi.uv_mode, tx_size_uv, pcs->ppcs->frm_hdr.reduced_tx_set);
3460
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3461
0
            continue;
3462
0
        }
3463
0
        cand->block_mi.ref_frame[0] = INTRA_FRAME;
3464
0
        cand->block_mi.ref_frame[1] = NONE_FRAME;
3465
0
        cand->block_mi.motion_mode  = SIMPLE_TRANSLATION;
3466
0
        INC_MD_CAND_CNT(can_total_cnt, pcs->ppcs->max_can_count);
3467
0
    }
3468
3469
    // update the total number of candidates injected
3470
0
    (*candidate_total_cnt) = can_total_cnt;
3471
3472
0
    return;
3473
0
}
3474
3475
0
static INLINE void eliminate_candidate_based_on_pme_me_results(ModeDecisionContext* ctx, uint8_t* dc_cand_only_flag) {
3476
0
    if (ctx->md_pme_dist != (uint32_t)~0 || ctx->md_me_dist != (uint32_t)~0) {
3477
0
        uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3478
0
        th *= ctx->blk_geom->bheight * ctx->blk_geom->bwidth;
3479
0
        const uint32_t best_me_distotion = MIN(ctx->md_pme_dist, ctx->md_me_dist);
3480
0
        if (best_me_distotion < th) {
3481
0
            *dc_cand_only_flag = 1;
3482
0
        }
3483
0
    }
3484
0
}
3485
3486
static bool valid_ref_frame_type(MvReferenceFrame rf[2], const MvReferenceFrame ref_frame_type_arr[],
3487
0
                                 uint8_t tot_ref_frame_types) {
3488
    // INTRA_FRAME is added in candidates sometimes, skip validation
3489
0
    if (rf[0] == INTRA_FRAME) {
3490
0
        return true;
3491
0
    }
3492
3493
0
    for (uint8_t i = 0; i < tot_ref_frame_types; i++) {
3494
0
        MvReferenceFrame rf_in_arr[2];
3495
0
        av1_set_ref_frame(rf_in_arr, ref_frame_type_arr[i]);
3496
0
        if (rf[0] == rf_in_arr[0] && rf[1] == rf_in_arr[1]) {
3497
0
            return true;
3498
0
        }
3499
0
    }
3500
0
    return false;
3501
0
}
3502
3503
// refer to inject_zz_backup_candidate, but use BWD ref instead of LAST
3504
static void inject_sframe_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3505
0
                                           uint32_t* candidate_total_cnt) {
3506
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3507
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3508
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3509
0
    cand_array[cand_total_cnt].drl_index   = 0;
3510
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3511
0
                                    svt_get_ref_frame_type(REF_LIST_1, 0),
3512
0
                                    NEWMV,
3513
0
                                    (Mv){{0}},
3514
0
                                    (Mv){{0}},
3515
0
                                    &cand_array[cand_total_cnt].drl_index,
3516
0
                                    best_pred_mv);
3517
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3518
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3519
0
        cand->block_mi.use_intrabc        = 0;
3520
0
        cand->skip_mode_allowed           = false;
3521
0
        cand->block_mi.mode               = NEWMV;
3522
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3523
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3524
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_1, 0);
3525
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3526
0
        cand->transform_type[0]           = DCT_DCT;
3527
0
        cand->transform_type_uv           = DCT_DCT;
3528
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3529
0
        cand->block_mi.is_interintra_used = 0;
3530
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3531
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_1, 0)].num;
3532
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3533
        // update the total number of candidates injected
3534
0
        (*candidate_total_cnt) = cand_total_cnt;
3535
0
    }
3536
0
}
3537
3538
// in MD stage 0, candidates are injected by different tools, but for S-Frame in RA mode
3539
// the ref frame types in ref_list0 has be pruned in PD for the reversed direction of ref MVs
3540
// here to check and reject the candidates if mismatches the available frame types array
3541
0
static uint32_t reject_candidate_sframe(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t cand_total_cnt) {
3542
0
    for (uint32_t i = 0; i < cand_total_cnt;) {
3543
0
        if (!valid_ref_frame_type(
3544
0
                ctx->fast_cand_array[i].block_mi.ref_frame, ctx->ref_frame_type_arr, ctx->tot_ref_frame_types)) {
3545
0
            for (uint32_t j = i; j < cand_total_cnt; j++) {
3546
0
                memcpy(&ctx->fast_cand_array[j], &ctx->fast_cand_array[j + 1], sizeof(ModeDecisionCandidate));
3547
0
            }
3548
0
            cand_total_cnt--;
3549
0
            continue;
3550
0
        }
3551
0
        i++;
3552
0
    }
3553
    // zero candidate in fast cand array risks in md stage 0, add a candidate from ref list1 as backup
3554
0
    if (cand_total_cnt == 0) {
3555
0
        inject_sframe_backup_candidate(pcs, ctx, &cand_total_cnt);
3556
0
    }
3557
0
    assert(cand_total_cnt > 0);
3558
0
    return cand_total_cnt;
3559
0
}
3560
3561
EbErrorType generate_md_stage_0_cand_pd0(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3562
156k
                                         PictureControlSet* pcs) {
3563
156k
    const SliceType slice_type     = pcs->slice_type;
3564
156k
    uint32_t        cand_total_cnt = 0;
3565
    //----------------------
3566
    // Intra
3567
156k
    if (ctx->blk_geom->sq_size < 128 && ctx->intra_ctrls.enable_intra) {
3568
156k
        inject_intra_candidates_pd0(pcs, ctx, &cand_total_cnt);
3569
156k
    }
3570
3571
156k
    if (slice_type != I_SLICE) {
3572
0
        inject_inter_candidates_pd0(pcs, ctx, &cand_total_cnt);
3573
0
    }
3574
3575
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_stage_0()
3576
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3577
156k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3578
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3579
0
    }
3580
3581
156k
    if (pcs->ppcs->sframe_ref_pruned) {
3582
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3583
0
    }
3584
3585
156k
    *candidate_total_count_ptr = cand_total_cnt;
3586
3587
156k
    return EB_ErrorNone;
3588
156k
}
3589
3590
/*
3591
   generate candidates for light pd1
3592
*/
3593
void generate_md_stage_0_cand_light_pd1(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3594
0
                                        PictureControlSet* pcs) {
3595
0
    const SliceType slice_type     = pcs->slice_type;
3596
0
    uint32_t        cand_total_cnt = 0;
3597
    // Reset duplicates variables
3598
0
    ctx->injected_mv_count = 0;
3599
0
    ctx->inject_new_me     = 1;
3600
0
    if (slice_type != I_SLICE) {
3601
0
        inject_inter_candidates_light_pd1(pcs, ctx, &cand_total_cnt);
3602
0
    }
3603
    //----------------------
3604
    // Intra
3605
0
    if (ctx->intra_ctrls.enable_intra && ctx->blk_geom->sq_size < 128) {
3606
0
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3607
0
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled && !dc_cand_only_flag &&
3608
0
            ctx->md_me_dist != (uint32_t)~0) {
3609
0
            uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3610
0
            th *= (ctx->blk_geom->bheight * ctx->blk_geom->bwidth);
3611
0
            if (ctx->md_me_dist < th) {
3612
0
                dc_cand_only_flag = 1;
3613
0
            }
3614
0
        }
3615
0
        inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3616
0
    }
3617
3618
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3619
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3620
0
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3621
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3622
0
    }
3623
3624
0
    if (pcs->ppcs->sframe_ref_pruned) {
3625
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3626
0
    }
3627
3628
0
    *candidate_total_count_ptr = cand_total_cnt;
3629
0
}
3630
3631
EbErrorType generate_md_stage_0_cand(PictureControlSet* pcs, ModeDecisionContext* ctx, const PC_TREE* const pc_tree,
3632
157k
                                     uint32_t* candidate_total_count_ptr) {
3633
157k
    const SequenceControlSet* scs            = pcs->scs;
3634
157k
    const SliceType           slice_type     = pcs->slice_type;
3635
157k
    uint32_t                  cand_total_cnt = 0;
3636
    // Reset duplicates variables
3637
157k
    ctx->injected_mv_count = 0;
3638
157k
    ctx->inject_new_me     = 1;
3639
157k
    ctx->inject_new_pme    = 1;
3640
    //----------------------
3641
    // Intra
3642
157k
    if (ctx->intra_ctrls.enable_intra) {
3643
157k
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3644
157k
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled) {
3645
0
            eliminate_candidate_based_on_pme_me_results(ctx, &dc_cand_only_flag);
3646
0
        }
3647
157k
        if (ctx->blk_geom->sq_size < 128) {
3648
157k
            inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3649
157k
        }
3650
157k
        if (ctx->filter_intra_ctrls.enabled && svt_aom_filter_intra_allowed_bsize(ctx->blk_geom->bsize)) {
3651
0
            inject_filter_intra_candidates(pcs, ctx, &cand_total_cnt);
3652
0
        }
3653
3654
157k
        bool eval_intrabc = true;
3655
3656
157k
        if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
3657
0
            uint32_t palette_start_cnt = cand_total_cnt;
3658
3659
0
            inject_palette_candidates(pcs, ctx, &cand_total_cnt);
3660
3661
0
            eval_intrabc = cand_total_cnt > palette_start_cnt;
3662
0
        }
3663
3664
157k
        if (ctx->md_allow_intrabc) {
3665
0
            if (!pcs->ppcs->intrabc_ctrls.palette_hint || eval_intrabc) {
3666
0
                bool do_intra_bc = true;
3667
3668
0
                if (ctx->shape == PART_N) {
3669
0
                    if (pcs->ppcs->intrabc_ctrls.b4_parent_gating && ctx->blk_geom->sq_size == 4 &&
3670
0
                        pc_tree->parent->tested_blk[PART_N][0]) {
3671
0
                        if (pc_tree->parent->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3672
0
                            do_intra_bc = false;
3673
0
                        }
3674
0
                    }
3675
0
                } else {
3676
0
                    if (pcs->ppcs->intrabc_ctrls.nsq_parent_gating && pc_tree->tested_blk[PART_N][0]) {
3677
0
                        if (pc_tree->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3678
0
                            do_intra_bc = false;
3679
0
                        }
3680
0
                    }
3681
0
                }
3682
3683
0
                if (do_intra_bc) {
3684
0
                    inject_intra_bc_candidates(pcs, ctx, scs, ctx->blk_ptr, &cand_total_cnt);
3685
0
                }
3686
0
            }
3687
0
        }
3688
157k
    }
3689
157k
    if (slice_type != I_SLICE) {
3690
0
        svt_aom_inject_inter_candidates(pcs, ctx, &cand_total_cnt);
3691
0
    }
3692
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3693
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3694
157k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3695
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3696
0
    }
3697
3698
157k
    if (pcs->ppcs->sframe_ref_pruned) {
3699
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3700
0
    }
3701
3702
157k
    *candidate_total_count_ptr = cand_total_cnt;
3703
3704
157k
    memset(ctx->md_stage_0_count, 0, CAND_CLASS_TOTAL * sizeof(uint32_t));
3705
157k
    bool merge_inter_cands = 0;
3706
157k
    if (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult != (uint8_t)~0) {
3707
157k
        uint16_t th = (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult * (63 - pcs->scs->static_config.qp)) >> 1;
3708
157k
        if ((MIN(ctx->md_me_dist, ctx->md_pme_dist) / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight)) < th) {
3709
148k
            merge_inter_cands = 1;
3710
148k
        }
3711
157k
    }
3712
3713
315k
    for (uint32_t cand_i = 0; cand_i < cand_total_cnt; cand_i++) {
3714
157k
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_i];
3715
157k
        if (is_intra_mode(cand->block_mi.mode)) {
3716
            // Intra prediction
3717
157k
            if ((cand->palette_info == NULL || cand->palette_size[0] == 0) && cand->block_mi.use_intrabc == 0) {
3718
157k
                cand->cand_class = CAND_CLASS_0;
3719
157k
                ctx->md_stage_0_count[CAND_CLASS_0]++;
3720
18.4E
            } else if (cand->block_mi.use_intrabc == 0) {
3721
                // Palette Prediction
3722
0
                cand->cand_class = CAND_CLASS_3;
3723
0
                ctx->md_stage_0_count[CAND_CLASS_3]++;
3724
18.4E
            } else {
3725
                // Intra-BC Prediction
3726
18.4E
                cand->cand_class = CAND_CLASS_4;
3727
18.4E
                ctx->md_stage_0_count[CAND_CLASS_4]++;
3728
18.4E
            }
3729
18.4E
        } else { // INTER
3730
18.4E
            if (cand->block_mi.mode == NEWMV || cand->block_mi.mode == NEW_NEWMV || merge_inter_cands) {
3731
                // MV Prediction
3732
0
                cand->cand_class = CAND_CLASS_2;
3733
0
                ctx->md_stage_0_count[CAND_CLASS_2]++;
3734
18.4E
            } else {
3735
                //MVP Prediction
3736
18.4E
                cand->cand_class = CAND_CLASS_1;
3737
18.4E
                ctx->md_stage_0_count[CAND_CLASS_1]++;
3738
18.4E
            }
3739
18.4E
        }
3740
157k
    }
3741
157k
    return EB_ErrorNone;
3742
157k
}
3743
3744
uint8_t av1_drl_ctx(const CandidateMv* ref_mv_stack, int32_t ref_idx);
3745
3746
/***************************************
3747
* Update symbols for light-PD1 path
3748
***************************************/
3749
void svt_aom_product_full_mode_decision_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
3750
0
                                                  ModeDecisionCandidateBuffer* cand_bf) {
3751
0
    BlkStruct*             blk_ptr = ctx->blk_ptr;
3752
0
    ModeDecisionCandidate* cand    = cand_bf->cand;
3753
0
    blk_ptr->total_rate            = cand_bf->total_rate;
3754
3755
    // Set common signals (INTER/INTRA)
3756
0
    memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3757
0
    blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3758
3759
    // Set INTER mode signals
3760
0
    if (is_inter_mode(cand->block_mi.mode)) {
3761
0
        blk_ptr->drl_index = cand->drl_index;
3762
0
        assert(IMPLIES(
3763
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3764
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3765
3766
        // Set MVs
3767
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3768
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3769
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3770
0
        }
3771
3772
0
        const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3773
        // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3774
0
        blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3775
        // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3776
0
        if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3777
0
            for (uint8_t idx = 0; idx < 2; ++idx) {
3778
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3779
0
                    blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3780
0
                } else {
3781
0
                    blk_ptr->drl_ctx[idx] = -1;
3782
0
                }
3783
0
            }
3784
0
        }
3785
3786
0
        if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3787
            // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3788
0
            for (uint8_t idx = 1; idx < 3; ++idx) {
3789
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3790
0
                    blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3791
0
                } else {
3792
0
                    blk_ptr->drl_ctx_near[idx - 1] = -1;
3793
0
                }
3794
0
            }
3795
0
        }
3796
0
    } else { // Set INTRA mode signals
3797
0
        cand->skip_mode_allowed = false;
3798
0
    }
3799
    // Set TX and coeff-related data
3800
0
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
3801
0
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
3802
3803
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
3804
0
    if (cand->skip_mode_allowed == true) {
3805
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
3806
0
    }
3807
3808
0
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
3809
0
                   cand->block_mi.interp_filters == 0));
3810
0
    if (blk_ptr->block_mi.skip_mode) {
3811
0
        blk_ptr->block_has_coeff = 0;
3812
0
        cand_bf->y_has_coeff     = 0;
3813
0
        cand_bf->u_has_coeff     = 0;
3814
0
        cand_bf->v_has_coeff     = 0;
3815
0
    }
3816
0
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
3817
3818
0
    const uint16_t txb_itr       = 0;
3819
0
    const int32_t  txb_1d_offset = 0, txb_1d_offset_uv = 0;
3820
0
    blk_ptr->y_has_coeff         = cand_bf->y_has_coeff;
3821
0
    blk_ptr->u_has_coeff         = cand_bf->u_has_coeff;
3822
0
    blk_ptr->v_has_coeff         = cand_bf->v_has_coeff;
3823
0
    blk_ptr->tx_type[txb_itr]    = cand->transform_type[txb_itr];
3824
0
    blk_ptr->tx_type_uv          = cand->transform_type_uv;
3825
0
    blk_ptr->quant_dc.y[txb_itr] = cand_bf->quant_dc.y[txb_itr];
3826
0
    blk_ptr->quant_dc.u[txb_itr] = cand_bf->quant_dc.u[txb_itr];
3827
0
    blk_ptr->quant_dc.v[txb_itr] = cand_bf->quant_dc.v[txb_itr];
3828
3829
0
    if (ctx->bypass_encdec) {
3830
0
        blk_ptr->eob.y[txb_itr] = cand_bf->eob.y[txb_itr];
3831
0
        blk_ptr->eob.u[txb_itr] = cand_bf->eob.u[txb_itr];
3832
0
        blk_ptr->eob.v[txb_itr] = cand_bf->eob.v[txb_itr];
3833
0
        int32_t* src_ptr;
3834
0
        int32_t* dst_ptr;
3835
3836
0
        const TxSize tx_size   = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
3837
0
        const int    tx_width  = tx_size_wide[tx_size];
3838
0
        const int    tx_height = tx_size_high[tx_size];
3839
3840
        // only one TX unit, so no need to bitmask
3841
0
        if (blk_ptr->y_has_coeff) {
3842
0
            src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
3843
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) + ctx->coded_area_sb;
3844
0
            memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
3845
0
        }
3846
0
        ctx->coded_area_sb += tx_width * tx_height;
3847
3848
0
        const TxSize tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3849
0
        const int    tx_width_uv  = tx_size_wide[tx_size_uv];
3850
0
        const int    tx_height_uv = tx_size_high[tx_size_uv];
3851
        // Cb
3852
        // only one TX unit, so no need to bitmask
3853
0
        if (blk_ptr->u_has_coeff) {
3854
0
            src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
3855
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
3856
0
                ctx->coded_area_sb_uv;
3857
0
            memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3858
0
        }
3859
3860
        // Cr
3861
        // only one TX unit, so no need to bitmask
3862
0
        if (blk_ptr->v_has_coeff) {
3863
0
            src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
3864
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
3865
0
                ctx->coded_area_sb_uv;
3866
0
            memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3867
0
        }
3868
0
        ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
3869
0
    }
3870
0
}
3871
3872
0
static INLINE double derive_ssim_threshold_factor_for_full_md(SequenceControlSet* scs) {
3873
0
    return scs->input_resolution >= INPUT_SIZE_1080p_RANGE ? 1.02 : 1.03;
3874
0
}
3875
3876
/***************************************
3877
* Full Mode Decision
3878
***************************************/
3879
uint32_t svt_aom_product_full_mode_decision(PictureControlSet* pcs, ModeDecisionContext* ctx,
3880
                                            ModeDecisionCandidateBuffer** buffer_ptr_array,
3881
157k
                                            uint32_t candidate_total_count, uint32_t* best_candidate_index_array) {
3882
157k
    SequenceControlSet* scs                = pcs->scs;
3883
157k
    BlkStruct*          blk_ptr            = ctx->blk_ptr;
3884
157k
    uint32_t            lowest_cost_index  = best_candidate_index_array[0];
3885
157k
    const bool          use_ssim_full_cost = ctx->tune_ssim_level > SSIM_LVL_0 ? true : false;
3886
3887
    // Find the candidate with the lowest cost
3888
    // Only need to sort if have multiple candidates
3889
157k
    if (ctx->md_stage_3_total_count > 1) {
3890
0
        if (use_ssim_full_cost) {
3891
            // Pass one: find candidate with the lowest SSD cost
3892
0
            uint64_t ssd_lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3893
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3894
0
                uint32_t cand_index = best_candidate_index_array[i];
3895
0
                uint64_t cost       = *(buffer_ptr_array[cand_index]->full_cost);
3896
0
                if (cost < ssd_lowest_cost) {
3897
0
                    lowest_cost_index = cand_index;
3898
0
                    ssd_lowest_cost   = cost;
3899
0
                }
3900
0
            }
3901
3902
            // Pass two: among the candidates with SSD cost not greater than the threshold, find the one with the lowest SSIM cost
3903
0
            const double   threshold_factor   = derive_ssim_threshold_factor_for_full_md(scs);
3904
0
            const uint64_t ssd_cost_threshold = (uint64_t)(threshold_factor * ssd_lowest_cost);
3905
0
            uint64_t       ssim_lowest_cost   = 0xFFFFFFFFFFFFFFFFull;
3906
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3907
0
                uint32_t cand_index = best_candidate_index_array[i];
3908
3909
0
                uint64_t ssim_cost = *(buffer_ptr_array[cand_index]->full_cost_ssim);
3910
0
                uint64_t ssd_cost  = *(buffer_ptr_array[cand_index]->full_cost);
3911
0
                if (ssim_cost < ssim_lowest_cost) {
3912
0
                    if (ssd_cost <= ssd_cost_threshold) {
3913
0
                        lowest_cost_index = cand_index;
3914
0
                        ssim_lowest_cost  = ssim_cost;
3915
0
                        ssd_lowest_cost   = ssd_cost;
3916
0
                    }
3917
0
                } else if (ssim_cost == ssim_lowest_cost) {
3918
                    // if two candidates have the same ssim cost, choose the one with lower ssd cost
3919
0
                    if (ssd_cost < ssd_lowest_cost) {
3920
0
                        lowest_cost_index = cand_index;
3921
0
                        ssd_lowest_cost   = ssd_cost;
3922
0
                    }
3923
0
                }
3924
0
            }
3925
0
        } else { // fallback to SSD based RD cost
3926
0
            uint64_t lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3927
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3928
0
                uint32_t cand_index = best_candidate_index_array[i];
3929
3930
0
                uint64_t cost = *(buffer_ptr_array[cand_index]->full_cost);
3931
0
                if (scs->vq_ctrls.sharpness_ctrls.unipred_bias && pcs->ppcs->is_noise_level &&
3932
0
                    is_inter_singleref_mode(buffer_ptr_array[cand_index]->cand->block_mi.mode)) {
3933
0
                    cost = (cost * uni_psy_bias[pcs->ppcs->picture_qp]) / 100;
3934
0
                }
3935
3936
0
                if (cost < lowest_cost) {
3937
0
                    lowest_cost_index = cand_index;
3938
0
                    lowest_cost       = cost;
3939
0
                }
3940
0
            }
3941
0
        }
3942
0
    }
3943
157k
    ModeDecisionCandidateBuffer* cand_bf = buffer_ptr_array[lowest_cost_index];
3944
157k
    ModeDecisionCandidate*       cand    = cand_bf->cand;
3945
157k
    blk_ptr->total_rate                  = cand_bf->total_rate;
3946
157k
    if (!(ctx->pd_pass == PD_PASS_1 && ctx->fixed_partition)) {
3947
        // When lambda tuning is on, lambda of each block is set separately, however at interdepth decision the sb lambda is used
3948
151k
        uint32_t full_lambda    = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_sb_lambda_md[EB_10_BIT_MD]
3949
151k
                                                                    : ctx->full_sb_lambda_md[EB_8_BIT_MD];
3950
151k
        ctx->blk_ptr->cost      = RDCOST(full_lambda, cand_bf->total_rate, cand_bf->full_dist);
3951
151k
        ctx->blk_ptr->full_dist = cand_bf->full_dist;
3952
151k
    }
3953
3954
    // Set common signals (INTER/INTRA)
3955
157k
    memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3956
    // Set INTER mode signals
3957
    // INTER signals set first b/c INTER shuts Palette, so INTRA must overwrite if Palette + intrabc is used
3958
157k
    if (is_inter_block(&blk_ptr->block_mi)) {
3959
0
        blk_ptr->drl_index = cand->drl_index;
3960
0
        assert(IMPLIES(
3961
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3962
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3963
3964
0
        blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3965
        // Set MVs
3966
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3967
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3968
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3969
0
        }
3970
0
        if (blk_ptr->block_mi.motion_mode == WARPED_CAUSAL ||
3971
0
            (cand->block_mi.mode == GLOBALMV || cand->block_mi.mode == GLOBAL_GLOBALMV)) {
3972
0
            memcpy(&ctx->blk_ptr->wm_params_l0, &cand->wm_params_l0, sizeof(WarpedMotionParams));
3973
0
            memcpy(&ctx->blk_ptr->wm_params_l1, &cand->wm_params_l1, sizeof(WarpedMotionParams));
3974
0
        }
3975
3976
0
        if (ctx->pd_pass == PD_PASS_1) {
3977
0
            const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3978
            // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3979
0
            blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3980
            // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3981
0
            if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3982
0
                for (uint8_t idx = 0; idx < 2; ++idx) {
3983
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3984
0
                        blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3985
0
                    } else {
3986
0
                        blk_ptr->drl_ctx[idx] = -1;
3987
0
                    }
3988
0
                }
3989
0
            }
3990
3991
0
            if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3992
                // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3993
0
                for (uint8_t idx = 1; idx < 3; ++idx) {
3994
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3995
0
                        blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3996
0
                    } else {
3997
0
                        blk_ptr->drl_ctx_near[idx - 1] = -1;
3998
0
                    }
3999
0
                }
4000
0
            }
4001
0
        }
4002
0
    }
4003
4004
    // Set INTRA mode signals
4005
157k
    if (is_intra_mode(blk_ptr->block_mi.mode)) {
4006
157k
        if (!cand->palette_info) {
4007
157k
            blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
4008
18.4E
        } else if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
4009
0
            memcpy(&blk_ptr->palette_info->pmi, &cand->palette_info->pmi, sizeof(PaletteModeInfo));
4010
0
            memcpy(blk_ptr->palette_info->color_idx_map, cand->palette_info->color_idx_map, MAX_PALETTE_SQUARE);
4011
0
            blk_ptr->palette_size[0] = cand->palette_size[0];
4012
0
            blk_ptr->palette_size[1] = cand->palette_size[1];
4013
0
        }
4014
4015
157k
        if (blk_ptr->block_mi.use_intrabc == 0) {
4016
157k
            cand->skip_mode_allowed = false;
4017
157k
        }
4018
157k
    }
4019
4020
    // Set TX and coeff-related data
4021
157k
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
4022
157k
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
4023
4024
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
4025
157k
    if (cand->skip_mode_allowed == true) {
4026
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
4027
0
    }
4028
4029
157k
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
4030
157k
                   cand->block_mi.interp_filters == 0));
4031
157k
    if (blk_ptr->block_mi.skip_mode) {
4032
0
        blk_ptr->block_has_coeff = 0;
4033
0
        cand_bf->y_has_coeff     = 0;
4034
0
        cand_bf->u_has_coeff     = 0;
4035
0
        cand_bf->v_has_coeff     = 0;
4036
0
    }
4037
4038
157k
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
4039
157k
    blk_ptr->y_has_coeff   = cand_bf->y_has_coeff;
4040
157k
    blk_ptr->u_has_coeff   = cand_bf->u_has_coeff;
4041
157k
    blk_ptr->v_has_coeff   = cand_bf->v_has_coeff;
4042
157k
    memcpy(blk_ptr->tx_type, cand->transform_type, sizeof(TxType) * MAX_TXB_COUNT);
4043
157k
    blk_ptr->tx_type_uv = cand->transform_type_uv;
4044
157k
    memcpy(&blk_ptr->quant_dc, &cand_bf->quant_dc, sizeof(QuantDcData));
4045
157k
    memcpy(&blk_ptr->eob, &cand_bf->eob, sizeof(EobData));
4046
4047
    // If bypassing EncDec, save recon/coeff
4048
157k
    if (ctx->bypass_encdec && ctx->pd_pass == PD_PASS_1) {
4049
157k
        const uint16_t tu_total_count = tx_blocks_per_depth[ctx->blk_geom->bsize][blk_ptr->block_mi.tx_depth];
4050
157k
        int32_t        txb_1d_offset = 0, txb_1d_offset_uv = 0;
4051
157k
        const TxSize   tx_size      = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
4052
157k
        const int      tx_width     = tx_size_wide[tx_size];
4053
157k
        const int      tx_height    = tx_size_high[tx_size];
4054
157k
        const TxSize   tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
4055
157k
        const int      tx_width_uv  = tx_size_wide[tx_size_uv];
4056
157k
        const int      tx_height_uv = tx_size_high[tx_size_uv];
4057
768k
        for (uint16_t txb_itr = 0; txb_itr < tu_total_count; txb_itr++) {
4058
610k
            const bool uv_pass = (blk_ptr->block_mi.tx_depth == 0 || txb_itr == 0);
4059
4060
610k
            int32_t* src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
4061
610k
            int32_t* dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->y_buffer)[txb_1d_offset]);
4062
4063
610k
            if (ctx->fixed_partition) {
4064
6.56k
                dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) +
4065
6.56k
                    ctx->coded_area_sb;
4066
6.56k
                ctx->coded_area_sb += tx_width * tx_height;
4067
6.56k
            }
4068
4069
610k
            if (blk_ptr->y_has_coeff & (1 << txb_itr)) {
4070
5.78k
                memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
4071
5.78k
            }
4072
4073
610k
            txb_1d_offset += tx_width * tx_height;
4074
4075
610k
            if (ctx->has_uv && uv_pass) {
4076
                // Cb
4077
157k
                src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
4078
157k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->u_buffer)[txb_1d_offset_uv]);
4079
4080
157k
                if (ctx->fixed_partition) {
4081
6.56k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
4082
6.56k
                        ctx->coded_area_sb_uv;
4083
6.56k
                }
4084
4085
157k
                if (blk_ptr->u_has_coeff & (1 << txb_itr)) {
4086
5.54k
                    memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4087
5.54k
                }
4088
4089
                // Cr
4090
157k
                src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
4091
157k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->v_buffer)[txb_1d_offset_uv]);
4092
4093
157k
                if (ctx->fixed_partition) {
4094
6.56k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
4095
6.56k
                        ctx->coded_area_sb_uv;
4096
6.56k
                    ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
4097
6.56k
                }
4098
4099
157k
                if (blk_ptr->v_has_coeff & (1 << txb_itr)) {
4100
5.54k
                    memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4101
5.54k
                }
4102
4103
157k
                txb_1d_offset_uv += tx_width_uv * tx_height_uv;
4104
157k
            }
4105
610k
        }
4106
157k
    }
4107
4108
157k
    return lowest_cost_index;
4109
157k
}
4110
4111
// Return the end column for the current superblock, in unit of TPL blocks.
4112
0
static int get_superblock_tpl_column_end(PictureParentControlSet* ppcs, int mi_col, int num_mi_w) {
4113
0
    const int mib_size_log2 = ppcs->scs->seq_header.sb_size == BLOCK_128X128 ? 5 : 4;
4114
    // Find the start column of this superblock.
4115
0
    const int sb_mi_col_start = (mi_col >> mib_size_log2) << mib_size_log2;
4116
    // Same but in superres upscaled dimension.
4117
0
    const int sb_mi_col_start_sr = coded_to_superres_mi(sb_mi_col_start, ppcs->superres_denom);
4118
    // Width of this superblock in mi units.
4119
0
    const int sb_mi_width = mi_size_wide[ppcs->scs->seq_header.sb_size];
4120
    // Same but in superres upscaled dimension.
4121
0
    const int sb_mi_width_sr = coded_to_superres_mi(sb_mi_width, ppcs->superres_denom);
4122
    // Superblock end in mi units.
4123
0
    const int sb_mi_end = sb_mi_col_start_sr + sb_mi_width_sr;
4124
    // Superblock end in TPL units.
4125
0
    return (sb_mi_end + num_mi_w - 1) / num_mi_w;
4126
0
}
4127
4128
0
void aom_av1_set_ssim_rdmult(ModeDecisionContext* ctx, PictureControlSet* pcs, const int mi_row, const int mi_col) {
4129
0
    const Av1Common* const cm    = pcs->ppcs->av1_cm;
4130
0
    BlockSize              bsize = ctx->blk_geom->bsize;
4131
4132
0
    const int bsize_base = BLOCK_16X16;
4133
0
    const int num_mi_w   = mi_size_wide[bsize_base];
4134
0
    const int num_mi_h   = mi_size_high[bsize_base];
4135
0
    const int num_cols   = (cm->mi_cols + num_mi_w - 1) / num_mi_w;
4136
0
    const int num_rows   = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4137
0
    const int num_bcols  = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w;
4138
0
    const int num_brows  = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4139
0
    int       row, col;
4140
0
    double    num_of_mi          = 0.0;
4141
0
    double    geom_mean_of_scale = 1.0;
4142
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4143
0
        for (col = mi_col / num_mi_h; col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) {
4144
0
            const int index = row * num_cols + col;
4145
0
            geom_mean_of_scale *= pcs->ppcs->pa_me_data->ssim_rdmult_scaling_factors[index];
4146
0
            num_of_mi += 1.0;
4147
0
        }
4148
0
    }
4149
0
    geom_mean_of_scale = pow(geom_mean_of_scale, (1.0 / num_of_mi));
4150
0
    if (!pcs->ppcs->blk_lambda_tuning) {
4151
0
        ctx->full_lambda_md[EB_8_BIT_MD] =
4152
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4153
0
        ctx->full_lambda_md[EB_10_BIT_MD] =
4154
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4155
4156
0
        ctx->fast_lambda_md[EB_8_BIT_MD] =
4157
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4158
0
        ctx->fast_lambda_md[EB_10_BIT_MD] =
4159
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4160
0
    } else {
4161
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->full_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4162
0
                                                      0.5);
4163
0
        ctx->full_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->full_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4164
0
                                                       0.5);
4165
4166
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->fast_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4167
0
                                                      0.5);
4168
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->fast_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4169
0
                                                       0.5);
4170
0
    }
4171
0
}
4172
4173
0
void svt_aom_set_tuned_blk_lambda(ModeDecisionContext* ctx, PictureControlSet* pcs) {
4174
0
    PictureParentControlSet* ppcs = pcs->ppcs;
4175
0
    Av1Common*               cm   = ppcs->av1_cm;
4176
4177
0
    BlockSize bsize  = ctx->blk_geom->bsize;
4178
0
    int       mi_row = ctx->blk_org_y / 4;
4179
0
    int       mi_col = ctx->blk_org_x / 4;
4180
4181
0
    const int mi_col_sr         = coded_to_superres_mi(mi_col, ppcs->superres_denom);
4182
0
    const int mi_cols_sr        = ((ppcs->enhanced_unscaled_pic->width + 15) / 16) << 2; // picture column boundary
4183
0
    const int block_mi_width_sr = coded_to_superres_mi(mi_size_wide[bsize], ppcs->superres_denom);
4184
0
    const int bsize_base        = ppcs->tpl_ctrls.synth_blk_size == 32 ? BLOCK_32X32 : BLOCK_16X16;
4185
0
    const int num_mi_w          = mi_size_wide[bsize_base];
4186
0
    const int num_mi_h          = mi_size_high[bsize_base];
4187
0
    const int num_cols          = (mi_cols_sr + num_mi_w - 1) / num_mi_w;
4188
0
    const int num_rows          = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4189
0
    const int num_bcols         = (block_mi_width_sr + num_mi_w - 1) / num_mi_w;
4190
0
    const int num_brows         = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4191
4192
    // This is required because the end col of superblock may be off by 1 in case
4193
    // of superres.
4194
0
    const int sb_bcol_end = get_superblock_tpl_column_end(ppcs, mi_col, num_mi_w);
4195
0
    int       row, col;
4196
0
    int32_t   base_block_count   = 0;
4197
0
    double    geom_mean_of_scale = 0.0;
4198
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4199
0
        for (col = mi_col_sr / num_mi_h; col < num_cols && col < mi_col_sr / num_mi_h + num_bcols && col < sb_bcol_end;
4200
0
             ++col) {
4201
0
            const int index = row * num_cols + col;
4202
0
            geom_mean_of_scale += log(ppcs->pa_me_data->tpl_sb_rdmult_scaling_factors[index]);
4203
0
            ++base_block_count;
4204
0
        }
4205
0
    }
4206
    // When superres is on, base_block_count could be zero.
4207
    // This function's counterpart in AOM, av1_get_hier_tpl_rdmult, will encounter division by zero
4208
0
    if (base_block_count == 0) {
4209
        // return a large number to indicate invalid state
4210
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4211
0
        ctx->full_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4212
4213
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4214
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4215
0
        return;
4216
0
    }
4217
4218
0
    geom_mean_of_scale = exp(geom_mean_of_scale / base_block_count);
4219
4220
0
    ctx->full_lambda_md[EB_8_BIT_MD] =
4221
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4222
0
    ctx->full_lambda_md[EB_10_BIT_MD] =
4223
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4224
4225
0
    ctx->fast_lambda_md[EB_8_BIT_MD] =
4226
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4227
0
    ctx->fast_lambda_md[EB_10_BIT_MD] =
4228
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4229
0
    if (ppcs->scs->static_config.tune == TUNE_SSIM || ppcs->scs->static_config.tune == TUNE_IQ ||
4230
0
        ppcs->scs->static_config.tune == TUNE_MS_SSIM) {
4231
0
        aom_av1_set_ssim_rdmult(ctx, pcs, mi_row, mi_col);
4232
0
    }
4233
0
}
4234
4235
0
double svt_ssim_4x4_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4236
0
    const int32_t count = 4 * 4;
4237
4238
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4239
0
    uint32_t i, j;
4240
0
    for (i = 0; i < 4; i++) {
4241
0
        for (j = 0; j < 4; j++) {
4242
0
            sum_s += s[j];
4243
0
            sum_r += r[j];
4244
0
            sum_sq_s += s[j] * s[j];
4245
0
            sum_sq_r += r[j] * r[j];
4246
0
            sum_sxr += s[j] * r[j];
4247
0
        }
4248
4249
0
        s += sp;
4250
0
        r += rp;
4251
0
    }
4252
4253
    //
4254
    // similarity
4255
    //
4256
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4257
0
    return score;
4258
0
}
4259
4260
0
double svt_ssim_8x8_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4261
0
    const int32_t count = 8 * 8;
4262
4263
    //
4264
    // is similar to svt_aom_ssim_parms_8x8_c, but supports MxN block size
4265
    //
4266
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4267
0
    uint32_t i, j;
4268
0
    for (i = 0; i < 8; i++) {
4269
0
        for (j = 0; j < 8; j++) {
4270
0
            sum_s += s[j];
4271
0
            sum_r += r[j];
4272
0
            sum_sq_s += s[j] * s[j];
4273
0
            sum_sq_r += r[j] * r[j];
4274
0
            sum_sxr += s[j] * r[j];
4275
0
        }
4276
4277
0
        s += sp;
4278
0
        r += rp;
4279
0
    }
4280
4281
    //
4282
    // similarity
4283
    //
4284
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4285
0
    return score;
4286
0
}
4287
4288
0
double svt_ssim_4x4_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4289
0
    const int32_t count = 4 * 4;
4290
4291
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4292
0
    uint32_t i, j;
4293
0
    for (i = 0; i < 4; i++) {
4294
0
        for (j = 0; j < 4; j++) {
4295
0
            sum_s += s[j];
4296
0
            sum_r += r[j];
4297
0
            sum_sq_s += s[j] * s[j];
4298
0
            sum_sq_r += r[j] * r[j];
4299
0
            sum_sxr += s[j] * r[j];
4300
0
        }
4301
4302
0
        s += sp;
4303
0
        r += rp;
4304
0
    }
4305
4306
    //
4307
    // similarity
4308
    //
4309
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4310
0
    return score;
4311
0
}
4312
4313
0
double svt_ssim_8x8_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4314
0
    const int32_t count = 8 * 8;
4315
4316
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4317
0
    uint32_t i, j;
4318
0
    for (i = 0; i < 8; i++) {
4319
0
        for (j = 0; j < 8; j++) {
4320
0
            sum_s += s[j];
4321
0
            sum_r += r[j];
4322
0
            sum_sq_s += s[j] * s[j];
4323
0
            sum_sq_r += r[j] * r[j];
4324
0
            sum_sxr += s[j] * r[j];
4325
0
        }
4326
4327
0
        s += sp;
4328
0
        r += rp;
4329
0
    }
4330
4331
    //
4332
    // similarity
4333
    //
4334
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4335
0
    return score;
4336
0
}
4337
4338
static double ssim_8x8_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4339
0
                              uint32_t height) {
4340
0
    uint32_t i, j;
4341
0
    int      samples    = 0;
4342
0
    double   ssim_total = 0;
4343
4344
    // sample point start with each 4x4 location
4345
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4346
0
        for (j = 0; j <= width - 8; j += 8) {
4347
0
            double v = svt_ssim_8x8(s + j, sp, r + j, rp);
4348
0
            v        = CLIP3(0, 1, v);
4349
0
            ssim_total += v;
4350
0
            samples++;
4351
0
        }
4352
0
    }
4353
0
    assert(samples > 0);
4354
0
    ssim_total /= samples;
4355
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4356
0
    return ssim_total;
4357
0
}
4358
4359
static double ssim_4x4_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4360
0
                              uint32_t height) {
4361
0
    uint32_t i, j;
4362
0
    int      samples    = 0;
4363
0
    double   ssim_total = 0;
4364
4365
    // sample point start with each 2x2 location
4366
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4367
0
        for (j = 0; j <= width - 4; j += 4) {
4368
0
            double v = svt_ssim_4x4(s + j, sp, r + j, rp);
4369
0
            v        = CLIP3(0, 1, v);
4370
0
            ssim_total += v;
4371
0
            samples++;
4372
0
        }
4373
0
    }
4374
0
    assert(samples > 0);
4375
0
    ssim_total /= samples;
4376
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4377
0
    return ssim_total;
4378
0
}
4379
4380
0
static double ssim(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width, uint32_t height) {
4381
0
    assert((width % 4) == 0 && (height % 4) == 0);
4382
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4383
0
        return ssim_8x8_blocks(s, sp, r, rp, width, height);
4384
0
    } else {
4385
0
        return ssim_4x4_blocks(s, sp, r, rp, width, height);
4386
0
    }
4387
0
}
4388
4389
static double ssim_8x8_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4390
0
                                  uint32_t height) {
4391
0
    uint32_t i, j;
4392
0
    int      samples    = 0;
4393
0
    double   ssim_total = 0;
4394
4395
    // sample point start with each 4x4 location
4396
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4397
0
        for (j = 0; j <= width - 8; j += 8) {
4398
0
            double v = svt_ssim_8x8_hbd(s + j, sp, r + j, rp);
4399
0
            v        = CLIP3(0, 1, v);
4400
0
            ssim_total += v;
4401
0
            samples++;
4402
0
        }
4403
0
    }
4404
0
    assert(samples > 0);
4405
0
    ssim_total /= samples;
4406
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4407
0
    return ssim_total;
4408
0
}
4409
4410
static double ssim_4x4_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4411
0
                                  uint32_t height) {
4412
0
    uint32_t i, j;
4413
0
    int      samples    = 0;
4414
0
    double   ssim_total = 0;
4415
4416
    // sample point start with each 2x2 location
4417
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4418
0
        for (j = 0; j <= width - 4; j += 4) {
4419
0
            double v = svt_ssim_4x4_hbd(s + j, sp, r + j, rp);
4420
0
            v        = CLIP3(0, 1, v);
4421
0
            ssim_total += v;
4422
0
            samples++;
4423
0
        }
4424
0
    }
4425
0
    assert(samples > 0);
4426
0
    ssim_total /= samples;
4427
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4428
0
    return ssim_total;
4429
0
}
4430
4431
static double ssim_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4432
0
                       uint32_t height) {
4433
0
    assert((width % 4) == 0 && (height % 4) == 0);
4434
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4435
0
        return ssim_8x8_blocks_hbd(s, sp, r, rp, width, height);
4436
0
    } else {
4437
0
        return ssim_4x4_blocks_hbd(s, sp, r, rp, width, height);
4438
0
    }
4439
0
}
4440
4441
uint64_t svt_spatial_full_distortion_ssim_kernel(uint8_t* input, uint32_t input_offset, uint32_t input_stride,
4442
                                                 uint8_t* recon, int32_t recon_offset, uint32_t recon_stride,
4443
0
                                                 uint32_t area_width, uint32_t area_height, bool hbd, double ac_bias) {
4444
0
    uint8_t        m     = 1;
4445
0
    const uint32_t count = area_width * area_height;
4446
4447
    // SSIM
4448
0
    uint64_t spatial_distortion;
4449
0
    double   ssim_score;
4450
4451
    // AC SAD
4452
0
    uint64_t psy_distortion = 0;
4453
4454
0
    if (!hbd) {
4455
0
        ssim_score = ssim(
4456
0
            input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4457
0
        if (ac_bias) {
4458
0
            uint64_t ac_distortion = svt_psy_distortion(
4459
0
                input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4460
0
            psy_distortion = (uint64_t)(ac_distortion * ac_bias);
4461
0
        }
4462
0
    } else {
4463
0
        m          = 8;
4464
0
        ssim_score = ssim_hbd((uint16_t*)input + input_offset,
4465
0
                              input_stride,
4466
0
                              (uint16_t*)recon + recon_offset,
4467
0
                              recon_stride,
4468
0
                              area_width,
4469
0
                              area_height);
4470
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
4471
0
        if (ac_bias) {
4472
0
            uint64_t ac_distortion = svt_psy_distortion_hbd((uint16_t*)input + input_offset,
4473
0
                                                            input_stride,
4474
0
                                                            (uint16_t*)recon + recon_offset,
4475
0
                                                            recon_stride,
4476
0
                                                            area_width,
4477
0
                                                            area_height);
4478
0
            psy_distortion         = (uint64_t)(ac_distortion * ac_bias);
4479
0
        }
4480
0
#endif
4481
0
    }
4482
4483
0
    spatial_distortion        = (uint64_t)((1 - ssim_score) * count * 100 * 7 * m);
4484
0
    uint64_t total_distortion = spatial_distortion + psy_distortion;
4485
4486
0
    return total_distortion;
4487
0
}