Coverage Report

Created: 2026-10-28 06:18

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
412k
    MULTI_LINE_MACRO_BEGIN                                   \
63
412k
    if (cnt + 1 < max_can_count)                             \
64
414k
        cnt++;                                               \
65
412k
    else                                                     \
66
18.4E
        SVT_ERROR("Mode decision candidate count exceeded"); \
67
412k
    MULTI_LINE_MACRO_END
68
69
0
#define SUPERRES_INVALID_STATE 0x7fffffff
70
71
2.71M
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
    // Lossless is frame-level: the MD configuration disables segmentation when lossless and lossy segments would mix,
78
    // so a segment is lossless exactly when segment 0 is.
79
2.71M
    (void)segment_id;
80
2.71M
    return pcs->lossless[0];
81
2.71M
#endif
82
2.71M
}
83
84
0
static bool check_mv_validity(int16_t x_mv, int16_t y_mv, uint8_t need_shift) {
85
0
    Mv mv;
86
    //go to 1/8th if input is 1/4pel
87
0
    mv.y = y_mv << need_shift;
88
0
    mv.x = x_mv << need_shift;
89
    /* AV1 limits
90
      -16384 < MV_x_in_1/8 or MV_y_in_1/8 < 16384
91
      which means in full pel:
92
      -2048 < MV_x_in_full_pel or MV_y_in_full_pel < 2048
93
    */
94
0
    if (!is_mv_valid(mv)) {
95
0
        return false;
96
0
    }
97
0
    return true;
98
0
}
99
100
int svt_is_interintra_allowed(uint8_t enable_inter_intra, BlockSize bsize, PredictionMode mode,
101
0
                              const MvReferenceFrame ref_frame[2]) {
102
0
    return enable_inter_intra && svt_aom_is_interintra_allowed_bsize((const BlockSize)bsize) &&
103
0
        svt_aom_is_interintra_allowed_mode(mode) && svt_aom_is_interintra_allowed_ref(ref_frame);
104
0
}
105
106
0
int svt_aom_filter_intra_allowed_bsize(BlockSize bs) {
107
0
    if (!CONFIG_ENABLE_FILTER_INTRA) {
108
0
        return 0; // filter_intra off -> const-folds, cascades DCE
109
0
    }
110
0
    return block_size_wide[bs] <= 32 && block_size_high[bs] <= 32;
111
0
}
112
113
415k
int svt_aom_filter_intra_allowed(uint8_t enable_filter_intra, BlockSize bsize, uint8_t palette_size, uint32_t mode) {
114
415k
    if (!CONFIG_ENABLE_FILTER_INTRA) {
115
0
        return 0; // filter_intra off
116
0
    }
117
415k
    return enable_filter_intra && mode == DC_PRED && palette_size == 0 && svt_aom_filter_intra_allowed_bsize(bsize);
118
415k
}
119
120
#if CONFIG_ENABLE_INTER_COMPOUND && CONFIG_ENABLE_COMPOUND_TYPES
121
// returns the max inter-inter compound type based on settings and block size
122
0
static MD_COMP_TYPE get_tot_comp_types_bsize(MD_COMP_TYPE tot_comp_types, BlockSize bsize) {
123
0
    return (svt_aom_get_wedge_params_bits(bsize) == 0) ? MIN(tot_comp_types, MD_COMP_WEDGE) : tot_comp_types;
124
0
}
125
#endif
126
127
/*
128
Get the ME offset for a given block (the offset used to locate the PA MVs from the parent PCS).
129
*/
130
uint32_t svt_aom_get_me_block_offset(const uint32_t org_x, const uint32_t org_y, const BlockSize bsize,
131
206k
                                     const uint8_t enable_me_8x8, const uint8_t enable_me_16x16) {
132
206k
    const int      bwidth     = block_size_wide[bsize];
133
206k
    const int      bheight    = block_size_high[bsize];
134
206k
    const uint32_t max_length = MAX(bwidth, bheight);
135
136
206k
    uint32_t me_idx = 0;
137
206k
    switch (max_length) {
138
0
    case 4:
139
202k
    case 8:
140
202k
        me_idx++;
141
202k
        if (org_x & 8) { // (org_x % 16) / 8
142
98.3k
            me_idx += 1;
143
98.3k
        }
144
202k
        if (org_y & 8) { // (org_y % 16) / 8
145
98.2k
            me_idx += 2;
146
98.2k
        }
147
202k
        AOM_FALLTHROUGH_INTENDED;
148
203k
    case 16:
149
203k
        me_idx++;
150
203k
        if (org_x & 16) { // (org_x % 32) / 16
151
96.6k
            me_idx += 5;
152
96.6k
        }
153
203k
        if (org_y & 16) { // (org_y % 32) / 16
154
96.7k
            me_idx += 10;
155
96.7k
        }
156
203k
        AOM_FALLTHROUGH_INTENDED;
157
203k
    case 32:
158
203k
        me_idx++;
159
203k
        if (org_x & 32) { // (org_x % 64) / 32
160
94.2k
            me_idx += 21;
161
94.2k
        }
162
203k
        if (org_y & 32) { // (org_y % 64) / 32
163
94.4k
            me_idx += 42;
164
94.4k
        }
165
203k
        break;
166
2.56k
    default:
167
        // me_idx = 0;
168
2.56k
        break;
169
206k
    }
170
171
206k
    uint32_t me_block_offset = me_idx_85[me_idx]; // convert idx to me_idx
172
173
206k
    if (!enable_me_8x8) {
174
206k
        if (me_block_offset >= MAX_SB64_PU_COUNT_NO_8X8) {
175
202k
            me_block_offset = me_idx_85_8x8_to_16x16_conversion[me_block_offset - MAX_SB64_PU_COUNT_NO_8X8];
176
202k
        }
177
206k
        assert(me_block_offset < 21);
178
206k
        if (!enable_me_16x16) {
179
0
            if (me_block_offset >= MAX_SB64_PU_COUNT_WO_16X16) {
180
0
                assert(me_block_offset < 21);
181
0
                me_block_offset = me_idx_16x16_to_parent_32x32_conversion[me_block_offset - MAX_SB64_PU_COUNT_WO_16X16];
182
0
            }
183
0
        }
184
206k
    }
185
186
206k
    return me_block_offset;
187
206k
}
188
189
//Given one reference frame identified by the pair (list_index,ref_index)
190
//indicate if ME data is valid
191
uint8_t svt_aom_is_me_data_present(uint32_t me_block_offset, uint32_t me_cand_offset, const MeSbResults* me_results,
192
0
                                   uint8_t list_idx, uint8_t ref_idx) {
193
0
    uint8_t            total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
194
0
    const MeCandidate* me_block_results = &me_results->me_candidate_array[me_cand_offset];
195
0
    for (uint32_t me_cand_i = 0; me_cand_i < total_me_cnt; ++me_cand_i) {
196
0
        const MeCandidate* me_cand = &me_block_results[me_cand_i];
197
0
        assert(me_cand->direction <= 2);
198
0
        if (me_cand->direction == 0 || me_cand->direction == 2) {
199
0
            if (list_idx == me_cand->ref0_list && ref_idx == me_cand->ref_idx_l0) {
200
0
                return 1;
201
0
            }
202
0
        }
203
0
        if (me_cand->direction == 1 || me_cand->direction == 2) {
204
0
            if (list_idx == me_cand->ref1_list && ref_idx == me_cand->ref_idx_l1) {
205
0
                return 1;
206
0
            }
207
0
        }
208
0
    }
209
0
    return 0;
210
0
}
211
212
/********************************************
213
* Constants
214
********************************************/
215
// 1 - Regular uni-pred ,
216
// 2 - Regular uni-pred + Wedge compound Inter Intra
217
// 3 - Regular uni-pred + Wedge compound Inter Intra + Smooth compound Inter Intra
218
219
#if CONFIG_ENABLE_OBMC || CONFIG_ENABLE_WARP
220
0
static bool warped_motion_mode_allowed(PictureControlSet* pcs, ModeDecisionContext* ctx) {
221
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
222
0
    return frm_hdr->allow_warped_motion && has_overlappable_candidates(ctx->blk_ptr) && ctx->blk_geom->bwidth >= 8 &&
223
0
        ctx->blk_geom->bheight >= 8 && ctx->wm_ctrls.enabled;
224
0
}
225
#endif
226
MotionMode svt_aom_obmc_motion_mode_allowed(
227
    const PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
228
    uint8_t          situation, // 0: candidate(s) preparation, 1: data preparation, 2: simple translation face-off
229
0
    MvReferenceFrame rf0, MvReferenceFrame rf1, PredictionMode mode) {
230
0
    if (!CONFIG_ENABLE_OBMC && !CONFIG_ENABLE_WARP) {
231
0
        return SIMPLE_TRANSLATION; // OBMC/warp off -> const-folds, cascades DCE
232
0
    }
233
0
    if (ctx->obmc_ctrls.trans_face_off && !situation) {
234
0
        return SIMPLE_TRANSLATION;
235
0
    }
236
    // check if should cap the max block size for obmc
237
238
0
    if (block_size_wide[bsize] > ctx->obmc_ctrls.max_blk_size ||
239
0
        block_size_high[bsize] > ctx->obmc_ctrls.max_blk_size) {
240
0
        return SIMPLE_TRANSLATION;
241
0
    }
242
0
    if (!ctx->obmc_ctrls.enabled) {
243
0
        return SIMPLE_TRANSLATION;
244
0
    }
245
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
246
247
0
    if (!frm_hdr->is_motion_mode_switchable) {
248
0
        return SIMPLE_TRANSLATION;
249
0
    }
250
251
0
    if (frm_hdr->force_integer_mv == 0) {
252
0
        const TransformationType gm_type = pcs->ppcs->global_motion[rf0].wmtype;
253
0
        if (is_global_mv_block(mode, bsize, gm_type)) {
254
0
            return SIMPLE_TRANSLATION;
255
0
        }
256
0
    }
257
0
    if (is_motion_variation_allowed_bsize(bsize) && is_inter_singleref_mode(mode) && rf1 != INTRA_FRAME &&
258
0
        !(rf1 > INTRA_FRAME)) // is_motion_variation_allowed_compound
259
0
    {
260
0
        if (!has_overlappable_candidates(ctx->blk_ptr)) { // check_num_overlappable_neighbors
261
0
            return SIMPLE_TRANSLATION;
262
0
        }
263
264
0
        return OBMC_CAUSAL;
265
0
    } else {
266
0
        return SIMPLE_TRANSLATION;
267
0
    }
268
0
}
269
270
//static uint32_t  AntiContouringIntraMode[11] = { EB_INTRA_PLANAR, EB_INTRA_DC, EB_INTRA_HORIZONTAL, EB_INTRA_VERTICAL,
271
//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 };
272
0
int32_t svt_aom_have_newmv_in_inter_mode(PredictionMode mode) {
273
0
    return (mode == NEWMV || mode == NEW_NEWMV || mode == NEAREST_NEWMV || mode == NEW_NEARESTMV ||
274
0
            mode == NEAR_NEWMV || mode == NEW_NEARMV);
275
0
}
276
277
static MvReferenceFrame to_ref_frame[2][4] = {{LAST_FRAME, LAST2_FRAME, LAST3_FRAME, GOLDEN_FRAME},
278
                                              {BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME, INVALID_REF}};
279
280
0
MvReferenceFrame svt_get_ref_frame_type(uint8_t list, uint8_t ref_idx) {
281
0
    return to_ref_frame[list][ref_idx];
282
0
};
283
284
0
uint8_t svt_aom_get_max_drl_index(uint8_t refmvCnt, PredictionMode mode) {
285
0
    uint8_t max_drl = 0;
286
287
0
    if (mode == NEWMV || mode == NEW_NEWMV) {
288
0
        if (refmvCnt < 2) {
289
0
            max_drl = 1;
290
0
        } else if (refmvCnt == 2) {
291
0
            max_drl = 2;
292
0
        } else {
293
0
            max_drl = 3;
294
0
        }
295
0
    }
296
297
0
    if (mode == NEARMV || mode == NEAR_NEARMV || mode == NEAR_NEWMV || mode == NEW_NEARMV) {
298
0
        if (refmvCnt < 3) {
299
0
            max_drl = 1;
300
0
        } else if (refmvCnt == 3) {
301
0
            max_drl = 2;
302
0
        } else {
303
0
            max_drl = 3;
304
0
        }
305
0
    }
306
307
0
    return max_drl;
308
0
}
309
310
0
#define MV_COST_WEIGHT 108
311
312
static int64_t pick_interintra_wedge(PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
313
                                     const uint8_t* const p0, const uint8_t* const p1, uint8_t* src_buf,
314
0
                                     uint32_t src_stride, int8_t* wedge_index_out) {
315
0
    assert(svt_aom_is_interintra_wedge_used(bsize));
316
    // assert(cpi->common.seq_params.enable_interintra_compound);
317
318
0
    const int bw = block_size_wide[bsize];
319
0
    const int bh = block_size_high[bsize];
320
0
    DECLARE_ALIGNED(32, int16_t, residual1[MAX_INTERINTRA_SB_SQUARE]); // src - pred1
321
0
    DECLARE_ALIGNED(32, int16_t, diff10[MAX_INTERINTRA_SB_SQUARE]); // pred1 - pred0
322
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
323
0
    if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
324
0
        svt_aom_highbd_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw, EB_TEN_BIT);
325
0
        svt_aom_highbd_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw, EB_TEN_BIT);
326
327
0
    } else
328
0
#endif
329
0
    {
330
0
        svt_aom_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw);
331
0
        svt_aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw);
332
0
    }
333
334
0
    int8_t  wedge_index = -1;
335
0
    int64_t rd          = pick_wedge_fixed_sign(pcs, ctx, bsize, residual1, diff10, 0, &wedge_index);
336
0
    *wedge_index_out    = wedge_index;
337
338
0
    return rd;
