Coverage Report

Created: 2026-08-13 07:23

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
304k
    MULTI_LINE_MACRO_BEGIN                                   \
63
304k
    if (cnt + 1 < max_can_count)                             \
64
305k
        cnt++;                                               \
65
304k
    else                                                     \
66
18.4E
        SVT_ERROR("Mode decision candidate count exceeded"); \
67
304k
    MULTI_LINE_MACRO_END
68
69
0
#define SUPERRES_INVALID_STATE 0x7fffffff
70
71
2.87M
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.87M
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
78
2.87M
    if (frm_hdr->segmentation_params.segmentation_enabled) {
79
0
        return pcs->lossless[segment_id];
80
2.87M
    } else {
81
2.87M
        return pcs->lossless[0];
82
2.87M
    }
83
2.87M
#endif
84
2.87M
}
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
305k
int svt_aom_filter_intra_allowed(uint8_t enable_filter_intra, BlockSize bsize, uint8_t palette_size, uint32_t mode) {
116
305k
    if (!CONFIG_ENABLE_FILTER_INTRA) {
117
0
        return 0; // filter_intra off
118
0
    }
119
305k
    return enable_filter_intra && mode == DC_PRED && palette_size == 0 && svt_aom_filter_intra_allowed_bsize(bsize);
120
305k
}
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
152k
                                     const uint8_t enable_me_8x8, const uint8_t enable_me_16x16) {
134
152k
    const int      bwidth     = block_size_wide[bsize];
135
152k
    const int      bheight    = block_size_high[bsize];
136
152k
    const uint32_t max_length = MAX(bwidth, bheight);
137
138
152k
    uint32_t me_idx = 0;
139
152k
    switch (max_length) {
140
0
    case 4:
141
148k
    case 8:
142
148k
        me_idx++;
143
148k
        if (org_x & 8) { // (org_x % 16) / 8
144
71.5k
            me_idx += 1;
145
71.5k
        }
146
148k
        if (org_y & 8) { // (org_y % 16) / 8
147
71.7k
            me_idx += 2;
148
71.7k
        }
149
148k
        AOM_FALLTHROUGH_INTENDED;
150
149k
    case 16:
151
149k
        me_idx++;
152
149k
        if (org_x & 16) { // (org_x % 32) / 16
153
70.5k
            me_idx += 5;
154
70.5k
        }
155
149k
        if (org_y & 16) { // (org_y % 32) / 16
156
70.5k
            me_idx += 10;
157
70.5k
        }
158
149k
        AOM_FALLTHROUGH_INTENDED;
159
149k
    case 32:
160
149k
        me_idx++;
161
149k
        if (org_x & 32) { // (org_x % 64) / 32
162
68.9k
            me_idx += 21;
163
68.9k
        }
164
149k
        if (org_y & 32) { // (org_y % 64) / 32
165
68.7k
            me_idx += 42;
166
68.7k
        }
167
149k
        break;
168
2.56k
    default:
169
        // me_idx = 0;
170
2.56k
        break;
171
152k
    }
172
173
152k
    uint32_t me_block_offset = me_idx_85[me_idx]; // convert idx to me_idx
174
175
152k
    if (!enable_me_8x8) {
176
152k
        if (me_block_offset >= MAX_SB64_PU_COUNT_NO_8X8) {
177
147k
            me_block_offset = me_idx_85_8x8_to_16x16_conversion[me_block_offset - MAX_SB64_PU_COUNT_NO_8X8];
178
147k
        }
179
152k
        assert(me_block_offset < 21);
180
152k
        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
152k
    }
187
188
152k
    return me_block_offset;
189
152k
}
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.08k
static void mode_decision_scratch_cand_bf_dctor(EbPtr p) {
654
3.08k
    ModeDecisionCandidateBuffer* obj = (ModeDecisionCandidateBuffer*)p;
655
3.08k
    EB_DELETE(obj->pred);
656
3.08k
    EB_DELETE(obj->residual);
657
3.08k
    EB_DELETE(obj->rec_coeff);
658
3.08k
    EB_DELETE(obj->recon);
659
3.08k
    EB_DELETE(obj->quant);
660
3.08k
}
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.4k
                                               uint64_t* fast_cost, uint64_t* full_cost, uint64_t* full_cost_ssim) {
669
15.4k
    buffer_ptr->dctor = mode_decision_cand_bf_dctor;
670
671
    // Candidate Ptr
672
15.4k
    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.4k
    buffer_ptr->pred      = pred;
677
15.4k
    buffer_ptr->residual  = temp_residual;
678
15.4k
    buffer_ptr->rec_coeff = rec_coeff;
679
15.4k
    buffer_ptr->quant     = quant;
680
15.4k
    buffer_ptr->recon     = temp_recon_ptr;
681
682
    // Costs
683
15.4k
    buffer_ptr->fast_cost      = fast_cost;
684
15.4k
    buffer_ptr->full_cost      = full_cost;
685
15.4k
    buffer_ptr->full_cost_ssim = full_cost_ssim;
686
15.4k
    return EB_ErrorNone;
687
15.4k
}
688
689
EbErrorType svt_aom_mode_decision_scratch_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, uint8_t sb_size,
690
3.08k
                                                       EbBitDepth max_bitdepth) {
691
3.08k
    EbPictureBufferDescInitData picture_buffer_desc_init_data;
692
3.08k
    EbPictureBufferDescInitData double_width_picture_buffer_desc_init_data;
693
3.08k
    EbPictureBufferDescInitData thirty_two_width_picture_buffer_desc_init_data;
694
695
3.08k
    buffer_ptr->dctor = mode_decision_scratch_cand_bf_dctor;
696
697
    // Init Picture Data
698
3.08k
    picture_buffer_desc_init_data.max_width                           = sb_size;
699
3.08k
    picture_buffer_desc_init_data.max_height                          = sb_size;
700
3.08k
    picture_buffer_desc_init_data.bit_depth                           = max_bitdepth;
701
3.08k
    picture_buffer_desc_init_data.color_format                        = EB_YUV420;
702
3.08k
    picture_buffer_desc_init_data.buffer_enable_mask                  = PICTURE_BUFFER_DESC_FULL_MASK;
703
3.08k
    picture_buffer_desc_init_data.border                              = 0;
704
3.08k
    picture_buffer_desc_init_data.split_mode                          = false;
705
3.08k
    picture_buffer_desc_init_data.is_16bit_pipeline                   = max_bitdepth > EB_EIGHT_BIT;
706
3.08k
    double_width_picture_buffer_desc_init_data.max_width              = sb_size;
707
3.08k
    double_width_picture_buffer_desc_init_data.max_height             = sb_size;
708
3.08k
    double_width_picture_buffer_desc_init_data.bit_depth              = EB_SIXTEEN_BIT;
709
3.08k
    double_width_picture_buffer_desc_init_data.color_format           = EB_YUV420;
710
3.08k
    double_width_picture_buffer_desc_init_data.buffer_enable_mask     = PICTURE_BUFFER_DESC_FULL_MASK;
711
3.08k
    double_width_picture_buffer_desc_init_data.border                 = 0;
712
3.08k
    double_width_picture_buffer_desc_init_data.split_mode             = false;
713
3.08k
    double_width_picture_buffer_desc_init_data.is_16bit_pipeline      = true;
714
3.08k
    thirty_two_width_picture_buffer_desc_init_data.max_width          = sb_size;
715
3.08k
    thirty_two_width_picture_buffer_desc_init_data.max_height         = sb_size;
716
3.08k
    thirty_two_width_picture_buffer_desc_init_data.bit_depth          = EB_THIRTYTWO_BIT;
717
3.08k
    thirty_two_width_picture_buffer_desc_init_data.color_format       = EB_YUV420;
718
3.08k
    thirty_two_width_picture_buffer_desc_init_data.buffer_enable_mask = PICTURE_BUFFER_DESC_FULL_MASK;
719
3.08k
    thirty_two_width_picture_buffer_desc_init_data.border             = 0;
720
3.08k
    thirty_two_width_picture_buffer_desc_init_data.split_mode         = false;
721
3.08k
    thirty_two_width_picture_buffer_desc_init_data.is_16bit_pipeline  = true;
722
723
    // Candidate Ptr
724
3.08k
    buffer_ptr->cand = NULL;
725
726
    // Video Buffers
727
3.08k
    EB_NEW(buffer_ptr->pred, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
728
3.08k
    EB_NEW(buffer_ptr->residual, svt_picture_buffer_desc_ctor, (EbPtr)&double_width_picture_buffer_desc_init_data);
729
3.08k
    EB_NEW(buffer_ptr->rec_coeff, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
730
3.08k
    EB_NEW(buffer_ptr->quant, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
731
732
3.08k
    EB_NEW(buffer_ptr->recon, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
733
3.08k
    return EB_ErrorNone;
734
3.08k
}
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
151k
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
151k
    if (!ctx->intra_ctrls.prune_using_edge_info || pcs->scs->super_block_size == 128 || ctx->shape != PART_N ||
850
151k
        ctx->blk_geom->sq_size == 4) {
851
0
        return 0;
852
0
    }
853
854
    // Block variance lookup
855
151k
    int            blk_idx;
856
151k
    int            sub_idx[4];
857
151k
    const Position blk_org = {.x = ctx->blk_org_x - ctx->sb_origin_x, .y = ctx->blk_org_y - ctx->sb_origin_y};
858
151k
    svt_aom_get_blk_var_map(ctx->blk_geom->sq_size, blk_org.x, blk_org.y, &blk_idx, sub_idx);
859
860
151k
    uint16_t* sb_var  = pcs->ppcs->variance[ctx->sb_index];
861
151k
    uint32_t  blk_var = sb_var[blk_idx];
862
863
    // For 8x8, we do not have 4x4 sub-variance, skip spread check
864
151k
    if (ctx->blk_geom->sq_size == 8) {
865
148k
        return (blk_var < 2000);
866
148k
    }
867
868
    // For 16x16 and above, compute spread from sub-blocks
869
3.56k
    uint32_t min_var = UINT32_MAX;
870
3.56k
    uint32_t max_var = 0;
871
872
21.4k
    for (int i = 0; i < 4; i++) {
873
17.8k
        uint32_t v = sb_var[sub_idx[i]];
874
17.8k
        min_var    = MIN(min_var, v);
875
17.8k
        max_var    = MAX(max_var, v);
876
17.8k
    }
877
878
3.56k
    uint32_t spread_var = max_var - min_var;
879
880
4.46k
    return (blk_var < 2000 && spread_var < 4000);
881
151k
}
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
        // 64-bit: (cost0 - cost1) * 100 can overflow int
1233
0
        int64_t diff = ((int64_t)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index] -
1234
0
                        (int64_t)ctx->post_subpel_me_mv_cost[ref1_list][list1_ref_index]) *
1235
0
            100;
1236
1237
0
        if (ctx->bipred3x3_ctrls.use_l0_l1_dev != (uint8_t)~0) {
1238
0
            if (llabs(diff) > ((int64_t)ctx->bipred3x3_ctrls.use_l0_l1_dev *
1239
0
                               (int)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index])) {
1240
0
                return;
1241
0
            }
1242
0
        }
1243
1244
        // Best list in terms of distortion reduction
1245
0
        if (ctx->bipred3x3_ctrls.use_best_list) {
1246
0
            best_list = ref0_list;
1247
0
            if (diff > 0) {
1248
0
                best_list = ref1_list;
1249
0
            }
1250
0
        }
1251
1252
0
        MvReferenceFrame rf[2]              = {svt_get_ref_frame_type(ref0_list, list0_ref_index),
1253
0
                                               svt_get_ref_frame_type(ref1_list, list1_ref_index)};
1254
0
        const uint8_t    to_inject_ref_type = av1_ref_frame_type(rf);
1255
0
        if (best_list == -1 || best_list == ref0_list) {
1256
            // (Best_L0, 8 Best_L1 neighbors)
1257
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1258
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1259
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1260
0
                        continue;
1261
0
                    }
1262
0
                }
1263
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1264
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1265
0
                to_inj_mv1.x += (bipred_3x3_x_pos[bipred_index] * (1 << !allow_high_precision_mv));
1266
0
                to_inj_mv1.y += (bipred_3x3_y_pos[bipred_index] * (1 << !allow_high_precision_mv));
1267
0
                if ((ctx->injected_mv_count == 0 ||
1268
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1269
0
                    uint8_t drl_index = 0;
1270
0
                    svt_aom_choose_best_av1_mv_pred(
1271
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1272
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1273
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1274
0
                        cand->block_mi.use_intrabc        = 0;
1275
0
                        cand->skip_mode_allowed           = false;
1276
0
                        cand->drl_index                   = drl_index;
1277
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1278
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1279
0
                        cand->block_mi.mode               = NEW_NEWMV;
1280
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1281
0
                        cand->block_mi.is_interintra_used = 0;
1282
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1283
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1284
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1285
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1286
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1287
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1288
1289
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1290
0
                            ctx->cmp_store.pred0_cnt = 0;
1291
0
                            ctx->cmp_store.pred1_cnt = 0;
1292
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1293
0
                        }
1294
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1295
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1296
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1297
0
                        ++ctx->injected_mv_count;
1298
0
                    }
1299
0
                }
1300
0
            }
1301
0
        }
1302
0
        if (best_list == -1 || best_list == ref1_list) {
1303
            // (8 Best_L0 neighbors, Best_L1) :
1304
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1305
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1306
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1307
0
                        continue;
1308
0
                    }
1309
0
                }
1310
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1311
0
                to_inj_mv0.x += (bipred_3x3_x_pos[bipred_index] * (1 << !allow_high_precision_mv));
1312
0
                to_inj_mv0.y += (bipred_3x3_y_pos[bipred_index] * (1 << !allow_high_precision_mv));
1313
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1314
0
                if ((ctx->injected_mv_count == 0 ||
1315
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1316
0
                    uint8_t drl_index = 0;
1317
0
                    svt_aom_choose_best_av1_mv_pred(
1318
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1319
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1320
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1321
0
                        cand->block_mi.use_intrabc        = 0;
1322
0
                        cand->skip_mode_allowed           = false;
1323
0
                        cand->drl_index                   = drl_index;
1324
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1325
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1326
0
                        cand->block_mi.mode               = NEW_NEWMV;
1327
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1328
0
                        cand->block_mi.is_interintra_used = 0;
1329
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1330
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1331
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1332
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1333
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1334
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1335
1336
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1337
0
                            ctx->cmp_store.pred0_cnt = 0;
1338
0
                            ctx->cmp_store.pred1_cnt = 0;
1339
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1340
0
                        }
1341
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1342
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1343
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1344
0
                        ++ctx->injected_mv_count;
1345
0
                    }
1346
0
                }
1347
0
            }
1348
0
        }
1349
0
    }
1350
1351
    // update the total number of candidates injected
1352
0
    (*candidate_total_cnt) = cand_total_cnt;
1353
1354
0
    return;
1355
0
}
1356
1357
/*********************************************************************
1358
**********************************************************************
1359
        Upto 12 inter Candidated injected
1360
        Min 6 inter Candidated injected
1361
UniPred L0 : NEARST         + upto 3x NEAR
1362
UniPred L1 : NEARST         + upto 3x NEAR
1363
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1364
**********************************************************************
1365
**********************************************************************/
1366
static void inject_mvp_candidates_ii_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candTotCnt,
1367
0
                                               const bool allow_bipred) {
1368
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1369
0
    uint32_t               cand_idx   = *candTotCnt;
1370
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1371
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1372
1373
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1
1374
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1375
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1376
0
        MvReferenceFrame rf[2];
1377
0
        av1_set_ref_frame(rf, ref_pair);
1378
1379
        //single ref/list
1380
0
        if (rf[1] == NONE_FRAME) {
1381
0
            MvReferenceFrame frame_type = rf[0];
1382
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1383
0
            if (ctx->cand_reduction_ctrls.lpd1_mvp_best_me_list) {
1384
0
                const MeSbResults* me_results           = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1385
0
                const uint8_t      total_me_cnt         = me_results->total_me_candidate_index[ctx->me_block_offset];
1386
0
                const MeCandidate* me_block_results     = &me_results->me_candidate_array[ctx->me_cand_offset];
1387
0
                const MeCandidate* me_block_results_ptr = &me_block_results[0];
1388
0
                const uint8_t      inter_direction      = me_block_results_ptr->direction;
1389
0
                if (total_me_cnt && list_idx != inter_direction) {
1390
0
                    continue;
1391
0
                }
1392
0
            }
1393
            //NEAREST
1394
            // Don't check if MV is already injected b/c NEAREST is the first INTER MV injected
1395
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1396
1397
0
            ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1398
0
            cand->block_mi.mode               = NEARESTMV;
1399
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1400
0
            cand->skip_mode_allowed           = false;
1401
0
            cand->drl_index                   = 0;
1402
0
            cand->block_mi.ref_frame[0]       = rf[0];
1403
0
            cand->block_mi.ref_frame[1]       = rf[1];
1404
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1405
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1406
0
            cand->block_mi.use_intrabc        = 0;
1407
0
            cand->block_mi.is_interintra_used = 0;
1408
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1409
1410
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1411
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1412
0
            ++ctx->injected_mv_count;
1413
            //NEAR
1414
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1415
0
            uint8_t       cap_max_drl_index = 0;
1416
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1417
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1418
0
            }
1419
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1420
0
                to_inj_mv.as_int = ctx->ref_mv_stack[frame_type][1 + drli].this_mv.as_int;
1421
1422
0
                if ((ctx->injected_mv_count == 0 ||
1423
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1424
0
                    cand                              = &cand_array[cand_idx];
1425
0
                    cand->block_mi.mode               = NEARMV;
1426
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1427
0
                    cand->skip_mode_allowed           = false;
1428
0
                    cand->drl_index                   = drli;
1429
0
                    cand->block_mi.use_intrabc        = 0;
1430
0
                    cand->block_mi.is_interintra_used = 0;
1431
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1432
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1433
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1434
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1435
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1436
1437
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1438
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1439
0
                    ++ctx->injected_mv_count;
1440
0
                }
1441
0
            }
1442
0
        } else if (allow_bipred) {
1443
            //NEAREST_NEAREST
1444
            // Don't check if MV is already injected b/c NEAREST_NEAREST is the first bipred INTER candidate injected
1445
0
            Mv         to_inj_mv0   = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1446
0
            Mv         to_inj_mv1   = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1447
0
            const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1448
0
                frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1449
0
                (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1450
0
            ModeDecisionCandidate* cand         = &cand_array[cand_idx];
1451
0
            cand->block_mi.mode                 = NEAREST_NEARESTMV;
1452
0
            cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1453
0
            cand->skip_mode_allowed             = is_skip_mode;
1454
0
            cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1455
0
            cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1456
0
            cand->drl_index                     = 0;
1457
0
            cand->block_mi.use_intrabc          = 0;
1458
0
            cand->block_mi.is_interintra_used   = 0;
1459
0
            cand->block_mi.ref_frame[0]         = rf[0];
1460
0
            cand->block_mi.ref_frame[1]         = rf[1];
1461
0
            cand->block_mi.comp_group_idx       = 0;
1462
0
            cand->block_mi.compound_idx         = 1;
1463
0
            cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1464
1465
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1466
1467
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1468
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1469
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1470
0
            ++ctx->injected_mv_count;
1471
1472
            //NEAR_NEAR
1473
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1474
0
            uint8_t       cap_max_drl_index = 0;
1475
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1476
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1477
0
            }
1478
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1479
0
                to_inj_mv0.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].this_mv.as_int;
