Coverage Report

Created: 2026-10-17 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/av1me.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
 */
11
12
#include <limits.h>
13
#include <math.h>
14
#include <stdio.h>
15
#include "av1me.h"
16
#include "mcomp.h"
17
#include "utility.h"
18
#include "pcs.h"
19
#include "sequence_control_set.h"
20
#include "aom_dsp_rtcd.h"
21
#include "md_process.h"
22
#include "adaptive_mv_pred.h"
23
24
AomVarianceFnPtr svt_aom_mefn_ptr[BLOCK_SIZES_ALL];
25
26
1
void init_fn_ptr(void) {
27
1
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
28
1
#define BFP0(w, h)                                                                     \
29
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdf       = svt_aom_sad##w##x##h;                \
30
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf        = svt_aom_variance##w##x##h;           \
31
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf_hbd_10 = svt_aom_highbd_10_variance##w##x##h; \
32
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].svf       = svt_aom_sub_pixel_variance##w##x##h; \
33
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdx4df    = svt_aom_sad##w##x##h##x4d;
34
#else
35
#define BFP0(w, h)                                                                  \
36
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdf    = svt_aom_sad##w##x##h;                \
37
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf     = svt_aom_variance##w##x##h;           \
38
    svt_aom_mefn_ptr[BLOCK_##w##X##h].svf    = svt_aom_sub_pixel_variance##w##x##h; \
39
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdx4df = svt_aom_sad##w##x##h##x4d;
40
#endif
41
1
    BFP0(4, 16)
42
1
    BFP0(16, 4)
43
1
    BFP0(8, 32)
44
1
    BFP0(32, 8)
45
1
    BFP0(16, 64)
46
1
    BFP0(64, 16)
47
1
    BFP0(128, 128)
48
1
    BFP0(128, 64)
49
1
    BFP0(64, 128)
50
1
    BFP0(32, 16)
51
1
    BFP0(16, 32)
52
1
    BFP0(64, 32)
53
1
    BFP0(32, 64)
54
1
    BFP0(32, 32)
55
1
    BFP0(64, 64)
56
1
    BFP0(16, 16)
57
1
    BFP0(16, 8)
58
1
    BFP0(8, 16)
59
1
    BFP0(8, 8)
60
1
    BFP0(8, 4)
61
1
    BFP0(4, 8)
62
1
    BFP0(4, 4)
63
1
#if CONFIG_ENABLE_OBMC
64
1
#define OBFP(w, h)                                                           \
65
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].osdf = svt_aom_obmc_sad##w##x##h;      \
66
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].ovf  = svt_aom_obmc_variance##w##x##h; \
67
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].osvf = svt_aom_obmc_sub_pixel_variance##w##x##h;
68
1
    OBFP(128, 128)
69
1
    OBFP(128, 64)
70
1
    OBFP(64, 128)
71
1
    OBFP(64, 64)
72
1
    OBFP(64, 32)
73
1
    OBFP(32, 64)
74
1
    OBFP(32, 32)
75
1
    OBFP(32, 16)
76
1
    OBFP(16, 32)
77
1
    OBFP(16, 16)
78
1
    OBFP(16, 8)
79
1
    OBFP(8, 16)
80
1
    OBFP(8, 8)
81
1
    OBFP(4, 8)
82
1
    OBFP(8, 4)
83
1
    OBFP(4, 4)
84
1
    OBFP(4, 16)
85
1
    OBFP(16, 4)
86
1
    OBFP(8, 32)
87
1
    OBFP(32, 8)
88
1
    OBFP(16, 64)
89
1
    OBFP(64, 16)
90
1
#endif
91
1
}
92
93
0
static INLINE const uint8_t* get_buf_from_mv(const Buf2D* buf, const Mv mv) {
94
0
    return &buf->buf[mv.y * buf->stride + mv.x];
95
0
}
96
97
0
void svt_av1_set_mv_search_range(MvLimits* mv_limits, const Mv mv) {
98
0
    int col_min = (mv.x >> 3) - MAX_FULL_PEL_VAL + !!(mv.x & 7);
99
0
    int row_min = (mv.y >> 3) - MAX_FULL_PEL_VAL + !!(mv.y & 7);
100
0
    int col_max = (mv.x >> 3) + MAX_FULL_PEL_VAL;
101
0
    int row_max = (mv.y >> 3) + MAX_FULL_PEL_VAL;
102
103
0
    col_min = AOMMAX(col_min, (MV_LOW >> 3) + 1);
104
0
    row_min = AOMMAX(row_min, (MV_LOW >> 3) + 1);
105
0
    col_max = AOMMIN(col_max, (MV_UPP >> 3) - 1);
106
0
    row_max = AOMMIN(row_max, (MV_UPP >> 3) - 1);
107
108
    // Get intersection of UMV window and valid MV window to reduce # of checks
109
    // in diamond search.
110
0
    if (mv_limits->col_min < col_min) {
111
0
        mv_limits->col_min = col_min;
112
0
    }
113
0
    if (mv_limits->col_max > col_max) {
114
0
        mv_limits->col_max = col_max;
115
0
    }
116
0
    if (mv_limits->row_min < row_min) {
117
0
        mv_limits->row_min = row_min;
118
0
    }
119
0
    if (mv_limits->row_max > row_max) {
120
0
        mv_limits->row_max = row_max;
121
0
    }
122
0
}
123
124
0
int svt_aom_mv_err_cost_light(const Mv mv, const Mv ref) {
125
0
    const uint32_t factor     = 50;
126
0
    const uint32_t absmvdiffx = ABS(mv.x - ref.x);
127
0
    const uint32_t absmvdiffy = ABS(mv.y - ref.y);
128
0
    const uint32_t mv_rate    = 1296 + (factor * (absmvdiffx + absmvdiffy));
129
0
    return mv_rate;
130
0
}
131
132
0
static int mvsad_err_cost_light(const Mv mv, const Mv ref) {
133
0
    const uint32_t factor     = 50;
134
0
    const uint32_t absmvdiffx = ABS(mv.x - ref.x) * 8;
135
0
    const uint32_t absmvdiffy = ABS(mv.y - ref.y) * 8;
136
0
    const uint32_t mv_rate    = 1296 + (factor * (absmvdiffx + absmvdiffy));
137
0
    return mv_rate;
138
0
}
139
140
0
int svt_aom_mv_err_cost(const Mv mv, const Mv ref, const int* mvjcost, const int* mvcost[2], int error_per_bit) {
141
0
    if (mvcost) {
142
0
        const Mv diff = (Mv){{mv.x - ref.x, mv.y - ref.y}};
143
0
        return (int)ROUND_POWER_OF_TWO_64(
144
0
            (int64_t)svt_mv_cost(diff, mvjcost, mvcost) * error_per_bit,
145
0
            RDDIV_BITS + AV1_PROB_COST_SHIFT - RD_EPB_SHIFT + PIXEL_TRANSFORM_ERROR_SCALE);
146
0
    }
147
0
    return 0;
148
0
}
149
150
0
static int mvsad_err_cost(const IntraBcContext* x, const Mv mv, const Mv ref, int sad_per_bit) {
151
0
    if (x->approx_inter_rate) {
152
0
        return mvsad_err_cost_light(mv, ref);
153
0
    }
154
0
    const Mv diff = (Mv){{(mv.x - ref.x) * 8, (mv.y - ref.y) * 8}};
155
0
    return ROUND_POWER_OF_TWO(
156
0
        (unsigned)svt_mv_cost(diff, x->nmv_vec_cost, (const int* const*)x->mv_cost_stack) * sad_per_bit,
157
0
        AV1_PROB_COST_SHIFT);
158
0
}
159
160
0
void svt_av1_init3smotion_compensation(SearchSiteConfig* cfg, int stride) {
161
0
    int len, ss_count = 1;
162
163
0
    cfg->ss[0].mv.as_int = 0;
164
0
    cfg->ss[0].offset    = 0;
165
166
0
    for (len = MAX_FIRST_STEP; len > 0; len /= 2) {
167
        // Generate offsets for 8 search sites per step.
168
0
        const Mv ss_mvs[8] = {{{0, -len}},
169
0
                              {{0, len}},
170
0
                              {{-len, 0}},
171
0
                              {{len, 0}},
172
0
                              {{-len, -len}},
173
0
                              {{len, -len}},
174
0
                              {{-len, len}},
175
0
                              {{len, len}}};
176
0
        int      i;
177
0
        for (i = 0; i < 8; ++i) {
178
0
            SearchSite* const ss = &cfg->ss[ss_count++];
179
0
            ss->mv               = ss_mvs[i];
180
0
            ss->offset           = ss->mv.y * stride + ss->mv.x;
181
0
        }
182
0
    }
183
184
0
    cfg->ss_count          = ss_count;
185
0
    cfg->searches_per_step = 8;
186
0
}
187
188
0
static INLINE int is_mv_in(const MvLimits* mv_limits, const Mv mv) {
189
0
    return (mv.x >= mv_limits->col_min) && (mv.x <= mv_limits->col_max) && (mv.y >= mv_limits->row_min) &&
190
0
        (mv.y <= mv_limits->row_max);
191
0
}
192
193
int svt_av1_get_mvpred_var(const IntraBcContext* x, const Mv best_mv, const Mv center_mv, const AomVarianceFnPtr* vfp,
194
0
                           int use_mvcost) {
195
0
    const Buf2D* const what    = &x->plane[0].src;
196
0
    const Buf2D* const in_what = &x->xdplane[0].pre[0];
197
0
    const Mv           mv      = {{best_mv.x * 8, best_mv.y * 8}};
198
0
    unsigned int       unused;
199
0
    if (x->approx_inter_rate) {
200
0
        return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), in_what->stride, &unused) +