339
0
}
340
341
0
static void inter_intra_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand) {
342
0
    SequenceControlSet* scs = pcs->scs;
343
0
    DECLARE_ALIGNED(16, uint8_t, tmp_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
344
0
    DECLARE_ALIGNED(16, uint8_t, ii_pred_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
345
    // get inter pred for ref0
346
0
    EbPictureBufferDesc* src_pic = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? pcs->input_frame16bit : pcs->ppcs->enhanced_pic;
347
0
    uint16_t* src_buf_hbd = (uint16_t*)src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
348
0
    uint8_t*  src_buf     = src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
349
350
0
    uint8_t  bit_depth   = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? EB_TEN_BIT : EB_EIGHT_BIT;
351
0
    uint32_t full_lambda = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_lambda_md[EB_10_BIT_MD]
352
0
                                                             : ctx->full_lambda_md[EB_8_BIT_MD];
353
354
0
    uint32_t            bwidth  = ctx->blk_geom->bwidth;
355
0
    uint32_t            bheight = ctx->blk_geom->bheight;
356
0
    EbPictureBufferDesc pred_desc;
357
0
    pred_desc.border   = 0;
358
0
    pred_desc.y_stride = bwidth;
359
360
0
    EbPictureBufferDesc* ref_pic_list0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
361
0
    EbPictureBufferDesc* ref_pic_list1 = NULL;
362
363
    // Use scaled references if resolution of the reference is different from that of the input
364
    // Only have one ref
365
0
    if (ref_pic_list0 != NULL) {
366
0
        uint8_t list_idx0  = get_list_idx(cand->block_mi.ref_frame[0]);
367
0
        int8_t  ref_idx_l0 = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
368
0
        svt_aom_use_scaled_rec_refs_if_needed(
369
0
            pcs,
370
0
            pcs->ppcs->enhanced_pic,
371
0
            (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx0][ref_idx_l0]->object_ptr,
372
0
            &ref_pic_list0,
373
0
            SVT_EFFECTIVE_HBD_MD(ctx->hbd_md));
374
0
    }
375
0
    pred_desc.y_buffer = tmp_buf;
376
377
    //we call the regular inter prediction path here (no compound)
378
0
    cand->block_mi.interp_filters     = 0;
379
0
    cand->block_mi.is_interintra_used = 0;
380
0
    svt_aom_inter_prediction(scs,
381
0
                             pcs,
382
0
                             &cand->block_mi,
383
0
                             &cand->wm_params_l0,
384
0
                             &cand->wm_params_l1,
385
0
                             ctx->blk_ptr,
386
0
                             ctx->blk_geom->bsize,
387
0
                             ctx->shape,
388
0
                             false, // use_precomputed_obmc
389
0
                             false, // use_precomputed_ii - ii not performed here
390
0
                             ctx,
391
0
                             NULL,
392
0
                             NULL,
393
0
                             NULL,
394
0
                             ref_pic_list0,
395
0
                             ref_pic_list1,
396
0
                             ctx->blk_org_x,
397
0
                             ctx->blk_org_y,
398
0
                             &pred_desc, //output
399
0
                             0, //output org_x,
400
0
                             0, //output org_y,
401
0
                             PICTURE_BUFFER_DESC_LUMA_MASK,
402
0
                             SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? EB_TEN_BIT : EB_EIGHT_BIT,
403
0
                             0); // is_16bit_pipeline
404
405
0
    assert(svt_aom_is_interintra_wedge_used(ctx->blk_geom->bsize)); //if not I need to add nowedge path!!
406
407
0
    int64_t        best_interintra_rd   = INT64_MAX;
408
0
    InterIntraMode best_interintra_mode = INTERINTRA_MODES;
409
0
    for (int j = 0; j < INTERINTRA_MODES; ++j) {
410
        // if ((!cpi->oxcf.enable_smooth_intra || cpi->sf.disable_smooth_intra) &&
411
        //     (InterIntraMode)j == II_SMOOTH_PRED)
412
        //   continue;
413
0
        InterIntraMode interintra_mode = (InterIntraMode)j;
414
        // rmode = interintra_mode_cost[mbmi->interintra_mode];
415
0
        const int bsize_group = eb_size_group_lookup[ctx->blk_geom->bsize];
416
0
        const int rmode       = ctx->md_rate_est_ctx->inter_intra_mode_fac_bits[bsize_group][interintra_mode];
417
        // av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw);
418
0
        if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
419
0
            svt_aom_combine_interintra_highbd(interintra_mode, // mode,
420
0
                                              0, // use_wedge_interintra,
421
0
                                              0, // cand->interintra_wedge_index,
422
0
                                              0, // int wedge_sign,
423
0
                                              ctx->blk_geom->bsize,
424
0
                                              ctx->blk_geom->bsize, // plane_bsize,
425
0
                                              ii_pred_buf,
426
0
                                              bwidth, /*uint8_t *comppred, int compstride,*/
427
0
                                              tmp_buf,
428
0
                                              bwidth, /*const uint8_t *interpred, int interstride,*/
429
0
                                              ctx->intrapred_buf[j],
430
0
                                              bwidth /*const uint8_t *intrapred,   int intrastride*/,
431
0
                                              bit_depth);
432
0
        } else {
433
0
            svt_aom_combine_interintra(interintra_mode, //mode,
434
0
                                       0, //use_wedge_interintra,
435
0
                                       0, //cand->interintra_wedge_index,
436
0
                                       0, //int wedge_sign,
437
0
                                       ctx->blk_geom->bsize,
438
0
                                       ctx->blk_geom->bsize, // plane_bsize,
439
0
                                       ii_pred_buf,
440
0
                                       bwidth, /*uint8_t *comppred, int compstride,*/
441
0
                                       tmp_buf,
442
0
                                       bwidth, /*const uint8_t *interpred, int interstride,*/
443
0
                                       ctx->intrapred_buf[j],
444
0
                                       bwidth /*const uint8_t *intrapred,   int intrastride*/);
445
0
        }
446
0
        int64_t rd;
447
0
        if (ctx->inter_intra_comp_ctrls.use_rd_model) {
448
0
            int     rate_sum;
449
0
            int64_t dist_sum;
450
0
            model_rd_for_sb_with_curvfit(pcs,
451
0
                                         ctx,
452
0
                                         ctx->blk_geom->bsize,
453
0
                                         bwidth,
454
0
                                         bheight,
455
0
                                         SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? (uint8_t*)src_buf_hbd : src_buf,
456
0
                                         src_pic->y_stride,
457
0
                                         ii_pred_buf,
458
0
                                         bwidth,
459
0
                                         0,
460
0
                                         0,
461
0
                                         0,
462
0
                                         0,
463
0
                                         &rate_sum,
464
0
                                         &dist_sum,
465
0
                                         NULL,
466
0
                                         NULL,
467
0
                                         NULL);
468
469
0
            rd = RDCOST(full_lambda, rate_sum + rmode, dist_sum);
470
0
        } else {
471
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
472
0
            if (SVT_EFFECTIVE_HBD_MD(ctx->hbd_md)) {
473
0
                rd = svt_aom_highbd_sse((uint8_t*)src_buf_hbd, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
474
0
            } else
475
0
#endif
476
0
            {
477
0
                rd = svt_aom_sse(src_buf, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
478
0
            }
479
0
        }
480
0
        if (rd < best_interintra_rd) {
481
0
            best_interintra_rd             = rd;
482
0
            cand->block_mi.interintra_mode = best_interintra_mode = interintra_mode;
483
0
        }
484
0
    }
485
    // To test: Enable wedge search if source variance and edge strength are above the thresholds.
486
    //CHKN need to re-do intra pred using the winner, or have a separate intra serch for wedge
487
0
    int64_t       best_interintra_rd_wedge = INT64_MAX;
488
0
    const uint8_t ii_wedge_mode            = ctx->shape == PART_N ? ctx->inter_intra_comp_ctrls.wedge_mode_sq
489
0
                                                                  : ctx->inter_intra_comp_ctrls.wedge_mode_nsq;
490
0
    if (ii_wedge_mode) {
491
0
        best_interintra_rd_wedge = pick_interintra_wedge(
492
0
            pcs,
493
0
            ctx,
494
0
            ctx->blk_geom->bsize,
495
0
            ctx->intrapred_buf[best_interintra_mode],
496
0
            tmp_buf,
497
0
            SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? (uint8_t*)src_buf_hbd : src_buf,
498
0
            src_pic->y_stride,
499
0
            &cand->block_mi.interintra_wedge_index);
500
0
    }
501
502
    // for ii_wedge_mode 1, always inject wedge as a separate candidate; for wedge mode 2 only inject
503
    // if wedge is better than non-wedge
504
0
    if (ii_wedge_mode == 1 || best_interintra_rd_wedge < best_interintra_rd) {
505
0
        cand->block_mi.use_wedge_interintra = 1;
506
0
    } else {
507
0
        cand->block_mi.use_wedge_interintra = 0;
508
0
    }
509
0
}
510
511
static COMPOUND_TYPE to_av1_compound_lut[] = {COMPOUND_AVERAGE, COMPOUND_DISTWTD, COMPOUND_DIFFWTD, COMPOUND_WEDGE};
512
513
static void determine_compound_mode(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
514
0
                                    MD_COMP_TYPE cur_type) {
515
#if !CONFIG_ENABLE_INTER_COMPOUND || !CONFIG_ENABLE_COMPOUND_TYPES
516
    (void)pcs;
517
    (void)ctx;
518
#endif
519
0
    BlockModeInfo* block_mi        = &cand->block_mi;
520
0
    block_mi->interinter_comp.type = to_av1_compound_lut[cur_type];
521
0
    switch (cur_type) {
522
0
    case MD_COMP_AVG:
523
0
        block_mi->comp_group_idx = 0;
524
0
        block_mi->compound_idx   = 1;
525
0
        break;
526
0
    case MD_COMP_DIST:
527
0
        block_mi->comp_group_idx = 0;
528
0
        block_mi->compound_idx   = 0;
529
0
        break;
530
0
    case MD_COMP_DIFF0:
531
0
        block_mi->comp_group_idx            = 1;
532
0
        block_mi->compound_idx              = 1;
533
0
        block_mi->interinter_comp.mask_type = 55;
534
0
#if CONFIG_ENABLE_INTER_COMPOUND && CONFIG_ENABLE_COMPOUND_TYPES
535
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
536
0
#endif
537
0
        break;
538
0
    case MD_COMP_WEDGE:
539
0
        block_mi->comp_group_idx = 1;
540
0
        block_mi->compound_idx   = 1;
541
0
#if CONFIG_ENABLE_INTER_COMPOUND && CONFIG_ENABLE_COMPOUND_TYPES
542
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
543
0
#endif
544
0
        break;
545
0
    default:
546
0
        SVT_ERROR("not used comp type\n");
547
0
        assert(0);
548
0
        break;
549
0
    }
550
0
}
551
552
void svt_aom_choose_best_av1_mv_pred(ModeDecisionContext* ctx, MvReferenceFrame ref_frame,
553
                                     PredictionMode mode, // NEW or NEW_NEW
554
                                     Mv mv0, Mv mv1,
555
                                     uint8_t* bestDrlIndex, // output
556
                                     Mv       best_pred_mv[2] // output
557
0
) {
558
0
    if (ctx->shut_fast_rate) {
559
0
        return;
560
0
    }
561
0
    if (ctx->approx_inter_rate > 1) {
562
0
        *bestDrlIndex   = 0;
563
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
564
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
565
0
        return;
566
0
    }
567
0
    int16_t mv0x = mv0.x;
568
0
    int16_t mv0y = mv0.y;
569
0
    int16_t mv1x = mv1.x;
570
0
    int16_t mv1y = mv1.y;
571
572
0
    uint8_t is_compound = is_inter_compound_mode(mode);
573
574
0
    struct MdRateEstimationContext* md_rate_est_ctx = ctx->md_rate_est_ctx;
575
0
    BlkStruct*                      blk_ptr         = ctx->blk_ptr;
576
0
    uint8_t                         max_drl_index;
577
0
    Mv                              nearestmv[2] = {{{0}}, {{0}}};
578
0
    Mv                              nearmv[2];
579
0
    Mv                              ref_mv[2];
580
0
    Mv                              mv;
581
582
0
    max_drl_index = svt_aom_get_max_drl_index(blk_ptr->av1xd->ref_mv_count[ref_frame], mode);
583
    // max_drl_index = 1;
584
585
0
    if (max_drl_index == 1) {
586
0
        *bestDrlIndex = 0;
587
588
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
589
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
590
0
    } else {
591
0
        uint8_t  drli;
592
0
        uint32_t best_mv_cost = 0xFFFFFFFF;
593
0
        for (drli = 0; drli < max_drl_index; drli++) {
594
0
            svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_frame, is_compound, mode, drli, nearestmv, nearmv, ref_mv);
595
596
            //compute the rate for this drli Cand
597
0
            mv.y             = mv0y;
598
0
            mv.x             = mv0x;
599
0
            uint32_t mv_rate = 0;
600
0
            if (ctx->approx_inter_rate) {
601
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost_light(mv, ref_mv[0]);
602
0
            } else {
603
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost(
604
0
                    mv, ref_mv[0], md_rate_est_ctx->nmv_vec_cost, md_rate_est_ctx->nmvcoststack, MV_COST_WEIGHT);
605
0
            }
606
607
0
            if (is_compound) {
608
0
                mv.y = mv1y;
609
0
                mv.x = mv1x;
610
0
                if (ctx->approx_inter_rate) {
611
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost_light(mv, ref_mv[1]);
612
0
                } else {
613
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost(
614
0
                        mv, ref_mv[1], md_rate_est_ctx->nmv_vec_cost, md_rate_est_ctx->nmvcoststack, MV_COST_WEIGHT);
615
0
                }
616
0
            }
617
618
0
            const int32_t new_mv = (mode == NEWMV || mode == NEW_NEWMV);
619
0
            if (new_mv) {
620
0
                int32_t idx;
621
0
                for (idx = 0; idx < 2; ++idx) {
622
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame] > idx + 1) {
623
0
                        uint8_t drl_1_ctx = av1_drl_ctx(&(ctx->ref_mv_stack[ref_frame][0]), idx);
624
0
                        mv_rate += ctx->md_rate_est_ctx->drl_mode_fac_bits[drl_1_ctx][drli != idx];
625
0
                        if (drli == idx) {
626
0
                            break;
627
0
                        }
628
0
                    }
629
0
                }
630
0
            }
631
632
0
            if (mv_rate < best_mv_cost) {
633
0
                best_mv_cost    = mv_rate;
634
0
                *bestDrlIndex   = drli;
635
0
                best_pred_mv[0] = ref_mv[0];
636
0
                best_pred_mv[1] = ref_mv[1];
637
0
            }
638
0
        }
639
0
    }
640
0
}
641
642
0
static void mode_decision_cand_bf_dctor(EbPtr p) {
643
    // pred/rec_coeff/quant are borrowed from the MD-context pools; residual/recon are
644
    // shared (temp_*). Nothing is owned by the candidate buffer itself.
645
0
    (void)p;
646
0
}
647
648
3.65k
static void mode_decision_scratch_cand_bf_dctor(EbPtr p) {
649
3.65k
    ModeDecisionCandidateBuffer* obj = (ModeDecisionCandidateBuffer*)p;
650
3.65k
    EB_DELETE(obj->pred);
651
3.65k
    EB_DELETE(obj->residual);
652
3.65k
    EB_DELETE(obj->rec_coeff);
653
3.65k
    EB_DELETE(obj->recon);
654
3.65k
    EB_DELETE(obj->quant);
655
3.65k
}
656
657
/***************************************
658
* Mode Decision Candidate Ctor
659
***************************************/
660
EbErrorType svt_aom_mode_decision_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, EbPictureBufferDesc* pred,
661
                                               EbPictureBufferDesc* rec_coeff, EbPictureBufferDesc* quant,
662
                                               EbPictureBufferDesc* temp_residual, EbPictureBufferDesc* temp_recon_ptr,
