This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 100ce4ac412ca80146f7f7d0042acce9c77ab006 Author: Niklas Haas <[email protected]> AuthorDate: Sat Apr 11 16:52:55 2026 +0200 Commit: Niklas Haas <[email protected]> CommitDate: Tue Jun 9 18:27:20 2026 +0200 tests/checkasm/sw_ops: rewrite using uops_macros.h This ensures 100% coverage of all uop primitives by generating the set of tests exactly from the list of seen primitives, using the uops macros. There are some annoying quirks still because of the fact that we have to essentially "untranslate" the UOPs back to SwsOps that result back in the intended uop after the translation, but overall it's not too bad and still much better than the status quo of hand-rolling the list of test cases. Signed-off-by: Niklas Haas <[email protected]> --- tests/checkasm/sw_ops.c | 841 +++++++++++++++++++----------------------------- 1 file changed, 336 insertions(+), 505 deletions(-) diff --git a/tests/checkasm/sw_ops.c b/tests/checkasm/sw_ops.c index cff4574627..90eb9d3fb7 100644 --- a/tests/checkasm/sw_ops.c +++ b/tests/checkasm/sw_ops.c @@ -25,7 +25,9 @@ #include "libavutil/refstruct.h" #include "libswscale/ops.h" -#include "libswscale/ops_internal.h" +#include "libswscale/ops_dispatch.h" +#include "libswscale/uops.h" +#include "libswscale/uops_macros.h" #include "checkasm.h" @@ -354,172 +356,35 @@ done: #define CHECK_RANGE(NAME, RANGE, N_IN, N_OUT, IN, OUT, ...) \ CHECK_RANGES(NAME, MK_RANGES(RANGE), N_IN, N_OUT, IN, OUT, __VA_ARGS__) -#define CHECK_COMMON_RANGE(NAME, RANGE, IN, OUT, ...) \ - CHECK_RANGE(FMT("%s_p1000", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ - CHECK_RANGE(FMT("%s_p1110", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ - CHECK_RANGE(FMT("%s_p1111", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ - CHECK_RANGE(FMT("%s_p1001", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__, { \ - .op = SWS_OP_SWIZZLE, \ - .type = OUT, \ - .swizzle = SWS_SWIZZLE(0, 3, 1, 2), \ - }) - #define CHECK(NAME, N_IN, N_OUT, IN, OUT, ...) \ CHECK_RANGE(NAME, 0, N_IN, N_OUT, IN, OUT, __VA_ARGS__) -#define CHECK_COMMON(NAME, IN, OUT, ...) \ - CHECK_COMMON_RANGE(NAME, 0, IN, OUT, __VA_ARGS__) - -static void check_read_write(void) +static inline int mask_num(const SwsCompMask mask) { - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - for (int i = 1; i <= 4; i++) { - /* Test N->N planar read/write */ - for (int o = 1; o <= i; o++) { - check_ops(FMT("rw_%d_%d_%s", i, o, type), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = t, - .rw.elems = i, - }, { - .op = SWS_OP_WRITE, - .type = t, - .rw.elems = o, - }, {0} - }); - } - - /* Test packed read/write */ - if (i == 1) - continue; - - check_ops(FMT("read_packed%d_%s", i, type), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = t, - .rw.elems = i, - .rw.packed = true, - }, { - .op = SWS_OP_WRITE, - .type = t, - .rw.elems = i, - }, {0} - }); - - check_ops(FMT("write_packed%d_%s", i, type), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = t, - .rw.elems = i, - }, { - .op = SWS_OP_WRITE, - .type = t, - .rw.elems = i, - .rw.packed = true, - }, {0} - }); - } - } - - /* Test fractional reads/writes */ - for (int frac = 1; frac <= 3; frac++) { - const int bits = 8 >> frac; - const int range = (1 << bits) - 1; - if (bits == 2) - continue; /* no 2 bit packed formats currently exist */ - - check_ops(FMT("read_frac%d", frac), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = U8, - .rw.elems = 1, - .rw.frac = frac, - }, { - .op = SWS_OP_WRITE, - .type = U8, - .rw.elems = 1, - }, {0} - }); - - check_ops(FMT("write_frac%d", frac), MK_RANGES(range), (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = U8, - .rw.elems = 1, - }, { - .op = SWS_OP_WRITE, - .type = U8, - .rw.elems = 1, - .rw.frac = frac, - }, {0} - }); + switch (mask) { + case SWS_COMP_ELEMS(1): return 1; + case SWS_COMP_ELEMS(2): return 2; + case SWS_COMP_ELEMS(3): return 3; + case SWS_COMP_ELEMS(4): return 4; + default: return 0; } } -static void check_swap_bytes(void) -{ - CHECK_COMMON("swap_bytes_16", U16, U16, { - .op = SWS_OP_SWAP_BYTES, - .type = U16, - }); - - CHECK_COMMON("swap_bytes_32", U32, U32, { - .op = SWS_OP_SWAP_BYTES, - .type = U32, - }); -} - -static void check_pack_unpack(void) -{ - const struct { - SwsPixelType type; - SwsPackOp op; - } patterns[] = { - { U8, {{ 3, 3, 2 }}}, - { U8, {{ 2, 3, 3 }}}, - { U8, {{ 1, 2, 1 }}}, - {U16, {{ 5, 6, 5 }}}, - {U16, {{ 5, 5, 5 }}}, - {U16, {{ 4, 4, 4 }}}, - {U32, {{ 2, 10, 10, 10 }}}, - {U32, {{10, 10, 10, 2 }}}, - }; - - for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { - const SwsPixelType type = patterns[i].type; - const SwsPackOp pack = patterns[i].op; - const int num = pack.pattern[3] ? 4 : 3; - const char *pat = FMT("%d%d%d%d", pack.pattern[0], pack.pattern[1], - pack.pattern[2], pack.pattern[3]); - const int total = pack.pattern[0] + pack.pattern[1] + - pack.pattern[2] + pack.pattern[3]; - const unsigned ranges[4] = { - (1 << pack.pattern[0]) - 1, - (1 << pack.pattern[1]) - 1, - (1 << pack.pattern[2]) - 1, - (1 << pack.pattern[3]) - 1, - }; - - CHECK_RANGES(FMT("pack_%s", pat), ranges, num, 1, type, type, { - .op = SWS_OP_PACK, - .type = type, - .pack = pack, - }); - - CHECK_RANGE(FMT("unpack_%s", pat), UINT32_MAX >> (32 - total), 1, num, type, type, { - .op = SWS_OP_UNPACK, - .type = type, - .pack = pack, - }); - } -} +#define CHECK_MASK(NAME, MASK, RANGES, IN, OUT, ...) \ +do { \ + const SwsCompMask mask = (MASK); \ + const int num = mask_num(mask); \ + if (!num) \ + break; /* can't test these with current infrastructure */ \ + CHECK_RANGES(NAME, RANGES, 4, num, IN, OUT, __VA_ARGS__); \ +} while (0) static AVRational rndq(SwsPixelType t) { const unsigned num = rnd(); if (ff_sws_pixel_type_is_int(t)) { - const unsigned mask = UINT_MAX >> (32 - ff_sws_pixel_type_size(t) * 8); + const int bits = ff_sws_pixel_type_size(t) * 8; + const unsigned mask = UINT_MAX >> (32 - bits); return (AVRational) { num & mask, 1 }; } else { const unsigned den = rnd(); @@ -527,409 +392,375 @@ static AVRational rndq(SwsPixelType t) } } -static void check_clear(void) +static void check_read(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - const int bits = ff_sws_pixel_type_size(t) * 8; + const int num = mask_num(uop->mask); + check_ops(name, NULL, (SwsOp[]) { + { + .op = SWS_OP_READ, + .type = uop->type, + .rw.elems = num, + .rw.packed = uop->uop != SWS_UOP_READ_PLANAR, + .rw.frac = uop->uop == SWS_UOP_READ_BIT ? 3 : + uop->uop == SWS_UOP_READ_NIBBLE ? 1 : 0, + }, { + .op = SWS_OP_WRITE, + .type = uop->type, + .rw.elems = num, + }, {0} + }); +} - /* TODO: AVRational can't fit 32 bit constants */ - if (bits < 32) { - const AVRational chroma = (AVRational) { 1 << (bits - 1), 1}; - const AVRational alpha = (AVRational) { (1 << bits) - 1, 1}; - const AVRational zero = (AVRational) { 0, 1}; - const AVRational none = {0}; - - const AVRational patterns[][4] = { - /* Zero only */ - { none, none, none, zero }, - { zero, none, none, none }, - /* Alpha only */ - { none, none, none, alpha }, - { alpha, none, none, none }, - /* Chroma only */ - { chroma, chroma, none, none }, - { none, chroma, chroma, none }, - { none, none, chroma, chroma }, - { chroma, none, chroma, none }, - { none, chroma, none, chroma }, - /* Alpha+chroma */ - { chroma, chroma, none, alpha }, - { none, chroma, chroma, alpha }, - { alpha, none, chroma, chroma }, - { chroma, none, chroma, alpha }, - { alpha, chroma, none, chroma }, - }; - - for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { - SwsClearOp clear = { .mask = ff_sws_comp_mask_q4(patterns[i]) }; - memcpy(clear.value, patterns[i], sizeof(clear.value)); - CHECK(FMT("clear_pattern_%s[%d]", type, i), 4, 4, t, t, { - .op = SWS_OP_CLEAR, - .type = t, - .clear = clear, - }); - } - } else if (!ff_sws_pixel_type_is_int(t)) { - /* Floating point YUV doesn't exist, only alpha needs to be cleared */ - CHECK(FMT("clear_alpha_%s", type), 4, 4, t, t, { - .op = SWS_OP_CLEAR, - .type = t, - .clear.value[3] = { 0, 1 }, - .clear.mask = SWS_COMP(3), - }); - } - } +static void check_write(const char *name, const SwsUOp *uop) +{ + const int frac = uop->uop == SWS_UOP_WRITE_BIT ? 3 : + uop->uop == SWS_UOP_WRITE_NIBBLE ? 1 : 0; + const int num = mask_num(uop->mask); + const int bits = 8 >> frac; + const unsigned range = (1 << bits) - 1; + + check_ops(name, MK_RANGES(range), (SwsOp[]) { + { + .op = SWS_OP_READ, + .type = uop->type, + .rw.elems = num, + }, { + .op = SWS_OP_WRITE, + .type = uop->type, + .rw.elems = num, + .rw.packed = uop->uop != SWS_UOP_WRITE_PLANAR, + .rw.frac = frac, + }, {0} + }); } -static void check_shift(void) +static void check_filter(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = U16; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - if (!ff_sws_pixel_type_is_int(t)) - continue; + const int num = mask_num(uop->mask); + const bool is_vert = uop->uop == SWS_UOP_READ_PLANAR_FV; - for (int shift = 1; shift <= 8; shift++) { - CHECK_COMMON(FMT("lshift%d_%s", shift, type), t, t, { - .op = SWS_OP_LSHIFT, - .type = t, - .shift = { shift }, - }); + SwsFilterParams par = { + .scaler_params = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT }, + .dst_size = is_vert ? LINES : PIXELS, + }; + + const SwsScaler scalers[] = { + SWS_SCALE_POINT, + SWS_SCALE_SINC, + }; - CHECK_COMMON(FMT("rshift%d_%s", shift, type), t, t, { - .op = SWS_OP_RSHIFT, - .type = t, - .shift = { shift }, + for (int s = 0; s < FF_ARRAY_ELEMS(scalers); s++) { + par.scaler = scalers[s]; + + for (par.src_size = 1; par.src_size <= par.dst_size; par.src_size <<= 1) { + SwsFilterWeights *filter; + if (ff_sws_filter_generate(NULL, &par, &filter) < 0) { + fail(); + return; + } + + char desc[256]; + snprintf(desc, sizeof(desc), "%s_%s_%d", name, filter->name, par.src_size); + check_ops(desc, NULL, (SwsOp[]) { + { + .op = SWS_OP_READ, + .type = uop->type, + .rw.elems = num, + .rw.filter = is_vert ? SWS_OP_FILTER_V : SWS_OP_FILTER_H, + .rw.kernel = filter, + }, { + .op = SWS_OP_WRITE, + .type = SWS_PIXEL_F32, + .rw.elems = num, + }, {0} }); + + av_refstruct_unref(&filter); } } } -static void check_swizzle(void) +static void check_cast(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - static const int patterns[][4] = { - /* Pure swizzle */ - {3, 0, 1, 2}, - {3, 0, 2, 1}, - {2, 1, 0, 3}, - {3, 2, 1, 0}, - {3, 1, 0, 2}, - {3, 2, 0, 1}, - {1, 2, 0, 3}, - {1, 0, 2, 3}, - {2, 0, 1, 3}, - {2, 3, 1, 0}, - {2, 1, 3, 0}, - {1, 2, 3, 0}, - {1, 3, 2, 0}, - {0, 2, 1, 3}, - {0, 2, 3, 1}, - {0, 3, 1, 2}, - {3, 1, 2, 0}, - {0, 3, 2, 1}, - /* Luma expansion */ - {0, 0, 0, 3}, - {3, 0, 0, 0}, - {0, 0, 0, 1}, - {1, 0, 0, 0}, - }; - - for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { - const int x = patterns[i][0], y = patterns[i][1], - z = patterns[i][2], w = patterns[i][3]; - CHECK(FMT("swizzle_%d%d%d%d_%s", x, y, z, w, type), 4, 4, t, t, { - .op = SWS_OP_SWIZZLE, - .type = t, - .swizzle = SWS_SWIZZLE(x, y, z, w), - }); - } + SwsPixelType dst; + switch (uop->uop) { + case SWS_UOP_TO_U8: dst = SWS_PIXEL_U8; break; + case SWS_UOP_TO_U16: dst = SWS_PIXEL_U16; break; + case SWS_UOP_TO_U32: dst = SWS_PIXEL_U32; break; + case SWS_UOP_TO_F32: dst = SWS_PIXEL_F32; break; + default: return; } + + const int isize = ff_sws_pixel_type_size(uop->type); + const int osize = ff_sws_pixel_type_size(dst); + unsigned range = UINT32_MAX >> (32 - osize * 8); + if (isize < osize || !ff_sws_pixel_type_is_int(dst)) + range = 0; + + CHECK_MASK(name, uop->mask, MK_RANGES(range), uop->type, dst, { + .op = SWS_OP_CONVERT, + .type = uop->type, + .convert.to = dst, + }); } -static void check_convert(void) +static void check_expand_bit(const char *name, const SwsUOp *uop) { - for (SwsPixelType i = U8; i < SWS_PIXEL_TYPE_NB; i++) { - const char *itype = ff_sws_pixel_type_name(i); - const int isize = ff_sws_pixel_type_size(i); - for (SwsPixelType o = U8; o < SWS_PIXEL_TYPE_NB; o++) { - const char *otype = ff_sws_pixel_type_name(o); - const int osize = ff_sws_pixel_type_size(o); - const char *name = FMT("convert_%s_%s", itype, otype); - if (i == o) - continue; - - if (isize < osize || !ff_sws_pixel_type_is_int(o)) { - CHECK_COMMON(name, i, o, { - .op = SWS_OP_CONVERT, - .type = i, - .convert.to = o, - }); - } else if (isize > osize || !ff_sws_pixel_type_is_int(i)) { - uint32_t range = UINT32_MAX >> (32 - osize * 8); - CHECK_COMMON_RANGE(name, range, i, o, { - .op = SWS_OP_CONVERT, - .type = i, - .convert.to = o, - }); - } - } + AVRational factor = { .den = 1 }; + switch (uop->type) { + case SWS_PIXEL_U8: factor.num = UINT8_MAX; break; + case SWS_PIXEL_U16: factor.num = UINT16_MAX; break; + case SWS_PIXEL_U32: factor.num = UINT32_MAX; break; + default: return; } - /* Check expanding conversions */ - CHECK_COMMON("expand16", U8, U16, { - .op = SWS_OP_CONVERT, - .type = U8, - .convert.to = U16, - .convert.expand = true, + CHECK_MASK(name, uop->mask, MK_RANGES(1), uop->type, uop->type, { + .op = SWS_OP_SCALE, + .type = uop->type, + .scale.factor = factor, }); +} - CHECK_COMMON("expand32", U8, U32, { - .op = SWS_OP_CONVERT, - .type = U8, - .convert.to = U32, - .convert.expand = true, +static void check_expand(const char *name, const SwsUOp *uop) +{ + SwsPixelType dst = SWS_PIXEL_NONE; + switch (uop->uop) { + case SWS_UOP_EXPAND_PAIR: dst = SWS_PIXEL_U16; break; + case SWS_UOP_EXPAND_QUAD: dst = SWS_PIXEL_U32; break; + } + + av_assert0(uop->type == SWS_PIXEL_U8); + CHECK_MASK(name, uop->mask, NULL, uop->type, dst, { + .op = SWS_OP_CONVERT, + .type = uop->type, + .convert = { + .to = dst, + .expand = true, + }, }); } -static void check_dither(void) +static void check_swizzle(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = F32; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - if (ff_sws_pixel_type_is_int(t)) - continue; + const SwsSwizzleUOp *swiz = &uop->par.swizzle; + CHECK_MASK(name, uop->mask, NULL, uop->type, uop->type, { + .op = SWS_OP_SWIZZLE, + .type = uop->type, + .swizzle.in = { swiz->in[0], swiz->in[1], swiz->in[2], swiz->in[3] }, + }); +} - /* Test all sizes up to 256x256 */ - for (int size_log2 = 0; size_log2 <= 8; size_log2++) { - const int size = 1 << size_log2; - const int mask = size - 1; - AVRational *matrix = av_refstruct_allocz(size * size * sizeof(*matrix)); - if (!matrix) { - fail(); - return; - } +static void check_scale(const char *name, const SwsUOp *uop) +{ + unsigned range = 0; + AVRational scale; + + if (ff_sws_pixel_type_is_int(uop->type)) { + /* Ensure the result won't exceed the value range */ + const int bits = ff_sws_pixel_type_size(uop->type) * 8; + const unsigned max = UINT32_MAX >> (32 - bits); + scale = (AVRational) { rnd() & (max >> 1), 1 }; + range = max / (scale.num ? scale.num : 1); + } else { + scale = rndq(uop->type); + } - if (size == 1) { - matrix[0] = (AVRational) { 1, 2 }; - } else { - for (int i = 0; i < size * size; i++) - matrix[i] = rndq(t); - } + CHECK_MASK(name, uop->mask, MK_RANGES(range), uop->type, uop->type, { + .op = SWS_OP_SCALE, + .type = uop->type, + .scale.factor = scale, + }); +} - CHECK_COMMON(FMT("dither_%dx%d_%s", size, size, type), t, t, { - .op = SWS_OP_DITHER, - .type = t, - .dither.size_log2 = size_log2, - .dither.matrix = matrix, - .dither.y_offset = {0, 3 & mask, 2 & mask, 5 & mask}, - }); +static void check_clamp(const char *name, const SwsUOp *uop) +{ + const SwsPixelType t = uop->type; + CHECK_MASK(name, uop->mask, NULL, t, t, { + .op = uop->uop == SWS_UOP_MIN ? SWS_OP_MIN : SWS_OP_MAX, + .type = t, + .clamp.limit = { rndq(t), rndq(t), rndq(t), rndq(t) }, + }); +} - av_refstruct_unref(&matrix); - } - } +static void check_swap_bytes(const char *name, const SwsUOp *uop) +{ + CHECK_MASK(name, uop->mask, NULL, uop->type, uop->type, { + .op = SWS_OP_SWAP_BYTES, + .type = uop->type, + }); } -static void check_min_max(void) +static void check_unpack(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - CHECK_COMMON(FMT("min_%s", type), t, t, { - .op = SWS_OP_MIN, - .type = t, - .clamp = {{ rndq(t), rndq(t), rndq(t), rndq(t) }}, - }); - - CHECK_COMMON(FMT("max_%s", type), t, t, { - .op = SWS_OP_MAX, - .type = t, - .clamp = {{ rndq(t), rndq(t), rndq(t), rndq(t) }}, - }); - } + const uint8_t *pat = uop->par.pack.pattern; + const int num = pat[3] ? 4 : 3; + const int total = pat[0] + pat[1] + pat[2] + pat[3]; + const unsigned range = UINT32_MAX >> (32 - total); + + CHECK_RANGE(name, range, 1, num, uop->type, uop->type, { + .op = SWS_OP_UNPACK, + .type = uop->type, + .pack.pattern = { pat[0], pat[1], pat[2], pat[3] }, + }); } -static void check_linear(void) +static void check_pack(const char *name, const SwsUOp *uop) { - static const struct { - const char *name; - uint32_t mask; - } patterns[] = { - { "luma", SWS_MASK_LUMA }, - { "alpha", SWS_MASK_ALPHA }, - { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA }, - { "dot3", 0x7 }, - { "row0", SWS_MASK_ROW(0) ^ SWS_MASK(0, 3) }, - { "diag3", SWS_MASK_DIAG3 }, - { "diag4", SWS_MASK_DIAG4 }, - { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA }, - { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 }, - { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 }, - { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA }, + const uint8_t *pat = uop->par.pack.pattern; + const unsigned ranges[4] = { + (1 << pat[0]) - 1, (1 << pat[1]) - 1, + (1 << pat[2]) - 1, (1 << pat[3]) - 1, }; - for (SwsPixelType t = F32; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - if (ff_sws_pixel_type_is_int(t)) - continue; + CHECK_RANGES(name, ranges, 4, 1, uop->type, uop->type, { + .op = SWS_OP_PACK, + .type = uop->type, + .pack.pattern = { pat[0], pat[1], pat[2], pat[3] }, + }); +} - for (int p = 0; p < FF_ARRAY_ELEMS(patterns); p++) { - const uint32_t mask = patterns[p].mask; - SwsLinearOp lin = { .mask = mask }; - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 5; j++) { - if (mask & SWS_MASK(i, j)) { - lin.m[i][j] = rndq(t); - } else { - lin.m[i][j] = (AVRational) { i == j, 1 }; - } - } - } +static void check_shift(const char *name, const SwsUOp *uop) +{ + CHECK_MASK(name, uop->mask, NULL, uop->type, uop->type, { + .op = uop->uop == SWS_UOP_LSHIFT ? SWS_OP_LSHIFT : SWS_OP_RSHIFT, + .type = uop->type, + .shift.amount = uop->par.shift.amount, + }); +} - CHECK(FMT("linear_%s_%s", patterns[p].name, type), 4, 4, t, t, { - .op = SWS_OP_LINEAR, - .type = t, - .lin = lin, - }); - } +static void check_clear(const char *name, const SwsUOp *uop) +{ + const SwsPixelType type = uop->type; + const int bits = ff_sws_pixel_type_size(type) * 8; + const unsigned range = UINT32_MAX >> (32 - bits); + const AVRational one = (AVRational) { (int) range, 1}; + const AVRational zero = (AVRational) { 0, 1}; + const AVRational val = { (rand() & 0x7F) | 1, 1 }; + + SwsClearOp clear = { .mask = uop->mask }; + for (int i = 0; i < 4; i++) { + if (SWS_COMP_TEST(uop->par.clear.one, i)) + clear.value[i] = one; + else if (SWS_COMP_TEST(uop->par.clear.zero, i)) + clear.value[i] = zero; + else + clear.value[i] = val; } + + CHECK(name, 4, 4, type, type, { + .op = SWS_OP_CLEAR, + .type = type, + .clear = clear, + }); } -static void check_scale(void) +static void check_linear(const char *name, const SwsUOp *uop) { - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - const int bits = ff_sws_pixel_type_size(t) * 8; - if (ff_sws_pixel_type_is_int(t)) { - const unsigned max = UINT32_MAX >> (32 - bits); - - /* Test fixed fast path for expansion from bits to full range */ - CHECK_COMMON_RANGE(FMT("scale_full_%s", type), 1, t, t, { - .op = SWS_OP_SCALE, - .type = t, - .scale = {{ max, 1 }}, - }); - - /* Ensure the result won't exceed the value range */ - const unsigned scale = rnd() & (max >> 1); - const unsigned range = max / (scale ? scale : 1); - CHECK_COMMON_RANGE(FMT("scale_%s", type), range, t, t, { - .op = SWS_OP_SCALE, - .type = t, - .scale = {{ scale, 1 }}, - }); - } else { - CHECK_COMMON(FMT("scale_%s", type), t, t, { - .op = SWS_OP_SCALE, - .type = t, - .scale = { rndq(t) }, - }); + const SwsPixelType type = uop->type; + av_assert0(!ff_sws_pixel_type_is_int(type)); + + SwsLinearOp lin; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + if (uop->par.lin.one & SWS_MASK(i, j)) + lin.m[i][j] = (AVRational) { 1, 1 }; + else if (uop->par.lin.zero & SWS_MASK(i, j)) + lin.m[i][j] = (AVRational) { 0, 1 }; + else + lin.m[i][j] = rndq(type); } } + + lin.mask = ff_sws_linear_mask(lin); + CHECK(name, 4, 4, type, type, { + .op = SWS_OP_LINEAR, + .type = type, + .lin = lin, + }); } -static void check_filter(void) +static void check_dither(const char *name, const SwsUOp *uop) { - SwsFilterParams params = { - .scaler_params = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT }, - }; - - const SwsScaler scalers[] = { - SWS_SCALE_POINT, - SWS_SCALE_SINC, - }; + const SwsPixelType type = uop->type; + av_assert0(!ff_sws_pixel_type_is_int(type)); - SwsFilterWeights *filter; - - for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { - const char *type = ff_sws_pixel_type_name(t); - for (int s = 0; s < FF_ARRAY_ELEMS(scalers); s++) { - params.scaler = scalers[s]; - params.dst_size = LINES; - for (int h = 1; h <= LINES; h += h) { - params.src_size = h; - int ret = ff_sws_filter_generate(NULL, ¶ms, &filter); - if (ret < 0) { - fail(); - return; - } - - const char *name = filter->name; - for (int n = 1; n <= 4; n++) { - check_ops(FMT("%s_filter%d_v_%dx%d_%s", name, n, PIXELS, h, type), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = t, - .rw.elems = n, - .rw.filter = SWS_OP_FILTER_V, - .rw.kernel = filter, - }, { - .op = SWS_OP_WRITE, - .type = SWS_PIXEL_F32, - .rw.elems = n, - }, {0} - }); - } - - av_refstruct_unref(&filter); - } + SwsDitherOp dither = { .size_log2 = uop->par.dither.size_log2 }; + const int size = 1 << dither.size_log2; + const uint8_t *y_offset = uop->par.dither.y_offset; + for (int i = 0; i < 4; i++) + dither.y_offset[i] = SWS_COMP_TEST(uop->mask, i) ? y_offset[i] : -1; - params.dst_size = PIXELS; - for (int w = 1; w <= PIXELS; w += w) { - params.src_size = w; - int ret = ff_sws_filter_generate(NULL, ¶ms, &filter); - if (ret < 0) { - fail(); - return; - } - - const char *name = filter->name; - for (int n = 1; n <= 4; n++) { - check_ops(FMT("%s_filter%d_h_%dx%d_%s", name, n, w, LINES, type), NULL, (SwsOp[]) { - { - .op = SWS_OP_READ, - .type = t, - .rw.elems = n, - .rw.filter = SWS_OP_FILTER_H, - .rw.kernel = filter, - }, { - .op = SWS_OP_WRITE, - .type = SWS_PIXEL_F32, - .rw.elems = n, - }, {0} - }); - } - - av_refstruct_unref(&filter); - } - } + dither.matrix = av_refstruct_allocz(size * size * sizeof(*dither.matrix)); + if (!dither.matrix) { + fail(); + return; } + + for (int i = 0; i < size * size; i++) + dither.matrix[i] = rndq(type); + + CHECK(name, 4, 4, type, type, { + .op = SWS_OP_DITHER, + .type = type, + .dither = dither, + }); + + av_refstruct_unref(&dither.matrix); +} + +static void check_add(const char *name, const SwsUOp *uop) +{ + /* SwsOp has no concept of SWS_OP_ADD; this is only used for + * SWS_OP_DITHER with a 1x1 dither matrix; so translate the uop */ + check_dither(name, &(SwsUOp) { + .uop = SWS_UOP_DITHER, + .type = uop->type, + .mask = uop->mask, + .par.dither.size_log2 = 0, + }); } +#define CHECK_FUNCTION(CHECK, NAME, ...) \ + CHECK(#NAME, &(SwsUOp) { __VA_ARGS__ }); + +#define CHECK_FOR(UOP, CHECK) \ + SWS_FOR_STRUCT(U8, UOP, CHECK_FUNCTION, CHECK) \ + SWS_FOR_STRUCT(U16, UOP, CHECK_FUNCTION, CHECK) \ + SWS_FOR_STRUCT(U32, UOP, CHECK_FUNCTION, CHECK) \ + SWS_FOR_STRUCT(F32, UOP, CHECK_FUNCTION, CHECK) \ + report(#UOP) + void checkasm_check_sw_ops(void) { - check_read_write(); - report("read_write"); - check_swap_bytes(); - report("swap_bytes"); - check_pack_unpack(); - report("pack_unpack"); - check_clear(); - report("clear"); - check_shift(); - report("shift"); - check_swizzle(); - report("swizzle"); - check_convert(); - report("convert"); - check_dither(); - report("dither"); - check_min_max(); - report("min_max"); - check_linear(); - report("linear"); - check_scale(); - report("scale"); - check_filter(); - report("filter"); + CHECK_FOR(READ_PLANAR, check_read); + CHECK_FOR(READ_PLANAR_FH, check_filter); + CHECK_FOR(READ_PLANAR_FV, check_filter); + CHECK_FOR(READ_PACKED, check_read); + CHECK_FOR(READ_NIBBLE, check_read); + CHECK_FOR(READ_BIT, check_read); + CHECK_FOR(WRITE_PLANAR, check_write); + CHECK_FOR(WRITE_PACKED, check_write); + CHECK_FOR(WRITE_NIBBLE, check_write); + CHECK_FOR(WRITE_BIT, check_write); + CHECK_FOR(PERMUTE, check_swizzle); + CHECK_FOR(COPY, check_swizzle); + CHECK_FOR(EXPAND_BIT, check_expand_bit); + CHECK_FOR(EXPAND_PAIR, check_expand); + CHECK_FOR(EXPAND_QUAD, check_expand); + CHECK_FOR(SWAP_BYTES, check_swap_bytes); + CHECK_FOR(TO_U8, check_cast); + CHECK_FOR(TO_U16, check_cast); + CHECK_FOR(TO_U32, check_cast); + CHECK_FOR(TO_F32, check_cast); + CHECK_FOR(SCALE, check_scale); + CHECK_FOR(ADD, check_add); + CHECK_FOR(MIN, check_clamp); + CHECK_FOR(MAX, check_clamp); + CHECK_FOR(UNPACK, check_unpack); + CHECK_FOR(PACK, check_pack); + CHECK_FOR(LSHIFT, check_shift); + CHECK_FOR(RSHIFT, check_shift); + CHECK_FOR(CLEAR, check_clear); + CHECK_FOR(LINEAR, check_linear); + CHECK_FOR(DITHER, check_dither); } _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