1480
0
                to_inj_mv1.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].comp_mv.as_int;
1481
0
                if ((ctx->injected_mv_count == 0 ||
1482
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1483
0
                    cand                                = &cand_array[cand_idx];
1484
0
                    cand->block_mi.mode                 = NEAR_NEARMV;
1485
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1486
0
                    cand->skip_mode_allowed             = false;
1487
0
                    cand->block_mi.use_intrabc          = 0;
1488
0
                    cand->block_mi.is_interintra_used   = 0;
1489
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1490
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1491
0
                    cand->drl_index                     = drli;
1492
0
                    cand->block_mi.ref_frame[0]         = rf[0];
1493
0
                    cand->block_mi.ref_frame[1]         = rf[1];
1494
0
                    cand->block_mi.comp_group_idx       = 0;
1495
0
                    cand->block_mi.compound_idx         = 1;
1496
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1497
1498
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1499
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1500
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1501
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1502
0
                    ++ctx->injected_mv_count;
1503
0
                }
1504
0
            }
1505
0
        }
1506
0
    }
1507
    //update tot Candidate count
1508
0
    *candTotCnt = cand_idx;
1509
0
}
1510
1511
/*********************************************************************
1512
**********************************************************************
1513
        Upto 12 inter Candidated injected
1514
        Min 6 inter Candidated injected
1515
UniPred L0 : NEARST         + upto 3x NEAR
1516
UniPred L1 : NEARST         + upto 3x NEAR
1517
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1518
**********************************************************************
1519
**********************************************************************/
1520
static void inject_mvp_candidates_ii(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* cand_total_cnt,
1521
0
                                     const bool allow_bipred) {
1522
0
    BlkStruct*             blk_ptr    = ctx->blk_ptr;
1523
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1524
0
    uint32_t               cand_idx   = *cand_total_cnt;
1525
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1526
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
1527
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1528
1529
    //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
1530
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1531
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1532
0
        MvReferenceFrame rf[2];
1533
0
        av1_set_ref_frame(rf, ref_pair);
1534
        //single ref/list
1535
0
        if (rf[1] == NONE_FRAME) {
1536
0
            MvReferenceFrame frame_type = rf[0];
1537
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1538
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
1539
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1540
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEAR_GROUP), list_idx, ref_idx)) {
1541
0
                continue;
1542
0
            }
1543
            //NEAREST
1544
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1545
0
            if ((ctx->injected_mv_count == 0 ||
1546
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1547
0
                assert(list_idx == 0 || list_idx == 1);
1548
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1549
0
                cand->block_mi.mode               = NEARESTMV;
1550
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1551
0
                cand->block_mi.use_intrabc        = 0;
1552
0
                cand->skip_mode_allowed           = false;
1553
0
                cand->drl_index                   = 0;
1554
0
                cand->block_mi.ref_frame[0]       = rf[0];
1555
0
                cand->block_mi.ref_frame[1]       = rf[1];
1556
0
                cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1557
0
                cand->block_mi.is_interintra_used = 0;
1558
0
                cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1559
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1560
1561
0
                const bool enable_ii   = true;
1562
0
                const bool enable_obmc = true;
1563
0
                const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1564
0
                inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1565
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1566
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1567
0
                ++ctx->injected_mv_count;
1568
0
            }
1569
1570
            //NEAR
1571
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1572
0
            uint8_t       cap_max_drl_index = 0;
1573
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1574
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1575
0
            }
1576
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1577
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, frame_type, 0, NEARMV, drli, nearestmv, nearmv, ref_mv);
1578
1579
0
                to_inj_mv.as_int = nearmv[0].as_int;
1580
0
                if ((ctx->injected_mv_count == 0 ||
1581
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1582
0
                    assert(list_idx == 0 || list_idx == 1);
1583
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1584
0
                    cand->block_mi.mode               = NEARMV;
1585
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1586
0
                    cand->block_mi.use_intrabc        = 0;
1587
0
                    cand->skip_mode_allowed           = false;
1588
0
                    cand->drl_index                   = drli;
1589
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1590
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1591
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1592
0
                    cand->block_mi.is_interintra_used = 0;
1593
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1594
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1595
1596
0
                    const bool enable_ii   = true;
1597
0
                    const bool enable_obmc = true;
1598
0
                    const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1599
0
                    inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1600
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1601
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1602
0
                    ++ctx->injected_mv_count;
1603
0
                }
1604
0
            }
1605
0
        } else if (allow_bipred) {
1606
0
            const uint8_t ref_idx_0 = get_ref_frame_idx(rf[0]);
1607
0
            const uint8_t ref_idx_1 = get_ref_frame_idx(rf[1]);
1608
1609
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1610
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1611
1612
0
            ctx->cmp_store.pred0_cnt = 0;
1613
0
            ctx->cmp_store.pred1_cnt = 0;
1614
1615
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1616
0
            if (!is_valid_bipred_ref(ctx, NRST_NEAR_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
1617
0
                continue;
1618
0
            }
1619
1620
            //NEAREST_NEAREST
1621
0
            Mv to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1622
0
            Mv to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1623
0
            if ((ctx->injected_mv_count == 0 ||
1624
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1625
0
                const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1626
0
                    frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1627
0
                    (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1628
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1629
0
                cand->block_mi.mode               = NEAREST_NEARESTMV;
1630
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1631
0
                cand->block_mi.is_interintra_used = 0;
1632
0
                cand->block_mi.use_intrabc        = 0;
1633
0
                cand->skip_mode_allowed           = /*cur_type == MD_COMP_AVG &&*/ is_skip_mode ? true : false;
1634
0
                cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1635
0
                cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1636
0
                cand->drl_index                   = 0;
1637
0
                cand->block_mi.ref_frame[0]       = rf[0];
1638
0
                cand->block_mi.ref_frame[1]       = rf[1];
1639
0
                determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1640
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1641
1642
0
                if (ctx->inter_comp_ctrls.do_nearest_nearest) {
1643
                    // Don't reset ctx->cmp_store.pred0_cnt for MVP
1644
0
                    inj_comp_modes(pcs, ctx, &cand_idx);
1645
0
                }
1646
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1647
0
                ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1648
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1649
0
                ++ctx->injected_mv_count;
1650
0
            }
1651
1652
            //NEAR_NEAR
1653
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1654
0
            uint8_t       cap_max_drl_index = 0;
1655
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1656
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1657
0
            }
1658
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1659
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_pair, 1, NEAR_NEARMV, drli, nearestmv, nearmv, ref_mv);
1660
1661
0
                to_inj_mv0.as_int = nearmv[0].as_int;
1662
0
                to_inj_mv1.as_int = nearmv[1].as_int;
1663
0
                if ((ctx->injected_mv_count == 0 ||
1664
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1665
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1666
0
                    cand->block_mi.mode               = NEAR_NEARMV;
1667
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1668
0
                    cand->block_mi.is_interintra_used = 0;
1669
0
                    cand->block_mi.use_intrabc        = 0;
1670
0
                    cand->skip_mode_allowed           = false;
1671
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1672
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1673
0
                    cand->drl_index                   = drli;
1674
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1675
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1676
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1677
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1678
1679
0
                    if (ctx->inter_comp_ctrls.do_near_near) {
1680
                        // Don't reset ctx->cmp_store.pred0_cnt for MVP
1681
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1682
0
                    }
1683
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1684
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1685
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1686
0
                    ++ctx->injected_mv_count;
1687
0
                }
1688
0
            }
1689
0
        }
1690
0
    }
1691
    //update tot Candidate count
1692
0
    *cand_total_cnt = cand_idx;
1693
0
}
1694
1695
static void inject_new_nearest_new_comb_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
1696
0
                                                   uint32_t* cand_tot_cnt) {
1697
0
    uint32_t               cand_idx   = *cand_tot_cnt;
1698
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1699
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1700
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1701
1702
    //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
1703
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1704
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1705
0
        MvReferenceFrame rf[2];
1706
0
        av1_set_ref_frame(rf, ref_pair);
1707
0
        if (rf[1] != NONE_FRAME) {
1708
0
            const uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
1709
0
            const uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
1710
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1711
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1712
0
            if (!svt_aom_is_valid_unipred_ref(
1713
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_0, ref_idx_0) ||
1714
0
                !svt_aom_is_valid_unipred_ref(
1715
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_1, ref_idx_1)) {
1716
0
                continue;
1717
0
            }
1718
1719
0
            {
1720
                //NEAREST_NEWMV
1721
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1722
0
                Mv                 to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1723
0
                Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1724
0
                bool               inj_mv =
1725
0
                    (ctx->injected_mv_count == 0 || !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1726
0
                    svt_aom_is_me_data_present(
1727
0
                        ctx->me_block_offset, ctx->me_cand_offset, me_results, get_list_idx(rf[1]), ref_idx_1);
1728
0
                if (inj_mv) {
1729
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1730
0
                                                ctx->blk_ptr,
1731
0
                                                ref_pair,
1732
0
                                                1, // is_compound
1733
0
                                                NEAREST_NEWMV,
1734
0
                                                0, //not needed drli,
1735
0
                                                nearestmv,
1736
0
                                                nearmv,
1737
0
                                                ref_mv);
1738
1739
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1740
0
                    cand->block_mi.mode               = NEAREST_NEWMV;
1741
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1742
0
                    cand->block_mi.is_interintra_used = 0;
1743
0
                    cand->block_mi.use_intrabc        = 0;
1744
0
                    cand->skip_mode_allowed           = false;
1745
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1746
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1747
0
                    cand->drl_index                   = 0;
1748
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1749
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1750
0
                    cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1751
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1752
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1753
1754
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1755
0
                        ctx->cmp_store.pred0_cnt = 0;
1756
0
                        ctx->cmp_store.pred1_cnt = 0;
1757
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1758
0
                    }
1759
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1760
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1761
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1762
0
                    ++ctx->injected_mv_count;
1763
0
                }
1764
0
            }
1765
1766
0
            {
1767
                //NEW_NEARESTMV
1768
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1769
0
                Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1770
0
                Mv                 to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1771
0
                bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1772
0
                               !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1773
0
                    svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1774
0
                if (inj_mv) {
1775
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1776
0
                                                ctx->blk_ptr,
1777
0
                                                ref_pair,
1778
0
                                                1, // is_compound
1779
0
                                                NEW_NEARESTMV,
1780
0
                                                0, //not needed drli,
1781
0
                                                nearestmv,
1782
0
                                                nearmv,
1783
0
                                                ref_mv);
1784
1785
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1786
0
                    cand->block_mi.mode               = NEW_NEARESTMV;
1787
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1788
0
                    cand->block_mi.is_interintra_used = 0;
1789
0
                    cand->block_mi.use_intrabc        = 0;
1790
0
                    cand->skip_mode_allowed           = false;
1791
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1792
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1793
0
                    cand->drl_index                   = 0;
1794
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1795
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1796
0
                    cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1797
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1798
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1799
1800
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1801
0
                        ctx->cmp_store.pred0_cnt = 0;
1802
0
                        ctx->cmp_store.pred1_cnt = 0;
1803
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1804
0
                    }
1805
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1806
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1807
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1808
0
                    ++ctx->injected_mv_count;
1809
0
                }
1810
0
            }
1811
            // For level 2, only inject NEAREST_NEW/NEW_NEAREST candidates
1812
0
            if (ctx->new_nearest_near_comb_injection >= 2) {
1813
0
                continue;
1814
0
            }
1815
1816
            //NEW_NEARMV
1817
0
            {
1818
0
                const uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEW_NEARMV);
1819
1820
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1821
0
                    svt_aom_get_av1_mv_pred_drl(
1822
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEW_NEARMV, drli, nearestmv, nearmv, ref_mv);
1823
1824
                    //NEW_NEARMV
1825
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1826
0
                    Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1827
0
                    Mv                 to_inj_mv1 = {.as_int = nearmv[1].as_int};
1828
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1829
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1830
0
                        svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1831
0
                    if (inj_mv) {
1832
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1833
0
                        cand->block_mi.mode               = NEW_NEARMV;
1834
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1835
0
                        cand->block_mi.is_interintra_used = 0;
1836
0
                        cand->block_mi.use_intrabc        = 0;
1837
0
                        cand->skip_mode_allowed           = false;
1838
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1839
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1840
0
                        cand->drl_index                   = drli;
1841
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1842
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1843
0
                        cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1844
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1845
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1846
1847
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1848
0
                            ctx->cmp_store.pred0_cnt = 0;
1849
0
                            ctx->cmp_store.pred1_cnt = 0;
1850
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1851
0
                        }
1852
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1853
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1854
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1855
0
                        ++ctx->injected_mv_count;
1856
0
                    }
1857
0
                }
1858
0
            }
1859
            //NEAR_NEWMV
1860
0
            {
1861
0
                uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEWMV);
1862
1863
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1864
0
                    svt_aom_get_av1_mv_pred_drl(
1865
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEAR_NEWMV, drli, nearestmv, nearmv, ref_mv);
1866
1867
                    //NEAR_NEWMV
1868
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1869
0
                    Mv                 to_inj_mv0 = {.as_int = nearmv[0].as_int};
1870
0
                    Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1871
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1872
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1873
0
                        svt_aom_is_me_data_present(
1874
0
                                      ctx->me_block_offset, ctx->me_cand_offset, me_results, list_idx_1, ref_idx_1);
1875
1876
0
                    if (inj_mv) {
1877
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1878
0
                        cand->block_mi.mode               = NEAR_NEWMV;
1879
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1880
0
                        cand->block_mi.is_interintra_used = 0;
1881
0
                        cand->block_mi.use_intrabc        = 0;
1882
0
                        cand->skip_mode_allowed           = false;
1883
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1884
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1885
0
                        cand->drl_index                   = drli;
1886
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1887
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1888
0
                        cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1889
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1890
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1891
1892
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1893
0
                            ctx->cmp_store.pred0_cnt = 0;
1894
0
                            ctx->cmp_store.pred1_cnt = 0;
1895
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1896
0
                        }
1897
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1898
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1899
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1900
0
                        ++ctx->injected_mv_count;
1901
0
                    }
1902
0
                }
1903
0
            }
1904
0
        }
1905
0
    }
1906
    //update tot Candidate count
1907
0
    *cand_tot_cnt = cand_idx;
1908
0
}
1909
1910
// Refine the WM MV (8 bit search).  Return true if search found a valid MV; false otherwise
1911
uint8_t svt_aom_wm_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
1912
0
                                     const bool shut_approx) {
1913
0
    PictureParentControlSet* ppcs         = pcs->ppcs;
1914
0
    const Mv                 neighbors[9] = {
1915
0
        {{0, 0}}, {{-1, 0}}, {{0, 1}}, {{1, 0}}, {{0, -1}}, {{1, -1}}, {{1, 1}}, {{-1, 1}}, {{-1, -1}}};
1916
1917
    // Set info used to get MV cost
1918
0
    int*        mvjcost       = ctx->md_rate_est_ctx->nmv_vec_cost;
1919
0
    const int** mvcost        = ctx->md_rate_est_ctx->nmvcoststack;
1920
0
    uint32_t    full_lambda   = ctx->full_lambda_md[EB_8_BIT_MD]; // 8bit only
1921
0
    int         error_per_bit = full_lambda >> RD_EPB_SHIFT;
1922
0
    error_per_bit += (error_per_bit == 0);
1923
0
    EbPictureBufferDesc*    input_pic          = ppcs->enhanced_pic; // 10BIT not supported
1924
0
    uint32_t                input_origin_index = (ctx->blk_org_y) * input_pic->y_stride + (ctx->blk_org_x);
1925
0
    const AomVarianceFnPtr* fn_ptr             = &svt_aom_mefn_ptr[ctx->blk_geom->bsize];
1926
0
    unsigned int            sse;
1927
0
    uint8_t*                src_y = input_pic->y_buffer + input_origin_index;
1928
1929
0
    int mv_prec_shift = ppcs->frm_hdr.allow_high_precision_mv ? 0 : 1;
1930
0
    int best_cost     = INT_MAX;
1931
    // local WM always uses one ref - MV for ref0 stored in idx0
1932
0
    assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1933
0
    Mv       search_centre_mv = {.as_int = cand->block_mi.mv[0].as_int};
1934
0
    Mv       best_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1935
0
    Mv       prev_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1936
0
    const Mv ref_mv           = {.as_int = cand->pred_mv[0].as_int};
1937
1938
0
    int      max_iterations  = ctx->wm_ctrls.refinement_iterations;
1939
0
    int      tot_checked_pos = 0;
1940
0
    uint32_t mv_record[256];
1941
0
    for (int iter = 0; iter < max_iterations; iter++) {
1942
        // search the (0,0) offset position only for the first search iteration
1943
0
        for (int i = (iter ? 1 : 0); i < (ctx->wm_ctrls.refine_diag ? 9 : 5); i++) {
1944
0
            const Mv test_mv = (Mv){{search_centre_mv.x + (neighbors[i].x * (1 << mv_prec_shift)),
1945
0
                                     search_centre_mv.y + (neighbors[i].y * (1 << mv_prec_shift))}};
1946
1947
            // Don't re-test previously tested positions
1948
0
            if (iter) {
1949
0
                if (prev_mv.as_int == test_mv.as_int) {
1950
0
                    continue;
1951
0
                }
1952
0
                int match_found = 0;
1953
0
                for (int j = 0; j < tot_checked_pos; j++) {
1954
0
                    if (test_mv.as_int == mv_record[j]) {
1955
0
                        match_found = 1;
1956
0
                    }
1957
0
                }
1958
0
                if (match_found) {
1959
0
                    continue;
1960
0
                }
1961
0
            }
1962
0
            mv_record[tot_checked_pos++] = test_mv.as_int;
1963
0
            uint8_t local_warp_valid     = svt_aom_warped_motion_parameters(ctx,
1964
0
                                                                        test_mv,
1965
0
                                                                        ctx->blk_geom,
1966
0
                                                                        cand->block_mi.ref_frame[0],
1967
0
                                                                        &cand->wm_params_l0,
1968
0
                                                                        &cand->block_mi.num_proj_ref,
1969
0
                                                                        ctx->wm_ctrls.lower_band_th,
1970
0
                                                                        ctx->wm_ctrls.upper_band_th,
1971
0
                                                                        shut_approx);
1972
0
            if (!local_warp_valid) {
1973
0
                continue;
1974
0
            }
1975
0
            assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1976
0
            EbPictureBufferDesc* ref_pic_0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
1977
0
            EbPictureBufferDesc* ref_pic_1 = NULL; // will stay NULL b/c this is unipred candidate
1978
1979
            // update MV to be testing MV before calling prediction function
1980
0
            cand->block_mi.mv[0].as_int = test_mv.as_int;
1981
0
            svt_aom_inter_prediction(pcs->scs,
1982
0
                                     pcs,
1983
0
                                     &cand->block_mi,
1984
0
                                     &cand->wm_params_l0,
1985
0
                                     &cand->wm_params_l1,
1986
0
                                     ctx->blk_ptr,
1987
0
                                     ctx->blk_geom->bsize,
1988
0
                                     ctx->shape,
1989
                                     // If using 8bit MD for HBD content, can't use pre-computed OBMC/II to
1990
                                     // generate conformant recon
1991
0
                                     true, //use_precomputed_obmc - not used here
1992
0
                                     true, //use_precomputed_ii - not used here
1993
0
                                     ctx,
1994
0
                                     ctx->recon_neigh_y,
1995
0
                                     ctx->recon_neigh_cb,
1996
0
                                     ctx->recon_neigh_cr,
1997
0
                                     ref_pic_0,
1998
0
                                     ref_pic_1, // this is NULL
1999
0
                                     ctx->blk_org_x,
2000
0
                                     ctx->blk_org_y,
2001
0
                                     ctx->scratch_prediction_ptr,
2002
0
                                     0,
2003
0
                                     0,
2004
0
                                     PICTURE_BUFFER_DESC_LUMA_MASK,
2005
0
                                     EB_EIGHT_BIT,
2006
0
                                     0); // is_16bit_pipeline
2007
2008
0
            int var = fn_ptr->vf(ctx->scratch_prediction_ptr->y_buffer,
2009
0
                                 ctx->scratch_prediction_ptr->y_stride,
2010
0
                                 src_y,
2011
0
                                 input_pic->y_stride,
2012
0
                                 &sse);
2013
0
            if (ctx->approx_inter_rate) {
2014
0
                var += svt_aom_mv_err_cost_light(&test_mv, &ref_mv);
2015
0
            } else {
2016
0
                var += svt_aom_mv_err_cost(&test_mv, &ref_mv, mvjcost, mvcost, error_per_bit);
2017
0
            }
2018
2019
0
            if (var < best_cost) {
2020
0
                best_mv.as_int = test_mv.as_int;
2021
0
                best_cost      = var;
2022
0
            }
2023
0
        }
2024
0
        prev_mv.as_int          = search_centre_mv.as_int;
2025
0
        search_centre_mv.as_int = best_mv.as_int;
2026
0
        if (prev_mv.as_int == best_mv.as_int) {
2027
0
            break;
2028
0
        }
2029
0
    }
2030
0
    cand->block_mi.mv[0].as_int = best_mv.as_int;
2031
2032
    // Derive pred MV for best WM position
2033
0
    Mv best_pred_mv[2] = {{{0}}, {{0}}};
2034
0
    svt_aom_choose_best_av1_mv_pred(ctx,
2035
0
                                    cand->block_mi.ref_frame[0], // WM only allowed for unipred cands
2036
0
                                    cand->block_mi.mode,
2037
0
                                    cand->block_mi.mv[0],
2038
0
                                    (Mv){{0}},
2039
0
                                    &cand->drl_index,
2040
0
                                    best_pred_mv);
2041
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2042
2043
    // Check that final chosen MV is valid
2044
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, best_mv, best_mv, 0)) {
2045
0
        return 1;
2046
0
    }