663
18.2k
                                               uint64_t* fast_cost, uint64_t* full_cost, uint64_t* full_cost_ssim) {
664
18.2k
    buffer_ptr->dctor = mode_decision_cand_bf_dctor;
665
666
    // Candidate Ptr
667
18.2k
    buffer_ptr->cand = NULL;
668
669
    // Video Buffers — pred/rec_coeff/quant borrowed from MD-context pools; residual/recon
670
    // shared with the MD context.
671
18.2k
    buffer_ptr->pred      = pred;
672
18.2k
    buffer_ptr->residual  = temp_residual;
673
18.2k
    buffer_ptr->rec_coeff = rec_coeff;
674
18.2k
    buffer_ptr->quant     = quant;
675
18.2k
    buffer_ptr->recon     = temp_recon_ptr;
676
677
    // Costs
678
18.2k
    buffer_ptr->fast_cost      = fast_cost;
679
18.2k
    buffer_ptr->full_cost      = full_cost;
680
18.2k
    buffer_ptr->full_cost_ssim = full_cost_ssim;
681
18.2k
    return EB_ErrorNone;
682
18.2k
}
683
684
EbErrorType svt_aom_mode_decision_scratch_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, uint8_t sb_size,
685
3.65k
                                                       EbBitDepth max_bitdepth) {
686
3.65k
    EbPictureBufferDescInitData picture_buffer_desc_init_data;
687
3.65k
    EbPictureBufferDescInitData double_width_picture_buffer_desc_init_data;
688
3.65k
    EbPictureBufferDescInitData thirty_two_width_picture_buffer_desc_init_data;
689
690
3.65k
    buffer_ptr->dctor = mode_decision_scratch_cand_bf_dctor;
691
692
    // Init Picture Data
693
3.65k
    picture_buffer_desc_init_data.max_width                           = sb_size;
694
3.65k
    picture_buffer_desc_init_data.max_height                          = sb_size;
695
3.65k
    picture_buffer_desc_init_data.bit_depth                           = max_bitdepth;
696
3.65k
    picture_buffer_desc_init_data.color_format                        = EB_YUV420;
697
3.65k
    picture_buffer_desc_init_data.buffer_enable_mask                  = PICTURE_BUFFER_DESC_FULL_MASK;
698
3.65k
    picture_buffer_desc_init_data.border                              = 0;
699
3.65k
    picture_buffer_desc_init_data.split_mode                          = false;
700
3.65k
    picture_buffer_desc_init_data.is_16bit_pipeline                   = max_bitdepth > EB_EIGHT_BIT;
701
3.65k
    double_width_picture_buffer_desc_init_data.max_width              = sb_size;
702
3.65k
    double_width_picture_buffer_desc_init_data.max_height             = sb_size;
703
3.65k
    double_width_picture_buffer_desc_init_data.bit_depth              = EB_SIXTEEN_BIT;
704
3.65k
    double_width_picture_buffer_desc_init_data.color_format           = EB_YUV420;
705
3.65k
    double_width_picture_buffer_desc_init_data.buffer_enable_mask     = PICTURE_BUFFER_DESC_FULL_MASK;
706
3.65k
    double_width_picture_buffer_desc_init_data.border                 = 0;
707
3.65k
    double_width_picture_buffer_desc_init_data.split_mode             = false;
708
3.65k
    double_width_picture_buffer_desc_init_data.is_16bit_pipeline      = true;
709
3.65k
    thirty_two_width_picture_buffer_desc_init_data.max_width          = sb_size;
710
3.65k
    thirty_two_width_picture_buffer_desc_init_data.max_height         = sb_size;
711
3.65k
    thirty_two_width_picture_buffer_desc_init_data.bit_depth          = EB_THIRTYTWO_BIT;
712
3.65k
    thirty_two_width_picture_buffer_desc_init_data.color_format       = EB_YUV420;
713
3.65k
    thirty_two_width_picture_buffer_desc_init_data.buffer_enable_mask = PICTURE_BUFFER_DESC_FULL_MASK;
714
3.65k
    thirty_two_width_picture_buffer_desc_init_data.border             = 0;
715
3.65k
    thirty_two_width_picture_buffer_desc_init_data.split_mode         = false;
716
3.65k
    thirty_two_width_picture_buffer_desc_init_data.is_16bit_pipeline  = true;
717
718
    // Candidate Ptr
719
3.65k
    buffer_ptr->cand = NULL;
720
721
    // Video Buffers
722
3.65k
    EB_NEW(buffer_ptr->pred, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
723
3.65k
    EB_NEW(buffer_ptr->residual, svt_picture_buffer_desc_ctor, (EbPtr)&double_width_picture_buffer_desc_init_data);
724
3.65k
    EB_NEW(buffer_ptr->rec_coeff, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
725
3.65k
    EB_NEW(buffer_ptr->quant, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
726
727
3.65k
    EB_NEW(buffer_ptr->recon, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
728
3.65k
    return EB_ErrorNone;
729
3.65k
}
730
731
/***************************************
732
* return true if the MV candidate is already injected
733
***************************************/
734
0
static bool mv_is_already_injected(ModeDecisionContext* ctx, Mv mv0, Mv mv1, uint8_t ref_type) {
735
0
    MvReferenceFrame rf[2];
736
0
    av1_set_ref_frame(rf, ref_type);
737
738
    // Unipred Candidate
739
0
    if (rf[1] <= INTRA_FRAME) {
740
        // First check the validity of the candidate MV, and exit if invalid MV
741
0
        if (ctx->corrupted_mv_check && !check_mv_validity(mv0.x, mv0.y, 0)) {
742
0
            return true;
743
0
        }
744
745
0
        for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
746
0
            if (ctx->injected_ref_types[cand_idx] == ref_type && ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int) {
747
0
                return true;
748
0
            }
749
0
        }
750
0
    } else { // Bipred Candidate
751
        // First check the validity of the candidate MV, and exit if invalid MV
752
0
        if (ctx->corrupted_mv_check && (!check_mv_validity(mv0.x, mv0.y, 0) || !check_mv_validity(mv1.x, mv1.y, 0))) {
753
0
            return true;
754
0
        }
755
756
0
        RedundantCandCtrls* redund_ctrls = &ctx->cand_reduction_ctrls.redundant_cand_ctrls;
757
0
        if (redund_ctrls->score_th) {
758
0
            uint8_t is_high_mag = (ABS(mv0.x) > redund_ctrls->mag_th) && (ABS(mv0.y) > redund_ctrls->mag_th) &&
759
0
                (ABS(mv1.x) > redund_ctrls->mag_th) && (ABS(mv1.y) > redund_ctrls->mag_th);
760
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
761
0
                if (ctx->injected_ref_types[cand_idx] == ref_type) {
762
0
                    int score = ABS(ctx->injected_mvs[cand_idx][0].x - mv0.x) +
763
0
                        ABS(ctx->injected_mvs[cand_idx][0].y - mv0.y) + ABS(ctx->injected_mvs[cand_idx][1].x - mv1.x) +
764
0
                        ABS(ctx->injected_mvs[cand_idx][1].y - mv1.y);
765
766
0
                    if (score == 0 || (score < redund_ctrls->score_th && is_high_mag)) {
767
0
                        return true;
768
0
                    }
769
0
                }
770
0
            }
771
0
        } else {
772
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
773
0
                if (ctx->injected_ref_types[cand_idx] == ref_type &&
774
0
                    ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int &&
775
0
                    ctx->injected_mvs[cand_idx][1].as_int == mv1.as_int) {
776
0
                    return true;
777
0
                }
778
0
            }
779
0
        }
780
0
    }
781
0
    return false;
782
0
}
783
784
bool svt_aom_is_valid_unipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx,
785
0
                                  uint8_t ref_idx) {
786
0
    if (!ctx->ref_pruning_ctrls.enabled) {
787
0
        return true;
788
0
    }
789
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx][ref_idx].do_ref &&
790
0
        (ref_idx || !ctx->ref_pruning_ctrls.closest_refs[inter_cand_group])) {
791
0
        return false;
792
0
    } else {
793
0
        return true;
794
0
    }
795
0
}
796
797
// Determine if the MV-to-MVP difference satisfies the mv_diff restriction
798
0
static bool is_valid_mv_diff(Mv best_pred_mv[2], Mv mv0, Mv mv1, uint8_t is_compound) {
799
0
    const uint8_t mv_diff_max_bit = MV_IN_USE_BITS;
800
801
0
    if (abs(mv0.x - best_pred_mv[0].x) > (1 << mv_diff_max_bit) ||
802
0
        abs(mv0.y - best_pred_mv[0].y) > (1 << mv_diff_max_bit)) {
803
0
        return false;
804
0
    }
805
806
0
    if (is_compound) {
807
0
        if (abs(mv1.x - best_pred_mv[1].x) > (1 << mv_diff_max_bit) ||
808
0
            abs(mv1.y - best_pred_mv[1].y) > (1 << mv_diff_max_bit)) {
809
0
            return false;
810
0
        }
811
0
    }
812
0
    return true;
813
0
}
814
815
static bool is_valid_bipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx_0,
816
0
                                uint8_t ref_idx_0, uint8_t list_idx_1, uint8_t ref_idx_1) {
817
0
    if (!ctx->ref_pruning_ctrls.enabled) {
818
0
        return true;
819
0
    }
820
    // 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
821
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx_0][ref_idx_0].do_ref ||
822
0
        !ctx->ref_filtering_res[inter_cand_group][list_idx_1][ref_idx_1].do_ref) {
823
        // Check whether we should check the closest, if no then there no need to move forward and return false
824
0
        if (!ctx->ref_pruning_ctrls.closest_refs[inter_cand_group]) {
825
0
            return false;
826
0
        }
827
828
        // Else check if ref are LAST and BWD, if not then return false
829
0
        if (ref_idx_0 || ref_idx_1) {
830
0
            return false;
831
0
        }
832
0
    }
833
0
    return true;
834
0
}
835
836
#if CONFIG_ENABLE_MD_MR_INJECTION || !MOBILE_BUILD
837
0
#define BIPRED_3x3_REFINMENT_POSITIONS 8
838
839
static int8_t allow_refinement_flag[BIPRED_3x3_REFINMENT_POSITIONS] = {1, 0, 1, 0, 1, 0, 1, 0};
840
static int8_t bipred_3x3_x_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {-1, -1, 0, 1, 1, 1, 0, -1};
841
static int8_t bipred_3x3_y_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {0, 1, 1, 1, 0, -1, -1, -1};
842
#endif
843
844
206k
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
206k
    if (!ctx->intra_ctrls.prune_using_edge_info || pcs->scs->super_block_size == 128 || ctx->shape != PART_N ||
847
206k
        ctx->blk_geom->sq_size == 4) {
848
0
        return 0;
849
0
    }
850
851
    // Block variance lookup
852
206k
    int            blk_idx;
853
206k
    int            sub_idx[4];
854
206k
    const Position blk_org = {.x = ctx->blk_org_x - ctx->sb_origin_x, .y = ctx->blk_org_y - ctx->sb_origin_y};
855
206k
    svt_aom_get_blk_var_map(ctx->blk_geom->sq_size, blk_org.x, blk_org.y, &blk_idx, sub_idx);
856
857
206k
    uint16_t* sb_var  = pcs->ppcs->variance[ctx->sb_index];
858
206k
    uint32_t  blk_var = sb_var[blk_idx];
859
860
    // For 8x8, we do not have 4x4 sub-variance, skip spread check
861
206k
    if (ctx->blk_geom->sq_size == 8) {
862
203k
        return (blk_var < 2000);
863
203k
    }
864
865
    // For 16x16 and above, compute spread from sub-blocks
866
2.88k
    uint32_t min_var = UINT32_MAX;
867
2.88k
    uint32_t max_var = 0;
868
869
20.8k
    for (int i = 0; i < 4; i++) {
870
18.0k
        uint32_t v = sb_var[sub_idx[i]];
871
18.0k
        min_var    = MIN(min_var, v);
872
18.0k
        max_var    = MAX(max_var, v);
873
18.0k
    }
874
875
2.88k
    uint32_t spread_var = max_var - min_var;
876
877
4.50k
    return (blk_var < 2000 && spread_var < 4000);
878
206k
}
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 || CONFIG_ENABLE_WARP
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
0
#endif // CONFIG_ENABLE_OBMC || CONFIG_ENABLE_WARP
969
#if CONFIG_ENABLE_OBMC // 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 && CONFIG_ENABLE_COMPOUND_TYPES
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 || !CONFIG_ENABLE_COMPOUND_TYPES
1055
    // Inter compound disabled (RTC / MINIMAL) or AVG-only (MOBILE: the body would return at once): nothing to
1056
    // inject here. Compiling the body out lets LTO cascade-DCE svt_aom_calc_pred_masked_compound + 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
#if CONFIG_ENABLE_MD_MR_INJECTION || !MOBILE_BUILD
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
#endif
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
#if CONFIG_ENABLE_MD_MR_INJECTION || !MOBILE_BUILD
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
#endif
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
#if CONFIG_ENABLE_MD_MR_INJECTION || !MOBILE_BUILD // NEAREST_NEWMV, NEW_NEARESTMV, NEAR_NEWMV, NEW_NEARMV
2931
0
    if (ctx->new_nearest_near_comb_injection && allow_bipred) {
2932
0
        inject_new_nearest_new_comb_candidates(pcs, ctx, cand_total_cnt);
2933
0
    }
2934
0
#endif
2935
0
    if (ctx->inject_new_me) {
2936
0
        inject_new_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2937
0
    }
2938
0
    if (SVT_EFFECTIVE_GM(ctx->global_mv_injection)) {
2939
0
        inject_global_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2940
0
    }
2941
#if CONFIG_ENABLE_MD_MR_INJECTION || !MOBILE_BUILD // bipred / unipred 3x3
2942
0
    if (ctx->bipred3x3_ctrls.enabled && allow_bipred) {
2943
0
        bipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2944
0
    }
2945
0
    if (ctx->unipred3x3_injection) {
2946
0
        unipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2947
0
    }