201
0
            (use_mvcost ? svt_aom_mv_err_cost_light(mv, center_mv) : 0);
202
0
    } else {
203
0
        return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), in_what->stride, &unused) +
204
0
            (use_mvcost ? svt_aom_mv_err_cost(mv, center_mv, x->nmv_vec_cost, x->mv_cost_stack, x->errorperbit) : 0);
205
0
    }
206
0
}
207
208
// Predictor-first early exit for RTC IntraBC: evaluate the AV1 DV predictor's SAD directly and, if
209
// the per-pixel SAD is within the budget (0 => exact match only), accept it and skip the hash and
210
// full-pixel searches. Returns 1 and writes *best_pred_mv (full-pel) when accepted, else 0.
211
int svt_av1_intrabc_pred_first(IntraBcContext* x, BlockSize bsize, const Mv* mvp_full, uint16_t pred_exit_th,
212
0
                               Mv* best_pred_mv) {
213
0
    if (!is_mv_in(&x->mv_limits, *mvp_full)) {
214
0
        return 0;
215
0
    }
216
0
    const AomVarianceFnPtr* fn_ptr  = &svt_aom_mefn_ptr[bsize];
217
0
    const Buf2D* const      what    = &x->plane[0].src;
218
0
    const Buf2D* const      in_what = &x->xdplane[0].pre[0];
219
0
    const unsigned int sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, *mvp_full), in_what->stride);
220
0
    const unsigned int area = (unsigned int)block_size_wide[bsize] * (unsigned int)block_size_high[bsize];
221
0
    if (sad <= (unsigned int)pred_exit_th * area) {
222
0
        *best_pred_mv = *mvp_full;
223
0
        return 1;
224
0
    }
225
0
    return 0;
226
0
}
227
228
// BVP candidate evaluation for the RTC IntraBC fallback: evaluate up to 4 full-pel DV candidates
229
// (neighbour predictor, second predictor, frame's last-used DV) in a single sad_x4d call and return
230
// the lowest-SAD one within the budget. Zero (self) and out-of-range candidates are excluded; their
231
// x4d slots are padded with the first valid candidate so all 4 addresses are safe.
232
// Returns 1 and writes *best (full-pel) when one qualifies, else 0.
233
0
int svt_av1_intrabc_pred_best4(IntraBcContext* x, BlockSize bsize, const Mv cands[4], uint16_t pred_exit_th, Mv* best) {
234
0
    bool valid[4];
235
0
    int  pad = -1;
236
0
    for (int i = 0; i < 4; ++i) {
237
0
        valid[i] = (cands[i].as_int != 0) && is_mv_in(&x->mv_limits, cands[i]);
238
0
        if (valid[i] && pad < 0) {
239
0
            pad = i;
240
0
        }
241
0
    }
242
0
    if (pad < 0) {
243
0
        return 0;
244
0
    }
245
0
    const AomVarianceFnPtr* fn_ptr  = &svt_aom_mefn_ptr[bsize];
246
0
    const Buf2D* const      what    = &x->plane[0].src;
247
0
    const Buf2D* const      in_what = &x->xdplane[0].pre[0];
248
0
    const uint8_t*          addrs[4];
249
0
    for (int i = 0; i < 4; ++i) {
250
0
        addrs[i] = get_buf_from_mv(in_what, valid[i] ? cands[i] : cands[pad]);
251
0
    }
252
0
    unsigned int sads[4];
253
0
    fn_ptr->sdx4df(what->buf, what->stride, addrs, in_what->stride, sads);
254
0
    const unsigned int area     = (unsigned int)block_size_wide[bsize] * (unsigned int)block_size_high[bsize];
255
0
    int                best_i   = -1;
256
0
    unsigned int       best_sad = UINT_MAX;
257
0
    for (int i = 0; i < 4; ++i) {
258
0
        if (valid[i] && sads[i] < best_sad) {
259
0
            best_sad = sads[i];
260
0
            best_i   = i;
261
0
        }
262
0
    }
263
0
    if (best_i >= 0 && best_sad <= (unsigned int)pred_exit_th * area) {
264
0
        *best = cands[best_i];
265
0
        return 1;
266
0
    }
267
0
    return 0;
268
0
}
269
270
// One-shot offset probe for the RTC IntraBC fallback (variant A): given a qualifying full-pel center
271
// DV, evaluate a fixed cloud of integer offsets around it (radius-1 ring then radius-2) in one pass
272
// and return the lowest-SAD point (possibly the center), at a fixed cost of ceil(npts/4) sad_x4d
273
// calls. Out-of-range offsets are skipped; x4d slots are padded with the first valid address.
274
0
void svt_av1_intrabc_probe_around(IntraBcContext* x, BlockSize bsize, Mv center, int npts, Mv* best) {
275
0
    static const int8_t off[16][2] = {{1, 0},
276
0
                                      {-1, 0},
277
0
                                      {0, 1},
278
0
                                      {0, -1},
279
0
                                      {1, 1},
280
0
                                      {1, -1},
281
0
                                      {-1, 1},
282
0
                                      {-1, -1},
283
0
                                      {2, 0},
284
0
                                      {-2, 0},
285
0
                                      {0, 2},
286
0
                                      {0, -2},
287
0
                                      {2, 2},
288
0
                                      {2, -2},
289
0
                                      {-2, 2},
290
0
                                      {-2, -2}};
291
0
    if (npts > 16) {
292
0
        npts = 16;
293
0
    }
294
0
    const AomVarianceFnPtr* fn_ptr  = &svt_aom_mefn_ptr[bsize];
295
0
    const Buf2D* const      what    = &x->plane[0].src;
296
0
    const Buf2D* const      in_what = &x->xdplane[0].pre[0];
297
0
    Mv                      bestmv  = center;
298
0
    unsigned int best_sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, center), in_what->stride);