2047
2048
0
    return 0;
2049
0
}
2050
2051
static INLINE void setup_pred_plane(Buf2D* dst, BlockSize bsize, uint8_t* src, int width, int height, int stride,
2052
0
                                    int mi_row, int mi_col, int subsampling_x, int subsampling_y) {
2053
    // Offset the buffer pointer
2054
0
    if (subsampling_y && (mi_row & 0x01) && (mi_size_high[bsize] == 1)) {
2055
0
        mi_row -= 1;
2056
0
    }
2057
0
    if (subsampling_x && (mi_col & 0x01) && (mi_size_wide[bsize] == 1)) {
2058
0
        mi_col -= 1;
2059
0
    }
2060
2061
0
    const int x = (MI_SIZE * mi_col) >> subsampling_x;
2062
0
    const int y = (MI_SIZE * mi_row) >> subsampling_y;
2063
0
    dst->buf    = src + (y * stride + x); // scaled_buffer_offset(x, y, stride, scale);
2064
0
    dst->buf0   = src;
2065
0
    dst->width  = width;
2066
0
    dst->height = height;
2067
0
    dst->stride = stride;
2068
0
}
2069
2070
void svt_av1_setup_pred_block(BlockSize bsize, Buf2D dst[MAX_PLANES], const Yv12BufferConfig* src, int mi_row,
2071
0
                              int mi_col) {
2072
0
    dst[0].buf    = src->y_buffer;
2073
0
    dst[0].stride = src->y_stride;
2074
0
    dst[1].buf    = src->u_buffer;
2075
0
    dst[2].buf    = src->v_buffer;
2076
0
    dst[1].stride = dst[2].stride = src->uv_stride;
2077
2078
0
    setup_pred_plane(
2079
0
        dst, bsize, dst[0].buf, src->y_crop_width, src->y_crop_height, dst[0].stride, mi_row, mi_col, 0, 0);
2080
0
}
2081
2082
static int sad_per_bit_lut_8[QINDEX_RANGE];
2083
static int sad_per_bit_lut_10[QINDEX_RANGE];
2084
2085
// Get the sad per bit for the relevant qindex and bit depth
2086
0
int svt_aom_get_sad_per_bit(int qidx, EbBitDepth is_hbd) {
2087
0
    return is_hbd ? sad_per_bit_lut_10[qidx] : sad_per_bit_lut_8[qidx];
2088
0
}
2089
2090
2
static void init_me_luts_bd(int* bit16lut, int range, EbBitDepth bit_depth) {
2091
2
    int i;
2092
    // Initialize the sad lut tables using a formulaic calculation for now.
2093
    // This is to make it easier to resolve the impact of experimental changes
2094
    // to the quantizer tables.
2095
514
    for (i = 0; i < range; i++) {
2096
512
        const double q = svt_av1_convert_qindex_to_q(i, bit_depth);
2097
512
        bit16lut[i]    = (int)(0.0418 * q + 2.4107);
2098
512
    }
2099
2
}
2100
2101
1
void svt_av1_init_me_luts(void) {
2102
1
    init_me_luts_bd(sad_per_bit_lut_8, QINDEX_RANGE, EB_EIGHT_BIT);
2103
1
    init_me_luts_bd(sad_per_bit_lut_10, QINDEX_RANGE, EB_TEN_BIT);
2104
1
}
2105
2106
#if CONFIG_ENABLE_OBMC
2107
static void single_motion_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2108
                                 Mv best_pred_mv, IntraBcContext* x, BlockSize bsize, Mv* ref_mv, int* rate_mv,
2109
0
                                 int refine_level) {
2110
0
    bool do_full_refine = 0;
2111
0
    bool do_frac_refine = 0;
2112
0
    switch (refine_level) {
2113
0
    case 0:
2114
0
    case 1:
2115
0
    case 3:
2116
0
        do_full_refine = 1;
2117
0
        do_frac_refine = 1;
2118
0
        break;
2119
0
    case 2:
2120
0
    case 4:
2121
0
        do_full_refine = 0;
2122
0
        do_frac_refine = 1;
2123
0
        break;
2124
0
    default:
2125
0
        break;
2126
0
    }
2127
0
    const Av1Common* const cm      = pcs->ppcs->av1_cm;
2128
0
    FrameHeader*           frm_hdr = &pcs->ppcs->frm_hdr;
2129
    // single_motion_search supports 8bit path only
2130
0
    uint32_t full_lambda = ctx->full_lambda_md[EB_8_BIT_MD];
2131
2132
0
    x->xd            = ctx->blk_ptr->av1xd;
2133
0
    const int mi_row = -x->xd->mb_to_top_edge / (8 * MI_SIZE);
2134
0
    const int mi_col = -x->xd->mb_to_left_edge / (8 * MI_SIZE);
2135
2136
0
    x->nmv_vec_cost  = ctx->md_rate_est_ctx->nmv_vec_cost;
2137
0
    x->mv_cost_stack = ctx->md_rate_est_ctx->nmvcoststack;
2138
    // Set up limit values for MV components.
2139
    // Mv beyond the range do not produce new/different prediction block.
2140
0
    const int mi_width   = mi_size_wide[bsize];
2141
0
    const int mi_height  = mi_size_high[bsize];
2142
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
2143
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
2144
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
2145
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
2146
    //set search paramters
2147
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
2148
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
2149
0
    x->errorperbit += (x->errorperbit == 0);
2150
0
    if (do_full_refine) {
2151
0
        int      sadpb         = x->sadperbit16;
2152
0
        MvLimits tmp_mv_limits = x->mv_limits;
2153
2154
        // Note: MV limits are modified here. Always restore the original values
2155
        // after full-pixel motion search.
2156
0
        svt_av1_set_mv_search_range(&x->mv_limits, ref_mv);
2157
2158
0
        Mv mvp_full = best_pred_mv; // mbmi->mv[0].as_mv;
2159
2160
        // TODO: should use get_fullmv_from_mv instead of shifting
2161
0
        mvp_full.x >>= 3;
2162
0
        mvp_full.y >>= 3;
2163
2164
0
        x->best_mv.as_int = x->second_best_mv.as_int = INVALID_MV; //D
2165
2166
0
        switch (cand->block_mi.motion_mode) {
2167
0
        case OBMC_CAUSAL:
2168
0
            svt_av1_obmc_full_pixel_search(
2169
0
                ctx, x, &mvp_full, sadpb, &svt_aom_mefn_ptr[bsize], ref_mv, &(x->best_mv), 0);
2170
0
            break;
2171
0
        default:
2172
0
            assert(0 && "Invalid motion mode!\n");
2173
0
        }
2174
2175
0
        x->mv_limits = tmp_mv_limits;
2176
0
    } else { // round-up the default
2177
0
        x->best_mv.x = best_pred_mv.x >> 3;
2178
0
        x->best_mv.y = best_pred_mv.y >> 3;
2179
0
    }
2180
2181
0
    if (do_frac_refine) {
2182
0
        int          dis; /* TODO: use dis in distortion calculation later. */
2183
0
        unsigned int sse1; //unused
2184
0
        switch (cand->block_mi.motion_mode) {
2185
0
        case OBMC_CAUSAL:
2186
0
            svt_av1_find_best_obmc_sub_pixel_tree_up(ctx,
2187
0
                                                     x,
2188
0
                                                     cm,
2189
0
                                                     mi_row,
2190
0
                                                     mi_col,
2191
0
                                                     &x->best_mv,
2192
0
                                                     ref_mv,
2193
0
                                                     frm_hdr->allow_high_precision_mv,
2194
0
                                                     x->errorperbit,
2195
0
                                                     &svt_aom_mefn_ptr[bsize],
2196
0
                                                     0, // mv.subpel_force_stop
2197
0
                                                     2, //  mv.subpel_iters_per_step
2198
0
                                                     x->nmv_vec_cost,
2199
0
                                                     x->mv_cost_stack,
2200
0
                                                     &dis,
2201
0
                                                     &sse1,
2202
0
                                                     0,
2203
0
                                                     USE_8_TAPS);
2204
2205
0
            break;
2206
0
        default:
2207
0
            assert(0 && "Invalid motion mode!\n");
2208
0
        }
2209
0
    } else {
2210
0
        x->best_mv.x *= 8;
2211
0
        x->best_mv.y *= 8;
2212
0
    }
2213
0
    if (ctx->approx_inter_rate) {
2214
0
        *rate_mv = svt_av1_mv_bit_cost_light(&x->best_mv, ref_mv);
2215
0
    } else {
2216
0
        *rate_mv = svt_av1_mv_bit_cost(&x->best_mv, ref_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT);
2217
0
    }
2218
0
}
2219
2220
// Refine the OBMC MV (8 bit search). Return true if search found a valid MV; false otherwise
2221
uint8_t svt_aom_obmc_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2222
0
                                       int refine_level) {
2223
0
    if (block_size_wide[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine ||
2224
0
        block_size_high[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine) {
2225
0
        return 1;
2226
0
    }
2227
2228
0
    if (ctx->obmc_weighted_pred_ready == false) {
2229
0
        int mi_row = ctx->blk_org_y >> 2;
2230
0
        int mi_col = ctx->blk_org_x >> 2;
2231
2232
0
        DECLARE_ALIGNED(16, uint8_t, dst_buf1_8b[4 * MAX_PLANES * MAX_SB_SQUARE]);
2233
2234
0
        uint8_t* dst_buf2_8b = dst_buf1_8b + 2 * MAX_PLANES * MAX_SB_SQUARE;
2235
0
        if (ctx->obmc_is_luma_neigh_10bit) {
2236
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_0,
2237
0
                              ctx->blk_geom->bwidth,
2238
0
                              dst_buf1_8b,
2239
0
                              ctx->blk_geom->bwidth,
2240
0
                              NULL,
2241
0
                              ctx->blk_geom->bwidth,
2242
0
                              ctx->blk_geom->bwidth,
2243
0
                              ctx->blk_geom->bheight);
2244
2245
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_1,
2246
0
                              ctx->blk_geom->bwidth,
2247
0
                              dst_buf2_8b,
2248
0
                              ctx->blk_geom->bwidth,
2249
0
                              NULL,
2250
0
                              ctx->blk_geom->bwidth,
2251
0
                              ctx->blk_geom->bwidth,
2252
0
                              ctx->blk_geom->bheight);
2253
0
        }
2254
2255
0
        calc_target_weighted_pred(pcs,
2256
0
                                  ctx,
2257
0
                                  pcs->ppcs->av1_cm,
2258
0
                                  ctx->blk_ptr->av1xd,
2259
0
                                  mi_row,
2260
0
                                  mi_col,
2261
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf1_8b : ctx->obmc_buff_0,
2262
0
                                  ctx->blk_geom->bwidth,
2263
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf2_8b : ctx->obmc_buff_1,
2264
0
                                  ctx->blk_geom->bwidth);
2265
2266
0
        ctx->obmc_weighted_pred_ready = true;
2267
0
    }
2268
0
    Mv              best_pred_mv[2] = {{{0}}, {{0}}};
2269
0
    IntraBcContext  x_st;
2270
0
    IntraBcContext* x = &x_st;
2271
2272
0
    MacroBlockD* xd;
2273
0
    xd = x->xd       = ctx->blk_ptr->av1xd;
2274
0
    const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE);
2275
0
    const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE);
2276
2277
0
    {
2278
0
        assert(cand->block_mi.ref_frame[1] == NONE_FRAME); // OBMC only allowed for unipred cands
2279
0
        uint8_t ref_idx  = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
2280
0
        uint8_t list_idx = get_list_idx(cand->block_mi.ref_frame[0]);
2281
2282
0
        assert(list_idx < MAX_NUM_OF_REF_PIC_LIST);
2283
0
        EbPictureBufferDesc* reference_picture =
2284
0
            ((EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr)->reference_picture;
2285
2286
0
        svt_aom_use_scaled_rec_refs_if_needed(pcs,
2287
0
                                              pcs->ppcs->enhanced_pic,
2288
0
                                              (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr,
2289
0
                                              &reference_picture,
2290
0
                                              EB_8_BIT_MD);
2291
0
        Yv12BufferConfig ref_buf;
2292
0
        svt_aom_link_eb_to_aom_buffer_desc_8bit(reference_picture, &ref_buf);
2293
2294
0
        Buf2D yv12_mb[MAX_PLANES];
2295
0
        svt_av1_setup_pred_block(ctx->blk_geom->bsize, yv12_mb, &ref_buf, mi_row, mi_col);
2296
0
        for (int i = 0; i < 1; ++i) {
2297
0
            x->xdplane[i].pre[0] = yv12_mb[i]; //ref in ME
2298
0
        }
2299
2300
0
        x->plane[0].src.buf  = 0; // x->xdplane[0].pre[0];
2301
0
        x->plane[0].src.buf0 = 0;
2302
0
    }
2303
2304
0
    Mv  best_mv = {.as_int = cand->block_mi.mv[0].as_int};
2305
0
    int tmp_rate_mv;
2306
2307
0
    Mv ref_mv = {.as_int = cand->pred_mv[0].as_int};
2308
2309
0
    single_motion_search(pcs, ctx, cand, best_mv, x, ctx->blk_geom->bsize, &ref_mv, &tmp_rate_mv, refine_level);
2310
0
    cand->block_mi.mv[0].as_int = x->best_mv.as_int;
2311
0
    svt_aom_choose_best_av1_mv_pred(ctx,
2312
0
                                    cand->block_mi.ref_frame[0], // OBMC only allowed for unipred candidtes
2313
0
                                    cand->block_mi.mode,
2314
0
                                    cand->block_mi.mv[0],
2315
0
                                    (Mv){{0}},
2316
0
                                    &cand->drl_index,
2317
0
                                    best_pred_mv);
2318
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2319
    // Check that final chosen MV is valid
2320
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, cand->block_mi.mv[0], cand->block_mi.mv[0], 0)) {
2321
0
        return 1;
2322
0
    }
2323
2324
0
    return 0;
2325
0
}
2326
#endif // CONFIG_ENABLE_OBMC
2327
2328
/*
2329
   inject ME candidates for Light PD0
2330
*/
2331
static void inject_new_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2332
0
                                      const bool allow_bipred) {
2333
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2334
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2335
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2336
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2337
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2338
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2339
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2340
2341
0
    const uint8_t max_refs = pcs->ppcs->pa_me_data->max_refs;
2342
0
    const uint8_t max_l0   = pcs->ppcs->pa_me_data->max_l0;
2343
2344
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2345
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2346
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2347
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2348
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2349
2350
0
        if (ctx->pd0_ctrls.pd0_level == PD0_LVL_6 && inter_direction == BI_PRED) {
2351
0
            continue;
2352
0
        }
2353
2354
        /**************
2355
            NEWMV
2356
        ************* */
2357
0
        if (inter_direction < BI_PRED) {
2358
0
            const uint8_t list_idx = inter_direction;
2359
0
            const uint8_t ref_idx  = inter_direction ? list1_ref_index : list0_ref_index;
2360
0
            const int16_t to_inject_mv_x =
2361
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].x) * 8;
2362
0
            const int16_t to_inject_mv_y =
2363
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].y) * 8;
2364
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2365
2366
0
            ModeDecisionCandidate* cand = &cand_array[cand_total_cnt];
2367
0
            cand->block_mi.mode         = NEWMV;
2368
0
            cand->block_mi.mv[0]        = (Mv){{to_inject_mv_x, to_inject_mv_y}};
2369
0
            cand->block_mi.ref_frame[0] = to_inject_ref_type;
2370
0
            cand->block_mi.ref_frame[1] = NONE_FRAME;
2371
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2372
0
            if (cand_total_cnt > 2) {
2373
0
                break;
2374
0
            }