2948
0
#endif
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
206k
                                           PlaneType plane_type) {
2974
206k
    const PredictionMode mode = (plane_type == PLANE_TYPE_Y) ? pred_mode : get_uv_mode(pred_mode_uv);
2975
206k
    assert(mode < INTRA_MODES);
2976
206k
    return g_intra_mode_to_tx_type[mode];
2977
206k
}
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
205k
TxType svt_aom_get_intra_uv_tx_type(UvPredictionMode pred_mode_uv, TxSize tx_size, int32_t reduced_tx_set) {
2983
205k
    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
205k
    TxType tx_type = intra_mode_to_tx_type(DC_PRED, pred_mode_uv, PLANE_TYPE_UV);
2991
205k
    assert(tx_type < TX_TYPES);
2992
205k
    const TxSetType tx_set_type = get_ext_tx_set_type(tx_size, /*is_inter*/ 0, reduced_tx_set);
2993
205k
    return !av1_ext_tx_used[tx_set_type][tx_type] ? DCT_DCT : tx_type;
2994
205k
}
2995
2996
#if CONFIG_ENABLE_INTRA_BC || !MOBILE_BUILD
2997
// Values are now correlated to quantizer.
2998
0
static INLINE int mv_check_bounds(const MvLimits* mv_limits, const Mv mv) {
2999
0
    return (mv.y >> 3) < mv_limits->row_min || (mv.y >> 3) > mv_limits->row_max || (mv.x >> 3) < mv_limits->col_min ||
3000
0
        (mv.x >> 3) > mv_limits->col_max;
3001
0
}
3002
3003
0
static void assert_release(int statement) {
3004
0
    if (statement == 0) {
3005
0
        SVT_LOG("ASSERT_ERRRR\n");
3006
0
    }
3007
0
}
3008
3009
static void intra_bc_search(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3010
0
                            BlkStruct* blk_ptr, Mv* dv_cand, uint8_t* num_dv_cand) {
3011
0
    IntraBcContext  x_st;
3012
0
    IntraBcContext* x           = &x_st;
3013
0
    uint32_t        full_lambda = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_lambda_md[EB_10_BIT_MD]
3014
0
                                                                    : ctx->full_lambda_md[EB_8_BIT_MD];
3015
3016
0
    x->approx_inter_rate = ctx->approx_inter_rate;
3017
0
    x->xd                = blk_ptr->av1xd;
3018
0
    x->nmv_vec_cost      = ctx->md_rate_est_ctx->nmv_vec_cost;
3019
0
    x->mv_cost_stack     = ctx->md_rate_est_ctx->nmvcoststack;
3020
0
    BlockSize bsize      = ctx->blk_geom->bsize;
3021
0
    assert(bsize < BLOCK_SIZES_ALL);
3022
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
3023
0
    const Av1Common* const cm         = pcs->ppcs->av1_cm;
3024
0
    MvReferenceFrame       ref_frame  = INTRA_FRAME;
3025
0
    const int              num_planes = 3;
3026
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
3027
0
    const TileInfo*        tile       = &xd->tile;
3028
0
    const int              mi_row     = -xd->mb_to_top_edge / (8 * MI_SIZE);
3029
0
    const int              mi_col     = -xd->mb_to_left_edge / (8 * MI_SIZE);
3030
0
    const int              w          = block_size_wide[bsize];
3031
0
    const int              h          = block_size_high[bsize];
3032
0
    const int              sb_row     = mi_row >> scs->seq_header.sb_size_log2;
3033
0
    const int              sb_col     = mi_col >> scs->seq_header.sb_size_log2;
3034
3035
    // Set up limit values for MV components.
3036
    // Mv beyond the range do not produce new/different prediction block.
3037
0
    const int mi_width   = mi_size_wide[bsize];
3038
0
    const int mi_height  = mi_size_high[bsize];
3039
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
3040
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
3041
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
3042
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
3043
    //set search paramters
3044
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
3045
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
3046
0
    x->errorperbit += (x->errorperbit == 0);
3047
    //temp buffer for hash me
3048
0
    for (int i = 0; i < 2; i++) {
3049
0
        EB_MALLOC_ARRAY_NO_CHECK(x->hash_value_buffer[i], AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
3050
0
    }
3051
3052
0
    Mv nearestmv, nearmv;
3053
0
    svt_av1_find_best_ref_mvs_from_stack(ctx->ref_mv_stack /*mbmi_ext*/, xd, ref_frame, &nearestmv, &nearmv);
3054
0
    if (nearestmv.as_int == INVALID_MV) {
3055
0
        nearestmv.as_int = 0;
3056
0
    }
3057
0
    if (nearmv.as_int == INVALID_MV) {
3058
0
        nearmv.as_int = 0;
3059
0
    }
3060
0
    Mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
3061
0
    if (dv_ref.as_int == 0) {
3062
0
        svt_aom_find_ref_dv(&dv_ref, tile, scs->seq_header.sb_mi_size, mi_row, mi_col);
3063
0
    }
3064
    // Ref DV should not have sub-pel.
3065
0
    assert((dv_ref.x & 7) == 0);
3066
0
    assert((dv_ref.y & 7) == 0);
3067
0
    ctx->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;
3068
3069
    /* pointer to current frame */
3070
0
    Yv12BufferConfig cur_buf;
3071
0
    svt_aom_link_eb_to_aom_buffer_desc_8bit(pcs->ppcs->enhanced_pic, &cur_buf);
3072
0
    struct Buf2D yv12_mb[MAX_PLANES];
3073
0
    svt_av1_setup_pred_block(bsize, yv12_mb, &cur_buf, mi_row, mi_col);
3074
0
    for (int i = 0; i < num_planes; ++i) {
3075
0
        x->xdplane[i].pre[0] = yv12_mb[i]; // ref in ME
3076
0
    }
3077
    // setup src for DV search same as ref
3078
0
    x->plane[0].src = x->xdplane[0].pre[0];
3079
3080
0
    enum IntrabcMotionDirection max_dir = pcs->ppcs->intrabc_ctrls.search_dir ? IBC_MOTION_LEFT : IBC_MOTION_DIRECTIONS;
3081
3082
0
    for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE; dir < max_dir; ++dir) {
3083
0
        const MvLimits tmp_mv_limits = x->mv_limits;
3084
3085
0
        switch (dir) {
3086
0
        case IBC_MOTION_ABOVE:
3087
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3088
0
            x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w;
3089
0
            x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE;
3090
0
            x->mv_limits.row_max = (sb_row * scs->seq_header.sb_mi_size - mi_row) * MI_SIZE - h;
3091
0
            break;
3092
0
        case IBC_MOTION_LEFT:
3093
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3094
0
            x->mv_limits.col_max = (sb_col * scs->seq_header.sb_mi_size - mi_col) * MI_SIZE - w;
3095
            // TODO: Minimize the overlap between above and
3096
            // left areas.
3097
0
            x->mv_limits.row_min     = (tile->mi_row_start - mi_row) * MI_SIZE;
3098
0
            int bottom_coded_mi_edge = AOMMIN((sb_row + 1) * scs->seq_header.sb_mi_size, tile->mi_row_end);
3099
0
            x->mv_limits.row_max     = (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
3100
0
            break;
3101
0
        default:
3102
0
            assert(0);
3103
0
        }
3104
0
        assert_release(x->mv_limits.col_min >= tmp_mv_limits.col_min);
3105
0
        assert_release(x->mv_limits.col_max <= tmp_mv_limits.col_max);
3106
0
        assert_release(x->mv_limits.row_min >= tmp_mv_limits.row_min);
3107
0
        assert_release(x->mv_limits.row_max <= tmp_mv_limits.row_max);
3108
3109
        // Search-range cap: keep the DV search local to the current + N neighbouring superblocks
3110
        // for a cheaper search and smaller (cheaper to code) DVs.
3111
0
        if (pcs->ppcs->intrabc_ctrls.local_search_sb) {
3112
0
            const int win        = (int)pcs->ppcs->intrabc_ctrls.local_search_sb * scs->seq_header.sb_mi_size * MI_SIZE;
3113
0
            x->mv_limits.col_min = MAX(x->mv_limits.col_min, -win);
3114
0
            x->mv_limits.row_min = MAX(x->mv_limits.row_min, -win);
3115
0
        }
3116
3117
0
        svt_av1_set_mv_search_range(&x->mv_limits, dv_ref);
3118
3119
0
        if (x->mv_limits.col_max < x->mv_limits.col_min || x->mv_limits.row_max < x->mv_limits.row_min) {
3120
0
            x->mv_limits = tmp_mv_limits;
3121
0
            continue;
3122
0
        }
3123
0
        Mv mvp_full = dv_ref;
3124
0
        mvp_full.x >>= 3;
3125
0
        mvp_full.y >>= 3;
3126
0
        x->best_mv.as_int = 0;
3127
3128
        // Predictor-first early-exit: if the AV1 DV predictor is an exact/near-exact match, take it
3129
        // and skip the hash + full-pixel search for this direction.
3130
0
        if (pcs->ppcs->intrabc_ctrls.pred_first) {
3131
0
            Mv pred_mv;
3132
0
            if (svt_av1_intrabc_pred_first(x, bsize, &mvp_full, pcs->ppcs->intrabc_ctrls.pred_exit_th, &pred_mv)) {
3133
0
                Mv dv = {{pred_mv.x * 8, pred_mv.y * 8}};
3134
0
                if (!mv_check_bounds(&x->mv_limits, dv) &&
3135
0
                    svt_aom_is_dv_valid(dv, xd, mi_row, mi_col, bsize, scs->seq_header.sb_size_log2)) {
3136
0
                    dv_cand[*num_dv_cand] = dv;
3137
0
                    (*num_dv_cand)++;
3138
0
                    ctx->intrabc_last_dv = pred_mv;
3139
0
                    x->mv_limits         = tmp_mv_limits;
3140
0
                    continue;
3141
0
                }
3142
0
            }
3143
0
        }
3144
3145
        // Hash Search
3146
0
        const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
3147
3148
0
        int best_hash_cost = INT_MAX;
3149
0
        Mv  best_hash_mv   = {{0, 0}};
3150
3151
0
        svt_av1_intrabc_hash_search(
3152
0
            pcs, x, bsize, mi_col * MI_SIZE, mi_row * MI_SIZE, dv_ref, 1, fn_ptr, &best_hash_cost, &best_hash_mv);
3153
3154
        // Hash produced a candidate
3155
0
        if (best_hash_cost < INT_MAX) {
3156
0
            Mv dv;
3157
0
            dv.x = best_hash_mv.x * 8;
3158
0
            dv.y = best_hash_mv.y * 8;
3159
3160
0
            dv_cand[*num_dv_cand] = dv;
3161
0
            (*num_dv_cand)++;
3162
3163
0
            x->best_mv           = best_hash_mv;
3164
0
            ctx->intrabc_last_dv = best_hash_mv;
3165
0
        }
3166
        // Fallback when the hash produced no candidate (hash miss, or block too big to hash):
3167
        //   mode 0 = full diamond search (heavy levels)
3168
        //   mode 1 = inject the SAD-gated predicted DV — block-vector prediction, no search (RTC)
3169
        //   mode 2 = skip
3170
0
        else {
3171
0
            const IntrabcCtrls* ic        = &pcs->ppcs->intrabc_ctrls;
3172
0
            bool                inject    = false;
3173
0
            Mv                  pred_orig = {{0, 0}}; // pre-probe BVP pick (variant A fallback)
3174
0
            if (ic->hash_miss_mode == 0) {
3175
0
                svt_av1_full_pixel_search(pcs, x, bsize, &mvp_full, 0, x->sadperbit16, NULL, dv_ref);
3176
0
                inject = true;
3177
0
            } else if (ic->hash_miss_mode == 1) {
3178
                // BVP fallback: evaluate neighbour DV, second predictor, and the segment's last-used
3179
                // DV in one sad_x4d call and inject the best (gated by a SAD budget) instead of
3180
                // searching. Slot 3 repeats slot 0 to fill the x4d call: filling it with a further
3181
                // AV1 predictor (default ref DV, 3rd ref-DV stack entry) measured BD-rate-neutral.
3182
0
                const Mv nearmv_fp = {{(int16_t)(nearmv.x >> 3), (int16_t)(nearmv.y >> 3)}};
3183
0
                const Mv cands[4]  = {mvp_full, nearmv_fp, ctx->intrabc_last_dv, mvp_full};
3184
0
                Mv       pred_mv;
3185
0
                if (svt_av1_intrabc_pred_best4(x, bsize, cands, ic->bvp_th, &pred_mv)) {
3186
0
                    pred_orig = pred_mv;
3187
0
                    if (ic->probe_pts) {
3188
                        // One-shot integer-offset cloud around the best predictor (no iteration):
3189
                        // screen-content matches often sit a few px off the spatial predictor.
3190
0
                        Mv refined;
3191
0
                        svt_av1_intrabc_probe_around(x, bsize, pred_mv, ic->probe_pts, &refined);
3192
0
                        pred_mv = refined;
3193
0
                    }
3194
0
                    x->best_mv = pred_mv;
3195
0
                    inject     = true;
3196
0
                }
3197
0
            }
3198
0
            if (inject) {
3199
                // Try the (possibly probed) DV; fall back to the pre-probe BVP DV if the probed
3200
                // point fails the AV1 DV-validity check, so the probe never costs a match.
3201
0
                Mv  tries[2];
3202
0
                int nt      = 0;
3203
0
                tries[nt++] = x->best_mv;
3204
0
                if (ic->hash_miss_mode == 1 && ic->probe_pts && pred_orig.as_int != x->best_mv.as_int) {
3205
0
                    tries[nt++] = pred_orig;
3206
0
                }
3207
0
                for (int t = 0; t < nt; ++t) {
3208
0
                    Mv dv = {{(int16_t)(tries[t].x * 8), (int16_t)(tries[t].y * 8)}};
3209
0
                    if (!mv_check_bounds(&x->mv_limits, dv) &&
3210
0
                        svt_aom_is_dv_valid(dv, xd, mi_row, mi_col, bsize, scs->seq_header.sb_size_log2)) {
3211
0
                        dv_cand[*num_dv_cand] = dv;
3212
0
                        (*num_dv_cand)++;
3213
0
                        ctx->intrabc_last_dv = tries[t];
3214
0
                        break;
3215
0
                    }
3216
0
                }
3217
0
            }
3218
0
        }
3219
3220
0
        x->mv_limits = tmp_mv_limits;
3221
0
    }
3222
3223
0
    for (int i = 0; i < 2; i++) {
3224
0
        EB_FREE_ARRAY(x->hash_value_buffer[i]);
3225
0
    }
3226
0
}
3227
3228
static void inject_intra_bc_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3229
0
                                       BlkStruct* blk_ptr, uint32_t* cand_cnt) {
3230
0
    Mv      dv_cand[2];
3231
0
    uint8_t num_dv_cand = 0;
3232
3233
    //perform dv-pred + search up to 2 dv(s)
3234
0
    intra_bc_search(pcs, ctx, scs, blk_ptr, dv_cand, &num_dv_cand);
3235
3236
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
3237
3238
0
    for (uint32_t dv_i = 0; dv_i < num_dv_cand; dv_i++) {
3239
0
        ModeDecisionCandidate* cand               = &cand_array[*cand_cnt];
3240
0
        cand->palette_info                        = NULL;
3241
0
        cand->block_mi.use_intrabc                = 1;
3242
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3243
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3244
0
        cand->block_mi.uv_mode                    = UV_DC_PRED;
3245
0
        cand->block_mi.cfl_alpha_signs            = 0;
3246
0
        cand->block_mi.cfl_alpha_idx              = 0;
3247
0
        cand->transform_type[0]                   = DCT_DCT;
3248
0
        cand->transform_type_uv                   = DCT_DCT;
3249
0
        cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3250
0
        cand->block_mi.ref_frame[1]               = NONE_FRAME;
3251
0
        cand->block_mi.mode                       = DC_PRED;
3252
0
        cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3253
        //inter ralated
3254
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3255
0
        cand->block_mi.is_interintra_used = 0;
3256
0
        cand->skip_mode_allowed           = false;
3257
0
        cand->block_mi.mv[0].as_int       = dv_cand[dv_i].as_int;
3258
0
        cand->pred_mv[0].as_int           = ctx->ref_mv_stack[INTRA_FRAME][0].this_mv.as_int;
3259
0
        cand->drl_index                   = 0;
3260
0
        cand->block_mi.interp_filters     = av1_broadcast_interp_filter(BILINEAR);
3261
0
        INC_MD_CAND_CNT((*cand_cnt), pcs->ppcs->max_can_count);
3262
0
    }
3263
0
}
3264
#endif
3265
3266
static void inject_intra_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
3267
207k
                                        uint32_t* candidate_total_cnt) {
3268
207k
    uint32_t               cand_total_cnt     = 0;
3269
207k
    ModeDecisionCandidate* cand               = &ctx->fast_cand_array[cand_total_cnt];
3270
207k
    cand->skip_mode_allowed                   = false;
3271
207k
    cand->palette_info                        = NULL;
3272
207k
    cand->block_mi.use_intrabc                = 0;
3273
207k
    cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3274
207k
    cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3275
207k
    cand->block_mi.uv_mode                    = UV_DC_PRED;
3276
207k
    cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3277
207k
    cand->block_mi.cfl_alpha_signs            = 0;
3278
207k
    cand->block_mi.cfl_alpha_idx              = 0;
3279
207k
    cand->transform_type[0]                   = DCT_DCT;
3280
207k
    cand->transform_type_uv                   = DCT_DCT;
3281
207k
    cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3282
207k
    cand->block_mi.ref_frame[1]               = NONE_FRAME;
3283
207k
    cand->block_mi.mode                       = DC_PRED;
3284
207k
    cand->block_mi.motion_mode                = SIMPLE_TRANSLATION;
3285
207k
    cand->block_mi.is_interintra_used         = 0;
3286
207k
    cand->block_mi.tx_depth                   = 0;
3287
207k
    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3288
    // update the total number of candidates injected
3289
207k
    (*candidate_total_cnt) = cand_total_cnt;
3290
207k
    return;
3291
207k
}
3292
3293
static void inject_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const bool dc_cand_only_flag,
3294
206k
                                    uint32_t* candidate_total_cnt) {
3295
206k
    FrameHeader*           frm_hdr          = &pcs->ppcs->frm_hdr;
3296
206k
    PredictionMode         intra_mode_start = DC_PRED;
3297
206k
    PredictionMode         intra_mode_end   = dc_cand_only_flag ? DC_PRED : ctx->intra_ctrls.intra_mode_end;
3298
206k
    uint32_t               cand_total_cnt   = *candidate_total_cnt;
3299
206k
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
3300
206k
    const bool    use_angle_delta = ctx->intra_ctrls.angular_pred_level ? av1_use_angle_delta(ctx->blk_geom->bsize) : 0;
3301
206k
    const uint8_t disable_angle_prediction                = (ctx->intra_ctrls.angular_pred_level == 0);
3302
206k
    uint8_t       directional_mode_skip_mask[INTRA_MODES] = {0};
3303
206k
    if (ctx->intra_ctrls.angular_pred_level >= 4) {
3304
2.25M
        for (uint8_t i = D45_PRED; i < INTRA_MODE_END; i++) {
3305
2.04M
            directional_mode_skip_mask[i] = 1;
3306
2.04M
        }
3307
204k
    }
3308
206k
    const TxSize tx_size_uv = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3309
3310
411k
    for (PredictionMode intra_mode = intra_mode_start; intra_mode <= intra_mode_end; ++intra_mode) {
3311
205k
        if (av1_is_directional_mode(intra_mode) &&
3312
0
            (disable_angle_prediction || directional_mode_skip_mask[intra_mode])) {
3313
0
            continue;
3314
0
        }
3315
3316
205k
        const uint8_t angle_delta_count = av1_is_directional_mode(intra_mode) &&
3317
0
                ctx->intra_ctrls.angular_pred_level <= 2 && use_angle_delta
3318
205k
            ? 7
3319
205k
            : 1;
3320
3321
409k
        for (uint8_t angle_delta_counter = 0; angle_delta_counter < angle_delta_count; ++angle_delta_counter) {
3322
204k
            int32_t angle_delta = CLIP((angle_delta_count == 1 ? 0 : angle_delta_counter - MAX_ANGLE_DELTA),
3323
204k
                                       -MAX_ANGLE_DELTA,
3324
204k
                                       MAX_ANGLE_DELTA);
3325
204k
            if ((ctx->intra_ctrls.angular_pred_level >= 2 &&
3326
204k
                 (angle_delta == -1 || angle_delta == 1 || angle_delta == -2 || angle_delta == 2)) ||
3327
204k
                (ctx->intra_ctrls.angular_pred_level >= 3 && angle_delta != 0)) {
3328
0
                continue;
3329
0
            }
3330
204k
            ModeDecisionCandidate* cand               = &cand_array[cand_total_cnt];
3331
204k
            cand->skip_mode_allowed                   = false;
3332
204k
            cand->palette_info                        = NULL;
3333
204k
            cand->block_mi.mode                       = intra_mode;
3334
204k
            cand->block_mi.use_intrabc                = 0;
3335
204k
            cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3336
204k
            cand->block_mi.angle_delta[PLANE_TYPE_Y]  = angle_delta;
3337
204k
            cand->block_mi.uv_mode                    = ctx->ind_uv_avail ? ctx->best_uv_mode[intra_mode]
3338
204k
                                                                          : intra_luma_to_chroma[intra_mode];
3339
204k
            cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[intra_mode]
3340
204k
                                                                          : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3341
204k
            cand->block_mi.cfl_alpha_signs            = 0;
3342
204k
            cand->block_mi.cfl_alpha_idx              = 0;
3343
204k
            cand->transform_type[0]                   = DCT_DCT;
3344
204k
            cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3345
204k
                cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3346
3347
204k
            if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3348
0
                continue;
3349
0
            }
3350
204k
            cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3351
204k
            cand->block_mi.ref_frame[1]       = NONE_FRAME;
3352
204k
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3353
204k
            cand->block_mi.is_interintra_used = 0;
3354
204k
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3355
204k
        }
3356
205k
    }
