loopfilter.c 7.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * Copyright © 2018, VideoLAN and dav1d authors
 * Copyright © 2018, Two Orioles, LLC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "tests/checkasm/checkasm.h"

#include <string.h>

#include "src/levels.h"
#include "src/loopfilter.h"

static void init_lpf_border(pixel *const dst, const ptrdiff_t stride,
36
                            int E, int I, int H, const int bitdepth_max)
37
{
38 39 40 41 42
    const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
    const int F = 1 << bitdepth_min_8;
    E <<= bitdepth_min_8;
    I <<= bitdepth_min_8;
    H <<= bitdepth_min_8;
43

44 45
    const int filter_type = rnd() % 4;
    const int edge_diff = rnd() % ((E + 2) * 4) - 2 * (E + 2);
46 47 48
    switch (filter_type) {
    case 0: // random, unfiltered
        for (int i = -8; i < 8; i++)
49
            dst[i * stride] = rnd() & bitdepth_max;
50 51
        break;
    case 1: // long flat
52 53 54
        dst[-8 * stride] = rnd() & bitdepth_max;
        dst[+7 * stride] = rnd() & bitdepth_max;
        dst[+0 * stride] = rnd() & bitdepth_max;
55 56 57
        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
        for (int i = 1; i < 7; i++) {
            dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
58
                                                 rnd() % (2 * (F + 1)) - (F + 1));
59
            dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
60
                                                 rnd() % (2 * (F + 1)) - (F + 1));
61 62 63 64
        }
        break;
    case 2: // short flat
        for (int i = 4; i < 8; i++) {
65 66
            dst[-(1 + i) * stride] = rnd() & bitdepth_max;
            dst[+(0 + i) * stride] = rnd() & bitdepth_max;
67
        }
68
        dst[+0 * stride] = rnd() & bitdepth_max;
69 70 71
        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
        for (int i = 1; i < 4; i++) {
            dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
72
                                                 rnd() % (2 * (F + 1)) - (F + 1));
73
            dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
74
                                                 rnd() % (2 * (F + 1)) - (F + 1));
75 76 77 78
        }
        break;
    case 3: // normal or hev
        for (int i = 4; i < 8; i++) {
79 80
            dst[-(1 + i) * stride] = rnd() & bitdepth_max;
            dst[+(0 + i) * stride] = rnd() & bitdepth_max;
81
        }
82
        dst[+0 * stride] = rnd() & bitdepth_max;
83 84 85
        dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
        for (int i = 1; i < 4; i++) {
            dst[-(1 + i) * stride] = iclip_pixel(dst[-(0 + i) * stride] +
86
                                                 rnd() % (2 * (I + 1)) - (I + 1));
87
            dst[+(0 + i) * stride] = iclip_pixel(dst[+(i - 1) * stride] +
88
                                                 rnd() % (2 * (I + 1)) - (I + 1));
89 90 91 92 93 94
        }
        break;
    }
}

static void check_lpf_sb(loopfilter_sb_fn fn, const char *const name,
95 96
                         const int n_blks, const int lf_idx,
                         const int is_chroma, const int dir)
