Coverage Report

Created: 2026-07-30 06:27

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