3357
3358
    // update the total number of candidates injected
3359
206k
    (*candidate_total_cnt) = cand_total_cnt;
3360
3361
206k
    return;
3362
206k
}
3363
3364
static void inject_filter_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
3365
0
                                           uint32_t* candidate_total_cnt) {
3366
0
    FilterIntraMode intra_mode_start = FILTER_DC_PRED;
3367
0
    FilterIntraMode intra_mode_end   = ctx->intra_ctrls.intra_mode_end == PAETH_PRED ? FILTER_PAETH_PRED
3368
0
        : ctx->intra_ctrls.intra_mode_end >= D157_PRED                               ? FILTER_D157_PRED
3369
0
        : ctx->intra_ctrls.intra_mode_end >= H_PRED                                  ? FILTER_H_PRED
3370
0
        : ctx->intra_ctrls.intra_mode_end >= V_PRED                                  ? FILTER_V_PRED
3371
0
                                                                                     : FILTER_DC_PRED;
3372
0
    intra_mode_end                   = MIN(intra_mode_end, ctx->filter_intra_ctrls.max_filter_intra_mode);
3373
3374
0
    const TxSize           tx_size_uv     = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3375
0
    uint32_t               cand_total_cnt = *candidate_total_cnt;
3376
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
3377
0
    FrameHeader*           frm_hdr        = &pcs->ppcs->frm_hdr;
3378
3379
0
    for (FilterIntraMode filter_intra_mode = intra_mode_start; filter_intra_mode <= intra_mode_end;
3380
0
         filter_intra_mode++) {
3381
0
        ModeDecisionCandidate* cand              = &cand_array[cand_total_cnt];
3382
0
        cand->skip_mode_allowed                  = false;
3383
0
        cand->block_mi.mode                      = DC_PRED;
3384
0
        cand->block_mi.use_intrabc               = 0;
3385
0
        cand->block_mi.filter_intra_mode         = filter_intra_mode;
3386
0
        cand->palette_info                       = NULL;
3387
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3388
3389
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[fimode_to_intramode[filter_intra_mode]]
3390
0
                                                   : intra_luma_to_chroma[fimode_to_intramode[filter_intra_mode]];
3391
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail
3392
0
            ? ctx->best_uv_angle[fimode_to_intramode[filter_intra_mode]]
3393
0
            : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3394
3395
0
        cand->block_mi.cfl_alpha_signs = 0;
3396
0
        cand->block_mi.cfl_alpha_idx   = 0;
3397
0
        cand->transform_type[0]        = DCT_DCT;
3398
0
        cand->transform_type_uv        = svt_aom_get_intra_uv_tx_type(
3399
0
            cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3400
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3401
0
            continue;
3402
0
        }
3403
0
        cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3404
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3405
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3406
0
        cand->block_mi.is_interintra_used = 0;
3407
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3408
0
    }
3409
3410
    // update the total number of candidates injected
3411
0
    (*candidate_total_cnt) = cand_total_cnt;
3412
3413
0
    return;
3414
0
}
3415
3416
static void inject_zz_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3417
0
                                       uint32_t* candidate_total_cnt) {
3418
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3419
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3420
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3421
0
    cand_array[cand_total_cnt].drl_index   = 0;
3422
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3423
0
                                    svt_get_ref_frame_type(REF_LIST_0, 0),
3424
0
                                    NEWMV,
3425
0
                                    (Mv){{0}},
3426
0
                                    (Mv){{0}},
3427
0
                                    &cand_array[cand_total_cnt].drl_index,
3428
0
                                    best_pred_mv);
3429
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3430
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3431
0
        cand->block_mi.use_intrabc        = 0;
3432
0
        cand->skip_mode_allowed           = false;
3433
0
        cand->block_mi.mode               = NEWMV;
3434
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3435
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3436
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_0, 0);
3437
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3438
0
        cand->transform_type[0]           = DCT_DCT;
3439
0
        cand->transform_type_uv           = DCT_DCT;
3440
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3441
0
        cand->block_mi.is_interintra_used = 0;
3442
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3443
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_0, 0)].num;
3444
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3445
        // update the total number of candidates injected
3446
0
        (*candidate_total_cnt) = cand_total_cnt;
3447
0
    }
3448
0
}
3449
3450
1.44M
int svt_av1_allow_palette(int allow_palette, BlockSize bsize) {
3451
#if !CONFIG_ENABLE_PALETTE
3452
    (void)allow_palette;
3453
    (void)bsize;
3454
    return 0;
3455
#else
3456
1.44M
    assert(bsize < BLOCK_SIZES_ALL);
3457
1.44M
    return allow_palette && block_size_wide[bsize] <= 64 && block_size_high[bsize] <= 64 && bsize >= BLOCK_8X8;
3458
1.44M
#endif
3459
1.44M
}
3460
3461
void search_palette_luma(PictureControlSet* pcs, ModeDecisionContext* ctx, PaletteInfo* palette_cand,
3462
                         uint8_t* palette_size_array, uint32_t* tot_palette_cands);
3463
3464
#if FTR_RTC_INTER_PALETTE
3465
// Per-pixel ME-residual floor at or below which an inter block is treated as unchanged content and
3466
// the palette search is skipped: palette cannot beat a ~0-bit zero-MV skip there.
3467
0
#define RTC_INTER_PALETTE_RES_FLOOR 4
3468
#endif
3469
3470
0
static void inject_palette_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt) {
3471
0
#if FTR_RTC_INTER_PALETTE
3472
    // Skip the palette search on inter blocks where inter prediction is essentially perfect; if
3473
    // neither ME nor PME distortion is available the search still runs. Returning with no candidates
3474
    // injected also clears eval_intrabc in generate_md_stage_0_cand when intrabc_ctrls.palette_hint
3475
    // is set - inert on this path (intrabc_level is 0 in RTC, and intra-BC only exists on intra
3476
    // frames), but relevant if palette_hint ever extends to inter frames.
3477
0
    if (pcs->slice_type != I_SLICE) {
3478
0
        uint32_t best_me = (uint32_t)~0;
3479
0
        if (ctx->md_me_dist != (uint32_t)~0) {
3480
0
            best_me = ctx->md_me_dist;
3481
0
        }
3482
0
        if (ctx->md_pme_dist != (uint32_t)~0 && ctx->md_pme_dist < best_me) {
3483
0
            best_me = ctx->md_pme_dist;
3484
0
        }
3485
0
        if (best_me != (uint32_t)~0) {
3486
0
            const uint32_t per_pix = best_me / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight);
3487
0
            if (per_pix <= RTC_INTER_PALETTE_RES_FLOOR) {
3488
0
                return;
3489
0
            }
3490
0
        }
3491
0
    }
3492
0
#endif
3493
0
    uint32_t               can_total_cnt      = *candidate_total_cnt;
3494
0
    ModeDecisionCandidate* cand_array         = ctx->fast_cand_array;
3495
0
    const TxSize           tx_size_uv         = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3496
0
    uint32_t               tot_palette_cands  = 0;
3497
0
    PaletteInfo*           palette_cand_array = ctx->palette_cand_array;
3498
    // MD palette search
3499
0
    uint8_t* palette_size_array_0 = ctx->palette_size_array_0;
3500
3501
0
    search_palette_luma(pcs, ctx, palette_cand_array, palette_size_array_0, &tot_palette_cands);
3502
3503
0
    for (uint32_t cand_i = 0; cand_i < tot_palette_cands; ++cand_i) {
3504
0
        ModeDecisionCandidate* cand       = &cand_array[can_total_cnt];
3505
0
        cand->block_mi.is_interintra_used = 0;
3506
0
        cand->palette_size[0]             = palette_size_array_0[cand_i];
3507
        // Palette is not supported for chroma
3508
0
        cand->palette_size[1] = 0;
3509
0
        cand->palette_info    = &palette_cand_array[cand_i];
3510
0
        assert(palette_size_array_0[cand_i] < 9);
3511
        //to re check these fields
3512
0
        cand->skip_mode_allowed    = false;
3513
0
        cand->block_mi.mode        = DC_PRED;
3514
0
        cand->block_mi.use_intrabc = 0;
3515
3516
0
        cand->block_mi.filter_intra_mode         = FILTER_INTRA_MODES;
3517
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3518
        // Palette is not supported for chroma mode, so we can set the intra chroma mode to anything. To use palette
3519
        // for chroma, we must force DC_PRED to be used for the intra chroma mode
3520
0
        assert(cand_array[can_total_cnt].palette_size[1] == 0);
3521
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[DC_PRED] : intra_luma_to_chroma[DC_PRED];
3522
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[DC_PRED]
3523
0
                                                                      : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3524
0
        cand->block_mi.cfl_alpha_signs            = 0;
3525
0
        cand->block_mi.cfl_alpha_idx              = 0;
3526
0
        cand->transform_type[0]                   = DCT_DCT;
3527
0
        cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3528
0
            cand->block_mi.uv_mode, tx_size_uv, pcs->ppcs->frm_hdr.reduced_tx_set);
3529
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3530
0
            continue;
3531
0
        }
3532
0
        cand->block_mi.ref_frame[0] = INTRA_FRAME;
3533
0
        cand->block_mi.ref_frame[1] = NONE_FRAME;
3534
0
        cand->block_mi.motion_mode  = SIMPLE_TRANSLATION;
3535
0
        INC_MD_CAND_CNT(can_total_cnt, pcs->ppcs->max_can_count);
3536
0
    }
3537
3538
    // update the total number of candidates injected
3539
0
    (*candidate_total_cnt) = can_total_cnt;
3540
3541
0
    return;