2375
0
        } else if (allow_bipred) {
2376
0
            assert(inter_direction == BI_PRED);
2377
            /**************
2378
               NEW_NEWMV
2379
            ************* */
2380
0
            const uint32_t ref0_offset = me_block_offset * max_refs +
2381
0
                (me_block_results_ptr->ref0_list > 0 ? max_l0 : 0) + list0_ref_index;
2382
0
            const uint32_t ref1_offset = me_block_offset * max_refs +
2383
0
                (me_block_results_ptr->ref1_list > 0 ? max_l0 : 0) + list1_ref_index;
2384
0
            const int16_t to_inject_mv_x_l0 = (me_results->me_mv_array[ref0_offset].x) * 8;
2385
0
            const int16_t to_inject_mv_y_l0 = (me_results->me_mv_array[ref0_offset].y) * 8;
2386
0
            const int16_t to_inject_mv_x_l1 = (me_results->me_mv_array[ref1_offset].x) * 8;
2387
0
            const int16_t to_inject_mv_y_l1 = (me_results->me_mv_array[ref1_offset].y) * 8;
2388
2389
0
            MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2390
0
                                      svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2391
2392
            // Inject AVG candidate only
2393
0
            ModeDecisionCandidate* cand   = &cand_array[cand_total_cnt];
2394
0
            cand->block_mi.mv[REF_LIST_0] = (Mv){{to_inject_mv_x_l0, to_inject_mv_y_l0}};
2395
0
            cand->block_mi.mv[REF_LIST_1] = (Mv){{to_inject_mv_x_l1, to_inject_mv_y_l1}};
2396
0
            cand->block_mi.mode           = NEW_NEWMV;
2397
0
            cand->block_mi.ref_frame[0]   = rf[0];
2398
0
            cand->block_mi.ref_frame[1]   = rf[1];
2399
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2400
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2401
0
            if (cand_total_cnt > 2) {
2402
0
                break;
2403
0
            }
2404
0
        }
2405
0
    }
2406
    // update the total number of candidates injected
2407
0
    (*candidate_total_cnt) = cand_total_cnt;
2408
0
}
2409
2410
static void inject_new_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2411
0
                                            uint32_t* candidate_total_cnt, const bool allow_bipred) {
2412
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2413
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2414
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2415
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2416
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2417
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2418
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2419
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2420
2421
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2422
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2423
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2424
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2425
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2426
2427
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates >= 2) {
2428
0
            if ((total_me_cnt > 1) && (inter_direction != 2)) {
2429
0
                continue;
2430
0
            }
2431
0
        } else if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2432
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2433
0
                continue;
2434
0
            }
2435
0
        }
2436
2437
        /**************
2438
            NEWMV
2439
        ************* */
2440
0
        if (inter_direction < BI_PRED) {
2441
0
            const uint8_t list_idx           = inter_direction;
2442
0
            const uint8_t ref_idx            = inter_direction ? list1_ref_index : list0_ref_index;
2443
0
            Mv            to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2444
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2445
0
            if (ctx->injected_mv_count == 0 ||
2446
0
                mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false) {
2447
0
                uint8_t drl_index = 0;
2448
0
                svt_aom_choose_best_av1_mv_pred(
2449
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2450
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2451
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2452
0
                    cand->block_mi.use_intrabc        = 0;
2453
0
                    cand->block_mi.is_interintra_used = 0;
2454
0
                    cand->skip_mode_allowed           = false;
2455
0
                    cand->block_mi.mode               = NEWMV;
2456
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2457
0
                    cand->drl_index                   = drl_index;
2458
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2459
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2460
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2461
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2462
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2463
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2464
                    // Add the injected MV to the list of injected MVs
2465
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2466
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2467
0
                    ++ctx->injected_mv_count;
2468
0
                }
2469
0
            }
2470
0
        } else if (allow_bipred && inter_direction == 2 &&
2471
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2472
            /**************
2473
               NEW_NEWMV
2474
            ************* */
2475
0
            Mv               to_inj_mv0 = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2476
0
            Mv               to_inj_mv1 = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2477
0
            MvReferenceFrame rf[2]      = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2478
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2479
0
            uint8_t          to_inject_ref_type = av1_ref_frame_type(rf);
2480
0
            if ((ctx->injected_mv_count == 0 ||
2481
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2482
0
                uint8_t drl_index = 0;
2483
0
                svt_aom_choose_best_av1_mv_pred(
2484
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2485
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2486
0
                    ModeDecisionCandidate* cand         = &cand_array[cand_total_cnt];
2487
0
                    cand->block_mi.use_intrabc          = 0;
2488
0
                    cand->block_mi.is_interintra_used   = 0;
2489
0
                    cand->skip_mode_allowed             = false;
2490
0
                    cand->drl_index                     = drl_index;
2491
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
2492
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
2493
0
                    cand->block_mi.mode                 = NEW_NEWMV;
2494
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
2495
0
                    cand->block_mi.ref_frame[0]         = rf[0];
2496
0
                    cand->block_mi.ref_frame[1]         = rf[1];
2497
0
                    cand->pred_mv[0].as_int             = best_pred_mv[0].as_int;
2498
0
                    cand->pred_mv[1].as_int             = best_pred_mv[1].as_int;
2499
0
                    cand->block_mi.comp_group_idx       = 0;
2500
0
                    cand->block_mi.compound_idx         = 1;
2501
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
2502
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2503
2504
                    // Add the injected MV to the list of injected MVs
2505
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2506
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2507
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2508
0
                    ++ctx->injected_mv_count;
2509
0
                }
2510
0
            }
2511
0
        }
2512
0
    }
2513
    // update the total number of candidates injected
2514
0
    (*candidate_total_cnt) = cand_total_cnt;
2515
0
}
2516
2517
static void inject_new_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2518
0
                                  const bool allow_bipred) {
2519
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2520
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2521
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2522
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2523
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2524
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2525
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2526
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2527
2528
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2529
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2530
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2531
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2532
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2533
2534
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2535
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2536
0
                continue;
2537
0
            }
2538
0
        }
2539
2540
        /**************
2541
            NEWMV unipred
2542
        ************* */
2543
0
        if (inter_direction < BI_PRED) {
2544
0
            const uint8_t list_idx = inter_direction;
2545
0
            const uint8_t ref_idx  = list_idx == REF_LIST_0 ? list0_ref_index : list1_ref_index;
2546
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, PA_ME_GROUP), list_idx, ref_idx)) {
2547
0
                continue;
2548
0
            }
2549
0
            Mv      to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2550
0
            uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2551
0
            if ((ctx->injected_mv_count == 0 ||
2552
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false)) {
2553
0
                uint8_t drl_index = 0;
2554
0
                svt_aom_choose_best_av1_mv_pred(
2555
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2556
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2557
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2558
0
                    cand->block_mi.use_intrabc        = 0;
2559
0
                    cand->skip_mode_allowed           = false;
2560
0
                    cand->block_mi.mode               = NEWMV;
2561
0
                    cand->drl_index                   = drl_index;
2562
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2563
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2564
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2565
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2566
0
                    cand->block_mi.is_interintra_used = 0;
2567
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2568
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2569
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2570
2571
0
                    const bool enable_ii   = true;
2572
0
                    const bool enable_obmc = true;
2573
0
                    const bool enable_warp = true;
2574
0
                    inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2575
2576
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2577
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2578
0
                    ++ctx->injected_mv_count;
2579
0
                }
2580
0
            }
2581
0
        } else if (allow_bipred &&
2582
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2583
0
            assert(inter_direction == BI_PRED);
2584
            /**************
2585
               NEW_NEWMV
2586
            ************* */
2587
0
            if (!is_valid_bipred_ref(ctx,
2588
0
                                     PA_ME_GROUP,
2589
0
                                     me_block_results_ptr->ref0_list,
2590
0
                                     list0_ref_index,
2591
0
                                     me_block_results_ptr->ref1_list,
2592
0
                                     list1_ref_index)) {
2593
0
                continue;
2594
0
            }
2595
0
            Mv      to_inj_mv0         = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2596
0
            Mv      to_inj_mv1         = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2597
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(
2598
0
                (const MvReferenceFrame[]){svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2599
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)});
2600
0
            if ((ctx->injected_mv_count == 0 ||
2601
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2602
0
                uint8_t drl_index = 0;
2603
0
                svt_aom_choose_best_av1_mv_pred(
2604
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2605
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2606
0
                    MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2607
0
                                              svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2608
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2609
0
                    cand->block_mi.use_intrabc        = 0;
2610
0
                    cand->skip_mode_allowed           = false;
2611
0
                    cand->drl_index                   = drl_index;
2612
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2613
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2614
0
                    cand->block_mi.mode               = NEW_NEWMV;
2615
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2616
0
                    cand->block_mi.is_interintra_used = 0;
2617
0
                    cand->block_mi.ref_frame[0]       = rf[0];
2618
0
                    cand->block_mi.ref_frame[1]       = rf[1];
2619
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2620
0
                    cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2621
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2622
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2623
2624
0
                    if (ctx->inter_comp_ctrls.do_me) {
2625
0
                        ctx->cmp_store.pred0_cnt = 0;
2626
0
                        ctx->cmp_store.pred1_cnt = 0;
2627
0
                        inj_comp_modes(pcs, ctx, &cand_total_cnt);
2628
0
                    }
2629
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2630
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2631
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2632
0
                    ++ctx->injected_mv_count;
2633
0
                }
2634
0
            }
2635
0
        }
2636
0
    }
2637
    // update the total number of candidates injected
2638
0
    (*candidate_total_cnt) = cand_total_cnt;
2639
0
}
2640
2641
static void inject_global_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2642
0
                                     const bool allow_bipred) {
2643
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
2644
0
    uint32_t               cand_total_cnt = (*candidate_total_cnt);
2645
0
    uint32_t               mi_row         = ctx->blk_org_y >> MI_SIZE_LOG2;
2646
0
    uint32_t               mi_col         = ctx->blk_org_x >> MI_SIZE_LOG2;
2647
2648
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2649
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2650
0
        MvReferenceFrame rf[2];
2651
0
        av1_set_ref_frame(rf, ref_pair);
2652
2653
        //single ref/list
2654
0
        if (rf[1] == NONE_FRAME) {
2655
0
            MvReferenceFrame frame_type = rf[0];
2656
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2657
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2658
2659
0
            if (!svt_aom_is_valid_unipred_ref(ctx, GLOBAL_GROUP, list_idx, ref_idx)) {
2660
0
                continue;
2661
0
            }
2662
            // Get gm params
2663
0
            WarpedMotionParams* gm_params = &pcs->ppcs->global_motion[frame_type];
2664
0
            if (pcs->ppcs->gm_ctrls.skip_identity && gm_params->wmtype == IDENTITY) {
2665
0
                continue;
2666
0
            }
2667
0
            Mv to_inj_mv = svt_aom_gm_get_motion_vector_enc(gm_params,
2668
0
                                                            pcs->ppcs->frm_hdr.allow_high_precision_mv,
2669
0
                                                            ctx->blk_geom->bsize,
2670
0
                                                            mi_col,
2671
0
                                                            mi_row,
2672
0
                                                            0 /* force_integer_mv */);
2673
2674
0
            assert(list_idx == 0 || list_idx == 1);
2675
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2676
0
            cand->block_mi.mode               = GLOBALMV;
2677
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2678
0
            cand->block_mi.is_interintra_used = 0;
2679
0
            cand->wm_params_l0                = *gm_params;
2680
0
            cand->wm_params_l1                = *gm_params;
2681
0
            cand->block_mi.use_intrabc        = 0;
2682
0
            cand->skip_mode_allowed           = false;
2683
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2684
0
            cand->drl_index                   = 0;
2685
0
            cand->block_mi.ref_frame[0]       = rf[0];
2686
0
            cand->block_mi.ref_frame[1]       = rf[1];
2687
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2688
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2689
2690
0
            const bool enable_ii   = true;
2691
0
            const bool enable_obmc = false;
2692
0
            const bool enable_warp = false;
2693
0
            inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2694
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2695
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2696
0
            ++ctx->injected_mv_count;
2697
0
        } else if (allow_bipred) {
2698
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2699
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2700
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2701
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2702
2703
0
            if (!is_valid_bipred_ref(ctx, GLOBAL_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
2704
0
                return;
2705
0
            }
2706
            // Get gm params
2707
0
            WarpedMotionParams* gm_params_0 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_0, ref_idx_0)];
2708
2709
0
            WarpedMotionParams* gm_params_1 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_1, ref_idx_1)];
2710
2711
0
            if (pcs->ppcs->gm_ctrls.skip_identity &&
2712
0
                (gm_params_0->wmtype == IDENTITY || gm_params_1->wmtype == IDENTITY)) {
2713
0
                continue;
2714
0
            }
2715
0
            Mv to_inj_mv0 = svt_aom_gm_get_motion_vector_enc(gm_params_0,
2716
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2717
0
                                                             ctx->blk_geom->bsize,
2718
0
                                                             mi_col,
2719
0
                                                             mi_row,
2720
0
                                                             0 /* force_integer_mv */);
2721
2722
0
            Mv      to_inj_mv1         = svt_aom_gm_get_motion_vector_enc(gm_params_1,
2723
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2724
0
                                                             ctx->blk_geom->bsize,
2725
0
                                                             mi_col,
2726
0
                                                             mi_row,
2727
0
                                                             0 /* force_integer_mv */);
2728
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(rf);
2729
2730
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2731
0
            cand->block_mi.use_intrabc        = 0;
2732
0
            cand->skip_mode_allowed           = false;
2733
0
            cand->block_mi.mode               = GLOBAL_GLOBALMV;
2734
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2735
0
            cand->wm_params_l0                = *gm_params_0;
2736
0
            cand->wm_params_l1                = *gm_params_1;
2737
0
            cand->block_mi.is_interintra_used = 0;
2738
0
            cand->drl_index                   = 0;
2739
0
            cand->block_mi.ref_frame[0]       = rf[0];
2740
0
            cand->block_mi.ref_frame[1]       = rf[1];
2741
0
            cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2742
0
            cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2743
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2744
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2745
2746
0
            if (ctx->inter_comp_ctrls.do_global) {
2747
0
                ctx->cmp_store.pred0_cnt = 0;
2748
0
                ctx->cmp_store.pred1_cnt = 0;
2749
0
                inj_comp_modes(pcs, ctx, &cand_total_cnt);
2750
0
            }
2751
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2752
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2753
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2754
0
            ++ctx->injected_mv_count;
2755
0
        }
2756
0
    }
2757
    // update the total number of candidates injected
2758
0
    (*candidate_total_cnt) = cand_total_cnt;
