/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with FFmpeg; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "checkasm.h" #include "libavutil/intreadwrite.h" #include "libavutil/macros.h" #include "libavutil/mem_internal.h" #include "libavcodec/vp3dsp.h" enum { MAX_STRIDE = 64, MIN_STRIDE = 8, /// Horizontal tests operate on 4x8 blocks HORIZONTAL_BUF_SIZE = ((8 /* lines */ - 1) * MAX_STRIDE + 4 /* width */ + 7 /* misalignment */), /// Vertical tests operate on 8x4 blocks VERTICAL_BUF_SIZE = ((4 /* lines */ - 1) * MAX_STRIDE + 8 /* width */ + 7 /* misalignment */), }; #define randomize_buffers(buf0, buf1, size) \ do { \ static_assert(sizeof(buf0[0]) == 1 && sizeof(buf1[0]) == 1, \ "Pointer arithmetic needs to be adapted"); \ for (size_t k = 0; k < (size & ~3); k += 4) { \ uint32_t r = rnd(); \ AV_WN32A(buf0 + k, r); \ AV_WN32A(buf1 + k, r); \ } \ for (size_t k = size & ~3; k < size; ++k) \ buf0[k] = buf1[k] = rnd(); \ } while (0) static void vp3_check_loop_filter(void) { DECLARE_ALIGNED(8, uint8_t, hor_buf0)[HORIZONTAL_BUF_SIZE]; DECLARE_ALIGNED(8, uint8_t, hor_buf1)[HORIZONTAL_BUF_SIZE]; DECLARE_ALIGNED(8, uint8_t, ver_buf0)[VERTICAL_BUF_SIZE]; DECLARE_ALIGNED(8, uint8_t, ver_buf1)[VERTICAL_BUF_SIZE]; DECLARE_ALIGNED(16, int, bounding_values_array)[256 + 4]; int *const bounding_values = bounding_values_array + 127; VP3DSPContext vp3dsp; static const struct { const char *name; size_t offset; int lines_above, lines_below; int pixels_left, pixels_right; unsigned alignment; int horizontal; } tests[] = { #define TEST(NAME) .name = #NAME, .offset = offsetof(VP3DSPContext, NAME) { TEST(v_loop_filter_unaligned), 2, 1, 0, 7, 1, 0 }, { TEST(h_loop_filter_unaligned), 0, 7, 2, 1, 1, 1 }, { TEST(v_loop_filter), 2, 1, 0, 7, VP3_LOOP_FILTER_NO_UNALIGNED_SUPPORT ? 8 : 1, 0 }, { TEST(h_loop_filter), 0, 7, 2, 1, VP3_LOOP_FILTER_NO_UNALIGNED_SUPPORT ? 8 : 1, 1 }, }; declare_func(void, uint8_t *src, ptrdiff_t stride, int *bounding_values); ff_vp3dsp_init(&vp3dsp); int filter_limit = rnd() % 128; ff_vp3dsp_set_bounding_values(bounding_values_array, filter_limit); for (size_t i = 0; i < FF_ARRAY_ELEMS(tests); ++i) { void (*loop_filter)(uint8_t *, ptrdiff_t, int*) = *(void(**)(uint8_t *, ptrdiff_t, int*))((char*)&vp3dsp + tests[i].offset); if (check_func(loop_filter, "%s", tests[i].name)) { uint8_t *buf0 = tests[i].horizontal ? hor_buf0 : ver_buf0; uint8_t *buf1 = tests[i].horizontal ? hor_buf1 : ver_buf1; size_t bufsize = tests[i].horizontal ? HORIZONTAL_BUF_SIZE : VERTICAL_BUF_SIZE; ptrdiff_t stride = (rnd() % (MAX_STRIDE / MIN_STRIDE) + 1) * MIN_STRIDE; // Don't always use pointers that are aligned to 8. size_t offset = FFALIGN(tests[i].pixels_left, tests[i].alignment) + (rnd() % (MIN_STRIDE / tests[i].alignment)) * tests[i].alignment + stride * tests[i].lines_above; uint8_t *dst0 = buf0 + offset, *dst1 = buf1 + offset; if (rnd() & 1) { // Flip stride. dst1 += (tests[i].lines_below - tests[i].lines_above) * stride; dst0 += (tests[i].lines_below - tests[i].lines_above) * stride; stride = -stride; } randomize_buffers(buf0, buf1, bufsize); call_ref(dst0, stride, bounding_values); call_new(dst1, stride, bounding_values); if (memcmp(buf0, buf1, bufsize)) fail(); bench_new(dst0, stride, bounding_values); } } } void checkasm_check_vp3dsp(void) { vp3_check_loop_filter(); }