3542
0
}
3543
3544
0
static INLINE void eliminate_candidate_based_on_pme_me_results(ModeDecisionContext* ctx, uint8_t* dc_cand_only_flag) {
3545
0
    if (ctx->md_pme_dist != (uint32_t)~0 || ctx->md_me_dist != (uint32_t)~0) {
3546
0
        uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3547
0
        th *= ctx->blk_geom->bheight * ctx->blk_geom->bwidth;
3548
0
        const uint32_t best_me_distotion = MIN(ctx->md_pme_dist, ctx->md_me_dist);
3549
0
        if (best_me_distotion < th) {
3550
0
            *dc_cand_only_flag = 1;
3551
0
        }
3552
0
    }
3553
0
}
3554
3555
static bool valid_ref_frame_type(MvReferenceFrame rf[2], const MvReferenceFrame ref_frame_type_arr[],
3556
0
                                 uint8_t tot_ref_frame_types) {
3557
    // INTRA_FRAME is added in candidates sometimes, skip validation
3558
0
    if (rf[0] == INTRA_FRAME) {
3559
0
        return true;
3560
0
    }
3561
3562
0
    for (uint8_t i = 0; i < tot_ref_frame_types; i++) {
3563
0
        MvReferenceFrame rf_in_arr[2];
3564
0
        av1_set_ref_frame(rf_in_arr, ref_frame_type_arr[i]);
3565
0
        if (rf[0] == rf_in_arr[0] && rf[1] == rf_in_arr[1]) {
3566
0
            return true;
3567
0
        }
3568
0
    }
3569
0
    return false;
3570
0
}
3571
3572
// refer to inject_zz_backup_candidate, but use BWD ref instead of LAST
3573
static void inject_sframe_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3574
0
                                           uint32_t* candidate_total_cnt) {
3575
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3576
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3577
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3578
0
    cand_array[cand_total_cnt].drl_index   = 0;
3579
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3580
0
                                    svt_get_ref_frame_type(REF_LIST_1, 0),
3581
0
                                    NEWMV,
3582
0
                                    (Mv){{0}},
3583
0
                                    (Mv){{0}},
3584
0
                                    &cand_array[cand_total_cnt].drl_index,
3585
0
                                    best_pred_mv);
3586
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3587
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3588
0
        cand->block_mi.use_intrabc        = 0;
3589
0
        cand->skip_mode_allowed           = false;
3590
0
        cand->block_mi.mode               = NEWMV;
3591
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3592
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3593
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_1, 0);
3594
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3595
0
        cand->transform_type[0]           = DCT_DCT;
3596
0
        cand->transform_type_uv           = DCT_DCT;
3597
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3598
0
        cand->block_mi.is_interintra_used = 0;
3599
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3600
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_1, 0)].num;
3601
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3602
        // update the total number of candidates injected
3603
0
        (*candidate_total_cnt) = cand_total_cnt;
3604
0
    }
3605
0
}
3606
3607
// in MD stage 0, candidates are injected by different tools, but for S-Frame in RA mode
3608
// the ref frame types in ref_list0 has be pruned in PD for the reversed direction of ref MVs
3609
// here to check and reject the candidates if mismatches the available frame types array
3610
0
static uint32_t reject_candidate_sframe(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t cand_total_cnt) {
3611
0
    for (uint32_t i = 0; i < cand_total_cnt;) {
3612
0
        if (!valid_ref_frame_type(
3613
0
                ctx->fast_cand_array[i].block_mi.ref_frame, ctx->ref_frame_type_arr, ctx->tot_ref_frame_types)) {
3614
0
            for (uint32_t j = i; j < cand_total_cnt; j++) {
3615
0
                memcpy(&ctx->fast_cand_array[j], &ctx->fast_cand_array[j + 1], sizeof(ModeDecisionCandidate));
3616
0
            }
3617
0
            cand_total_cnt--;
3618
0
            continue;
3619
0
        }
3620
0
        i++;
3621
0
    }
3622
    // zero candidate in fast cand array risks in md stage 0, add a candidate from ref list1 as backup
3623
0
    if (cand_total_cnt == 0) {
3624
0
        inject_sframe_backup_candidate(pcs, ctx, &cand_total_cnt);
3625
0
    }
3626
0
    assert(cand_total_cnt > 0);
3627
0
    return cand_total_cnt;
3628
0
}
3629
3630
EbErrorType generate_md_stage_0_cand_pd0(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3631
207k
                                         PictureControlSet* pcs) {
3632
207k
    const SliceType slice_type     = pcs->slice_type;
3633
207k
    uint32_t        cand_total_cnt = 0;
3634
    //----------------------
3635
    // Intra
3636
207k
    if (ctx->blk_geom->sq_size < 128 && ctx->intra_ctrls.enable_intra) {
3637
207k
        inject_intra_candidates_pd0(pcs, ctx, &cand_total_cnt);
3638
207k
    }
3639
3640
207k
    if (slice_type != I_SLICE) {
3641
0
        inject_inter_candidates_pd0(pcs, ctx, &cand_total_cnt);
3642
0
    }
3643
3644
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_stage_0()
3645
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3646
207k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3647
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3648
0
    }
3649
3650
207k
    if (pcs->ppcs->sframe_ref_pruned) {
3651
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3652
0
    }
3653
3654
207k
    *candidate_total_count_ptr = cand_total_cnt;
3655
3656
207k
    return EB_ErrorNone;
3657
207k
}
3658
3659
/*
3660
   generate candidates for light pd1
3661
*/
3662
void generate_md_stage_0_cand_light_pd1(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3663
0
                                        PictureControlSet* pcs) {
3664
0
    const SliceType slice_type     = pcs->slice_type;
3665
0
    uint32_t        cand_total_cnt = 0;
3666
    // Reset duplicates variables
3667
0
    ctx->injected_mv_count = 0;
3668
0
    ctx->inject_new_me     = 1;
3669
0
    if (slice_type != I_SLICE) {
3670
0
        inject_inter_candidates_light_pd1(pcs, ctx, &cand_total_cnt);
3671
0
    }
3672
    //----------------------
3673
    // Intra
3674
0
    if (ctx->intra_ctrls.enable_intra && ctx->blk_geom->sq_size < 128) {
3675
0
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3676
0
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled && !dc_cand_only_flag &&
3677
0
            ctx->md_me_dist != (uint32_t)~0) {
3678
0
            uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3679
0
            th *= (ctx->blk_geom->bheight * ctx->blk_geom->bwidth);
3680
0
            if (ctx->md_me_dist < th) {
3681
0
                dc_cand_only_flag = 1;
3682
0
            }
3683
0
        }
3684
0
        inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3685
0
    }
3686
3687
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3688
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3689
0
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3690
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3691
0
    }
3692
3693
0
    if (pcs->ppcs->sframe_ref_pruned) {
3694
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3695
0
    }
3696
3697
0
    *candidate_total_count_ptr = cand_total_cnt;
3698
0
}
3699
3700
EbErrorType generate_md_stage_0_cand(PictureControlSet* pcs, ModeDecisionContext* ctx, const PC_TREE* const pc_tree,
3701
206k
                                     uint32_t* candidate_total_count_ptr) {
3702
206k
    const SequenceControlSet* scs            = pcs->scs;
3703
206k
    const SliceType           slice_type     = pcs->slice_type;
3704
206k
    uint32_t                  cand_total_cnt = 0;
3705
    // Reset duplicates variables
3706
206k
    ctx->injected_mv_count = 0;
3707
206k
    ctx->inject_new_me     = 1;
3708
206k
    ctx->inject_new_pme    = 1;
3709
    //----------------------
3710
    // Intra
3711
206k
    if (ctx->intra_ctrls.enable_intra) {
3712
206k
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3713
206k
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled) {
3714
0
            eliminate_candidate_based_on_pme_me_results(ctx, &dc_cand_only_flag);
3715
0
        }
3716
207k
        if (ctx->blk_geom->sq_size < 128) {
3717
207k
            inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3718
207k
        }
3719
206k
        if (ctx->filter_intra_ctrls.enabled && svt_aom_filter_intra_allowed_bsize(ctx->blk_geom->bsize)) {
3720
0
            inject_filter_intra_candidates(pcs, ctx, &cand_total_cnt);
3721
0
        }
3722
3723
206k
        bool eval_intrabc = true;
3724
3725
206k
        if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
3726
0
            uint32_t palette_start_cnt = cand_total_cnt;
3727
3728
0
            inject_palette_candidates(pcs, ctx, &cand_total_cnt);
3729
3730
0
            eval_intrabc = cand_total_cnt > palette_start_cnt;
3731
0
        }
3732
3733
206k
#if CONFIG_ENABLE_INTRA_BC || !MOBILE_BUILD
3734
206k
        if (ctx->md_allow_intrabc) {
3735
0
            if (!pcs->ppcs->intrabc_ctrls.palette_hint || eval_intrabc) {
3736
0
                bool do_intra_bc = true;
3737
3738
0
                if (ctx->shape == PART_N) {
3739
0
                    if (pcs->ppcs->intrabc_ctrls.b4_parent_gating && ctx->blk_geom->sq_size == 4 &&
3740
0
                        pc_tree->parent->tested_blk[PART_N][0]) {
3741
0
                        if (pc_tree->parent->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3742
0
                            do_intra_bc = false;
3743
0
                        }
3744
0
                    }
3745
0
                } else {
3746
0
                    if (pcs->ppcs->intrabc_ctrls.nsq_parent_gating && pc_tree->tested_blk[PART_N][0]) {
3747
0
                        if (pc_tree->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3748
0
                            do_intra_bc = false;
3749
0
                        }
3750
0
                    }
3751
0
                }
3752
3753
0
                if (do_intra_bc) {
3754
0
                    inject_intra_bc_candidates(pcs, ctx, scs, ctx->blk_ptr, &cand_total_cnt);
3755
0
                }
3756
0
            }
3757
0
        }
3758
#else
3759
        (void)scs;
3760
        (void)pc_tree;
3761
        (void)eval_intrabc;
3762
#endif
3763
206k
    }
3764
206k
    if (slice_type != I_SLICE) {
3765
0
        svt_aom_inject_inter_candidates(pcs, ctx, &cand_total_cnt);
3766
0
    }
3767
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3768
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3769
206k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3770
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3771
0
    }
3772
3773
206k
    if (pcs->ppcs->sframe_ref_pruned) {
3774
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3775
0
    }
3776
3777
206k
    *candidate_total_count_ptr = cand_total_cnt;
3778
3779
206k
    memset(ctx->md_stage_0_count, 0, CAND_CLASS_TOTAL * sizeof(uint32_t));
3780
206k
    bool merge_inter_cands = 0;
3781
206k
    if (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult != (uint8_t)~0) {
3782
205k
        uint16_t th = (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult * (63 - pcs->scs->static_config.qp)) >> 1;
3783
205k
        if ((MIN(ctx->md_me_dist, ctx->md_pme_dist) / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight)) < th) {
3784
199k
            merge_inter_cands = 1;
3785
199k
        }
3786
205k
    }
3787
3788
412k
    for (uint32_t cand_i = 0; cand_i < cand_total_cnt; cand_i++) {
3789
205k
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_i];
3790
205k
        if (is_intra_mode(cand->block_mi.mode)) {
3791
            // Intra prediction
3792
205k
            if ((cand->palette_info == NULL || cand->palette_size[0] == 0) && cand->block_mi.use_intrabc == 0) {
3793
205k
                cand->cand_class = CAND_CLASS_0;
3794
205k
                ctx->md_stage_0_count[CAND_CLASS_0]++;
3795
205k
            } else if (cand->block_mi.use_intrabc == 0) {
3796
                // Palette Prediction
3797
0
                cand->cand_class = CAND_CLASS_3;
3798
0
                ctx->md_stage_0_count[CAND_CLASS_3]++;
3799
63
            } else {
3800
                // Intra-BC Prediction
3801
63
                cand->cand_class = CAND_CLASS_4;
3802
63
                ctx->md_stage_0_count[CAND_CLASS_4]++;
3803
63
            }
3804
18.4E
        } else { // INTER
3805
18.4E
            if (cand->block_mi.mode == NEWMV || cand->block_mi.mode == NEW_NEWMV || merge_inter_cands) {
3806
                // MV Prediction
3807
0
                cand->cand_class = CAND_CLASS_2;
3808
0
                ctx->md_stage_0_count[CAND_CLASS_2]++;
3809
18.4E
            } else {
3810
                //MVP Prediction
3811
18.4E
                cand->cand_class = CAND_CLASS_1;
3812
18.4E
                ctx->md_stage_0_count[CAND_CLASS_1]++;
3813
18.4E
            }
3814
18.4E
        }
3815
205k
    }
3816
206k
    return EB_ErrorNone;
3817
206k
}
3818
3819
uint8_t av1_drl_ctx(const CandidateMv* ref_mv_stack, int32_t ref_idx);
3820
3821
/***************************************
3822
* Update symbols for light-PD1 path
3823
***************************************/
3824
void svt_aom_product_full_mode_decision_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
3825
0
                                                  ModeDecisionCandidateBuffer* cand_bf) {
3826
0
    BlkStruct*             blk_ptr = ctx->blk_ptr;
3827
0
    ModeDecisionCandidate* cand    = cand_bf->cand;
3828
0
    blk_ptr->total_rate            = cand_bf->total_rate;
3829
3830
    // Set common signals (INTER/INTRA)
3831
0
    memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3832
0
    blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3833
3834
    // Set INTER mode signals
3835
0
    if (is_inter_mode(cand->block_mi.mode)) {
3836
0
        blk_ptr->drl_index = cand->drl_index;
3837
0
        assert(IMPLIES(
3838
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3839
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3840
3841
        // Set MVs
3842
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3843
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3844
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3845
0
        }
3846
3847
0
        const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3848
        // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3849
0
        blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3850
        // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3851
0
        if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3852
0
            for (uint8_t idx = 0; idx < 2; ++idx) {
3853
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3854
0
                    blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3855
0
                } else {
3856
0
                    blk_ptr->drl_ctx[idx] = -1;
3857
0
                }
3858
0
            }
3859
0
        }
3860
3861
0
        if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3862
            // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3863
0
            for (uint8_t idx = 1; idx < 3; ++idx) {
3864
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3865
0
                    blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3866
0
                } else {
3867
0
                    blk_ptr->drl_ctx_near[idx - 1] = -1;
3868
0
                }
3869
0
            }
3870
0
        }
3871
0
    } else { // Set INTRA mode signals
3872
0
        cand->skip_mode_allowed = false;
3873
0
    }
3874
    // Set TX and coeff-related data
3875
0
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
3876
0
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
3877
3878
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
3879
0
    if (cand->skip_mode_allowed == true) {
3880
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
3881
0
    }
3882
3883
0
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
3884
0
                   cand->block_mi.interp_filters == 0));
3885
0
    if (blk_ptr->block_mi.skip_mode) {
3886
0
        blk_ptr->block_has_coeff = 0;
3887
0
        cand_bf->y_has_coeff     = 0;
3888
0
        cand_bf->u_has_coeff     = 0;
3889
0
        cand_bf->v_has_coeff     = 0;
3890
0
    }
3891
0
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
3892
3893
0
    const uint16_t txb_itr       = 0;
3894
0
    const int32_t  txb_1d_offset = 0, txb_1d_offset_uv = 0;
3895
0
    blk_ptr->y_has_coeff         = cand_bf->y_has_coeff;
3896
0
    blk_ptr->u_has_coeff         = cand_bf->u_has_coeff;