2759
0
}
2760
2761
static void inject_pme_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2762
0
                                  const bool allow_bipred) {
2763
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
2764
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
2765
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
2766
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2767
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2768
0
        MvReferenceFrame rf[2];
2769
0
        av1_set_ref_frame(rf, ref_pair);
2770
2771
        //single ref/list
2772
0
        if (rf[1] == NONE_FRAME) {
2773
0
            MvReferenceFrame frame_type = rf[0];
2774
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2775
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2776
2777
0
            if (ctx->valid_pme_mv[list_idx][ref_idx]) {
2778
0
                Mv to_inj_mv = ctx->best_pme_mv[list_idx][ref_idx];
2779
0
                if ((ctx->injected_mv_count == 0 ||
2780
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
2781
0
                    uint8_t drl_index = 0;
2782
0
                    svt_aom_choose_best_av1_mv_pred(
2783
0
                        ctx, frame_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2784
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2785
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2786
0
                        cand->block_mi.use_intrabc        = 0;
2787
0
                        cand->skip_mode_allowed           = false;
2788
0
                        cand->block_mi.mode               = NEWMV;
2789
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2790
0
                        cand->block_mi.is_interintra_used = 0;
2791
0
                        cand->drl_index                   = drl_index;
2792
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2793
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2794
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2795
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2796
0
                        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2797
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2798
2799
0
                        const bool enable_ii   = true;
2800
0
                        const bool enable_obmc = true;
2801
0
                        const bool enable_warp = true;
2802
0
                        inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2803
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2804
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2805
0
                        ++ctx->injected_mv_count;
2806
0
                    }
2807
0
                }
2808
0
            }
2809
0
        } else if (allow_bipred) {
2810
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2811
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2812
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2813
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2814
2815
0
            if (ctx->valid_pme_mv[list_idx_0][ref_idx_0] && ctx->valid_pme_mv[list_idx_1][ref_idx_1]) {
2816
0
                Mv            to_inj_mv0         = ctx->best_pme_mv[list_idx_0][ref_idx_0];
2817
0
                Mv            to_inj_mv1         = ctx->best_pme_mv[list_idx_1][ref_idx_1];
2818
0
                const uint8_t to_inject_ref_type = av1_ref_frame_type((const MvReferenceFrame[]){
2819
0
                    svt_get_ref_frame_type(list_idx_0, ref_idx_0),
2820
0
                    svt_get_ref_frame_type(list_idx_1, ref_idx_1),
2821
0
                });
2822
0
                if ((ctx->injected_mv_count == 0 ||
2823
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2824
0
                    uint8_t drl_index = 0;
2825
0
                    svt_aom_choose_best_av1_mv_pred(
2826
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2827
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2828
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2829
0
                        cand->block_mi.use_intrabc        = 0;
2830
0
                        cand->skip_mode_allowed           = false;
2831
0
                        cand->drl_index                   = drl_index;
2832
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2833
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2834
0
                        cand->block_mi.mode               = NEW_NEWMV;
2835
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2836
0
                        cand->block_mi.is_interintra_used = 0;
2837
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2838
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2839
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2840
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2841
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2842
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2843
2844
0
                        if (ctx->inter_comp_ctrls.do_pme) {
2845
0
                            ctx->cmp_store.pred0_cnt = 0;
2846
0
                            ctx->cmp_store.pred1_cnt = 0;
2847
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
2848
0
                        }
2849
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2850
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2851
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2852
0
                        ++ctx->injected_mv_count;
2853
0
                    }
2854
0
                }
2855
0
            }
2856
0
        }
2857
0
    }
2858
0
    (*candidate_total_cnt) = cand_total_cnt;
2859
0
}
2860
2861
static void inject_inter_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
2862
0
                                        uint32_t* candidate_total_cnt) {
2863
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2864
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2865
    // See AV1 spec 5.11.25
2866
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2867
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2868
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2869
2870
0
    inject_new_candidates_pd0(pcs, ctx, candidate_total_cnt, allow_bipred);
2871
0
}
2872
2873
static void inject_inter_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2874
0
                                              uint32_t* cand_total_cnt) {
2875
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2876
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2877
    // See AV1 spec 5.11.25
2878
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2879
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2880
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2881
    // Needed in case WM/OBMC is on at the frame level (even though not used in light-PD1 path)
2882
0
    if (frm_hdr->is_motion_mode_switchable) {
2883
0
        const uint16_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2884
0
        const uint16_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2885
0
        svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2886
0
    } else {
2887
        // Overlappable neighbours only needed for non-"SIMPLE_TRANSLATION" candidates
2888
0
        ctx->blk_ptr->overlappable_neighbors = 0;
2889
0
    }
2890
0
    svt_aom_init_wm_samples(pcs, ctx);
2891
    // Inject MVP candidates
2892
0
    if (ctx->new_nearest_injection &&
2893
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2894
0
        inject_mvp_candidates_ii_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2895
0
    }
2896
2897
    // Inject ME candidates
2898
0
    if (ctx->inject_new_me) {
2899
0
        inject_new_candidates_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2900
0
    }
2901
0
}
2902
2903
static void svt_aom_inject_inter_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
2904
0
                                            uint32_t* cand_total_cnt) {
2905
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2906
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2907
    // See AV1 spec 5.11.25
2908
    // RTC low-delay is single-reference (no compound / 2nd ref): CONFIG_ENABLE_INTER_COMPOUND folds this to false.
2909
0
    const bool allow_bipred = CONFIG_ENABLE_INTER_COMPOUND && frm_hdr->reference_mode != SINGLE_REFERENCE &&
2910
0
        ctx->blk_geom->bwidth != 4 && ctx->blk_geom->bheight != 4;
2911
2912
0
    const uint32_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2913
0
    const uint32_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2914
2915
0
    svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2916
0
    svt_aom_init_wm_samples(pcs, ctx);
2917
0
#if CONFIG_ENABLE_OBMC
2918
0
    if (ctx->obmc_ctrls.enabled && ctx->obmc_ctrls.refine_level == 0) {
2919
0
        const uint8_t is_obmc_allowed = svt_aom_obmc_motion_mode_allowed(
2920
0
                                            pcs, ctx, ctx->blk_geom->bsize, 1, LAST_FRAME, -1, NEWMV) == OBMC_CAUSAL;
2921
0
        if (is_obmc_allowed) {
2922
0
            svt_aom_precompute_obmc_data(pcs, ctx, PICTURE_BUFFER_DESC_LUMA_MASK);
2923
0
        }
2924
0
    }
2925
0
#endif
2926
    /**************
2927
         MVP
2928
    ************* */
2929
0
    if (ctx->new_nearest_injection &&
2930
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2931
0
        inject_mvp_candidates_ii(pcs, ctx, cand_total_cnt, allow_bipred);
2932
0
    }
2933
    //----------------------
2934
    //    NEAREST_NEWMV, NEW_NEARESTMV, NEAR_NEWMV, NEW_NEARMV.
2935
    //----------------------
2936
0
    if (ctx->new_nearest_near_comb_injection && allow_bipred) {
2937
0
        inject_new_nearest_new_comb_candidates(pcs, ctx, cand_total_cnt);
2938
0
    }
2939
0
    if (ctx->inject_new_me) {
2940
0
        inject_new_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2941
0
    }
2942
0
    if (ctx->global_mv_injection) {
2943
0
        inject_global_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2944
0
    }
2945
0
    if (ctx->bipred3x3_ctrls.enabled && allow_bipred) {
2946
0
        bipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2947
0
    }
2948
2949
0
    if (ctx->unipred3x3_injection) {
2950
0
        unipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2951
0
    }
2952
2953
    // determine when to inject pme candidates based on size and resolution of block
2954
0
    if (ctx->inject_new_pme && ctx->updated_enable_pme) {
2955
0
        inject_pme_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2956
0
    }
2957
0
}
2958
2959
static const TxType g_intra_mode_to_tx_type[INTRA_MODES] = {
2960
    DCT_DCT, // DC
2961
    ADST_DCT, // V
2962
    DCT_ADST, // H
2963
    DCT_DCT, // D45
2964
    ADST_ADST, // D135
2965
    ADST_DCT, // D117
2966
    DCT_ADST, // D153
2967
    DCT_ADST, // D207
2968
    ADST_DCT, // D63
2969
    ADST_ADST, // SMOOTH
2970
    ADST_DCT, // SMOOTH_V
2971
    DCT_ADST, // SMOOTH_H
2972
    ADST_ADST, // PAETH
2973
};
2974
2975
static INLINE TxType intra_mode_to_tx_type(PredictionMode pred_mode, UvPredictionMode pred_mode_uv,
2976
151k
                                           PlaneType plane_type) {
2977
151k
    const PredictionMode mode = (plane_type == PLANE_TYPE_Y) ? pred_mode : get_uv_mode(pred_mode_uv);
2978
151k
    assert(mode < INTRA_MODES);
2979
151k
    return g_intra_mode_to_tx_type[mode];
2980
151k
}
2981
2982
/* For intra prediction, the chroma transform type may not follow the luma type.
2983
This function will return the intra chroma TX type to be used, which is based on TX size and chroma mode.
2984
Refer to section 5.11.40 of the AV1 spec (compute_tx_type). */
2985
151k
TxType svt_aom_get_intra_uv_tx_type(UvPredictionMode pred_mode_uv, TxSize tx_size, int32_t reduced_tx_set) {
2986
151k
    if (txsize_sqr_up_map[tx_size] > TX_32X32) {
2987
0
        return DCT_DCT;
2988
0
    }
2989
2990
    // In intra mode, uv planes don't share the same prediction mode as y
2991
    // plane, so the tx_type should not be shared. Pass DC_PRED as luma mode because the argument
2992
    // will not be used.
2993
151k
    TxType tx_type = intra_mode_to_tx_type(DC_PRED, pred_mode_uv, PLANE_TYPE_UV);
2994
151k
    assert(tx_type < TX_TYPES);
2995
151k
    const TxSetType tx_set_type = get_ext_tx_set_type(tx_size, /*is_inter*/ 0, reduced_tx_set);
2996
151k
    return !av1_ext_tx_used[tx_set_type][tx_type] ? DCT_DCT : tx_type;
2997
151k
}
2998
2999
// Values are now correlated to quantizer.
3000
0
static INLINE int mv_check_bounds(const MvLimits* mv_limits, const Mv* mv) {
3001
0
    return (mv->y >> 3) < mv_limits->row_min || (mv->y >> 3) > mv_limits->row_max ||
3002
0
        (mv->x >> 3) < mv_limits->col_min || (mv->x >> 3) > mv_limits->col_max;
3003
0
}
3004
3005
0
static void assert_release(int statement) {
3006
0
    if (statement == 0) {
3007
0
        SVT_LOG("ASSERT_ERRRR\n");
3008
0
    }
3009
0
}
3010
3011
static void intra_bc_search(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3012
0
                            BlkStruct* blk_ptr, Mv* dv_cand, uint8_t* num_dv_cand) {
3013
0
    IntraBcContext  x_st;
3014
0
    IntraBcContext* x           = &x_st;
3015
0
    uint32_t        full_lambda = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_lambda_md[EB_10_BIT_MD]
3016
0
                                                                    : ctx->full_lambda_md[EB_8_BIT_MD];
3017
3018
0
    x->approx_inter_rate = ctx->approx_inter_rate;
3019
0
    x->xd                = blk_ptr->av1xd;
3020
0
    x->nmv_vec_cost      = ctx->md_rate_est_ctx->nmv_vec_cost;
3021
0
    x->mv_cost_stack     = ctx->md_rate_est_ctx->nmvcoststack;
3022
0
    BlockSize bsize      = ctx->blk_geom->bsize;
3023
0
    assert(bsize < BLOCK_SIZES_ALL);
3024
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
3025
0
    const Av1Common* const cm         = pcs->ppcs->av1_cm;
3026
0
    MvReferenceFrame       ref_frame  = INTRA_FRAME;
3027
0
    const int              num_planes = 3;
3028
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
3029
0
    const TileInfo*        tile       = &xd->tile;
3030
0
    const int              mi_row     = -xd->mb_to_top_edge / (8 * MI_SIZE);
3031
0
    const int              mi_col     = -xd->mb_to_left_edge / (8 * MI_SIZE);
3032
0
    const int              w          = block_size_wide[bsize];
3033
0
    const int              h          = block_size_high[bsize];
3034
0
    const int              sb_row     = mi_row >> scs->seq_header.sb_size_log2;
3035
0
    const int              sb_col     = mi_col >> scs->seq_header.sb_size_log2;
3036
3037
    // Set up limit values for MV components.
3038
    // Mv beyond the range do not produce new/different prediction block.
3039
0
    const int mi_width   = mi_size_wide[bsize];
3040
0
    const int mi_height  = mi_size_high[bsize];
3041
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
3042
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
3043
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
3044
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
3045
    //set search paramters
3046
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
3047
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
3048
0
    x->errorperbit += (x->errorperbit == 0);
3049
    //temp buffer for hash me
3050
0
    for (int i = 0; i < 2; i++) {
3051
0
        EB_MALLOC_ARRAY_NO_CHECK(x->hash_value_buffer[i], AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
3052
0
    }
3053
3054
0
    Mv nearestmv, nearmv;
3055
0
    svt_av1_find_best_ref_mvs_from_stack(ctx->ref_mv_stack /*mbmi_ext*/, xd, ref_frame, &nearestmv, &nearmv);
3056
0
    if (nearestmv.as_int == INVALID_MV) {
3057
0
        nearestmv.as_int = 0;
3058
0
    }
3059
0
    if (nearmv.as_int == INVALID_MV) {
3060
0
        nearmv.as_int = 0;
3061
0
    }
3062
0
    Mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
3063
0
    if (dv_ref.as_int == 0) {
3064
0
        svt_aom_find_ref_dv(&dv_ref, tile, scs->seq_header.sb_mi_size, mi_row, mi_col);
3065
0
    }
3066
    // Ref DV should not have sub-pel.
3067
0
    assert((dv_ref.x & 7) == 0);
3068
0
    assert((dv_ref.y & 7) == 0);
3069
0
    ctx->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;
3070
3071
    /* pointer to current frame */
3072
0
    Yv12BufferConfig cur_buf;
3073
0
    svt_aom_link_eb_to_aom_buffer_desc_8bit(pcs->ppcs->enhanced_pic, &cur_buf);
3074
0
    struct Buf2D yv12_mb[MAX_PLANES];
3075
0
    svt_av1_setup_pred_block(bsize, yv12_mb, &cur_buf, mi_row, mi_col);
3076
0
    for (int i = 0; i < num_planes; ++i) {
3077
0
        x->xdplane[i].pre[0] = yv12_mb[i]; // ref in ME
3078
0
    }
3079
    // setup src for DV search same as ref
3080
0
    x->plane[0].src = x->xdplane[0].pre[0];
3081
3082
0
    enum IntrabcMotionDirection max_dir = pcs->ppcs->intrabc_ctrls.search_dir ? IBC_MOTION_LEFT : IBC_MOTION_DIRECTIONS;
3083
3084
0
    for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE; dir < max_dir; ++dir) {
3085
0
        const MvLimits tmp_mv_limits = x->mv_limits;
3086
3087
0
        switch (dir) {
3088
0
        case IBC_MOTION_ABOVE:
3089
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3090
0
            x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w;
3091
0
            x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE;
3092
0
            x->mv_limits.row_max = (sb_row * scs->seq_header.sb_mi_size - mi_row) * MI_SIZE - h;
3093
0
            break;
3094
0
        case IBC_MOTION_LEFT:
3095
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3096
0
            x->mv_limits.col_max = (sb_col * scs->seq_header.sb_mi_size - mi_col) * MI_SIZE - w;
3097
            // TODO: Minimize the overlap between above and
3098
            // left areas.
3099
0
            x->mv_limits.row_min     = (tile->mi_row_start - mi_row) * MI_SIZE;
3100
0
            int bottom_coded_mi_edge = AOMMIN((sb_row + 1) * scs->seq_header.sb_mi_size, tile->mi_row_end);
3101
0
            x->mv_limits.row_max     = (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
3102
0
            break;
3103
0
        default:
3104
0
            assert(0);
3105
0
        }
3106
0
        assert_release(x->mv_limits.col_min >= tmp_mv_limits.col_min);
3107
0
        assert_release(x->mv_limits.col_max <= tmp_mv_limits.col_max);
3108
0
        assert_release(x->mv_limits.row_min >= tmp_mv_limits.row_min);
3109
0
        assert_release(x->mv_limits.row_max <= tmp_mv_limits.row_max);
3110
3111
0
        svt_av1_set_mv_search_range(&x->mv_limits, &dv_ref);
3112
3113
0
        if (x->mv_limits.col_max < x->mv_limits.col_min || x->mv_limits.row_max < x->mv_limits.row_min) {
3114
0
            x->mv_limits = tmp_mv_limits;
3115
0
            continue;
3116
0
        }
3117
0
        Mv mvp_full = dv_ref;
3118
0
        mvp_full.x >>= 3;
3119
0
        mvp_full.y >>= 3;
3120
0
        x->best_mv.as_int = 0;
3121
3122
        // Hash Search
3123
0
        const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
3124
3125
0
        int best_hash_cost = INT_MAX;
3126
0
        Mv  best_hash_mv   = {{0, 0}};
3127
3128
0
        svt_av1_intrabc_hash_search(
3129
0
            pcs, x, bsize, mi_col * MI_SIZE, mi_row * MI_SIZE, &dv_ref, 1, fn_ptr, &best_hash_cost, &best_hash_mv);
3130
3131
        // Hash produced a candidate
3132
0
        if (best_hash_cost < INT_MAX) {
3133
0
            Mv dv;
3134
0
            dv.x = best_hash_mv.x * 8;
3135
0
            dv.y = best_hash_mv.y * 8;
3136
3137
0
            dv_cand[*num_dv_cand] = dv;
3138
0
            (*num_dv_cand)++;
3139
3140
0
            x->best_mv = best_hash_mv;
3141
0
        }
3142
        // Full-pixel fallback if hash didn't produce a candidate
3143
0
        else {
3144
0
            svt_av1_full_pixel_search(pcs, x, bsize, &mvp_full, 0, x->sadperbit16, NULL, &dv_ref);
3145
3146
0
            Mv dv = {{x->best_mv.x * 8, x->best_mv.y * 8}};
3147
3148
0
            if (!mv_check_bounds(&x->mv_limits, &dv) &&
3149
0
                svt_aom_is_dv_valid(dv, xd, mi_row, mi_col, bsize, scs->seq_header.sb_size_log2)) {
3150
0
                dv_cand[*num_dv_cand] = dv;
3151
0
                (*num_dv_cand)++;
3152
0
            }
3153
0
        }
3154
3155
0
        x->mv_limits = tmp_mv_limits;
3156
0
    }
3157
3158
0
    for (int i = 0; i < 2; i++) {
3159
0
        EB_FREE_ARRAY(x->hash_value_buffer[i]);
3160
0
    }
3161
0
}
3162
3163
static void inject_intra_bc_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3164
0
                                       BlkStruct* blk_ptr, uint32_t* cand_cnt) {
3165
0
    Mv      dv_cand[2];
3166
0
    uint8_t num_dv_cand = 0;
3167
3168
    //perform dv-pred + search up to 2 dv(s)
3169
0
    intra_bc_search(pcs, ctx, scs, blk_ptr, dv_cand, &num_dv_cand);
3170
3171
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
3172
3173
0
    for (uint32_t dv_i = 0; dv_i < num_dv_cand; dv_i++) {
3174
0
        ModeDecisionCandidate* cand               = &cand_array[*cand_cnt];
3175
0
        cand->palette_info                        = NULL;
3176
0
        cand->block_mi.use_intrabc                = 1;
3177
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3178
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3179
0
        cand->block_mi.uv_mode                    = UV_DC_PRED;
3180
0
        cand->block_mi.cfl_alpha_signs            = 0;
3181
0
        cand->block_mi.cfl_alpha_idx              = 0;
3182
0
        cand->transform_type[0]                   = DCT_DCT;
3183
0
        cand->transform_type_uv                   = DCT_DCT;
3184
0
        cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3185
0
        cand->block_mi.ref_frame[1]               = NONE_FRAME;
3186
0
        cand->block_mi.mode                       = DC_PRED;
3187
0
        cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3188
        //inter ralated
3189
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3190
0
        cand->block_mi.is_interintra_used = 0;
3191
0
        cand->skip_mode_allowed           = false;
3192
0
        cand->block_mi.mv[0].as_int       = dv_cand[dv_i].as_int;
3193
0
        cand->pred_mv[0].as_int           = ctx->ref_mv_stack[INTRA_FRAME][0].this_mv.as_int;
3194
0
        cand->drl_index                   = 0;
3195
0
        cand->block_mi.interp_filters     = av1_broadcast_interp_filter(BILINEAR);
3196
0
        INC_MD_CAND_CNT((*cand_cnt), pcs->ppcs->max_can_count);
3197
0
    }
3198
0
}
3199
3200
static void inject_intra_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
3201
153k
                                        uint32_t* candidate_total_cnt) {
3202
153k
    uint32_t               cand_total_cnt     = 0;
3203
153k
    ModeDecisionCandidate* cand               = &ctx->fast_cand_array[cand_total_cnt];
3204
153k
    cand->skip_mode_allowed                   = false;
3205
153k
    cand->palette_info                        = NULL;
3206
153k
    cand->block_mi.use_intrabc                = 0;
3207
153k
    cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3208
153k
    cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3209
153k
    cand->block_mi.uv_mode                    = UV_DC_PRED;
3210
153k
    cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3211
153k
    cand->block_mi.cfl_alpha_signs            = 0;
3212
153k
    cand->block_mi.cfl_alpha_idx              = 0;
3213
153k
    cand->transform_type[0]                   = DCT_DCT;
3214
153k
    cand->transform_type_uv                   = DCT_DCT;
3215
153k
    cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3216
153k
    cand->block_mi.ref_frame[1]               = NONE_FRAME;
3217
153k
    cand->block_mi.mode                       = DC_PRED;
3218
153k
    cand->block_mi.motion_mode                = SIMPLE_TRANSLATION;
3219
153k
    cand->block_mi.is_interintra_used         = 0;
3220
153k
    cand->block_mi.tx_depth                   = 0;
3221
153k
    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3222
    // update the total number of candidates injected
3223
153k
    (*candidate_total_cnt) = cand_total_cnt;
3224
153k
    return;
3225
153k
}
3226
3227
static void inject_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const bool dc_cand_only_flag,
3228
151k
                                    uint32_t* candidate_total_cnt) {
3229
151k
    FrameHeader*           frm_hdr          = &pcs->ppcs->frm_hdr;
3230
151k
    PredictionMode         intra_mode_start = DC_PRED;
3231
151k
    PredictionMode         intra_mode_end   = dc_cand_only_flag ? DC_PRED : ctx->intra_ctrls.intra_mode_end;
3232
151k
    uint32_t               cand_total_cnt   = *candidate_total_cnt;
3233
151k
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
3234
151k
    const bool    use_angle_delta = ctx->intra_ctrls.angular_pred_level ? av1_use_angle_delta(ctx->blk_geom->bsize) : 0;
3235
151k
    const uint8_t disable_angle_prediction                = (ctx->intra_ctrls.angular_pred_level == 0);
3236
151k
    uint8_t       directional_mode_skip_mask[INTRA_MODES] = {0};
3237
151k
    if (ctx->intra_ctrls.angular_pred_level >= 4) {
3238
1.64M
        for (uint8_t i = D45_PRED; i < INTRA_MODE_END; i++) {
3239
1.49M
            directional_mode_skip_mask[i] = 1;
3240
1.49M
        }
3241
150k
    }
3242
151k
    const TxSize tx_size_uv = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3243
3244
302k
    for (PredictionMode intra_mode = intra_mode_start; intra_mode <= intra_mode_end; ++intra_mode) {
3245
151k
        if (av1_is_directional_mode(intra_mode) &&
3246
0
            (disable_angle_prediction || directional_mode_skip_mask[intra_mode])) {
3247
0
            continue;
3248
0
        }
3249
3250
151k
        const uint8_t angle_delta_count = av1_is_directional_mode(intra_mode) &&
3251
0
                ctx->intra_ctrls.angular_pred_level <= 2 && use_angle_delta
3252
151k
            ? 7
3253
151k
            : 1;
3254
3255
301k
        for (uint8_t angle_delta_counter = 0; angle_delta_counter < angle_delta_count; ++angle_delta_counter) {
3256
150k
            int32_t angle_delta = CLIP((angle_delta_count == 1 ? 0 : angle_delta_counter - MAX_ANGLE_DELTA),
3257
150k
                                       -MAX_ANGLE_DELTA,
3258
150k
                                       MAX_ANGLE_DELTA);
3259
150k
            if ((ctx->intra_ctrls.angular_pred_level >= 2 &&
3260
151k
                 (angle_delta == -1 || angle_delta == 1 || angle_delta == -2 || angle_delta == 2)) ||
3261
151k
                (ctx->intra_ctrls.angular_pred_level >= 3 && angle_delta != 0)) {
3262
0
                continue;
3263
0
            }
3264
150k
            ModeDecisionCandidate* cand               = &cand_array[cand_total_cnt];
3265
150k
            cand->skip_mode_allowed                   = false;
3266
150k
            cand->palette_info                        = NULL;
3267
150k
            cand->block_mi.mode                       = intra_mode;
3268
150k
            cand->block_mi.use_intrabc                = 0;
3269
150k
            cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3270
150k
            cand->block_mi.angle_delta[PLANE_TYPE_Y]  = angle_delta;
3271
150k
            cand->block_mi.uv_mode                    = ctx->ind_uv_avail ? ctx->best_uv_mode[intra_mode]
3272
150k
                                                                          : intra_luma_to_chroma[intra_mode];
3273
150k
            cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[intra_mode]
3274
150k
                                                                          : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3275
150k
            cand->block_mi.cfl_alpha_signs            = 0;
3276
150k
            cand->block_mi.cfl_alpha_idx              = 0;
3277
150k
            cand->transform_type[0]                   = DCT_DCT;
3278
150k
            cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3279
150k
                cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3280
3281
150k
            if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3282
0
                continue;
3283
0
            }
3284
150k
            cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3285
150k
            cand->block_mi.ref_frame[1]       = NONE_FRAME;
3286
150k
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3287
150k
            cand->block_mi.is_interintra_used = 0;
3288
150k
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3289
150k
        }
3290
151k
    }