299
0
    for (int base = 0; base < npts; base += 4) {
300
0
        Mv             cand[4];
301
0
        const uint8_t* addr[4];
302
0
        int            nv = 0;
303
0
        for (int k = 0; k < 4 && base + k < npts; ++k) {
304
0
            Mv c = {{(int16_t)(center.x + off[base + k][0]), (int16_t)(center.y + off[base + k][1])}};
305
0
            if (is_mv_in(&x->mv_limits, c)) {
306
0
                cand[nv] = c;
307
0
                addr[nv] = get_buf_from_mv(in_what, c);
308
0
                ++nv;
309
0
            }
310
0
        }
311
0
        if (!nv) {
312
0
            continue;
313
0
        }
314
0
        for (int k = nv; k < 4; ++k) {
315
0
            cand[k] = cand[0];
316
0
            addr[k] = addr[0];
317
0
        }
318
0
        unsigned int sads[4];
319
0
        fn_ptr->sdx4df(what->buf, what->stride, addr, in_what->stride, sads);
320
0
        for (int k = 0; k < nv; ++k) {
321
0
            if (sads[k] < best_sad) {
322
0
                best_sad = sads[k];
323
0
                bestmv   = cand[k];
324
0
            }
325
0
        }
326
0
    }
327
0
    *best = bestmv;
328
0
}
329
330
// Exhaustive motion search around a given centre position with a given
331
// step size.
332
static int exhaustive_mesh_search(IntraBcContext* x, Mv* ref_mv, Mv* best_mv, int range, int step, int sad_per_bit,
333
0
                                  const AomVarianceFnPtr* fn_ptr, const Mv center_mv) {
334
0
    const Buf2D* const what       = &x->plane[0].src;
335
0
    const Buf2D* const in_what    = &x->xdplane[0].pre[0];
336
0
    Mv                 fcenter_mv = {.as_int = center_mv.as_int};
337
0
    unsigned int       best_sad   = INT_MAX;
338
0
    int                r, c, i;
339
0
    int                start_col, end_col, start_row, end_row;
340
0
    int                col_step = (step > 1) ? step : 4;
341
342
0
    assert(step >= 1);
343
344
0
    clamp_mv(&fcenter_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
345
0
    *best_mv = fcenter_mv;
346
0
    best_sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, fcenter_mv), in_what->stride) +
347
0
        mvsad_err_cost(x, fcenter_mv, *ref_mv, sad_per_bit);
348
0
    start_row = AOMMAX(-range, x->mv_limits.row_min - fcenter_mv.y);
349
0
    start_col = AOMMAX(-range, x->mv_limits.col_min - fcenter_mv.x);
350
0
    end_row   = AOMMIN(range, x->mv_limits.row_max - fcenter_mv.y);
351
0
    end_col   = AOMMIN(range, x->mv_limits.col_max - fcenter_mv.x);
352
353
0
    for (r = start_row; r <= end_row; r += step) {
354
0
        for (c = start_col; c <= end_col; c += col_step) {
355
            // Step > 1 means we are not checking every location in this pass.
356
0
            if (step > 1) {
357
0
                const Mv     mv  = {{fcenter_mv.x + c, fcenter_mv.y + r}};
358
0
                unsigned int sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
359
0
                if (sad < best_sad) {
360
0
                    sad += mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
361
0
                    if (sad < best_sad) {
362
0
                        best_sad          = sad;
363
0
                        x->second_best_mv = *best_mv;
364
0
                        *best_mv          = mv;
365
0
                    }
366
0
                }
367
0
            } else {
368
                // 4 sads in a single call if we are checking every location
369
0
                if (c + 3 <= end_col) {
370
0
                    unsigned int   sads[4];
371
0
                    const uint8_t* addrs[4];
372
0
                    for (i = 0; i < 4; ++i) {
373
0
                        const Mv mv = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
374
0
                        addrs[i]    = get_buf_from_mv(in_what, mv);
375
0
                    }
376
0
                    fn_ptr->sdx4df(what->buf, what->stride, addrs, in_what->stride, sads);
377
378
0
                    for (i = 0; i < 4; ++i) {
379
0
                        if (sads[i] < best_sad) {
380
0
                            const Mv           mv  = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
381
0
                            const unsigned int sad = sads[i] + mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
382
0
                            if (sad < best_sad) {
383
0
                                best_sad          = sad;
384
0
                                x->second_best_mv = *best_mv;
385
0
                                *best_mv          = mv;
386
0
                            }
387
0
                        }
388
0
                    }
389
0
                } else {
390
0
                    for (i = 0; i < end_col - c; ++i) {
391
0
                        const Mv     mv  = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
392
0
                        unsigned int sad = fn_ptr->sdf(
393
0
                            what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
394
0
                        if (sad < best_sad) {
395
0
                            sad += mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
396
0
                            if (sad < best_sad) {
397
0
                                best_sad          = sad;
398
0
                                x->second_best_mv = *best_mv;
399
0
                                *best_mv          = mv;
400
0
                            }
401
0
                        }
402
0
                    }
403
0
                }
404
0
            }
405
0
        }
406
0
    }
407
408
0
    return best_sad;
409
0
}
410
411
int svt_av1_diamond_search_sad_c(IntraBcContext* x, const SearchSiteConfig* cfg, Mv* ref_mv, Mv* best_mv,
412
                                 int search_param, int sad_per_bit, int* num00, const AomVarianceFnPtr* fn_ptr,
413
0
                                 const Mv center_mv) {
414
0
    int i, j, step;
415
416
0
    uint8_t*       what        = x->plane[0].src.buf;
417
0
    const int      what_stride = x->plane[0].src.stride;
418
0
    const uint8_t* in_what;
419
0
    const int      in_what_stride = x->xdplane[0].pre[0].stride;
420
0
    const uint8_t* best_address;
421
422
0
    unsigned int bestsad;
423
0
    int          best_site = 0;
424
0
    int          last_site = 0;
425
426
0
    int ref_row;
427
0
    int ref_col;
428
429
    // search_param determines the length of the initial step and hence the number
430
    // of iterations.
431
    // 0 = initial step (MAX_FIRST_STEP) pel
432
    // 1 = (MAX_FIRST_STEP/2) pel,
433
    // 2 = (MAX_FIRST_STEP/4) pel...
434
0
    const SearchSite* ss        = &cfg->ss[search_param * cfg->searches_per_step];
435
0
    const int         tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param;
436
437
0
    const Mv fcenter_mv = {{center_mv.x >> 3, center_mv.y >> 3}};
438
0
    clamp_mv(ref_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
439
0
    ref_row    = ref_mv->y;
440
0
    ref_col    = ref_mv->x;
441
0
    *num00     = 0;
442
0
    best_mv->y = ref_row;
443
0
    best_mv->x = ref_col;
444
445
    // Work out the start point for the search
446
0
    in_what      = x->xdplane[0].pre[0].buf + ref_row * in_what_stride + ref_col;
447
0
    best_address = in_what;
448
449
    // Check the starting position
450
0
    bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride) +
451
0
        mvsad_err_cost(x, *best_mv, fcenter_mv, sad_per_bit);
452
453
0
    i = 1;
454
455
0
    for (step = 0; step < tot_steps; step++) {
456
0
        int all_in = 1;
457
458
        // All_in is true if every one of the points we are checking are within
459
        // the bounds of the image.
460
0
        all_in &= ((best_mv->y + ss[i].mv.y) > x->mv_limits.row_min);
461
0
        all_in &= ((best_mv->y + ss[i + 1].mv.y) < x->mv_limits.row_max);
462
0
        all_in &= ((best_mv->x + ss[i + 2].mv.x) > x->mv_limits.col_min);
463
0
        all_in &= ((best_mv->x + ss[i + 3].mv.x) < x->mv_limits.col_max);
464
465
        // If all the pixels are within the bounds we don't check whether the
466
        // search point is valid in this loop,  otherwise we check each point
467
        // for validity..
468
0
        if (all_in) {
469
0
            unsigned int sad_array[4];
470
471
0
            for (j = 0; j < cfg->searches_per_step; j += 4) {
472
0
                unsigned char const* block_offset[4];
473
474
0
                for (int t = 0; t < 4; t++) {
475
0
                    block_offset[t] = ss[i + t].offset + best_address;
476
0
                }
477
478
0
                fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array);
479
480
0
                for (int t = 0; t < 4; t++, i++) {
481
0
                    if (sad_array[t] < bestsad) {
482
0
                        const Mv this_mv = {{best_mv->x + ss[i].mv.x, best_mv->y + ss[i].mv.y}};
483
0
                        sad_array[t] += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
484
0
                        if (sad_array[t] < bestsad) {
485
0
                            bestsad   = sad_array[t];
486
0
                            best_site = i;
487
0
                        }
488
0
                    }
489
0
                }
490
0
            }
491
0
        } else {
492
0
            for (j = 0; j < cfg->searches_per_step; j++) {
493
                // Trap illegal vectors
494
0
                const Mv this_mv = {{best_mv->x + ss[i].mv.x, best_mv->y + ss[i].mv.y}};
495
496
0
                if (is_mv_in(&x->mv_limits, this_mv)) {
497
0
                    const uint8_t* const check_here = ss[i].offset + best_address;
498
0
                    unsigned int         thissad    = fn_ptr->sdf(what, what_stride, check_here, in_what_stride);
499
500
0
                    if (thissad < bestsad) {
501
0
                        thissad += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
502
0
                        if (thissad < bestsad) {
503
0
                            bestsad   = thissad;
504
0
                            best_site = i;
505
0
                        }
506
0
                    }
507
0
                }
508
0
                i++;
509
0
            }
510
0
        }
511
0
        if (best_site != last_site) {
512
0
            x->second_best_mv = *best_mv;
513
0
            best_mv->y += ss[best_site].mv.y;
514
0
            best_mv->x += ss[best_site].mv.x;
515
0
            best_address += ss[best_site].offset;
516
0
            last_site = best_site;
517
#if defined(NEW_DIAMOND_SEARCH)
518
            while (1) {
519
                const Mv this_mv = {{best_mv->x + ss[best_site].mv.x, best_mv->y + ss[best_site].mv.y}};
520
                if (is_mv_in(&x->mv_limits, &this_mv)) {
521
                    const uint8_t* const check_here = ss[best_site].offset + best_address;
522
                    unsigned int         thissad    = fn_ptr->sdf(what, what_stride, check_here, in_what_stride);
523
                    if (thissad < bestsad) {
524
                        thissad += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
525
                        if (thissad < bestsad) {
526
                            bestsad = thissad;
527
                            best_mv->y += ss[best_site].mv.y;
528
                            best_mv->x += ss[best_site].mv.x;
529
                            best_address += ss[best_site].offset;
530
                            continue;
531
                        }
532
                    }
533
                }
534
                break;
535
            }
536
#endif
537
0
        } else if (best_address == in_what) {
538
0
            (*num00)++;
539
0
        }
540
0
    }