3897
0
    blk_ptr->v_has_coeff         = cand_bf->v_has_coeff;
3898
0
    blk_ptr->tx_type[txb_itr]    = cand->transform_type[txb_itr];
3899
0
    blk_ptr->tx_type_uv          = cand->transform_type_uv;
3900
0
    blk_ptr->quant_dc.y[txb_itr] = cand_bf->quant_dc.y[txb_itr];
3901
0
    blk_ptr->quant_dc.u[txb_itr] = cand_bf->quant_dc.u[txb_itr];
3902
0
    blk_ptr->quant_dc.v[txb_itr] = cand_bf->quant_dc.v[txb_itr];
3903
3904
0
    if (ctx->bypass_encdec) {
3905
0
        blk_ptr->eob.y[txb_itr] = cand_bf->eob.y[txb_itr];
3906
0
        blk_ptr->eob.u[txb_itr] = cand_bf->eob.u[txb_itr];
3907
0
        blk_ptr->eob.v[txb_itr] = cand_bf->eob.v[txb_itr];
3908
0
        int32_t* src_ptr;
3909
0
        int32_t* dst_ptr;
3910
3911
0
        const TxSize tx_size   = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
3912
0
        const int    tx_width  = tx_size_wide[tx_size];
3913
0
        const int    tx_height = tx_size_high[tx_size];
3914
3915
        // only one TX unit, so no need to bitmask
3916
0
        if (blk_ptr->y_has_coeff) {
3917
0
            src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
3918
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) + ctx->coded_area_sb;
3919
0
            memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
3920
0
        }
3921
0
        ctx->coded_area_sb += tx_width * tx_height;
3922
3923
0
        const TxSize tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3924
0
        const int    tx_width_uv  = tx_size_wide[tx_size_uv];
3925
0
        const int    tx_height_uv = tx_size_high[tx_size_uv];
3926
        // Cb
3927
        // only one TX unit, so no need to bitmask
3928
0
        if (blk_ptr->u_has_coeff) {
3929
0
            src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
3930
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
3931
0
                ctx->coded_area_sb_uv;
3932
0
            memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3933
0
        }
3934
3935
        // Cr
3936
        // only one TX unit, so no need to bitmask
3937
0
        if (blk_ptr->v_has_coeff) {
3938
0
            src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
3939
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
3940
0
                ctx->coded_area_sb_uv;
3941
0
            memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3942
0
        }
3943
0
        ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
3944
0
    }
3945
0
}
3946
3947
0
static INLINE double derive_ssim_threshold_factor_for_full_md(SequenceControlSet* scs) {
3948
0
    return scs->input_resolution >= INPUT_SIZE_1080p_RANGE ? 1.02 : 1.03;
3949
0
}
3950
3951
/***************************************
3952
* Full Mode Decision
3953
***************************************/
3954
uint32_t svt_aom_product_full_mode_decision(PictureControlSet* pcs, ModeDecisionContext* ctx,
3955
                                            ModeDecisionCandidateBuffer** buffer_ptr_array,
3956
207k
                                            uint32_t candidate_total_count, uint32_t* best_candidate_index_array) {
3957
207k
    SequenceControlSet* scs                = pcs->scs;
3958
207k
    BlkStruct*          blk_ptr            = ctx->blk_ptr;
3959
207k
    uint32_t            lowest_cost_index  = best_candidate_index_array[0];
3960
207k
    const bool          use_ssim_full_cost = ctx->tune_ssim_level > SSIM_LVL_0 ? true : false;
3961
3962
    // Find the candidate with the lowest cost
3963
    // Only need to sort if have multiple candidates
3964
207k
    if (ctx->md_stage_3_total_count > 1) {
3965
0
        if (use_ssim_full_cost) {
3966
            // Pass one: find candidate with the lowest SSD cost
3967
0
            uint64_t ssd_lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3968
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3969
0
                uint32_t cand_index = best_candidate_index_array[i];
3970
0
                uint64_t cost       = *(buffer_ptr_array[cand_index]->full_cost);
3971
0
                if (cost < ssd_lowest_cost) {
3972
0
                    lowest_cost_index = cand_index;
3973
0
                    ssd_lowest_cost   = cost;
3974
0
                }
3975
0
            }
3976
3977
            // Pass two: among the candidates with SSD cost not greater than the threshold, find the one with the lowest SSIM cost
3978
0
            const double   threshold_factor   = derive_ssim_threshold_factor_for_full_md(scs);
3979
0
            const uint64_t ssd_cost_threshold = (uint64_t)(threshold_factor * ssd_lowest_cost);
3980
0
            uint64_t       ssim_lowest_cost   = 0xFFFFFFFFFFFFFFFFull;
3981
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3982
0
                uint32_t cand_index = best_candidate_index_array[i];
3983
3984
0
                uint64_t ssim_cost = *(buffer_ptr_array[cand_index]->full_cost_ssim);
3985
0
                uint64_t ssd_cost  = *(buffer_ptr_array[cand_index]->full_cost);
3986
0
                if (ssim_cost < ssim_lowest_cost) {
3987
0
                    if (ssd_cost <= ssd_cost_threshold) {
3988
0
                        lowest_cost_index = cand_index;
3989
0
                        ssim_lowest_cost  = ssim_cost;
3990
0
                        ssd_lowest_cost   = ssd_cost;
3991
0
                    }
3992
0
                } else if (ssim_cost == ssim_lowest_cost) {
3993
                    // if two candidates have the same ssim cost, choose the one with lower ssd cost
3994
0
                    if (ssd_cost < ssd_lowest_cost) {
3995
0
                        lowest_cost_index = cand_index;
3996
0
                        ssd_lowest_cost   = ssd_cost;
3997
0
                    }
3998
0
                }
3999
0
            }
4000
0
        } else { // fallback to SSD based RD cost
4001
0
            uint64_t lowest_cost = 0xFFFFFFFFFFFFFFFFull;
4002
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
4003
0
                uint32_t cand_index = best_candidate_index_array[i];
4004
4005
0
                uint64_t cost = *(buffer_ptr_array[cand_index]->full_cost);
4006
0
                if (scs->vq_ctrls.sharpness_ctrls.unipred_bias && pcs->ppcs->is_noise_level &&
4007
0
                    is_inter_singleref_mode(buffer_ptr_array[cand_index]->cand->block_mi.mode)) {
4008
0
                    cost = (cost * uni_psy_bias[pcs->ppcs->picture_qp]) / 100;
4009
0
                }
4010
4011
0
                if (cost < lowest_cost) {
4012
0
                    lowest_cost_index = cand_index;
4013
0
                    lowest_cost       = cost;
4014
0
                }
4015
0
            }
4016
0
        }
4017
0
    }
4018
207k
    ModeDecisionCandidateBuffer* cand_bf = buffer_ptr_array[lowest_cost_index];
4019
207k
    ModeDecisionCandidate*       cand    = cand_bf->cand;
4020
207k
    blk_ptr->total_rate                  = cand_bf->total_rate;
4021
207k
    if (!(ctx->pd_pass == PD_PASS_1 && ctx->fixed_partition)) {
4022
        // When lambda tuning is on, lambda of each block is set separately, however at interdepth decision the sb lambda is used
4023
200k
        uint32_t full_lambda    = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_sb_lambda_md[EB_10_BIT_MD]
4024
200k
                                                                    : ctx->full_sb_lambda_md[EB_8_BIT_MD];
4025
200k
        ctx->blk_ptr->cost      = RDCOST(full_lambda, cand_bf->total_rate, cand_bf->full_dist);
4026
200k
        ctx->blk_ptr->full_dist = cand_bf->full_dist;
4027
200k
    }
4028
4029
    // Set common signals (INTER/INTRA)
4030
207k
    memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
4031
    // Set INTER mode signals
4032
    // INTER signals set first b/c INTER shuts Palette, so INTRA must overwrite if Palette + intrabc is used
4033
207k
    if (is_inter_block(&blk_ptr->block_mi)) {
4034
0
        blk_ptr->drl_index = cand->drl_index;
4035
0
        assert(IMPLIES(
4036
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
4037
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
4038
4039
0
        blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
4040
        // Set MVs
4041
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
4042
0
        if (has_second_ref(&blk_ptr->block_mi)) {
4043
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
4044
0
        }
4045
0
        if (blk_ptr->block_mi.motion_mode == WARPED_CAUSAL ||
4046
0
            (cand->block_mi.mode == GLOBALMV || cand->block_mi.mode == GLOBAL_GLOBALMV)) {
4047
0
            memcpy(&ctx->blk_ptr->wm_params_l0, &cand->wm_params_l0, sizeof(WarpedMotionParams));
4048
0
            memcpy(&ctx->blk_ptr->wm_params_l1, &cand->wm_params_l1, sizeof(WarpedMotionParams));
4049
0
        }
4050
4051
0
        if (ctx->pd_pass == PD_PASS_1) {
4052
0
            const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
4053
            // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
4054
0
            blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
4055
            // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
4056
0
            if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
4057
0
                for (uint8_t idx = 0; idx < 2; ++idx) {
4058
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
4059
0
                        blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
4060
0
                    } else {
4061
0
                        blk_ptr->drl_ctx[idx] = -1;
4062
0
                    }
4063
0
                }
4064
0
            }
4065
4066
0
            if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
4067
                // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
4068
0
                for (uint8_t idx = 1; idx < 3; ++idx) {
4069
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
4070
0
                        blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
4071
0
                    } else {
4072
0
                        blk_ptr->drl_ctx_near[idx - 1] = -1;
4073
0
                    }
4074
0
                }
4075
0
            }
4076
0
        }
4077
0
    }
4078
4079
    // Set INTRA mode signals
4080
207k
    if (is_intra_mode(blk_ptr->block_mi.mode)) {
4081
206k
        if (!cand->palette_info) {
4082
206k
            blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
4083
18.4E
        } else if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
4084
0
            memcpy(&blk_ptr->palette_info->pmi, &cand->palette_info->pmi, sizeof(PaletteModeInfo));
4085
0
            memcpy(blk_ptr->palette_info->color_idx_map, cand->palette_info->color_idx_map, MAX_PALETTE_SQUARE);
4086
0
            blk_ptr->palette_size[0] = cand->palette_size[0];
4087
0
            blk_ptr->palette_size[1] = cand->palette_size[1];
4088
0
        }
4089
4090
206k
        if (blk_ptr->block_mi.use_intrabc == 0) {
4091
206k
            cand->skip_mode_allowed = false;
4092
206k
        }
4093
206k
    }
4094
4095
    // Set TX and coeff-related data
4096
207k
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
4097
207k
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
4098
4099
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
4100
207k
    if (cand->skip_mode_allowed == true) {
4101
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
4102
0
    }
4103
4104
207k
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
4105
207k
                   cand->block_mi.interp_filters == 0));
4106
207k
    if (blk_ptr->block_mi.skip_mode) {
4107
0
        blk_ptr->block_has_coeff = 0;
4108
0
        cand_bf->y_has_coeff     = 0;
4109
0
        cand_bf->u_has_coeff     = 0;
4110
0
        cand_bf->v_has_coeff     = 0;
4111
0
    }
4112
4113
207k
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
4114
207k
    blk_ptr->y_has_coeff   = cand_bf->y_has_coeff;
4115
207k
    blk_ptr->u_has_coeff   = cand_bf->u_has_coeff;
4116
207k
    blk_ptr->v_has_coeff   = cand_bf->v_has_coeff;
4117
207k
    memcpy(blk_ptr->tx_type, cand->transform_type, sizeof(TxType) * MAX_TXB_COUNT);
4118
207k
    blk_ptr->tx_type_uv = cand->transform_type_uv;
4119
207k
    memcpy(&blk_ptr->quant_dc, &cand_bf->quant_dc, sizeof(QuantDcData));
4120
207k
    memcpy(&blk_ptr->eob, &cand_bf->eob, sizeof(EobData));
4121
4122
    // If bypassing EncDec, save recon/coeff
4123
207k
    if (ctx->bypass_encdec && ctx->pd_pass == PD_PASS_1) {
4124
206k
        const uint16_t tu_total_count = tx_blocks_per_depth[ctx->blk_geom->bsize][blk_ptr->block_mi.tx_depth];
4125
206k
        int32_t        txb_1d_offset = 0, txb_1d_offset_uv = 0;
4126
206k
        const TxSize   tx_size      = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
4127
206k
        const int      tx_width     = tx_size_wide[tx_size];
4128
206k
        const int      tx_height    = tx_size_high[tx_size];
4129
206k
        const TxSize   tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
4130
206k
        const int      tx_width_uv  = tx_size_wide[tx_size_uv];
4131
206k
        const int      tx_height_uv = tx_size_high[tx_size_uv];
4132
999k
        for (uint16_t txb_itr = 0; txb_itr < tu_total_count; txb_itr++) {
4133
793k
            const bool uv_pass = (blk_ptr->block_mi.tx_depth == 0 || txb_itr == 0);
4134
4135
793k
            int32_t* src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
4136
793k
            int32_t* dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->y_buffer)[txb_1d_offset]);
4137
4138
793k
            if (ctx->fixed_partition) {
4139
7.10k
                dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) +
4140
7.10k
                    ctx->coded_area_sb;
4141
7.10k
                ctx->coded_area_sb += tx_width * tx_height;
4142
7.10k
            }
4143
4144
793k
            if (blk_ptr->y_has_coeff & (1 << txb_itr)) {
4145
6.58k
                memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
4146
6.58k
            }
4147
4148
793k
            txb_1d_offset += tx_width * tx_height;
4149
4150
793k
            if (ctx->has_uv && uv_pass) {
4151
                // Cb
4152
206k
                src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
4153
206k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->u_buffer)[txb_1d_offset_uv]);
4154
4155
206k
                if (ctx->fixed_partition) {
4156
7.10k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
4157
7.10k
                        ctx->coded_area_sb_uv;
4158
7.10k
                }
4159
4160
206k
                if (blk_ptr->u_has_coeff & (1 << txb_itr)) {
4161
6.65k
                    memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4162
6.65k
                }
4163
4164
                // Cr
4165
206k
                src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
4166
206k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->v_buffer)[txb_1d_offset_uv]);
4167
4168
206k
                if (ctx->fixed_partition) {
4169
7.10k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
4170
7.10k
                        ctx->coded_area_sb_uv;
4171
7.10k
                    ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
4172
7.10k
                }
4173
4174
206k
                if (blk_ptr->v_has_coeff & (1 << txb_itr)) {
4175
6.64k
                    memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4176
6.64k
                }
4177
4178
206k
                txb_1d_offset_uv += tx_width_uv * tx_height_uv;
4179
206k
            }
4180
793k
        }
4181
206k
    }
4182
4183
207k
    return lowest_cost_index;