3291
3292
    // update the total number of candidates injected
3293
151k
    (*candidate_total_cnt) = cand_total_cnt;
3294
3295
151k
    return;
3296
151k
}
3297
3298
static void inject_filter_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
3299
0
                                           uint32_t* candidate_total_cnt) {
3300
0
    FilterIntraMode intra_mode_start = FILTER_DC_PRED;
3301
0
    FilterIntraMode intra_mode_end   = ctx->intra_ctrls.intra_mode_end == PAETH_PRED ? FILTER_PAETH_PRED
3302
0
          : ctx->intra_ctrls.intra_mode_end >= D157_PRED                             ? FILTER_D157_PRED
3303
0
          : ctx->intra_ctrls.intra_mode_end >= H_PRED                                ? FILTER_H_PRED
3304
0
          : ctx->intra_ctrls.intra_mode_end >= V_PRED                                ? FILTER_V_PRED
3305
0
                                                                                     : FILTER_DC_PRED;
3306
0
    intra_mode_end                   = MIN(intra_mode_end, ctx->filter_intra_ctrls.max_filter_intra_mode);
3307
3308
0
    const TxSize           tx_size_uv     = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3309
0
    uint32_t               cand_total_cnt = *candidate_total_cnt;
3310
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
3311
0
    FrameHeader*           frm_hdr        = &pcs->ppcs->frm_hdr;
3312
3313
0
    for (FilterIntraMode filter_intra_mode = intra_mode_start; filter_intra_mode <= intra_mode_end;
3314
0
         filter_intra_mode++) {
3315
0
        ModeDecisionCandidate* cand              = &cand_array[cand_total_cnt];
3316
0
        cand->skip_mode_allowed                  = false;
3317
0
        cand->block_mi.mode                      = DC_PRED;
3318
0
        cand->block_mi.use_intrabc               = 0;
3319
0
        cand->block_mi.filter_intra_mode         = filter_intra_mode;
3320
0
        cand->palette_info                       = NULL;
3321
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3322
3323
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[fimode_to_intramode[filter_intra_mode]]
3324
0
                                                   : intra_luma_to_chroma[fimode_to_intramode[filter_intra_mode]];
3325
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail
3326
0
            ? ctx->best_uv_angle[fimode_to_intramode[filter_intra_mode]]
3327
0
            : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3328
3329
0
        cand->block_mi.cfl_alpha_signs = 0;
3330
0
        cand->block_mi.cfl_alpha_idx   = 0;
3331
0
        cand->transform_type[0]        = DCT_DCT;
3332
0
        cand->transform_type_uv        = svt_aom_get_intra_uv_tx_type(
3333
0
            cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3334
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3335
0
            continue;
3336
0
        }
3337
0
        cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3338
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3339
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3340
0
        cand->block_mi.is_interintra_used = 0;
3341
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3342
0
    }
3343
3344
    // update the total number of candidates injected
3345
0
    (*candidate_total_cnt) = cand_total_cnt;
3346
3347
0
    return;
3348
0
}
3349
3350
static void inject_zz_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3351
0
                                       uint32_t* candidate_total_cnt) {
3352
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3353
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3354
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3355
0
    cand_array[cand_total_cnt].drl_index   = 0;
3356
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3357
0
                                    svt_get_ref_frame_type(REF_LIST_0, 0),
3358
0
                                    NEWMV,
3359
0
                                    (Mv){{0}},
3360
0
                                    (Mv){{0}},
3361
0
                                    &cand_array[cand_total_cnt].drl_index,
3362
0
                                    best_pred_mv);
3363
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3364
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3365
0
        cand->block_mi.use_intrabc        = 0;
3366
0
        cand->skip_mode_allowed           = false;
3367
0
        cand->block_mi.mode               = NEWMV;
3368
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3369
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3370
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_0, 0);
3371
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3372
0
        cand->transform_type[0]           = DCT_DCT;
3373
0
        cand->transform_type_uv           = DCT_DCT;
3374
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3375
0
        cand->block_mi.is_interintra_used = 0;
3376
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3377
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_0, 0)].num;
3378
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3379
        // update the total number of candidates injected
3380
0
        (*candidate_total_cnt) = cand_total_cnt;
3381
0
    }
3382
0
}
3383
3384
1.06M
int svt_av1_allow_palette(int allow_palette, BlockSize bsize) {
3385
#if !CONFIG_ENABLE_PALETTE
3386
    (void)allow_palette;
3387
    (void)bsize;
3388
    return 0;
3389
#else
3390
1.06M
    assert(bsize < BLOCK_SIZES_ALL);
3391
1.06M
    return allow_palette && block_size_wide[bsize] <= 64 && block_size_high[bsize] <= 64 && bsize >= BLOCK_8X8;
3392
1.06M
#endif
3393
1.06M
}
3394
3395
void search_palette_luma(PictureControlSet* pcs, ModeDecisionContext* ctx, PaletteInfo* palette_cand,
3396
                         uint8_t* palette_size_array, uint32_t* tot_palette_cands);
3397
3398
#if FTR_RTC_INTER_PALETTE
3399
// Per-pixel ME-residual floor at or below which an inter block is treated as unchanged content and
3400
// the palette search is skipped: palette cannot beat a ~0-bit zero-MV skip there.
3401
0
#define RTC_INTER_PALETTE_RES_FLOOR 4
3402
#endif
3403
3404
0
static void inject_palette_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt) {
3405
0
#if FTR_RTC_INTER_PALETTE
3406
    // Skip the palette search on inter blocks where inter prediction is essentially perfect; if
3407
    // neither ME nor PME distortion is available the search still runs. Returning with no candidates
3408
    // injected also clears eval_intrabc in generate_md_stage_0_cand when intrabc_ctrls.palette_hint
3409
    // is set - inert on this path (intrabc_level is 0 in RTC, and intra-BC only exists on intra
3410
    // frames), but relevant if palette_hint ever extends to inter frames.
3411
0
    if (pcs->slice_type != I_SLICE) {
3412
0
        uint32_t best_me = (uint32_t)~0;
3413
0
        if (ctx->md_me_dist != (uint32_t)~0) {
3414
0
            best_me = ctx->md_me_dist;
3415
0
        }
3416
0
        if (ctx->md_pme_dist != (uint32_t)~0 && ctx->md_pme_dist < best_me) {
3417
0
            best_me = ctx->md_pme_dist;
3418
0
        }
3419
0
        if (best_me != (uint32_t)~0) {
3420
0
            const uint32_t per_pix = best_me / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight);
3421
0
            if (per_pix <= RTC_INTER_PALETTE_RES_FLOOR) {
3422
0
                return;
3423
0
            }
3424
0
        }
3425
0
    }
3426
0
#endif
3427
0
    uint32_t               can_total_cnt      = *candidate_total_cnt;
3428
0
    ModeDecisionCandidate* cand_array         = ctx->fast_cand_array;
3429
0
    const TxSize           tx_size_uv         = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3430
0
    uint32_t               tot_palette_cands  = 0;
3431
0
    PaletteInfo*           palette_cand_array = ctx->palette_cand_array;
3432
    // MD palette search
3433
0
    uint8_t* palette_size_array_0 = ctx->palette_size_array_0;
3434
3435
0
    search_palette_luma(pcs, ctx, palette_cand_array, palette_size_array_0, &tot_palette_cands);
3436
3437
0
    for (uint32_t cand_i = 0; cand_i < tot_palette_cands; ++cand_i) {
3438
0
        ModeDecisionCandidate* cand       = &cand_array[can_total_cnt];
3439
0
        cand->block_mi.is_interintra_used = 0;
3440
0
        cand->palette_size[0]             = palette_size_array_0[cand_i];
3441
        // Palette is not supported for chroma
3442
0
        cand->palette_size[1] = 0;
3443
0
        cand->palette_info    = &palette_cand_array[cand_i];
3444
0
        assert(palette_size_array_0[cand_i] < 9);
3445
        //to re check these fields
3446
0
        cand->skip_mode_allowed    = false;
3447
0
        cand->block_mi.mode        = DC_PRED;
3448
0
        cand->block_mi.use_intrabc = 0;
3449
3450
0
        cand->block_mi.filter_intra_mode         = FILTER_INTRA_MODES;
3451
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3452
        // Palette is not supported for chroma mode, so we can set the intra chroma mode to anything. To use palette
3453
        // for chroma, we must force DC_PRED to be used for the intra chroma mode
3454
0
        assert(cand_array[can_total_cnt].palette_size[1] == 0);
3455
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[DC_PRED] : intra_luma_to_chroma[DC_PRED];
3456
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[DC_PRED]
3457
0
                                                                      : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3458
0
        cand->block_mi.cfl_alpha_signs            = 0;
3459
0
        cand->block_mi.cfl_alpha_idx              = 0;
3460
0
        cand->transform_type[0]                   = DCT_DCT;
3461
0
        cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3462
0
            cand->block_mi.uv_mode, tx_size_uv, pcs->ppcs->frm_hdr.reduced_tx_set);
3463
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3464
0
            continue;
3465
0
        }
3466
0
        cand->block_mi.ref_frame[0] = INTRA_FRAME;
3467
0
        cand->block_mi.ref_frame[1] = NONE_FRAME;
3468
0
        cand->block_mi.motion_mode  = SIMPLE_TRANSLATION;
3469
0
        INC_MD_CAND_CNT(can_total_cnt, pcs->ppcs->max_can_count);
3470
0
    }
3471
3472
    // update the total number of candidates injected
3473
0
    (*candidate_total_cnt) = can_total_cnt;
3474
3475
0
    return;
3476
0
}
3477
3478
0
static INLINE void eliminate_candidate_based_on_pme_me_results(ModeDecisionContext* ctx, uint8_t* dc_cand_only_flag) {
3479
0
    if (ctx->md_pme_dist != (uint32_t)~0 || ctx->md_me_dist != (uint32_t)~0) {
3480
0
        uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3481
0
        th *= ctx->blk_geom->bheight * ctx->blk_geom->bwidth;
3482
0
        const uint32_t best_me_distotion = MIN(ctx->md_pme_dist, ctx->md_me_dist);
3483
0
        if (best_me_distotion < th) {
3484
0
            *dc_cand_only_flag = 1;
3485
0
        }
3486
0
    }
3487
0
}
3488
3489
static bool valid_ref_frame_type(MvReferenceFrame rf[2], const MvReferenceFrame ref_frame_type_arr[],
3490
0
                                 uint8_t tot_ref_frame_types) {
3491
    // INTRA_FRAME is added in candidates sometimes, skip validation
3492
0
    if (rf[0] == INTRA_FRAME) {
3493
0
        return true;
3494
0
    }
3495
3496
0
    for (uint8_t i = 0; i < tot_ref_frame_types; i++) {
3497
0
        MvReferenceFrame rf_in_arr[2];
3498
0
        av1_set_ref_frame(rf_in_arr, ref_frame_type_arr[i]);
3499
0
        if (rf[0] == rf_in_arr[0] && rf[1] == rf_in_arr[1]) {
3500
0
            return true;
3501
0
        }
3502
0
    }
3503
0
    return false;
3504
0
}
3505
3506
// refer to inject_zz_backup_candidate, but use BWD ref instead of LAST
3507
static void inject_sframe_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3508
0
                                           uint32_t* candidate_total_cnt) {
3509
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3510
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3511
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3512
0
    cand_array[cand_total_cnt].drl_index   = 0;
3513
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3514
0
                                    svt_get_ref_frame_type(REF_LIST_1, 0),
3515
0
                                    NEWMV,
3516
0
                                    (Mv){{0}},
3517
0
                                    (Mv){{0}},
3518
0
                                    &cand_array[cand_total_cnt].drl_index,
3519
0
                                    best_pred_mv);
3520
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3521
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3522
0
        cand->block_mi.use_intrabc        = 0;
3523
0
        cand->skip_mode_allowed           = false;
3524
0
        cand->block_mi.mode               = NEWMV;
3525
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3526
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3527
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_1, 0);
3528
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3529
0
        cand->transform_type[0]           = DCT_DCT;
3530
0
        cand->transform_type_uv           = DCT_DCT;
3531
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3532
0
        cand->block_mi.is_interintra_used = 0;
3533
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3534
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_1, 0)].num;
3535
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3536
        // update the total number of candidates injected
3537
0
        (*candidate_total_cnt) = cand_total_cnt;
3538
0
    }
3539
0
}
3540
3541
// in MD stage 0, candidates are injected by different tools, but for S-Frame in RA mode
3542
// the ref frame types in ref_list0 has be pruned in PD for the reversed direction of ref MVs
3543
// here to check and reject the candidates if mismatches the available frame types array
3544
0
static uint32_t reject_candidate_sframe(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t cand_total_cnt) {
3545
0
    for (uint32_t i = 0; i < cand_total_cnt;) {
3546
0
        if (!valid_ref_frame_type(
3547
0
                ctx->fast_cand_array[i].block_mi.ref_frame, ctx->ref_frame_type_arr, ctx->tot_ref_frame_types)) {
3548
0
            for (uint32_t j = i; j < cand_total_cnt; j++) {
3549
0
                memcpy(&ctx->fast_cand_array[j], &ctx->fast_cand_array[j + 1], sizeof(ModeDecisionCandidate));
3550
0
            }
3551
0
            cand_total_cnt--;
3552
0
            continue;
3553
0
        }
3554
0
        i++;
3555
0
    }
3556
    // zero candidate in fast cand array risks in md stage 0, add a candidate from ref list1 as backup
3557
0
    if (cand_total_cnt == 0) {
3558
0
        inject_sframe_backup_candidate(pcs, ctx, &cand_total_cnt);
3559
0
    }
3560
0
    assert(cand_total_cnt > 0);
3561
0
    return cand_total_cnt;
3562
0
}
3563
3564
EbErrorType generate_md_stage_0_cand_pd0(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3565
153k
                                         PictureControlSet* pcs) {
3566
153k
    const SliceType slice_type     = pcs->slice_type;
3567
153k
    uint32_t        cand_total_cnt = 0;
3568
    //----------------------
3569
    // Intra
3570
153k
    if (ctx->blk_geom->sq_size < 128 && ctx->intra_ctrls.enable_intra) {
3571
153k
        inject_intra_candidates_pd0(pcs, ctx, &cand_total_cnt);
3572
153k
    }
3573
3574
153k
    if (slice_type != I_SLICE) {
3575
0
        inject_inter_candidates_pd0(pcs, ctx, &cand_total_cnt);
3576
0
    }
3577
3578
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_stage_0()
3579
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3580
153k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3581
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3582
0
    }
3583
3584
153k
    if (pcs->ppcs->sframe_ref_pruned) {
3585
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3586
0
    }
3587
3588
153k
    *candidate_total_count_ptr = cand_total_cnt;
3589
3590
153k
    return EB_ErrorNone;
3591
153k
}
3592
3593
/*
3594
   generate candidates for light pd1
3595
*/
3596
void generate_md_stage_0_cand_light_pd1(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3597
0
                                        PictureControlSet* pcs) {
3598
0
    const SliceType slice_type     = pcs->slice_type;
3599
0
    uint32_t        cand_total_cnt = 0;
3600
    // Reset duplicates variables
3601
0
    ctx->injected_mv_count = 0;
3602
0
    ctx->inject_new_me     = 1;
3603
0
    if (slice_type != I_SLICE) {
3604
0
        inject_inter_candidates_light_pd1(pcs, ctx, &cand_total_cnt);
3605
0
    }
3606
    //----------------------
3607
    // Intra
3608
0
    if (ctx->intra_ctrls.enable_intra && ctx->blk_geom->sq_size < 128) {
3609
0
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3610
0
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled && !dc_cand_only_flag &&
3611
0
            ctx->md_me_dist != (uint32_t)~0) {
3612
0
            uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3613
0
            th *= (ctx->blk_geom->bheight * ctx->blk_geom->bwidth);
3614
0
            if (ctx->md_me_dist < th) {
3615
0
                dc_cand_only_flag = 1;
3616
0
            }
3617
0
        }
3618
0
        inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3619
0
    }
3620
3621
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3622
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3623
0
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3624
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3625
0
    }
3626
3627
0
    if (pcs->ppcs->sframe_ref_pruned) {
3628
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3629
0
    }
3630
3631
0
    *candidate_total_count_ptr = cand_total_cnt;