541
0
    return bestsad;
542
0
}
543
544
static int svt_av1_refining_search_sad(IntraBcContext* x, Mv* ref_mv, int error_per_bit, int search_range,
545
0
                                       const AomVarianceFnPtr* fn_ptr, const Mv center_mv) {
546
0
    const Mv           neighbors[4] = {{{0, -1}}, {{-1, 0}}, {{1, 0}}, {{0, 1}}};
547
0
    const Buf2D* const what         = &x->plane[0].src;
548
0
    const Buf2D* const in_what      = &x->xdplane[0].pre[0];
549
0
    const Mv           fcenter_mv   = {{center_mv.x >> 3, center_mv.y >> 3}};
550
0
    const uint8_t*     best_address = get_buf_from_mv(in_what, *ref_mv);
551
0
    unsigned int       best_sad     = fn_ptr->sdf(what->buf, what->stride, best_address, in_what->stride) +
552
0
        mvsad_err_cost(x, *ref_mv, fcenter_mv, error_per_bit);
553
0
    for (int i = 0; i < search_range; i++) {
554
0
        int       best_site = -1;
555
0
        const int all_in    = (ref_mv->y - 1) > x->mv_limits.row_min && (ref_mv->y + 1) < x->mv_limits.row_max &&
556
0
            (ref_mv->x - 1) > x->mv_limits.col_min && (ref_mv->x + 1) < x->mv_limits.col_max;
557
558
0
        if (all_in) {
559
0
            unsigned int         sads[4];
560
0
            const uint8_t* const positions[4] = {
561
0
                best_address - in_what->stride, best_address - 1, best_address + 1, best_address + in_what->stride};
562
563
0
            fn_ptr->sdx4df(what->buf, what->stride, positions, in_what->stride, sads);
564
565
0
            for (int j = 0; j < 4; ++j) {
566
0
                if (sads[j] < best_sad) {
567
0
                    const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
568
0
                    sads[j] += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
569
0
                    if (sads[j] < best_sad) {
570
0
                        best_sad  = sads[j];
571
0
                        best_site = j;
572
0
                    }
573
0
                }
574
0
            }
575
0
        } else {
576
0
            for (int j = 0; j < 4; ++j) {
577
0
                const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
578
579
0
                if (is_mv_in(&x->mv_limits, mv)) {
580
0
                    unsigned int sad = fn_ptr->sdf(
581
0
                        what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
582
0
                    if (sad < best_sad) {
583
0
                        sad += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
584
0
                        if (sad < best_sad) {
585
0
                            best_sad  = sad;
586
0
                            best_site = j;
587
0
                        }
588
0
                    }
589
0
                }
590
0
            }
591
0
        }
592
593
0
        if (best_site == -1) {
594
0
            break;
595
0
        } else {
596
0
            x->second_best_mv = *ref_mv;
597
0
            ref_mv->y += neighbors[best_site].y;
598
0
            ref_mv->x += neighbors[best_site].x;
599
0
            best_address = get_buf_from_mv(in_what, *ref_mv);
600
0
        }
601
0
    }
602
603
0
    return best_sad;
604
0
}
605
606
/* do_refine: If last step (1-away) of n-step search doesn't pick the center
607
              point as the best match, we will do a final 1-away diamond
608
              refining search  */
609
static int full_pixel_diamond(PictureControlSet* pcs, IntraBcContext /*MACROBLOCK*/* x, Mv* mvp_full, int step_param,
610
                              int sadpb, int further_steps, int do_refine, int* cost_list,
611
0
                              const AomVarianceFnPtr* fn_ptr, const Mv ref_mv) {
612
0
    Mv  temp_mv;
613
0
    int thissme, n, num00 = 0;
614
0
    (void)cost_list;
615
    /*int bestsme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
616
                                        step_param, sadpb, &n, fn_ptr, ref_mv);*/
617
0
    int bestsme = svt_av1_diamond_search_sad_c(
618
0
        x, &pcs->ss_cfg, mvp_full, &temp_mv, step_param, sadpb, &n, fn_ptr, ref_mv);
619
620
0
    if (bestsme < INT_MAX) {
621
0
        bestsme = svt_av1_get_mvpred_var(x, temp_mv, ref_mv, fn_ptr, 1);
622
0
    }
623
0
    x->best_mv = temp_mv;
624
625
    // If there won't be more n-step search, check to see if refining search is
626
    // needed.
627
0
    if (n > further_steps) {
628
0
        do_refine = 0;
629
0
    }
630
631
0
    while (n < further_steps) {
632
0
        ++n;
633
634
0
        if (num00) {
635
0
            num00--;
636
0
        } else {
637
            /*thissme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
638
                                        step_param + n, sadpb, &num00, fn_ptr,
639
                                        ref_mv);*/
640
0
            thissme = svt_av1_diamond_search_sad_c(
641
0
                x, &pcs->ss_cfg, mvp_full, &temp_mv, step_param + n, sadpb, &num00, fn_ptr, ref_mv);
642
643
0
            if (thissme < INT_MAX) {
644
0
                thissme = svt_av1_get_mvpred_var(x, temp_mv, ref_mv, fn_ptr, 1);
645
0
            }
646
647
            // check to see if refining search is needed.
648
0
            if (num00 > further_steps - n) {
649
0
                do_refine = 0;
650
0
            }
651
652
0
            if (thissme < bestsme) {
653
0
                bestsme    = thissme;
654
0
                x->best_mv = temp_mv;
655
0
            }
656
0
        }
657
0
    }
658
659
    // final 1-away diamond refining search
660
0
    if (do_refine) {
661
0
        const int search_range = 8;
662
0
        Mv        best_mv      = x->best_mv;
663
0
        thissme                = svt_av1_refining_search_sad(x, &best_mv, sadpb, search_range, fn_ptr, ref_mv);
664
0
        if (thissme < INT_MAX) {
665
0
            thissme = svt_av1_get_mvpred_var(x, best_mv, ref_mv, fn_ptr, 1);
666
0
        }
667
0
        if (thissme < bestsme) {
668
0
            bestsme    = thissme;
669
0
            x->best_mv = best_mv;
670
0
        }
671
0
    }
672
673
    // Return cost list.
674
    /* if (cost_list) {
675
    calc_int_cost_list(x, ref_mv, sadpb, fn_ptr, &x->best_mv.as_mv, cost_list);
676
  }*/
677
0
    return bestsme;
678
0
}
679
680
0
#define MIN_RANGE 7
681
0
#define MAX_RANGE 256
682
0
#define MIN_INTERVAL 1
683
684
// Runs an limited range exhaustive mesh search using a pattern set
685
// according to the encode speed profile.
686
static int intrabc_full_pixel_exhaustive(PictureControlSet* pcs, IntraBcContext* x, const Mv center_mv, int sadpb,
687
0
                                         const AomVarianceFnPtr* fn_ptr, const Mv ref_mv, Mv* dst_mv) {
688
0
    const IntrabcCtrls* ctrls = &pcs->ppcs->intrabc_ctrls;
689
690
0
    Mv search_mv = center_mv;
691
0
    Mv ref_mv_fp = {{ref_mv.x >> 3, ref_mv.y >> 3}};
692
693
0
    int range     = ctrls->mesh_patterns[0].range;
694
0
    int interval  = ctrls->mesh_patterns[0].interval;
695
0
    int best_cost = INT_MAX;
696
697
    // Validate parameters
698
0
    if (range < MIN_RANGE || range > MAX_RANGE || interval < MIN_INTERVAL || interval > range) {
699
0
        return INT_MAX;
700
0
    }
701
702
0
    const int base_interval_div = range / interval;
703
704
    // Adapt search range based on center MV magnitude
705
0
    int mv_mag = AOMMAX(abs(search_mv.x), abs(search_mv.y));
706
0
    range      = AOMMAX(range, (5 * mv_mag) / 4);
707
0
    range      = AOMMIN(range, MAX_RANGE);
708
0
    interval   = AOMMAX(interval, range / base_interval_div);
709
710
    // Initial coarse search
711
0
    best_cost = exhaustive_mesh_search(x, &ref_mv_fp, &search_mv, range, interval, sadpb, fn_ptr, search_mv);
712
713
    // Progressive refinement
714
0
    if (interval > MIN_INTERVAL && range > MIN_RANGE) {
715
0
        for (int i = 1; i < MAX_MESH_STEP; i++) {
716
0
            const MeshPattern* pattern = &ctrls->mesh_patterns[i];
717
718
0
            if (pattern->range == 0) {
719
0
                break;
720
0
            }
721
722
0
            best_cost = exhaustive_mesh_search(
723
0
                x, &ref_mv_fp, &search_mv, pattern->range, pattern->interval, sadpb, fn_ptr, search_mv);
724
725
0
            if (pattern->interval == 1) {
726
0
                break;
727
0
            }
728
0
        }
729
0
    }
730
731
    // Final cost evaluation
732
0
    if (best_cost < INT_MAX) {
733
0
        best_cost = svt_av1_get_mvpred_var(x, search_mv, ref_mv, fn_ptr, 1);
734
0
    }
735
736
0
    *dst_mv = search_mv;
737
738
0
    return best_cost;
739
0
}
740
#if CONFIG_ENABLE_OBMC
741
static int get_obmc_mvpred_var(const IntraBcContext* x, const int32_t* wsrc, const int32_t* mask, const Mv best_mv,
742
0
                               const Mv center_mv, const AomVarianceFnPtr* vfp, int use_mvcost, int is_second) {
743
0
    const Buf2D* in_what = (const Buf2D*)(&x->xdplane[0].pre[is_second]);
744
0
    const Mv     mv      = {{best_mv.x * 8, best_mv.y * 8}};
745
0
    unsigned int unused;
746
0
    if (x->approx_inter_rate) {
747
0
        return vfp->ovf(get_buf_from_mv((const Buf2D*)in_what, best_mv), in_what->stride, wsrc, mask, &unused) +
748
0
            (use_mvcost ? svt_aom_mv_err_cost_light(mv, center_mv) : 0);
749
0
    } else {
750
0
        return vfp->ovf(get_buf_from_mv((const Buf2D*)in_what, best_mv), in_what->stride, wsrc, mask, &unused) +
751
0
            (use_mvcost ? svt_aom_mv_err_cost(mv, center_mv, x->nmv_vec_cost, x->mv_cost_stack, x->errorperbit) : 0);
752
0
    }
753
0
}
754
755
static int obmc_refining_search_sad(const IntraBcContext* x, const int32_t* wsrc, const int32_t* mask, Mv* ref_mv,
756
                                    int error_per_bit, int search_range, const AomVarianceFnPtr* fn_ptr,
757
0
                                    const Mv center_mv, int is_second, uint8_t search_diag) {
758
0
    const Mv     neighbors[8] = {{{0, -1}}, {{-1, 0}}, {{1, 0}}, {{0, 1}}, {{1, -1}}, {{1, 1}}, {{-1, 1}}, {{-1, -1}}};
759
0
    const Buf2D* in_what      = (const Buf2D*)(&x->xdplane[0].pre[is_second]);
760
0
    const Mv     fcenter_mv   = {{center_mv.x >> 3, center_mv.y >> 3}};
761
0
    unsigned int best_sad = fn_ptr->osdf(get_buf_from_mv((const Buf2D*)in_what, *ref_mv), in_what->stride, wsrc, mask) +
762
0
        mvsad_err_cost(x, *ref_mv, fcenter_mv, error_per_bit);
763
0
    int i, j;
764
765
0
    for (i = 0; i < search_range; i++) {
766
0
        int best_site = -1;
767
768
0
        for (j = 0; j < (search_diag ? 8 : 4); j++) {
769
0
            const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
770
0
            if (is_mv_in(&x->mv_limits, mv)) {
771
0
                unsigned int sad = fn_ptr->osdf(
772
0
                    get_buf_from_mv((const Buf2D*)in_what, mv), in_what->stride, wsrc, mask);
773
0
                if (sad < best_sad) {
774
0
                    sad += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
775
0
                    if (sad < best_sad) {
776
0
                        best_sad  = sad;
777
0
                        best_site = j;
778
0
                    }
779
0
                }
780
0
            }
781
0
        }
782
783
0
        if (best_site == -1) {
784
0
            break;
785
0
        } else {
786
0
            ref_mv->y += neighbors[best_site].y;
787
0
            ref_mv->x += neighbors[best_site].x;
788
0
        }
789
0
    }
790
0
    return best_sad;
791
0
}
792
793
int svt_av1_obmc_full_pixel_search(ModeDecisionContext* ctx, IntraBcContext* x, const Mv mvp_full, int sadpb,
794
0
                                   const AomVarianceFnPtr* fn_ptr, const Mv ref_mv, Mv* dst_mv, int is_second) {
795
    // obmc_full_pixel_diamond does not provide BDR gain on 360p
796
0
    const int32_t* wsrc         = ctx->wsrc_buf;
797
0
    const int32_t* mask         = ctx->mask_buf;
798
0
    const int      search_range = ctx->obmc_ctrls.fpel_search_range;
799
0
    *dst_mv                     = mvp_full;
800
0
    x->approx_inter_rate        = ctx->approx_inter_rate;
801
0
    clamp_mv(dst_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
802
0
    clamp_mv(dst_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
803
0
    int thissme = obmc_refining_search_sad(
804
0
        x, wsrc, mask, dst_mv, sadpb, search_range, fn_ptr, ref_mv, is_second, ctx->obmc_ctrls.fpel_search_diag);
805
0
    if (thissme < INT_MAX) {
806
0
        thissme = get_obmc_mvpred_var(x, wsrc, mask, *dst_mv, ref_mv, fn_ptr, 1, is_second);
807
0
    }
808
809
0
    return thissme;
810
0
}
811
#endif
812
813
#if CONFIG_ENABLE_OBMC
814
static INLINE void set_subpel_mv_search_range(const MvLimits* mv_limits, int* col_min, int* col_max, int* row_min,
815
0
                                              int* row_max, const Mv ref_mv) {
816
0
    const int max_mv = MAX_FULL_PEL_VAL * 8;
817
0
    const int minc   = AOMMAX(mv_limits->col_min * 8, ref_mv.x - max_mv);
818
0
    const int maxc   = AOMMIN(mv_limits->col_max * 8, ref_mv.x + max_mv);
819
0
    const int minr   = AOMMAX(mv_limits->row_min * 8, ref_mv.y - max_mv);
820
0
    const int maxr   = AOMMIN(mv_limits->row_max * 8, ref_mv.y + max_mv);
821
822
0
    *col_min = AOMMAX(MV_LOW + 1, minc);
823
0
    *col_max = AOMMIN(MV_UPP - 1, maxc);
824
0
    *row_min = AOMMAX(MV_LOW + 1, minr);
825
0
    *row_max = AOMMIN(MV_UPP - 1, maxr);
826
0
}
827
828
static const Mv search_step_table[12] = {
829
    // left, right, up, down
830
    {{-4, 0}},
831
    {{4, 0}},
832
    {{0, -4}},
833
    {{0, 4}},
834
    {{-2, 0}},
835
    {{2, 0}},
836
    {{0, -2}},
837
    {{0, 2}},
838
    {{-1, 0}},
839
    {{1, 0}},
840
    {{0, -1}},
841
    {{0, 1}}};
842
843
static unsigned int setup_obmc_center_error(const int32_t* mask, const Mv bestmv, const Mv ref_mv, int error_per_bit,
844
                                            const AomVarianceFnPtr* vfp, const int32_t* const wsrc,
845
                                            const uint8_t* const y, int y_stride, int offset, int* mvjcost,
846
                                            const int* mvcost[2], unsigned int* sse1,
847
0
                                            uint8_t use_low_precision_cost_estimation, int* distortion) {
848
0
    unsigned int besterr;
849
0
    besterr     = vfp->ovf(y + offset, y_stride, wsrc, mask, sse1);
850
0
    *distortion = besterr;
851
0
    if (use_low_precision_cost_estimation) {
852
0
        besterr += svt_aom_mv_err_cost_light(bestmv, ref_mv);
853
0
    } else {
854
0
        besterr += svt_aom_mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
855
0
    }
856
0
    return besterr;
857
0
}
858
859
/* returns subpixel variance error function */
860
0
#define DIST(r, c) vfp->osvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, mask, &sse)
861
#define CHECK_BETTER(v, r, c, lp)                                                                    \
862
0
    do {                                                                                             \
863
0
        if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                                      \
864
0
            thismse = (DIST(r, c));                                                                  \
865
0
                                                                                                     \
866
0
            if (lp)                                                                                  \
867
0
                v = svt_aom_mv_err_cost_light((const Mv){{c, r}}, ref_mv);                           \
868
0
            else                                                                                     \
869
0
                v = svt_aom_mv_err_cost((const Mv){{c, r}}, ref_mv, mvjcost, mvcost, error_per_bit); \
870
0
            if ((v + thismse) < besterr) {                                                           \
871
0
                besterr     = v + thismse;                                                           \
872
0
                br          = r;                                                                     \
873
0
                bc          = c;                                                                     \
874
0
                *distortion = thismse;                                                               \
875
0
                *sse1       = sse;                                                                   \
876
0
            }                                                                                        \
877
0
        } else                                                                                       \
878
0
            v = INT_MAX;                                                                             \
879
0
    } while (0)
880
0
#define CHECK_BETTER0(v, r, c, lp) CHECK_BETTER(v, r, c, lp)
881
#define CHECK_BETTER1(v, r, c, lp)                                                        \
882
0
    do {                                                                                  \
883
0
        if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                           \
884
0
            Mv this_mv = {{c, r}};                                                        \
885
0
            thismse    = upsampled_obmc_pref_error(xd,                                    \
886
0
                                                   cm,                                    \
887
0
                                                   mi_row,                                \
888
0
                                                   mi_col,                                \
889
0
                                                   mask,                                  \
890
0
                                                   vfp,                                   \
891
0
                                                   z,                                     \
892
0
                                                   pre(y, y_stride, r, c),                \
893
0
                                                   y_stride,                              \
894
0
                                                   sp(c),                                 \
895
0
                                                   sp(r),                                 \
896
0
                                                   w,                                     \
897
0
                                                   h,                                     \
898
0
                                                   &sse,                                  \
899
0
                                                   use_accurate_subpel_search);           \
900
0
            if (lp)                                                                       \
901
0
                v = svt_aom_mv_err_cost_light(this_mv, ref_mv);                           \
902
0
            else                                                                          \
903
0
                v = svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \
904
0
            if ((v + thismse) < besterr) {                                                \
905
0
                besterr     = v + thismse;                                                \
906
0
                br          = r;                                                          \
907
0
                bc          = c;                                                          \
908
0
                *distortion = thismse;                                                    \
909
0
                *sse1       = sse;                                                        \
910
0
            }                                                                             \
911
0
        } else                                                                            \
912
0
            v = INT_MAX;                                                                  \
913
0
    } while (0)
914
#define SECOND_LEVEL_CHECKS_BEST(k)                          \
915
0
    do {                                                     \
916
0
        unsigned int second;                                 \
917
0
        int          br0 = br;                               \
918
0
        int          bc0 = bc;                               \
919
0
        assert(tr == br || tc == bc);                        \
920
0
        if (tr == br && tc != bc)                            \
921
0
            kc = bc - tc;                                    \
922
0
        else if (tr != br && tc == bc)                       \
923
0
            kr = br - tr;                                    \
924
0
        CHECK_BETTER##k(second, br0 + kr, bc0, lp);          \
925
0
        CHECK_BETTER##k(second, br0, bc0 + kc, lp);          \
926
0
        if (br0 != br || bc0 != bc)                          \
927
0
            CHECK_BETTER##k(second, br0 + kr, bc0 + kc, lp); \
928
0
    } while (0)
929
930
static int upsampled_obmc_pref_error(MacroBlockD* xd, const Av1Common* const cm, int mi_row, int mi_col,
931
                                     const int32_t* mask, const AomVarianceFnPtr* vfp, const int32_t* const wsrc,
932
                                     const uint8_t* const y, int y_stride, int subpel_x_q3, int subpel_y_q3, int w,
933
0
                                     int h, unsigned int* sse, int subpel_search) {
934
0
    unsigned int besterr;
935
936
0
    DECLARE_ALIGNED(16, uint8_t, pred[2 * MAX_SB_SQUARE]);
937
0
    svt_aom_upsampled_pred(xd,
938
0
                           (const struct AV1Common* const)cm,
939
0
                           mi_row,
940
0
                           mi_col,
941
0
                           pred,
942
0
                           w,
943
0
                           h,
944
0
                           subpel_x_q3,
945
0
                           subpel_y_q3,
946
0
                           y,
947
0
                           y_stride,
948
0
                           subpel_search);
949
950
0
    besterr = vfp->ovf(pred, w, wsrc, mask, sse);
951
0
    return besterr;
952
0
}
953
954
static unsigned int upsampled_setup_obmc_center_error(MacroBlockD* xd, const Av1Common* const cm, int mi_row,
955
                                                      int mi_col, const int32_t* mask, const Mv bestmv, const Mv ref_mv,
956
                                                      int error_per_bit, const AomVarianceFnPtr* vfp,
957
                                                      const int32_t* const wsrc, const uint8_t* const y, int y_stride,
958
                                                      int w, int h, int offset, int* mvjcost, const int* mvcost[2],
959
                                                      unsigned int* sse1, int* distortion,
960
0
                                                      uint8_t use_low_precision_cost_estimation, int subpel_search) {
961
0
    unsigned int besterr = upsampled_obmc_pref_error(
962
0
        xd, cm, mi_row, mi_col, mask, vfp, wsrc, y + offset, y_stride, 0, 0, w, h, sse1, subpel_search);
963
0
    *distortion = besterr;
964
0
    if (use_low_precision_cost_estimation) {
965
0
        besterr += svt_aom_mv_err_cost_light(bestmv, ref_mv);
966
0
    } else {
967
0
        besterr += svt_aom_mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
968
0
    }
969
0
    return besterr;
970
0
}
971
972
// convert motion vector component to offset for sv[a]f calc
973
0
static INLINE int sp(int x) {
974
0
    return x & 7;
975
0
}
976
977
0
static INLINE const uint8_t* pre(const uint8_t* buf, int stride, int r, int c) {
978
0
    const int offset = (r >> 3) * stride + (c >> 3);
979
0
    return buf + offset;
980
0
}
981
982
int svt_av1_find_best_obmc_sub_pixel_tree_up(ModeDecisionContext* ctx, IntraBcContext* x,
983
                                             const struct Av1Common* const cm, int mi_row, int mi_col, Mv* bestmv,
984
                                             const Mv ref_mv, int allow_hp, int error_per_bit,
985
                                             const AomVarianceFnPtr* vfp, int forced_stop, int iters_per_step,
986
                                             int* mvjcost, const int* mvcost[2], int* distortion, unsigned int* sse1,
987
0
                                             int is_second, int use_accurate_subpel_search) {
988
0
    const int32_t*                 wsrc        = ctx->wsrc_buf;
989
0
    const int32_t*                 mask        = ctx->mask_buf;
990
0
    const int* const               z           = wsrc;
991
0
    const int* const               src_address = z;
992
0
    MacroBlockD*                   xd          = x->xd;
993
0
    struct MacroBlockDPlane* const pd          = &x->xdplane[0];
994
0
    unsigned int                   besterr     = INT_MAX;
995
0
    unsigned int                   sse;
996
0
    unsigned int                   thismse;
997
0
    int                            br    = bestmv->y * 8;
998
0
    int                            bc    = bestmv->x * 8;
999
0
    int                            hstep = 4;
1000
0
    int                            round = 3 - forced_stop;
1001
0
    int                            tr;
1002
0
    int                            tc;
1003
0
    const Mv*                      search_step = search_step_table;
1004
0
    int                            best_idx    = -1;
1005
0
    unsigned int                   cost_array[5];
1006
0
    const int                      w  = block_size_wide[ctx->blk_geom->bsize];
1007
0
    const int                      h  = block_size_high[ctx->blk_geom->bsize];
1008
0
    const uint8_t                  lp = ctx->approx_inter_rate;
1009
0
    int                            minc, maxc, minr, maxr;
1010
1011
0
    set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, ref_mv);
1012
1013
0
    const uint8_t* y        = pd->pre[is_second].buf;
1014
0
    int            y_stride = pd->pre[is_second].stride;
1015
0
    int            offset   = bestmv->y * y_stride + bestmv->x;
1016
1017
0
    if (!allow_hp && round == 3) {
1018
0
        round = 2;
1019
0
    }
1020
1021
0
    bestmv->y *= 8;
1022
0
    bestmv->x *= 8;
1023
    // use_accurate_subpel_search can be 0 or 1 or 2
1024
0
    besterr = use_accurate_subpel_search
1025
0
        ? upsampled_setup_obmc_center_error(xd,
1026
0
                                            cm,
1027
0
                                            mi_row,
1028
0
                                            mi_col,
1029
0
                                            mask,
1030
0
                                            *bestmv,
1031
0
                                            ref_mv,
1032
0
                                            error_per_bit,
1033
0
                                            vfp,
1034
0
                                            z,
1035
0
                                            y,
1036
0
                                            y_stride,
1037
0
                                            w,
1038
0
                                            h,
1039
0
                                            offset,
1040
0
                                            mvjcost,
1041
0
                                            mvcost,
1042
0
                                            sse1,
1043
0
                                            distortion,
1044
0
                                            lp,
1045
0
                                            use_accurate_subpel_search)
1046
0
        : setup_obmc_center_error(
1047
0
              mask, *bestmv, ref_mv, error_per_bit, vfp, z, y, y_stride, offset, mvjcost, mvcost, sse1, lp, distortion);
1048
1049
0
    for (int iter = 0; iter < round; ++iter) {
1050
        // Check vertical and horizontal sub-pixel positions.
1051
0
        int idx = 0;
1052
0
        for (; idx < 4; ++idx) {
1053
0
            tr = br + search_step[idx].y;
1054
0
            tc = bc + search_step[idx].x;
1055
0
            if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) {
1056
0
                Mv this_mv = {{tc, tr}};
1057
0
                thismse    = use_accurate_subpel_search
1058
0
                    ? (unsigned)upsampled_obmc_pref_error(xd,
1059
0
                                                          cm,
1060
0
                                                          mi_row,
1061
0
                                                          mi_col,
1062
0
                                                          mask,
1063
0
                                                          vfp,
1064
0
                                                          src_address,
1065
0
                                                          pre(y, y_stride, tr, tc),
1066
0
                                                          y_stride,
1067
0
                                                          sp(tc),
1068
0
                                                          sp(tr),
1069
0
                                                          w,
1070
0
                                                          h,
1071
0
                                                          &sse,
1072
0
                                                          use_accurate_subpel_search)
1073
0
                    : vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), src_address, mask, &sse);
1074
0
                if (lp) {
1075
0
                    cost_array[idx] = thismse + svt_aom_mv_err_cost_light(this_mv, ref_mv);
1076
0
                } else {
1077
0
                    cost_array[idx] = thismse + svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit);
1078
0
                }