97
{
98 99
    ALIGN_STK_32(pixel, c_dst_mem, 128 * 16,);
    ALIGN_STK_32(pixel, a_dst_mem, 128 * 16,);
100 101 102 103 104

    declare_func(void, pixel *dst, ptrdiff_t dst_stride, const uint32_t *mask,
                 const uint8_t (*l)[4], ptrdiff_t b4_stride,
                 const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX);

105 106 107 108 109 110 111 112 113 114 115 116 117
    pixel *a_dst, *c_dst;
    ptrdiff_t stride, b4_stride;
    if (dir) {
        a_dst = a_dst_mem + 128 * 8;
        c_dst = c_dst_mem + 128 * 8;
        stride = 128 * sizeof(pixel);
        b4_stride = 32;
    } else {
        a_dst = a_dst_mem + 8;
        c_dst = c_dst_mem + 8;
        stride = 16 * sizeof(pixel);
        b4_stride = 2;
    }
118 119

    Av1FilterLUT lut;
120
    const int sharp = rnd() & 7;
121 122 123 124 125 126 127 128 129 130 131 132
    for (int level = 0; level < 64; level++) {
        int limit = level;

        if (sharp > 0) {
            limit >>= (sharp + 3) >> 2;
            limit = imin(limit, 9 - sharp);
        }
        limit = imax(limit, 1);

        lut.i[level] = limit;
        lut.e[level] = 2 * (level + 2) + limit;
    }
133 134
    lut.sharp[0] = (sharp + 3) >> 2;
    lut.sharp[1] = sharp ? 9 - sharp : 0xff;
135

136
    const int n_strengths = is_chroma ? 2 : 3;
137 138
    for (int i = 0; i < n_strengths; i++) {
        if (check_func(fn, "%s_w%d_%dbpc", name,
139
                       is_chroma ? 4 + 2 * i : 4 << i, BITDEPTH))
140
        {
141
            uint32_t vmask[4] = { 0 };
142 143 144
            uint8_t l[32 * 2][4];

            for (int j = 0; j < n_blks; j++) {
145
                const int idx = rnd() % (i + 2);
146
                if (idx) vmask[idx - 1] |= 1U << j;
147
                if (dir) {
148 149
                    l[j][lf_idx] = rnd() & 63;
                    l[j + 32][lf_idx] = rnd() & 63;
150
                } else {
151 152
                    l[j * 2][lf_idx] = rnd() & 63;
                    l[j * 2 + 1][lf_idx] = rnd() & 63;
153
                }
154
            }
155
#if BITDEPTH == 16
156
            const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
157 158 159
#else
            const int bitdepth_max = 0xff;
#endif
160

161
            for (int i = 0; i < 4 * n_blks; i++) {
162
                const int x = i >> 2;
163 164 165 166 167 168 169
                int L;
                if (dir) {
                    L = l[32 + x][lf_idx] ? l[32 + x][lf_idx] : l[x][lf_idx];
                } else {
                    L = l[2 * x + 1][lf_idx] ? l[2 * x + 1][lf_idx] : l[2 * x][lf_idx];
                }
                init_lpf_border(c_dst + i * (dir ? 1 : 16), dir ? 128 : 1,
170
                                lut.e[L], lut.i[L], L >> 4, bitdepth_max);
171
            }
172
            memcpy(a_dst_mem, c_dst_mem, 128 * sizeof(pixel) * 16);
173

174 175
            call_ref(c_dst, stride,
                     vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
176
                     &lut, n_blks HIGHBD_TAIL_SUFFIX);
177 178
            call_new(a_dst, stride,
                     vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
179
                     &lut, n_blks HIGHBD_TAIL_SUFFIX);
180
            if (memcmp(c_dst_mem, a_dst_mem, 128 * 16 * sizeof(*a_dst)))  fail();
181

182 183
            bench_new(a_dst, stride,
                      vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
184
                      &lut, n_blks HIGHBD_TAIL_SUFFIX);
185 186 187 188 189 190 191 192 193 194
        }
    }
    report(name);
}

void bitfn(checkasm_check_loopfilter)(void) {
    Dav1dLoopFilterDSPContext c;

    bitfn(dav1d_loop_filter_dsp_init)(&c);

195 196 197 198
    check_lpf_sb(c.loop_filter_sb[0][0], "lpf_h_sb_y", 32, 0, 0, 0);
    check_lpf_sb(c.loop_filter_sb[0][1], "lpf_v_sb_y", 32, 1, 0, 1);
    check_lpf_sb(c.loop_filter_sb[1][0], "lpf_h_sb_uv", 16, 2, 1, 0);
    check_lpf_sb(c.loop_filter_sb[1][1], "lpf_v_sb_uv", 16, 2, 1, 1);
199
}