3632
0
}
3633
3634
EbErrorType generate_md_stage_0_cand(PictureControlSet* pcs, ModeDecisionContext* ctx, const PC_TREE* const pc_tree,
3635
152k
                                     uint32_t* candidate_total_count_ptr) {
3636
152k
    const SequenceControlSet* scs            = pcs->scs;
3637
152k
    const SliceType           slice_type     = pcs->slice_type;
3638
152k
    uint32_t                  cand_total_cnt = 0;
3639
    // Reset duplicates variables
3640
152k
    ctx->injected_mv_count = 0;
3641
152k
    ctx->inject_new_me     = 1;
3642
152k
    ctx->inject_new_pme    = 1;
3643
    //----------------------
3644
    // Intra
3645
152k
    if (ctx->intra_ctrls.enable_intra) {
3646
152k
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3647
151k
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled) {
3648
0
            eliminate_candidate_based_on_pme_me_results(ctx, &dc_cand_only_flag);
3649
0
        }
3650
152k
        if (ctx->blk_geom->sq_size < 128) {
3651
152k
            inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3652
152k
        }
3653
151k
        if (ctx->filter_intra_ctrls.enabled && svt_aom_filter_intra_allowed_bsize(ctx->blk_geom->bsize)) {
3654
0
            inject_filter_intra_candidates(pcs, ctx, &cand_total_cnt);
3655
0
        }
3656
3657
151k
        bool eval_intrabc = true;
3658
3659
151k
        if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
3660
0
            uint32_t palette_start_cnt = cand_total_cnt;
3661
3662
0
            inject_palette_candidates(pcs, ctx, &cand_total_cnt);
3663
3664
0
            eval_intrabc = cand_total_cnt > palette_start_cnt;
3665
0
        }
3666
3667
151k
        if (ctx->md_allow_intrabc) {
3668
0
            if (!pcs->ppcs->intrabc_ctrls.palette_hint || eval_intrabc) {
3669
0
                bool do_intra_bc = true;
3670
3671
0
                if (ctx->shape == PART_N) {
3672
0
                    if (pcs->ppcs->intrabc_ctrls.b4_parent_gating && ctx->blk_geom->sq_size == 4 &&
3673
0
                        pc_tree->parent->tested_blk[PART_N][0]) {
3674
0
                        if (pc_tree->parent->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3675
0
                            do_intra_bc = false;
3676
0
                        }
3677
0
                    }
3678
0
                } else {
3679
0
                    if (pcs->ppcs->intrabc_ctrls.nsq_parent_gating && pc_tree->tested_blk[PART_N][0]) {
3680
0
                        if (pc_tree->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3681
0
                            do_intra_bc = false;
3682
0
                        }
3683
0
                    }
3684
0
                }
3685
3686
0
                if (do_intra_bc) {
3687
0
                    inject_intra_bc_candidates(pcs, ctx, scs, ctx->blk_ptr, &cand_total_cnt);
3688
0
                }
3689
0
            }
3690
0
        }
3691
151k
    }
3692
152k
    if (slice_type != I_SLICE) {
3693
0
        svt_aom_inject_inter_candidates(pcs, ctx, &cand_total_cnt);
3694
0
    }
3695
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3696
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3697
152k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3698
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3699
0
    }
3700
3701
152k
    if (pcs->ppcs->sframe_ref_pruned) {
3702
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3703
0
    }
3704
3705
152k
    *candidate_total_count_ptr = cand_total_cnt;
3706
3707
152k
    memset(ctx->md_stage_0_count, 0, CAND_CLASS_TOTAL * sizeof(uint32_t));
3708
152k
    bool merge_inter_cands = 0;
3709
152k
    if (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult != (uint8_t)~0) {
3710
151k
        uint16_t th = (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult * (63 - pcs->scs->static_config.qp)) >> 1;
3711
151k
        if ((MIN(ctx->md_me_dist, ctx->md_pme_dist) / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight)) < th) {
3712
140k
            merge_inter_cands = 1;
3713
140k
        }
3714
151k
    }
3715
3716
303k
    for (uint32_t cand_i = 0; cand_i < cand_total_cnt; cand_i++) {
3717
151k
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_i];
3718
151k
        if (is_intra_mode(cand->block_mi.mode)) {
3719
            // Intra prediction
3720
151k
            if ((cand->palette_info == NULL || cand->palette_size[0] == 0) && cand->block_mi.use_intrabc == 0) {
3721
151k
                cand->cand_class = CAND_CLASS_0;
3722
151k
                ctx->md_stage_0_count[CAND_CLASS_0]++;
3723
18.4E
            } else if (cand->block_mi.use_intrabc == 0) {
3724
                // Palette Prediction
3725
0
                cand->cand_class = CAND_CLASS_3;
3726
0
                ctx->md_stage_0_count[CAND_CLASS_3]++;
3727
18.4E
            } else {
3728
                // Intra-BC Prediction
3729
18.4E
                cand->cand_class = CAND_CLASS_4;
3730
18.4E
                ctx->md_stage_0_count[CAND_CLASS_4]++;
3731
18.4E
            }
3732
151k
        } else { // INTER
3733
36
            if (cand->block_mi.mode == NEWMV || cand->block_mi.mode == NEW_NEWMV || merge_inter_cands) {
3734
                // MV Prediction
3735
0
                cand->cand_class = CAND_CLASS_2;
3736
0
                ctx->md_stage_0_count[CAND_CLASS_2]++;
3737
36
            } else {
3738
                //MVP Prediction
3739
36
                cand->cand_class = CAND_CLASS_1;
3740
36
                ctx->md_stage_0_count[CAND_CLASS_1]++;
3741
36
            }
3742
36
        }
3743
151k
    }
3744
152k
    return EB_ErrorNone;
3745
152k
}
3746
3747
uint8_t av1_drl_ctx(const CandidateMv* ref_mv_stack, int32_t ref_idx);
3748
3749
/***************************************
3750
* Update symbols for light-PD1 path
3751
***************************************/
3752
void svt_aom_product_full_mode_decision_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
3753
0
                                                  ModeDecisionCandidateBuffer* cand_bf) {
3754
0
    BlkStruct*             blk_ptr = ctx->blk_ptr;
3755
0
    ModeDecisionCandidate* cand    = cand_bf->cand;
3756
0
    blk_ptr->total_rate            = cand_bf->total_rate;
3757
3758
    // Set common signals (INTER/INTRA)
3759
0
    svt_memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3760
0
    blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3761
3762
    // Set INTER mode signals
3763
0
    if (is_inter_mode(cand->block_mi.mode)) {
3764
0
        blk_ptr->drl_index = cand->drl_index;
3765
0
        assert(IMPLIES(
3766
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3767
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3768
3769
        // Set MVs
3770
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3771
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3772
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3773
0
        }
3774
3775
0
        const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3776
        // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3777
0
        blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3778
        // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3779
0
        if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3780
0
            for (uint8_t idx = 0; idx < 2; ++idx) {
3781
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3782
0
                    blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3783
0
                } else {
3784
0
                    blk_ptr->drl_ctx[idx] = -1;
3785
0
                }
3786
0
            }
3787
0
        }
3788
3789
0
        if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3790
            // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3791
0
            for (uint8_t idx = 1; idx < 3; ++idx) {
3792
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3793
0
                    blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3794
0
                } else {
3795
0
                    blk_ptr->drl_ctx_near[idx - 1] = -1;
3796
0
                }
3797
0
            }
3798
0
        }
3799
0
    } else { // Set INTRA mode signals
3800
0
        cand->skip_mode_allowed = false;
3801
0
    }
3802
    // Set TX and coeff-related data
3803
0
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
3804
0
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
3805
3806
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
3807
0
    if (cand->skip_mode_allowed == true) {
3808
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
3809
0
    }
3810
3811
0
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
3812
0
                   cand->block_mi.interp_filters == 0));
3813
0
    if (blk_ptr->block_mi.skip_mode) {
3814
0
        blk_ptr->block_has_coeff = 0;
3815
0
        cand_bf->y_has_coeff     = 0;
3816
0
        cand_bf->u_has_coeff     = 0;
3817
0
        cand_bf->v_has_coeff     = 0;
3818
0
    }
3819
0
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
3820
3821
0
    const uint16_t txb_itr       = 0;
3822
0
    const int32_t  txb_1d_offset = 0, txb_1d_offset_uv = 0;
3823
0
    blk_ptr->y_has_coeff         = cand_bf->y_has_coeff;
3824
0
    blk_ptr->u_has_coeff         = cand_bf->u_has_coeff;
3825
0
    blk_ptr->v_has_coeff         = cand_bf->v_has_coeff;
3826
0
    blk_ptr->tx_type[txb_itr]    = cand->transform_type[txb_itr];
3827
0
    blk_ptr->tx_type_uv          = cand->transform_type_uv;
3828
0
    blk_ptr->quant_dc.y[txb_itr] = cand_bf->quant_dc.y[txb_itr];
3829
0
    blk_ptr->quant_dc.u[txb_itr] = cand_bf->quant_dc.u[txb_itr];
3830
0
    blk_ptr->quant_dc.v[txb_itr] = cand_bf->quant_dc.v[txb_itr];
3831
3832
0
    if (ctx->bypass_encdec) {
3833
0
        blk_ptr->eob.y[txb_itr] = cand_bf->eob.y[txb_itr];
3834
0
        blk_ptr->eob.u[txb_itr] = cand_bf->eob.u[txb_itr];
3835
0
        blk_ptr->eob.v[txb_itr] = cand_bf->eob.v[txb_itr];
3836
0
        int32_t* src_ptr;
3837
0
        int32_t* dst_ptr;
3838
3839
0
        const TxSize tx_size   = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
3840
0
        const int    tx_width  = tx_size_wide[tx_size];
3841
0
        const int    tx_height = tx_size_high[tx_size];
3842
3843
        // only one TX unit, so no need to bitmask
3844
0
        if (blk_ptr->y_has_coeff) {
3845
0
            src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
3846
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) + ctx->coded_area_sb;
3847
0
            svt_memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
3848
0
        }
3849
0
        ctx->coded_area_sb += tx_width * tx_height;
3850
3851
0
        const TxSize tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3852
0
        const int    tx_width_uv  = tx_size_wide[tx_size_uv];
3853
0
        const int    tx_height_uv = tx_size_high[tx_size_uv];
3854
        // Cb
3855
        // only one TX unit, so no need to bitmask
3856
0
        if (blk_ptr->u_has_coeff) {
3857
0
            src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
3858
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
3859
0
                ctx->coded_area_sb_uv;
3860
0
            svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3861
0
        }
3862
3863
        // Cr
3864
        // only one TX unit, so no need to bitmask
3865
0
        if (blk_ptr->v_has_coeff) {
3866
0
            src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
3867
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
3868
0
                ctx->coded_area_sb_uv;
3869
0
            svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3870
0
        }
3871
0
        ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
3872
0
    }
3873
0
}
3874
3875
0
static INLINE double derive_ssim_threshold_factor_for_full_md(SequenceControlSet* scs) {
3876
0
    return scs->input_resolution >= INPUT_SIZE_1080p_RANGE ? 1.02 : 1.03;
3877
0
}
3878
3879
/***************************************
3880
* Full Mode Decision
3881
***************************************/
3882
uint32_t svt_aom_product_full_mode_decision(PictureControlSet* pcs, ModeDecisionContext* ctx,
3883
                                            ModeDecisionCandidateBuffer** buffer_ptr_array,
3884
153k
                                            uint32_t candidate_total_count, uint32_t* best_candidate_index_array) {
3885
153k
    SequenceControlSet* scs                = pcs->scs;
3886
153k
    BlkStruct*          blk_ptr            = ctx->blk_ptr;
3887
153k
    uint32_t            lowest_cost_index  = best_candidate_index_array[0];
3888
153k
    const bool          use_ssim_full_cost = ctx->tune_ssim_level > SSIM_LVL_0 ? true : false;
3889
3890
    // Find the candidate with the lowest cost
3891
    // Only need to sort if have multiple candidates
3892
153k
    if (ctx->md_stage_3_total_count > 1) {
3893
0
        if (use_ssim_full_cost) {
3894
            // Pass one: find candidate with the lowest SSD cost
3895
0
            uint64_t ssd_lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3896
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3897
0
                uint32_t cand_index = best_candidate_index_array[i];
3898
0
                uint64_t cost       = *(buffer_ptr_array[cand_index]->full_cost);
3899
0
                if (cost < ssd_lowest_cost) {
3900
0
                    lowest_cost_index = cand_index;
3901
0
                    ssd_lowest_cost   = cost;
3902
0
                }
3903
0
            }
3904
3905
            // Pass two: among the candidates with SSD cost not greater than the threshold, find the one with the lowest SSIM cost
3906
0
            const double   threshold_factor   = derive_ssim_threshold_factor_for_full_md(scs);
3907
0
            const uint64_t ssd_cost_threshold = (uint64_t)(threshold_factor * ssd_lowest_cost);
3908
0
            uint64_t       ssim_lowest_cost   = 0xFFFFFFFFFFFFFFFFull;
3909
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3910
0
                uint32_t cand_index = best_candidate_index_array[i];
3911
3912
0
                uint64_t ssim_cost = *(buffer_ptr_array[cand_index]->full_cost_ssim);
3913
0
                uint64_t ssd_cost  = *(buffer_ptr_array[cand_index]->full_cost);
3914
0
                if (ssim_cost < ssim_lowest_cost) {
3915
0
                    if (ssd_cost <= ssd_cost_threshold) {
3916
0
                        lowest_cost_index = cand_index;
3917
0
                        ssim_lowest_cost  = ssim_cost;
3918
0
                        ssd_lowest_cost   = ssd_cost;
3919
0
                    }
3920
0
                } else if (ssim_cost == ssim_lowest_cost) {
3921
                    // if two candidates have the same ssim cost, choose the one with lower ssd cost
3922
0
                    if (ssd_cost < ssd_lowest_cost) {
3923
0
                        lowest_cost_index = cand_index;
3924
0
                        ssd_lowest_cost   = ssd_cost;
3925
0
                    }
3926
0
                }
3927
0
            }
3928
0
        } else { // fallback to SSD based RD cost
3929
0
            uint64_t lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3930
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3931
0
                uint32_t cand_index = best_candidate_index_array[i];
3932
3933
0
                uint64_t cost = *(buffer_ptr_array[cand_index]->full_cost);
3934
0
                if (scs->vq_ctrls.sharpness_ctrls.unipred_bias && pcs->ppcs->is_noise_level &&
3935
0
                    is_inter_singleref_mode(buffer_ptr_array[cand_index]->cand->block_mi.mode)) {
3936
0
                    cost = (cost * uni_psy_bias[pcs->ppcs->picture_qp]) / 100;
3937
0
                }
3938
3939
0
                if (cost < lowest_cost) {
3940
0
                    lowest_cost_index = cand_index;
3941
0
                    lowest_cost       = cost;
3942
0
                }
3943
0
            }
3944
0
        }
3945
0
    }
3946
153k
    ModeDecisionCandidateBuffer* cand_bf = buffer_ptr_array[lowest_cost_index];
3947
153k
    ModeDecisionCandidate*       cand    = cand_bf->cand;
3948
153k
    blk_ptr->total_rate                  = cand_bf->total_rate;
3949
153k
    if (!(ctx->pd_pass == PD_PASS_1 && ctx->fixed_partition)) {
3950
        // When lambda tuning is on, lambda of each block is set separately, however at interdepth decision the sb lambda is used
3951
144k
        uint32_t full_lambda    = SVT_EFFECTIVE_HBD_MD(ctx->hbd_md) ? ctx->full_sb_lambda_md[EB_10_BIT_MD]
3952
144k
                                                                    : ctx->full_sb_lambda_md[EB_8_BIT_MD];
3953
144k
        ctx->blk_ptr->cost      = RDCOST(full_lambda, cand_bf->total_rate, cand_bf->full_dist);
3954
144k
        ctx->blk_ptr->full_dist = cand_bf->full_dist;
3955
144k
    }
3956
3957
    // Set common signals (INTER/INTRA)
3958
153k
    svt_memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3959
    // Set INTER mode signals
3960
    // INTER signals set first b/c INTER shuts Palette, so INTRA must overwrite if Palette + intrabc is used
3961
153k
    if (is_inter_block(&blk_ptr->block_mi)) {
3962
0
        blk_ptr->drl_index = cand->drl_index;
3963
0
        assert(IMPLIES(
3964
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3965
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3966
3967
0
        blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3968
        // Set MVs
3969
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3970
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3971
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3972
0
        }
3973
0
        if (blk_ptr->block_mi.motion_mode == WARPED_CAUSAL ||
3974
0
            (cand->block_mi.mode == GLOBALMV || cand->block_mi.mode == GLOBAL_GLOBALMV)) {
3975
0
            svt_memcpy(&ctx->blk_ptr->wm_params_l0, &cand->wm_params_l0, sizeof(WarpedMotionParams));
3976
0
            svt_memcpy(&ctx->blk_ptr->wm_params_l1, &cand->wm_params_l1, sizeof(WarpedMotionParams));
3977
0
        }
3978
3979
0
        if (ctx->pd_pass == PD_PASS_1) {
3980
0
            const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3981
            // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3982
0
            blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3983
            // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3984
0
            if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3985
0
                for (uint8_t idx = 0; idx < 2; ++idx) {
3986
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3987
0
                        blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3988
0
                    } else {
3989
0
                        blk_ptr->drl_ctx[idx] = -1;
3990
0
                    }
3991
0
                }
3992
0
            }
3993
3994
0
            if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3995
                // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3996
0
                for (uint8_t idx = 1; idx < 3; ++idx) {
3997
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3998
0
                        blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3999
0
                    } else {
4000
0
                        blk_ptr->drl_ctx_near[idx - 1] = -1;
4001
0
                    }
4002
0
                }
4003
0
            }
4004
0
        }
4005
0
    }
4006
4007
    // Set INTRA mode signals
4008
153k
    if (is_intra_mode(blk_ptr->block_mi.mode)) {
4009
151k
        if (!cand->palette_info) {
4010
150k
            blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
4011
150k
        } else if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
4012
0
            memcpy(&blk_ptr->palette_info->pmi, &cand->palette_info->pmi, sizeof(PaletteModeInfo));
4013
0
            memcpy(blk_ptr->palette_info->color_idx_map, cand->palette_info->color_idx_map, MAX_PALETTE_SQUARE);
4014
0
            blk_ptr->palette_size[0] = cand->palette_size[0];
4015
0
            blk_ptr->palette_size[1] = cand->palette_size[1];
4016
0
        }
4017
4018
151k
        if (blk_ptr->block_mi.use_intrabc == 0) {
4019
150k
            cand->skip_mode_allowed = false;
4020
150k
        }
4021
151k
    }
4022
4023
    // Set TX and coeff-related data
4024
153k
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
4025
153k
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
4026
4027
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
4028
153k
    if (cand->skip_mode_allowed == true) {
4029
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
4030
0
    }
4031
4032
153k
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
4033
153k
                   cand->block_mi.interp_filters == 0));
4034
153k
    if (blk_ptr->block_mi.skip_mode) {
4035
0
        blk_ptr->block_has_coeff = 0;
4036
0
        cand_bf->y_has_coeff     = 0;
4037
0
        cand_bf->u_has_coeff     = 0;
4038
0
        cand_bf->v_has_coeff     = 0;
4039
0
    }
4040
4041
153k
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
4042
153k
    blk_ptr->y_has_coeff   = cand_bf->y_has_coeff;