1079
0
                if (cost_array[idx] < besterr) {
1080
0
                    best_idx    = idx;
1081
0
                    besterr     = cost_array[idx];
1082
0
                    *distortion = thismse;
1083
0
                    *sse1       = sse;
1084
0
                }
1085
0
            } else {
1086
0
                cost_array[idx] = INT_MAX;
1087
0
            }
1088
0
        }
1089
1090
        // Check diagonal sub-pixel position
1091
0
        int kc = (cost_array[0] <= cost_array[1] ? -hstep : hstep);
1092
0
        int kr = (cost_array[2] <= cost_array[3] ? -hstep : hstep);
1093
1094
0
        tc = bc + kc;
1095
0
        tr = br + kr;
1096
0
        if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) {
1097
0
            Mv this_mv = {{tc, tr}};
1098
0
            thismse    = use_accurate_subpel_search
1099
0
                ? (unsigned)upsampled_obmc_pref_error(xd,
1100
0
                                                      cm,
1101
0
                                                      mi_row,
1102
0
                                                      mi_col,
1103
0
                                                      mask,
1104
0
                                                      vfp,
1105
0
                                                      src_address,
1106
0
                                                      pre(y, y_stride, tr, tc),
1107
0
                                                      y_stride,
1108
0
                                                      sp(tc),
1109
0
                                                      sp(tr),
1110
0
                                                      w,
1111
0
                                                      h,
1112
0
                                                      &sse,
1113
0
                                                      use_accurate_subpel_search)
1114
0
                : vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), src_address, mask, &sse);