4184
207k
}
4185
4186
// Return the end column for the current superblock, in unit of TPL blocks.
4187
0
static int get_superblock_tpl_column_end(PictureParentControlSet* ppcs, int mi_col, int num_mi_w) {
4188
0
    const int mib_size_log2 = ppcs->scs->seq_header.sb_size == BLOCK_128X128 ? 5 : 4;
4189
    // Find the start column of this superblock.
4190
0
    const int sb_mi_col_start = (mi_col >> mib_size_log2) << mib_size_log2;
4191
    // Same but in superres upscaled dimension.
4192
0
    const int sb_mi_col_start_sr = coded_to_superres_mi(sb_mi_col_start, ppcs->superres_denom);
4193
    // Width of this superblock in mi units.
4194
0
    const int sb_mi_width = mi_size_wide[ppcs->scs->seq_header.sb_size];
4195
    // Same but in superres upscaled dimension.
4196
0
    const int sb_mi_width_sr = coded_to_superres_mi(sb_mi_width, ppcs->superres_denom);
4197
    // Superblock end in mi units.
4198
0
    const int sb_mi_end = sb_mi_col_start_sr + sb_mi_width_sr;
4199
    // Superblock end in TPL units.
4200
0
    return (sb_mi_end + num_mi_w - 1) / num_mi_w;
4201
0
}
4202
4203
0
void aom_av1_set_ssim_rdmult(ModeDecisionContext* ctx, PictureControlSet* pcs, const int mi_row, const int mi_col) {
4204
0
    const Av1Common* const cm    = pcs->ppcs->av1_cm;
4205
0
    BlockSize              bsize = ctx->blk_geom->bsize;
4206
4207
0
    const int bsize_base = BLOCK_16X16;
4208
0
    const int num_mi_w   = mi_size_wide[bsize_base];
4209
0
    const int num_mi_h   = mi_size_high[bsize_base];
4210
0
    const int num_cols   = (cm->mi_cols + num_mi_w - 1) / num_mi_w;
4211
0
    const int num_rows   = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4212
0
    const int num_bcols  = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w;
4213
0
    const int num_brows  = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4214
0
    int       row, col;
4215
0
    double    num_of_mi          = 0.0;
4216
0
    double    geom_mean_of_scale = 1.0;
4217
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4218
0
        for (col = mi_col / num_mi_h; col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) {
4219
0
            const int index = row * num_cols + col;
4220
0
            geom_mean_of_scale *= pcs->ppcs->pa_me_data->ssim_rdmult_scaling_factors[index];
4221
0
            num_of_mi += 1.0;
4222
0
        }
4223
0
    }
4224
0
    geom_mean_of_scale = pow(geom_mean_of_scale, (1.0 / num_of_mi));
4225
0
    if (!pcs->ppcs->blk_lambda_tuning) {
4226
0
        ctx->full_lambda_md[EB_8_BIT_MD] =
4227
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4228
0
        ctx->full_lambda_md[EB_10_BIT_MD] =
4229
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4230
4231
0
        ctx->fast_lambda_md[EB_8_BIT_MD] =
4232
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4233
0
        ctx->fast_lambda_md[EB_10_BIT_MD] =
4234
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4235
0
    } else {
4236
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->full_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4237
0
                                                       0.5);
4238
0
        ctx->full_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->full_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4239
0
                                                       0.5);
4240
4241
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->fast_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4242
0
                                                       0.5);
4243
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->fast_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4244
0
                                                       0.5);
4245
0
    }
4246
0
}
4247
4248
0
void svt_aom_set_tuned_blk_lambda(ModeDecisionContext* ctx, PictureControlSet* pcs) {
4249
0
    PictureParentControlSet* ppcs = pcs->ppcs;
4250
0
    Av1Common*               cm   = ppcs->av1_cm;
4251
4252
0
    BlockSize bsize  = ctx->blk_geom->bsize;
4253
0
    int       mi_row = ctx->blk_org_y / 4;
4254
0
    int       mi_col = ctx->blk_org_x / 4;
4255
4256
0
    const int mi_col_sr         = coded_to_superres_mi(mi_col, ppcs->superres_denom);
4257
0
    const int mi_cols_sr        = ((ppcs->enhanced_unscaled_pic->width + 15) / 16) << 2; // picture column boundary
4258
0
    const int block_mi_width_sr = coded_to_superres_mi(mi_size_wide[bsize], ppcs->superres_denom);
4259
0
    const int bsize_base        = ppcs->tpl_ctrls.synth_blk_size == 32 ? BLOCK_32X32 : BLOCK_16X16;
4260
0
    const int num_mi_w          = mi_size_wide[bsize_base];
4261
0
    const int num_mi_h          = mi_size_high[bsize_base];
4262
0
    const int num_cols          = (mi_cols_sr + num_mi_w - 1) / num_mi_w;
4263
0
    const int num_rows          = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4264
0
    const int num_bcols         = (block_mi_width_sr + num_mi_w - 1) / num_mi_w;
4265
0
    const int num_brows         = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4266
4267
    // This is required because the end col of superblock may be off by 1 in case
4268
    // of superres.
4269
0
    const int sb_bcol_end = get_superblock_tpl_column_end(ppcs, mi_col, num_mi_w);
4270
0
    int       row, col;
4271
0
    int32_t   base_block_count   = 0;
4272
0
    double    geom_mean_of_scale = 0.0;
4273
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4274
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;
4275
0
             ++col) {
4276
0
            const int index = row * num_cols + col;
4277
0
            geom_mean_of_scale += log(ppcs->pa_me_data->tpl_sb_rdmult_scaling_factors[index]);
4278
0
            ++base_block_count;
4279
0
        }
4280
0
    }
4281
    // When superres is on, base_block_count could be zero.
4282
    // This function's counterpart in AOM, av1_get_hier_tpl_rdmult, will encounter division by zero
4283
0
    if (base_block_count == 0) {
4284
        // return a large number to indicate invalid state
4285
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4286
0
        ctx->full_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4287
4288
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4289
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4290
0
        return;
4291
0
    }
4292
4293
0
    geom_mean_of_scale = exp(geom_mean_of_scale / base_block_count);
4294
4295
0
    ctx->full_lambda_md[EB_8_BIT_MD] =
4296
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4297
0
    ctx->full_lambda_md[EB_10_BIT_MD] =
4298
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4299
4300
0
    ctx->fast_lambda_md[EB_8_BIT_MD] =
4301
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4302
0
    ctx->fast_lambda_md[EB_10_BIT_MD] =
4303
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4304
0
    if (ppcs->scs->static_config.tune == TUNE_SSIM || ppcs->scs->static_config.tune == TUNE_IQ ||
4305
0
        ppcs->scs->static_config.tune == TUNE_MS_SSIM) {
4306
0
        aom_av1_set_ssim_rdmult(ctx, pcs, mi_row, mi_col);
4307
0
    }
4308
0
}
4309
4310
0
double svt_ssim_4x4_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4311
0
    const int32_t count = 4 * 4;
4312
4313
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4314
0
    uint32_t i, j;
4315
0
    for (i = 0; i < 4; i++) {
4316
0
        for (j = 0; j < 4; j++) {
4317
0
            sum_s += s[j];
4318
0
            sum_r += r[j];
4319
0
            sum_sq_s += s[j] * s[j];
4320
0
            sum_sq_r += r[j] * r[j];
4321
0
            sum_sxr += s[j] * r[j];
4322
0
        }
4323
4324
0
        s += sp;
4325
0
        r += rp;
4326
0
    }
4327
4328
    //
4329
    // similarity
4330
    //
4331
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4332
0
    return score;
4333
0
}
4334
4335
0
double svt_ssim_8x8_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4336
0
    const int32_t count = 8 * 8;
4337
4338
    //
4339
    // is similar to svt_aom_ssim_parms_8x8_c, but supports MxN block size
4340
    //
4341
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4342
0
    uint32_t i, j;
4343
0
    for (i = 0; i < 8; i++) {
4344
0
        for (j = 0; j < 8; j++) {
4345
0
            sum_s += s[j];
4346
0
            sum_r += r[j];
4347
0
            sum_sq_s += s[j] * s[j];
4348
0
            sum_sq_r += r[j] * r[j];
4349
0
            sum_sxr += s[j] * r[j];
4350
0
        }
4351
4352
0
        s += sp;
4353
0
        r += rp;
4354
0
    }
4355
4356
    //
4357
    // similarity
4358
    //
4359
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4360
0
    return score;
4361
0
}
4362
4363
0
double svt_ssim_4x4_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4364
0
    const int32_t count = 4 * 4;
4365
4366
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4367
0
    uint32_t i, j;
4368
0
    for (i = 0; i < 4; i++) {
4369
0
        for (j = 0; j < 4; j++) {
4370
0
            sum_s += s[j];
4371
0
            sum_r += r[j];
4372
0
            sum_sq_s += s[j] * s[j];
4373
0
            sum_sq_r += r[j] * r[j];
4374
0
            sum_sxr += s[j] * r[j];
4375
0
        }
4376
4377
0
        s += sp;
4378
0
        r += rp;
4379
0
    }
4380
4381
    //
4382
    // similarity
4383
    //
4384
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4385
0
    return score;
4386
0
}
4387
4388
0
double svt_ssim_8x8_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4389
0
    const int32_t count = 8 * 8;
4390
4391
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4392
0
    uint32_t i, j;
4393
0
    for (i = 0; i < 8; i++) {
4394
0
        for (j = 0; j < 8; j++) {
4395
0
            sum_s += s[j];
4396
0
            sum_r += r[j];
4397
0
            sum_sq_s += s[j] * s[j];
4398
0
            sum_sq_r += r[j] * r[j];
4399
0
            sum_sxr += s[j] * r[j];
4400
0
        }
4401
4402
0
        s += sp;
4403
0
        r += rp;
4404
0
    }
4405
4406
    //
4407
    // similarity
4408
    //
4409
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4410
0
    return score;
4411
0
}
4412
4413
static double ssim_8x8_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4414
0
                              uint32_t height) {
4415
0
    uint32_t i, j;
4416
0
    int      samples    = 0;
4417
0
    double   ssim_total = 0;
4418
4419
    // sample point start with each 4x4 location
4420
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4421
0
        for (j = 0; j <= width - 8; j += 8) {
4422
0
            double v = svt_ssim_8x8(s + j, sp, r + j, rp);
4423
0
            v        = CLIP3(0, 1, v);
4424
0
            ssim_total += v;
4425
0
            samples++;
4426
0
        }
4427
0
    }
4428
0
    assert(samples > 0);
4429
0
    ssim_total /= samples;
4430
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4431
0
    return ssim_total;
4432
0
}
4433
4434
static double ssim_4x4_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4435
0
                              uint32_t height) {
4436
0
    uint32_t i, j;
4437
0
    int      samples    = 0;
4438
0
    double   ssim_total = 0;
4439
4440
    // sample point start with each 2x2 location
4441
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4442
0
        for (j = 0; j <= width - 4; j += 4) {
4443
0
            double v = svt_ssim_4x4(s + j, sp, r + j, rp);
4444
0
            v        = CLIP3(0, 1, v);
4445
0
            ssim_total += v;
4446
0
            samples++;
4447
0
        }
4448
0
    }
4449
0
    assert(samples > 0);
4450
0
    ssim_total /= samples;
4451
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4452
0
    return ssim_total;
4453
0
}
4454
4455
0
static double ssim(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width, uint32_t height) {
4456
0
    assert((width % 4) == 0 && (height % 4) == 0);
4457
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4458
0
        return ssim_8x8_blocks(s, sp, r, rp, width, height);
4459
0
    } else {
4460
0
        return ssim_4x4_blocks(s, sp, r, rp, width, height);
4461
0
    }
4462
0
}
4463
4464
static double ssim_8x8_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4465
0
                                  uint32_t height) {
4466
0
    uint32_t i, j;
4467
0
    int      samples    = 0;
4468
0
    double   ssim_total = 0;
4469
4470
    // sample point start with each 4x4 location
4471
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4472
0
        for (j = 0; j <= width - 8; j += 8) {
4473
0
            double v = svt_ssim_8x8_hbd(s + j, sp, r + j, rp);
4474
0
            v        = CLIP3(0, 1, v);
4475
0
            ssim_total += v;
4476
0
            samples++;
4477
0
        }
4478
0
    }
4479
0
    assert(samples > 0);
4480
0
    ssim_total /= samples;
4481
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4482
0
    return ssim_total;
4483
0
}
4484
4485
static double ssim_4x4_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4486
0
                                  uint32_t height) {
4487
0
    uint32_t i, j;
4488
0
    int      samples    = 0;
4489
0
    double   ssim_total = 0;
4490
4491
    // sample point start with each 2x2 location
4492
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4493
0
        for (j = 0; j <= width - 4; j += 4) {
4494
0
            double v = svt_ssim_4x4_hbd(s + j, sp, r + j, rp);
4495
0
            v        = CLIP3(0, 1, v);
4496
0
            ssim_total += v;
4497
0
            samples++;
4498
0
        }
4499
0
    }
4500
0
    assert(samples > 0);
4501
0
    ssim_total /= samples;
4502
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4503
0
    return ssim_total;
4504
0
}
4505
4506
static double ssim_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4507
0
                       uint32_t height) {
4508
0
    assert((width % 4) == 0 && (height % 4) == 0);
4509
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4510
0
        return ssim_8x8_blocks_hbd(s, sp, r, rp, width, height);
4511
0
    } else {
4512
0
        return ssim_4x4_blocks_hbd(s, sp, r, rp, width, height);
4513
0
    }
4514
0
}
4515
4516
uint64_t svt_spatial_full_distortion_ssim_kernel(uint8_t* input, uint32_t input_offset, uint32_t input_stride,
4517
                                                 uint8_t* recon, int32_t recon_offset, uint32_t recon_stride,
4518
0
                                                 uint32_t area_width, uint32_t area_height, bool hbd, double ac_bias) {
4519
0
    uint8_t        m     = 1;
4520
0
    const uint32_t count = area_width * area_height;
4521
4522
    // SSIM
4523
0
    uint64_t spatial_distortion;
4524
0
    double   ssim_score;
4525
4526
    // AC SAD
4527
0
    uint64_t psy_distortion = 0;
4528
4529
0
    if (!hbd) {
4530
0
        ssim_score = ssim(
4531
0
            input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4532
0
        if (ac_bias) {
4533
0
            uint64_t ac_distortion = svt_psy_distortion(
4534
0
                input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4535
0
            psy_distortion = (uint64_t)(ac_distortion * ac_bias);
4536
0
        }
4537
0
    } else {
4538
0
        m          = 8;
4539
0
        ssim_score = ssim_hbd((uint16_t*)input + input_offset,
4540
0
                              input_stride,
4541
0
                              (uint16_t*)recon + recon_offset,
4542
0
                              recon_stride,
4543
0
                              area_width,
4544
0
                              area_height);
4545
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
4546
0
        if (ac_bias) {
4547
0
            uint64_t ac_distortion = svt_psy_distortion_hbd((uint16_t*)input + input_offset,
4548
0
                                                            input_stride,
4549
0
                                                            (uint16_t*)recon + recon_offset,
4550
0
                                                            recon_stride,
4551
0
                                                            area_width,
4552
0
                                                            area_height);
4553
0
            psy_distortion         = (uint64_t)(ac_distortion * ac_bias);
4554
0
        }
4555
0
#endif
4556
0
    }
4557
4558
0
    spatial_distortion        = (uint64_t)((1 - ssim_score) * count * 100 * 7 * m);
4559
0
    uint64_t total_distortion = spatial_distortion + psy_distortion;
4560
4561
0
    return total_distortion;
4562
0
}