4043
153k
    blk_ptr->u_has_coeff   = cand_bf->u_has_coeff;
4044
153k
    blk_ptr->v_has_coeff   = cand_bf->v_has_coeff;
4045
153k
    svt_memcpy(blk_ptr->tx_type, cand->transform_type, sizeof(TxType) * MAX_TXB_COUNT);
4046
153k
    blk_ptr->tx_type_uv = cand->transform_type_uv;
4047
153k
    svt_memcpy(&blk_ptr->quant_dc, &cand_bf->quant_dc, sizeof(QuantDcData));
4048
153k
    svt_memcpy(&blk_ptr->eob, &cand_bf->eob, sizeof(EobData));
4049
4050
    // If bypassing EncDec, save recon/coeff
4051
153k
    if (ctx->bypass_encdec && ctx->pd_pass == PD_PASS_1) {
4052
151k
        const uint16_t tu_total_count = tx_blocks_per_depth[ctx->blk_geom->bsize][blk_ptr->block_mi.tx_depth];
4053
151k
        int32_t        txb_1d_offset = 0, txb_1d_offset_uv = 0;
4054
151k
        const TxSize   tx_size      = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
4055
151k
        const int      tx_width     = tx_size_wide[tx_size];
4056
151k
        const int      tx_height    = tx_size_high[tx_size];
4057
151k
        const TxSize   tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
4058
151k
        const int      tx_width_uv  = tx_size_wide[tx_size_uv];
4059
151k
        const int      tx_height_uv = tx_size_high[tx_size_uv];
4060
724k
        for (uint16_t txb_itr = 0; txb_itr < tu_total_count; txb_itr++) {
4061
573k
            const bool uv_pass = (blk_ptr->block_mi.tx_depth == 0 || txb_itr == 0);
4062
4063
573k
            int32_t* src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
4064
573k
            int32_t* dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->y_buffer)[txb_1d_offset]);
4065
4066
573k
            if (ctx->fixed_partition) {
4067
7.64k
                dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) +
4068
7.64k
                    ctx->coded_area_sb;
4069
7.64k
                ctx->coded_area_sb += tx_width * tx_height;
4070
7.64k
            }
4071
4072
573k
            if (blk_ptr->y_has_coeff & (1 << txb_itr)) {
4073
5.81k
                svt_memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
4074
5.81k
            }
4075
4076
573k
            txb_1d_offset += tx_width * tx_height;
4077
4078
573k
            if (ctx->has_uv && uv_pass) {
4079
                // Cb
4080
151k
                src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
4081
151k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->u_buffer)[txb_1d_offset_uv]);
4082
4083
151k
                if (ctx->fixed_partition) {
4084
7.64k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
4085
7.64k
                        ctx->coded_area_sb_uv;
4086
7.64k
                }
4087
4088
151k
                if (blk_ptr->u_has_coeff & (1 << txb_itr)) {
4089
5.57k
                    svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4090
5.57k
                }
4091
4092
                // Cr
4093
151k
                src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
4094
151k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->v_buffer)[txb_1d_offset_uv]);
4095
4096
151k
                if (ctx->fixed_partition) {
4097
7.64k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
4098
7.64k
                        ctx->coded_area_sb_uv;
4099
7.64k
                    ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
4100
7.64k
                }
4101
4102
151k
                if (blk_ptr->v_has_coeff & (1 << txb_itr)) {
4103
5.57k
                    svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4104
5.57k
                }
4105
4106
151k
                txb_1d_offset_uv += tx_width_uv * tx_height_uv;
4107
151k
            }
4108
573k
        }
4109
151k
    }
4110
4111
153k
    return lowest_cost_index;
4112
153k
}
4113
4114
// Return the end column for the current superblock, in unit of TPL blocks.
4115
0
static int get_superblock_tpl_column_end(PictureParentControlSet* ppcs, int mi_col, int num_mi_w) {
4116
0
    const int mib_size_log2 = ppcs->scs->seq_header.sb_size == BLOCK_128X128 ? 5 : 4;
4117
    // Find the start column of this superblock.
4118
0
    const int sb_mi_col_start = (mi_col >> mib_size_log2) << mib_size_log2;
4119
    // Same but in superres upscaled dimension.
4120
0
    const int sb_mi_col_start_sr = coded_to_superres_mi(sb_mi_col_start, ppcs->superres_denom);
4121
    // Width of this superblock in mi units.
4122
0
    const int sb_mi_width = mi_size_wide[ppcs->scs->seq_header.sb_size];
4123
    // Same but in superres upscaled dimension.
4124
0
    const int sb_mi_width_sr = coded_to_superres_mi(sb_mi_width, ppcs->superres_denom);
4125
    // Superblock end in mi units.
4126
0
    const int sb_mi_end = sb_mi_col_start_sr + sb_mi_width_sr;
4127
    // Superblock end in TPL units.
4128
0
    return (sb_mi_end + num_mi_w - 1) / num_mi_w;
4129
0
}
4130
4131
0
void aom_av1_set_ssim_rdmult(ModeDecisionContext* ctx, PictureControlSet* pcs, const int mi_row, const int mi_col) {
4132
0
    const Av1Common* const cm    = pcs->ppcs->av1_cm;
4133
0
    BlockSize              bsize = ctx->blk_geom->bsize;
4134
4135
0
    const int bsize_base = BLOCK_16X16;
4136
0
    const int num_mi_w   = mi_size_wide[bsize_base];
4137
0
    const int num_mi_h   = mi_size_high[bsize_base];
4138
0
    const int num_cols   = (cm->mi_cols + num_mi_w - 1) / num_mi_w;
4139
0
    const int num_rows   = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4140
0
    const int num_bcols  = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w;
4141
0
    const int num_brows  = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4142
0
    int       row, col;
4143
0
    double    num_of_mi          = 0.0;
4144
0
    double    geom_mean_of_scale = 1.0;
4145
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4146
0
        for (col = mi_col / num_mi_h; col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) {
4147
0
            const int index = row * num_cols + col;
4148
0
            geom_mean_of_scale *= pcs->ppcs->pa_me_data->ssim_rdmult_scaling_factors[index];
4149
0
            num_of_mi += 1.0;
4150
0
        }
4151
0
    }
4152
0
    geom_mean_of_scale = pow(geom_mean_of_scale, (1.0 / num_of_mi));
4153
0
    if (!pcs->ppcs->blk_lambda_tuning) {
4154
0
        ctx->full_lambda_md[EB_8_BIT_MD] =
4155
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4156
0
        ctx->full_lambda_md[EB_10_BIT_MD] =
4157
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4158
4159
0
        ctx->fast_lambda_md[EB_8_BIT_MD] =
4160
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4161
0
        ctx->fast_lambda_md[EB_10_BIT_MD] =
4162
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4163
0
    } else {
4164
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->full_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4165
0
                                                      0.5);
4166
0
        ctx->full_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->full_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4167
0
                                                       0.5);
4168
4169
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->fast_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4170
0
                                                      0.5);
4171
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->fast_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4172
0
                                                       0.5);
4173
0
    }
4174
0
}
4175
4176
0
void svt_aom_set_tuned_blk_lambda(ModeDecisionContext* ctx, PictureControlSet* pcs) {
4177
0
    PictureParentControlSet* ppcs = pcs->ppcs;
4178
0
    Av1Common*               cm   = ppcs->av1_cm;
4179
4180
0
    BlockSize bsize  = ctx->blk_geom->bsize;
4181
0
    int       mi_row = ctx->blk_org_y / 4;
4182
0
    int       mi_col = ctx->blk_org_x / 4;
4183
4184
0
    const int mi_col_sr         = coded_to_superres_mi(mi_col, ppcs->superres_denom);
4185
0
    const int mi_cols_sr        = ((ppcs->enhanced_unscaled_pic->width + 15) / 16) << 2; // picture column boundary
4186
0
    const int block_mi_width_sr = coded_to_superres_mi(mi_size_wide[bsize], ppcs->superres_denom);
4187
0
    const int bsize_base        = ppcs->tpl_ctrls.synth_blk_size == 32 ? BLOCK_32X32 : BLOCK_16X16;
4188
0
    const int num_mi_w          = mi_size_wide[bsize_base];
4189
0
    const int num_mi_h          = mi_size_high[bsize_base];
4190
0
    const int num_cols          = (mi_cols_sr + num_mi_w - 1) / num_mi_w;
4191
0
    const int num_rows          = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4192
0
    const int num_bcols         = (block_mi_width_sr + num_mi_w - 1) / num_mi_w;
4193
0
    const int num_brows         = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4194
4195
    // This is required because the end col of superblock may be off by 1 in case
4196
    // of superres.
4197
0
    const int sb_bcol_end = get_superblock_tpl_column_end(ppcs, mi_col, num_mi_w);
4198
0
    int       row, col;
4199
0
    int32_t   base_block_count   = 0;
4200
0
    double    geom_mean_of_scale = 0.0;
4201
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4202
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;
4203
0
             ++col) {
4204
0
            const int index = row * num_cols + col;
4205
0
            geom_mean_of_scale += log(ppcs->pa_me_data->tpl_sb_rdmult_scaling_factors[index]);
4206
0
            ++base_block_count;
4207
0
        }
4208
0
    }
4209
    // When superres is on, base_block_count could be zero.
4210
    // This function's counterpart in AOM, av1_get_hier_tpl_rdmult, will encounter division by zero
4211
0
    if (base_block_count == 0) {
4212
        // return a large number to indicate invalid state
4213
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4214
0
        ctx->full_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4215
4216
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4217
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4218
0
        return;
4219
0
    }
4220
4221
0
    geom_mean_of_scale = exp(geom_mean_of_scale / base_block_count);
4222
4223
0
    ctx->full_lambda_md[EB_8_BIT_MD] =
4224
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4225
0
    ctx->full_lambda_md[EB_10_BIT_MD] =
4226
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4227
4228
0
    ctx->fast_lambda_md[EB_8_BIT_MD] =
4229
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4230
0
    ctx->fast_lambda_md[EB_10_BIT_MD] =
4231
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4232
0
    if (ppcs->scs->static_config.tune == TUNE_SSIM || ppcs->scs->static_config.tune == TUNE_IQ ||
4233
0
        ppcs->scs->static_config.tune == TUNE_MS_SSIM) {
4234
0
        aom_av1_set_ssim_rdmult(ctx, pcs, mi_row, mi_col);
4235
0
    }
4236
0
}
4237
4238
0
double svt_ssim_4x4_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4239
0
    const int32_t count = 4 * 4;
4240
4241
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4242
0
    uint32_t i, j;
4243
0
    for (i = 0; i < 4; i++) {
4244
0
        for (j = 0; j < 4; j++) {
4245
0
            sum_s += s[j];
4246
0
            sum_r += r[j];
4247
0
            sum_sq_s += s[j] * s[j];
4248
0
            sum_sq_r += r[j] * r[j];
4249
0
            sum_sxr += s[j] * r[j];
4250
0
        }
4251
4252
0
        s += sp;
4253
0
        r += rp;
4254
0
    }
4255
4256
    //
4257
    // similarity
4258
    //
4259
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4260
0
    return score;
4261
0
}
4262
4263
0
double svt_ssim_8x8_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4264
0
    const int32_t count = 8 * 8;
4265
4266
    //
4267
    // is similar to svt_aom_ssim_parms_8x8_c, but supports MxN block size
4268
    //
4269
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4270
0
    uint32_t i, j;
4271
0
    for (i = 0; i < 8; i++) {
4272
0
        for (j = 0; j < 8; j++) {
4273
0
            sum_s += s[j];
4274
0
            sum_r += r[j];
4275
0
            sum_sq_s += s[j] * s[j];
4276
0
            sum_sq_r += r[j] * r[j];
4277
0
            sum_sxr += s[j] * r[j];
4278
0
        }
4279
4280
0
        s += sp;
4281
0
        r += rp;
4282
0
    }
4283
4284
    //
4285
    // similarity
4286
    //
4287
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4288
0
    return score;
4289
0
}
4290
4291
0
double svt_ssim_4x4_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4292
0
    const int32_t count = 4 * 4;
4293
4294
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4295
0
    uint32_t i, j;
4296
0
    for (i = 0; i < 4; i++) {
4297
0
        for (j = 0; j < 4; j++) {
4298
0
            sum_s += s[j];
4299
0
            sum_r += r[j];
4300
0
            sum_sq_s += s[j] * s[j];
4301
0
            sum_sq_r += r[j] * r[j];
4302
0
            sum_sxr += s[j] * r[j];
4303
0
        }
4304
4305
0
        s += sp;
4306
0
        r += rp;
4307
0
    }
4308
4309
    //
4310
    // similarity
4311
    //
4312
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4313
0
    return score;
4314
0
}
4315
4316
0
double svt_ssim_8x8_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4317
0
    const int32_t count = 8 * 8;
4318
4319
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4320
0
    uint32_t i, j;
4321
0
    for (i = 0; i < 8; i++) {
4322
0
        for (j = 0; j < 8; j++) {
4323
0
            sum_s += s[j];
4324
0
            sum_r += r[j];
4325
0
            sum_sq_s += s[j] * s[j];
4326
0
            sum_sq_r += r[j] * r[j];
4327
0
            sum_sxr += s[j] * r[j];
4328
0
        }
4329
4330
0
        s += sp;
4331
0
        r += rp;
4332
0
    }
4333
4334
    //
4335
    // similarity
4336
    //
4337
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4338
0
    return score;
4339
0
}
4340
4341
static double ssim_8x8_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4342
0
                              uint32_t height) {
4343
0
    uint32_t i, j;
4344
0
    int      samples    = 0;
4345
0
    double   ssim_total = 0;
4346
4347
    // sample point start with each 4x4 location
4348
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4349
0
        for (j = 0; j <= width - 8; j += 8) {
4350
0
            double v = svt_ssim_8x8(s + j, sp, r + j, rp);
4351
0
            v        = CLIP3(0, 1, v);
4352
0
            ssim_total += v;
4353
0
            samples++;
4354
0
        }
4355
0
    }
4356
0
    assert(samples > 0);
4357
0
    ssim_total /= samples;
4358
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4359
0
    return ssim_total;
4360
0
}
4361
4362
static double ssim_4x4_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4363
0
                              uint32_t height) {
4364
0
    uint32_t i, j;
4365
0
    int      samples    = 0;
4366
0
    double   ssim_total = 0;
4367
4368
    // sample point start with each 2x2 location
4369
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4370
0
        for (j = 0; j <= width - 4; j += 4) {
4371
0
            double v = svt_ssim_4x4(s + j, sp, r + j, rp);
4372
0
            v        = CLIP3(0, 1, v);
4373
0
            ssim_total += v;
4374
0
            samples++;
4375
0
        }
4376
0
    }
4377
0
    assert(samples > 0);
4378
0
    ssim_total /= samples;
4379
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4380
0
    return ssim_total;
4381
0
}
4382
4383
0
static double ssim(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width, uint32_t height) {
4384
0
    assert((width % 4) == 0 && (height % 4) == 0);
4385
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4386
0
        return ssim_8x8_blocks(s, sp, r, rp, width, height);
4387
0
    } else {
4388
0
        return ssim_4x4_blocks(s, sp, r, rp, width, height);
4389
0
    }
4390
0
}
4391
4392
static double ssim_8x8_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4393
0
                                  uint32_t height) {
4394
0
    uint32_t i, j;
4395
0
    int      samples    = 0;
4396
0
    double   ssim_total = 0;
4397
4398
    // sample point start with each 4x4 location
4399
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4400
0
        for (j = 0; j <= width - 8; j += 8) {
4401
0
            double v = svt_ssim_8x8_hbd(s + j, sp, r + j, rp);
4402
0
            v        = CLIP3(0, 1, v);
4403
0
            ssim_total += v;
4404
0
            samples++;
4405
0
        }
4406
0
    }
4407
0
    assert(samples > 0);
4408
0
    ssim_total /= samples;
4409
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4410
0
    return ssim_total;
4411
0
}
4412
4413
static double ssim_4x4_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4414
0
                                  uint32_t height) {
4415
0
    uint32_t i, j;
4416
0
    int      samples    = 0;
4417
0
    double   ssim_total = 0;
4418
4419
    // sample point start with each 2x2 location
4420
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4421
0
        for (j = 0; j <= width - 4; j += 4) {
4422
0
            double v = svt_ssim_4x4_hbd(s + j, sp, r + j, rp);
4423
0
            v        = CLIP3(0, 1, v);
4424
0
            ssim_total += v;
4425
0
            samples++;
4426
0
        }
4427
0
    }
4428
0
    assert(samples > 0);
4429
0
    ssim_total /= samples;
4430
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4431
0
    return ssim_total;
4432
0
}
4433
4434
static double ssim_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4435
0
                       uint32_t height) {
4436
0
    assert((width % 4) == 0 && (height % 4) == 0);
4437
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4438
0
        return ssim_8x8_blocks_hbd(s, sp, r, rp, width, height);
4439
0
    } else {
4440
0
        return ssim_4x4_blocks_hbd(s, sp, r, rp, width, height);
4441
0
    }
4442
0
}
4443
4444
uint64_t svt_spatial_full_distortion_ssim_kernel(uint8_t* input, uint32_t input_offset, uint32_t input_stride,
4445
                                                 uint8_t* recon, int32_t recon_offset, uint32_t recon_stride,
4446
0
                                                 uint32_t area_width, uint32_t area_height, bool hbd, double ac_bias) {
4447
0
    uint8_t        m     = 1;
4448
0
    const uint32_t count = area_width * area_height;
4449
4450
    // SSIM
4451
0
    uint64_t spatial_distortion;
4452
0
    double   ssim_score;
4453
4454
    // AC SAD
4455
0
    uint64_t psy_distortion = 0;
4456
4457
0
    if (!hbd) {
4458
0
        ssim_score = ssim(
4459
0
            input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4460
0
        if (ac_bias) {
4461
0
            uint64_t ac_distortion = svt_psy_distortion(
4462
0
                input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4463
0
            psy_distortion = (uint64_t)(ac_distortion * ac_bias);
4464
0
        }
4465
0
    } else {
4466
0
        m          = 8;
4467
0
        ssim_score = ssim_hbd((uint16_t*)input + input_offset,
4468
0
                              input_stride,
4469
0
                              (uint16_t*)recon + recon_offset,
4470
0
                              recon_stride,
4471
0
                              area_width,
4472
0
                              area_height);
4473
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
4474
0
        if (ac_bias) {
4475
0
            uint64_t ac_distortion = svt_psy_distortion_hbd((uint16_t*)input + input_offset,
4476
0
                                                            input_stride,
4477
0
                                                            (uint16_t*)recon + recon_offset,
4478
0
                                                            recon_stride,
4479
0
                                                            area_width,
4480
0
                                                            area_height);
4481
0
            psy_distortion         = (uint64_t)(ac_distortion * ac_bias);
4482
0
        }
4483
0
#endif
4484
0
    }
4485
4486
0
    spatial_distortion        = (uint64_t)((1 - ssim_score) * count * 100 * 7 * m);
4487
0
    uint64_t total_distortion = spatial_distortion + psy_distortion;
4488
4489
0
    return total_distortion;
4490
0
}