1115
0
            if (lp) {
1116
0
                cost_array[4] = thismse + svt_aom_mv_err_cost_light(this_mv, ref_mv);
1117
0
            } else {
1118
0
                cost_array[4] = thismse + svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit);
1119
0
            }
1120
1121
0
            if (cost_array[4] < besterr) {
1122
0
                best_idx    = 4;
1123
0
                besterr     = cost_array[4];
1124
0
                *distortion = thismse;
1125
0
                *sse1       = sse;
1126
0
            }
1127
0
        } else {
1128
0
            cost_array[idx] = INT_MAX;
1129
0
        }
1130
1131
0
        if (best_idx < 4 && best_idx >= 0) {
1132
0
            br += search_step[best_idx].y;
1133
0
            bc += search_step[best_idx].x;
1134
0
        } else if (best_idx == 4) {
1135
0
            br = tr;
1136
0
            bc = tc;
1137
0
        }
1138
1139
0
        if (iters_per_step > 1 && best_idx != -1) {
1140
0
            if (use_accurate_subpel_search) {
1141
0
                SECOND_LEVEL_CHECKS_BEST(1);
1142
0
            } else {
1143
0
                SECOND_LEVEL_CHECKS_BEST(0);
1144
0
            }
1145
0
        }
1146
1147
0
        search_step += 4;
1148
0
        hstep >>= 1;
1149
0
        best_idx = -1;
1150
0
    }
1151
1152
0
    bestmv->y = br;
1153
0
    bestmv->x = bc;
1154
1155
0
    return besterr;
1156
0
}
1157
#endif
1158
void svt_av1_intrabc_hash_search(PictureControlSet* pcs, IntraBcContext* x, BlockSize bsize, int x_pos, int y_pos,
1159
                                 const Mv ref_mv, int intra, const AomVarianceFnPtr* fn_ptr, int* best_hash_cost,
1160
0
                                 Mv* best_hash_mv) {
1161
0
    const int block_width  = block_size_wide[bsize];
1162
0
    const int block_height = block_size_high[bsize];
1163
1164
0
    if (block_width != block_height || block_width > pcs->ppcs->intrabc_ctrls.max_block_size_hash) {
1165
0
        return;
1166
0
    }
1167
1168
0
    uint8_t* src_buf    = x->plane[0].src.buf;
1169
0
    int      src_stride = x->plane[0].src.stride;
1170
1171
0
    uint32_t hash_value1, hash_value2;
1172
1173
0
    svt_av1_get_block_hash_value(src_buf, src_stride, block_width, &hash_value1, &hash_value2, 0, x);
1174
1175
0
    HashTable* ref_frame_hash = &pcs->hash_table;
1176
0
    int        count          = svt_av1_hash_table_count(ref_frame_hash, hash_value1);
1177
1178
0
    if (count <= (intra ? 1 : 0)) {
1179
0
        return;
1180
0
    }
1181
1182
0
    const BlockHash* cands = svt_av1_hash_get_first(ref_frame_hash, hash_value1);
1183
1184
0
    const int mi_col = x_pos / MI_SIZE;
1185
0
    const int mi_row = y_pos / MI_SIZE;
1186
1187
0
    for (int i = 0; i < count; i++) {
1188
0
        const BlockHash ref_block_hash = cands[i];
1189
1190
0
        if (hash_value2 != ref_block_hash.hash_value2) {
1191
0
            continue;
1192
0
        }
1193
1194
0
        if (intra) {
1195
0
            Mv dv = {{8 * (ref_block_hash.x - x_pos), 8 * (ref_block_hash.y - y_pos)}};
1196
1197
0
            if (!svt_aom_is_dv_valid(dv, x->xd, mi_row, mi_col, bsize, pcs->ppcs->scs->seq_header.sb_size_log2)) {
1198
0
                continue;
1199
0
            }
1200
0
        }
1201
1202
0
        Mv hash_mv = {{ref_block_hash.x - x_pos, ref_block_hash.y - y_pos}};
1203
1204
0
        if (!is_mv_in(&x->mv_limits, hash_mv)) {
1205
0
            continue;
1206
0
        }
1207
1208
0
        int ref_cost = svt_av1_get_mvpred_var(x, hash_mv, ref_mv, fn_ptr, 1);
1209
1210
0
        if (ref_cost < *best_hash_cost) {
1211
0
            *best_hash_cost = ref_cost;
1212
0
            *best_hash_mv   = hash_mv;
1213
0
        }
1214
0
    }
1215
0
}
1216
1217
int svt_av1_full_pixel_search(PictureControlSet* pcs, IntraBcContext* x, BlockSize bsize, Mv* mvp_full, int step_param,
1218
0
                              int error_per_bit, int* cost_list, const Mv ref_mv) {
1219
0
    const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
1220
0
    int                     var    = 0;
1221
1222
    // Initialize cost list if requested
1223
0
    if (cost_list) {
1224
0
        for (int i = 0; i < 5; i++) {
1225
0
            cost_list[i] = INT_MAX;
1226
0
        }
1227
0
    }
1228
1229
    // Primary diamond search
1230
0
    var = full_pixel_diamond(
1231
0
        pcs, x, mvp_full, step_param, error_per_bit, MAX_MVSEARCH_STEPS - 1 - step_param, 1, cost_list, fn_ptr, ref_mv);
1232
1233
    // Decide whether to run exhaustive refinement
1234
0
    bool run_mesh_search = 0;
1235
1236
0
    int exhaustive_mesh_thresh = (int)pcs->ppcs->intrabc_ctrls.exhaustive_mesh_thresh;
1237
1238
    // Scale threshold by block size
1239
0
    exhaustive_mesh_thresh >>= 10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]);
1240
1241
0
    if (var > exhaustive_mesh_thresh) {
1242
0
        run_mesh_search = 1;
1243
0
    }
1244
0
    const int32_t full_pel_mv_diff = MAX(abs(mvp_full->x - x->best_mv.x), abs(mvp_full->y - x->best_mv.y));
1245
0
    if (full_pel_mv_diff <= pcs->ppcs->intrabc_ctrls.mesh_search_mv_diff_threshold) {
1246
0
        run_mesh_search = 0;
1247
0
    }
1248
    // Exhaustive (Mesh) Search
1249
0
    if (run_mesh_search) {
1250
0
        int var_ex;
1251
0
        Mv  mv_ex;
1252
1253
0
        var_ex = intrabc_full_pixel_exhaustive(pcs, x, x->best_mv, error_per_bit, fn_ptr, ref_mv, &mv_ex);
1254
1255
0
        if (var_ex < var) {
1256
0
            x->best_mv = mv_ex;
1257
0
        }
1258
0
    }
1259
1260
0
    return 0;
1261
0
}