| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * Copyright (C) 2025 Niklas Haas | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License along | ||
| 17 | * with FFmpeg; if not, write to the Free Software Foundation, Inc., | ||
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <string.h> | ||
| 22 | |||
| 23 | #include "libavutil/avassert.h" | ||
| 24 | #include "libavutil/mem_internal.h" | ||
| 25 | #include "libavutil/refstruct.h" | ||
| 26 | |||
| 27 | #include "libswscale/ops.h" | ||
| 28 | #include "libswscale/ops_internal.h" | ||
| 29 | |||
| 30 | #include "checkasm.h" | ||
| 31 | |||
| 32 | enum { | ||
| 33 | NB_PLANES = 4, | ||
| 34 | PIXELS = 64, | ||
| 35 | LINES = 16, | ||
| 36 | }; | ||
| 37 | |||
| 38 | enum { | ||
| 39 | U8 = SWS_PIXEL_U8, | ||
| 40 | U16 = SWS_PIXEL_U16, | ||
| 41 | U32 = SWS_PIXEL_U32, | ||
| 42 | F32 = SWS_PIXEL_F32, | ||
| 43 | }; | ||
| 44 | |||
| 45 | #define FMT(fmt, ...) tprintf((char[256]) {0}, 256, fmt, __VA_ARGS__) | ||
| 46 | 26683 | static const char *tprintf(char buf[], size_t size, const char *fmt, ...) | |
| 47 | { | ||
| 48 | va_list ap; | ||
| 49 | 26683 | va_start(ap, fmt); | |
| 50 | 26683 | vsnprintf(buf, size, fmt, ap); | |
| 51 | 26683 | va_end(ap); | |
| 52 | 26683 | return buf; | |
| 53 | } | ||
| 54 | |||
| 55 | 22170 | static int rw_pixel_bits(const SwsOp *op) | |
| 56 | { | ||
| 57 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 21906 times.
|
22170 | const int elems = op->rw.packed ? op->rw.elems : 1; |
| 58 | 22170 | const int size = ff_sws_pixel_type_size(op->type); | |
| 59 | 22170 | const int bits = 8 >> op->rw.frac; | |
| 60 | av_assert1(bits >= 1); | ||
| 61 | 22170 | return elems * size * bits; | |
| 62 | } | ||
| 63 | |||
| 64 | 19431424 | static float rndf(void) | |
| 65 | { | ||
| 66 | union { uint32_t u; float f; } x; | ||
| 67 | do { | ||
| 68 | 19584313 | x.u = rnd(); | |
| 69 |
2/2✓ Branch 0 taken 152889 times.
✓ Branch 1 taken 19431424 times.
|
19584313 | } while (!isnormal(x.f)); |
| 70 | 19431424 | return x.f; | |
| 71 | } | ||
| 72 | |||
| 73 | 4872 | static void fill32f(float *line, int num, unsigned range) | |
| 74 | { | ||
| 75 | 4872 | const float scale = (float) range / UINT32_MAX; | |
| 76 |
2/2✓ Branch 0 taken 19955712 times.
✓ Branch 1 taken 4872 times.
|
19960584 | for (int i = 0; i < num; i++) |
| 77 |
2/2✓ Branch 0 taken 524288 times.
✓ Branch 1 taken 19431424 times.
|
19955712 | line[i] = range ? scale * rnd() : rndf(); |
| 78 | 4872 | } | |
| 79 | |||
| 80 | 15860 | static void fill32(uint32_t *line, int num, unsigned range) | |
| 81 | { | ||
| 82 |
2/2✓ Branch 0 taken 64962560 times.
✓ Branch 1 taken 15860 times.
|
64978420 | for (int i = 0; i < num; i++) |
| 83 |
4/4✓ Branch 0 taken 851968 times.
✓ Branch 1 taken 64110592 times.
✓ Branch 2 taken 753664 times.
✓ Branch 3 taken 98304 times.
|
64962560 | line[i] = (range && range < UINT_MAX) ? rnd() % (range + 1) : rnd(); |
| 84 | 15860 | } | |
| 85 | |||
| 86 | 5832 | static void fill16(uint16_t *line, int num, unsigned range) | |
| 87 | { | ||
| 88 |
2/2✓ Branch 0 taken 5657 times.
✓ Branch 1 taken 175 times.
|
5832 | if (!range) { |
| 89 | 5657 | fill32((uint32_t *) line, AV_CEIL_RSHIFT(num, 1), 0); | |
| 90 | } else { | ||
| 91 |
2/2✓ Branch 0 taken 1433600 times.
✓ Branch 1 taken 175 times.
|
1433775 | for (int i = 0; i < num; i++) |
| 92 | 1433600 | line[i] = rnd() % (range + 1); | |
| 93 | } | ||
| 94 | 5832 | } | |
| 95 | |||
| 96 | 6076 | static void fill8(uint8_t *line, int num, unsigned range) | |
| 97 | { | ||
| 98 |
2/2✓ Branch 0 taken 5779 times.
✓ Branch 1 taken 297 times.
|
6076 | if (!range) { |
| 99 | 5779 | fill32((uint32_t *) line, AV_CEIL_RSHIFT(num, 2), 0); | |
| 100 | } else { | ||
| 101 |
2/2✓ Branch 0 taken 4866048 times.
✓ Branch 1 taken 297 times.
|
4866345 | for (int i = 0; i < num; i++) |
| 102 | 4866048 | line[i] = rnd() % (range + 1); | |
| 103 | } | ||
| 104 | 6076 | } | |
| 105 | |||
| 106 | 37968 | static void set_range(AVRational *rangeq, unsigned range, unsigned range_def) | |
| 107 | { | ||
| 108 |
2/2✓ Branch 0 taken 35028 times.
✓ Branch 1 taken 2940 times.
|
37968 | if (!range) |
| 109 | 35028 | range = range_def; | |
| 110 |
3/4✓ Branch 0 taken 37968 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25872 times.
✓ Branch 3 taken 12096 times.
|
37968 | if (range && range <= INT_MAX) |
| 111 | 25872 | *rangeq = (AVRational) { range, 1 }; | |
| 112 | 37968 | } | |
| 113 | |||
| 114 | 5301 | static void check_compiled(const char *name, const SwsOpBackend *backend, | |
| 115 | const SwsOp *read_op, const SwsOp *write_op, | ||
| 116 | const int ranges[NB_PLANES], | ||
| 117 | const SwsCompiledOp *comp_ref, | ||
| 118 | const SwsCompiledOp *comp_new) | ||
| 119 | { | ||
| 120 | 5301 | declare_func(void, const SwsOpExec *, const void *, int bx, int y, int bx_end, int y_end); | |
| 121 | |||
| 122 | static DECLARE_ALIGNED_64(char, src0)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])]; | ||
| 123 | static DECLARE_ALIGNED_64(char, src1)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])]; | ||
| 124 | static DECLARE_ALIGNED_64(char, dst0)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])]; | ||
| 125 | static DECLARE_ALIGNED_64(char, dst1)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])]; | ||
| 126 | |||
| 127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5301 times.
|
5301 | av_assert0(PIXELS % comp_new->block_size == 0); |
| 128 |
2/2✓ Branch 0 taken 21204 times.
✓ Branch 1 taken 5301 times.
|
26505 | for (int p = 0; p < NB_PLANES; p++) { |
| 129 | 21204 | void *plane = src0[p]; | |
| 130 |
4/5✓ Branch 0 taken 6076 times.
✓ Branch 1 taken 5832 times.
✓ Branch 2 taken 4424 times.
✓ Branch 3 taken 4872 times.
✗ Branch 4 not taken.
|
21204 | switch (read_op->type) { |
| 131 | 6076 | case U8: | |
| 132 | 6076 | fill8(plane, sizeof(src0[p]) / sizeof(uint8_t), ranges[p]); | |
| 133 | 6076 | break; | |
| 134 | 5832 | case U16: | |
| 135 | 5832 | fill16(plane, sizeof(src0[p]) / sizeof(uint16_t), ranges[p]); | |
| 136 | 5832 | break; | |
| 137 | 4424 | case U32: | |
| 138 | 4424 | fill32(plane, sizeof(src0[p]) / sizeof(uint32_t), ranges[p]); | |
| 139 | 4424 | break; | |
| 140 | 4872 | case F32: | |
| 141 | 4872 | fill32f(plane, sizeof(src0[p]) / sizeof(uint32_t), ranges[p]); | |
| 142 | 4872 | break; | |
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | 5301 | memcpy(src1, src0, sizeof(src0)); | |
| 147 | 5301 | memset(dst0, 0, sizeof(dst0)); | |
| 148 | 5301 | memset(dst1, 0, sizeof(dst1)); | |
| 149 | |||
| 150 | 5301 | const int read_size = PIXELS * rw_pixel_bits(read_op) >> 3; | |
| 151 | 5301 | const int write_size = PIXELS * rw_pixel_bits(write_op) >> 3; | |
| 152 | |||
| 153 | 5301 | SwsOpExec exec = {0}; | |
| 154 | 5301 | exec.width = PIXELS; | |
| 155 | 5301 | exec.height = exec.slice_h = LINES; | |
| 156 |
2/2✓ Branch 0 taken 21204 times.
✓ Branch 1 taken 5301 times.
|
26505 | for (int i = 0; i < NB_PLANES; i++) { |
| 157 | 21204 | exec.in_stride[i] = sizeof(src0[i][0]); | |
| 158 | 21204 | exec.out_stride[i] = sizeof(dst0[i][0]); | |
| 159 | 21204 | exec.in_bump[i] = exec.in_stride[i] - read_size; | |
| 160 | 21204 | exec.out_bump[i] = exec.out_stride[i] - write_size; | |
| 161 | } | ||
| 162 | |||
| 163 | int32_t in_bump_y[LINES]; | ||
| 164 |
2/2✓ Branch 0 taken 440 times.
✓ Branch 1 taken 4861 times.
|
5301 | if (read_op->rw.filter == SWS_OP_FILTER_V) { |
| 165 | 440 | const int *offsets = read_op->rw.kernel->offsets; | |
| 166 |
2/2✓ Branch 0 taken 6600 times.
✓ Branch 1 taken 440 times.
|
7040 | for (int y = 0; y < LINES - 1; y++) |
| 167 | 6600 | in_bump_y[y] = offsets[y + 1] - offsets[y] - 1; | |
| 168 | 440 | in_bump_y[LINES - 1] = 0; | |
| 169 | 440 | exec.in_bump_y = in_bump_y; | |
| 170 | } | ||
| 171 | |||
| 172 | int32_t in_offset_x[PIXELS]; | ||
| 173 |
2/2✓ Branch 0 taken 616 times.
✓ Branch 1 taken 4685 times.
|
5301 | if (read_op->rw.filter == SWS_OP_FILTER_H) { |
| 174 | 616 | const int *offsets = read_op->rw.kernel->offsets; | |
| 175 | 616 | const int rw_bits = rw_pixel_bits(read_op); | |
| 176 |
2/2✓ Branch 0 taken 39424 times.
✓ Branch 1 taken 616 times.
|
40040 | for (int x = 0; x < PIXELS; x++) |
| 177 | 39424 | in_offset_x[x] = offsets[x] * rw_bits >> 3; | |
| 178 | 616 | exec.in_offset_x = in_offset_x; | |
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * We can't use `check_func()` alone because the actual function pointer | ||
| 183 | * may be a wrapper or entry point shared by multiple implementations. | ||
| 184 | * Solve it by hashing in the active CPU flags as well. | ||
| 185 | */ | ||
| 186 | 5301 | uintptr_t id = (uintptr_t) comp_new->func; | |
| 187 | 5301 | id ^= (id << 6) + (id >> 2) + 0x9e3779b97f4a7c15 + comp_new->cpu_flags; | |
| 188 | |||
| 189 |
2/2✓ Branch 3 taken 2738 times.
✓ Branch 4 taken 2563 times.
|
5301 | if (check_key((void*) id, "%s/%s", name, backend->name)) { |
| 190 | 2738 | exec.block_size_in = comp_ref->block_size * rw_pixel_bits(read_op) >> 3; | |
| 191 | 2738 | exec.block_size_out = comp_ref->block_size * rw_pixel_bits(write_op) >> 3; | |
| 192 |
2/2✓ Branch 0 taken 10952 times.
✓ Branch 1 taken 2738 times.
|
13690 | for (int i = 0; i < NB_PLANES; i++) { |
| 193 | 10952 | exec.in[i] = (void *) src0[i]; | |
| 194 | 10952 | exec.out[i] = (void *) dst0[i]; | |
| 195 | } | ||
| 196 | 2738 | checkasm_call(comp_ref->func, &exec, comp_ref->priv, 0, 0, PIXELS / comp_ref->block_size, LINES); | |
| 197 | |||
| 198 | 2738 | exec.block_size_in = comp_new->block_size * rw_pixel_bits(read_op) >> 3; | |
| 199 | 2738 | exec.block_size_out = comp_new->block_size * rw_pixel_bits(write_op) >> 3; | |
| 200 |
2/2✓ Branch 0 taken 10952 times.
✓ Branch 1 taken 2738 times.
|
13690 | for (int i = 0; i < NB_PLANES; i++) { |
| 201 | 10952 | exec.in[i] = (void *) src1[i]; | |
| 202 | 10952 | exec.out[i] = (void *) dst1[i]; | |
| 203 | } | ||
| 204 | 2738 | checkasm_call_checked(comp_new->func, &exec, comp_new->priv, 0, 0, PIXELS / comp_new->block_size, LINES); | |
| 205 | |||
| 206 |
2/2✓ Branch 0 taken 10835 times.
✓ Branch 1 taken 2699 times.
|
13534 | for (int i = 0; i < NB_PLANES; i++) { |
| 207 | 10835 | const char *desc = FMT("%s[%d]", name, i); | |
| 208 | 10835 | const int stride = sizeof(dst0[i][0]); | |
| 209 | |||
| 210 |
4/5✓ Branch 0 taken 1388 times.
✓ Branch 1 taken 2117 times.
✓ Branch 2 taken 1581 times.
✓ Branch 3 taken 5749 times.
✗ Branch 4 not taken.
|
10835 | switch (write_op->type) { |
| 211 | 1388 | case U8: | |
| 212 | 1388 | checkasm_check(uint8_t, (void *) dst0[i], stride, | |
| 213 | (void *) dst1[i], stride, | ||
| 214 | write_size, LINES, desc); | ||
| 215 | 1388 | break; | |
| 216 | 2117 | case U16: | |
| 217 | 2117 | checkasm_check(uint16_t, (void *) dst0[i], stride, | |
| 218 | (void *) dst1[i], stride, | ||
| 219 | write_size >> 1, LINES, desc); | ||
| 220 | 2117 | break; | |
| 221 | 1581 | case U32: | |
| 222 | 1581 | checkasm_check(uint32_t, (void *) dst0[i], stride, | |
| 223 | (void *) dst1[i], stride, | ||
| 224 | write_size >> 2, LINES, desc); | ||
| 225 | 1581 | break; | |
| 226 | 5749 | case F32: | |
| 227 | 5749 | checkasm_check(float_ulp, (void *) dst0[i], stride, | |
| 228 | (void *) dst1[i], stride, | ||
| 229 | write_size >> 2, LINES, desc, 0); | ||
| 230 | 5749 | break; | |
| 231 | } | ||
| 232 | |||
| 233 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 10796 times.
|
10835 | if (write_op->rw.packed) |
| 234 | 39 | break; | |
| 235 | } | ||
| 236 | |||
| 237 |
1/8✗ Branch 1 not taken.
✓ Branch 2 taken 2738 times.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
|
2738 | bench(comp_new->func, &exec, comp_new->priv, 0, 0, PIXELS / comp_new->block_size, LINES); |
| 238 | } | ||
| 239 | 5301 | } | |
| 240 | |||
| 241 | 12376 | static void check_ops(const char *name, const unsigned ranges[NB_PLANES], | |
| 242 | const SwsOp *ops) | ||
| 243 | { | ||
| 244 | 12376 | SwsContext *ctx = sws_alloc_context(); | |
| 245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12376 times.
|
12376 | if (!ctx) |
| 246 | ✗ | return; | |
| 247 | 12376 | ctx->flags = SWS_BITEXACT; | |
| 248 | |||
| 249 | static const unsigned def_ranges[4] = {0}; | ||
| 250 |
2/2✓ Branch 0 taken 6300 times.
✓ Branch 1 taken 6076 times.
|
12376 | if (!ranges) |
| 251 | 6300 | ranges = def_ranges; | |
| 252 | |||
| 253 | const SwsOp *read_op, *write_op; | ||
| 254 | 12376 | SwsOpList oplist = { | |
| 255 | .ops = (SwsOp *) ops, | ||
| 256 | .plane_src = {0, 1, 2, 3}, | ||
| 257 | .plane_dst = {0, 1, 2, 3}, | ||
| 258 | }; | ||
| 259 | |||
| 260 | 12376 | read_op = &ops[0]; | |
| 261 |
2/2✓ Branch 0 taken 31808 times.
✓ Branch 1 taken 12376 times.
|
44184 | for (oplist.num_ops = 0; ops[oplist.num_ops].op; oplist.num_ops++) |
| 262 | 31808 | write_op = &ops[oplist.num_ops]; | |
| 263 | |||
| 264 |
2/2✓ Branch 0 taken 49504 times.
✓ Branch 1 taken 12376 times.
|
61880 | for (int p = 0; p < NB_PLANES; p++) { |
| 265 |
4/5✓ Branch 0 taken 10864 times.
✓ Branch 1 taken 14000 times.
✓ Branch 2 taken 13104 times.
✓ Branch 3 taken 11536 times.
✗ Branch 4 not taken.
|
49504 | switch (read_op->type) { |
| 266 | 10864 | case U8: | |
| 267 | 10864 | set_range(&oplist.comps_src.max[p], ranges[p], UINT8_MAX); | |
| 268 | 10864 | oplist.comps_src.min[p] = (AVRational) { 0, 1 }; | |
| 269 | 10864 | break; | |
| 270 | 14000 | case U16: | |
| 271 | 14000 | set_range(&oplist.comps_src.max[p], ranges[p], UINT16_MAX); | |
| 272 | 14000 | oplist.comps_src.min[p] = (AVRational) { 0, 1 }; | |
| 273 | 14000 | break; | |
| 274 | 13104 | case U32: | |
| 275 | 13104 | set_range(&oplist.comps_src.max[p], ranges[p], UINT32_MAX); | |
| 276 | 13104 | oplist.comps_src.min[p] = (AVRational) { 0, 1 }; | |
| 277 | 13104 | break; | |
| 278 | 11536 | case F32: | |
| 279 |
4/4✓ Branch 0 taken 672 times.
✓ Branch 1 taken 10864 times.
✓ Branch 2 taken 448 times.
✓ Branch 3 taken 224 times.
|
11536 | if (ranges[p] && ranges[p] <= INT_MAX) { |
| 280 | 448 | oplist.comps_src.max[p] = (AVRational) { ranges[p], 1 }; | |
| 281 | 448 | oplist.comps_src.min[p] = (AVRational) { 0, 1 }; | |
| 282 | } | ||
| 283 | 11536 | break; | |
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | static const SwsOpBackend *backend_ref; | ||
| 288 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12375 times.
|
12376 | if (!backend_ref) { |
| 289 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | for (int n = 0; ff_sws_op_backends[n]; n++) { |
| 290 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (!strcmp(ff_sws_op_backends[n]->name, "c")) { |
| 291 | 1 | backend_ref = ff_sws_op_backends[n]; | |
| 292 | 1 | break; | |
| 293 | } | ||
| 294 | } | ||
| 295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | av_assert0(backend_ref); |
| 296 | } | ||
| 297 | |||
| 298 | /* Always compile `ops` using the C backend as a reference */ | ||
| 299 | 12376 | SwsCompiledOp comp_ref = {0}; | |
| 300 | 12376 | int ret = ff_sws_ops_compile_backend(ctx, backend_ref, &oplist, &comp_ref); | |
| 301 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12376 times.
|
12376 | if (ret < 0) { |
| 302 | ✗ | av_assert0(ret != AVERROR(ENOTSUP)); | |
| 303 | ✗ | fail(); | |
| 304 | ✗ | goto done; | |
| 305 | } | ||
| 306 | |||
| 307 | /* Iterate over every other backend, and test it against the C reference */ | ||
| 308 |
2/2✓ Branch 0 taken 37128 times.
✓ Branch 1 taken 12376 times.
|
49504 | for (int n = 0; ff_sws_op_backends[n]; n++) { |
| 309 | 37128 | const SwsOpBackend *backend = ff_sws_op_backends[n]; | |
| 310 |
3/4✓ Branch 0 taken 37128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12376 times.
✓ Branch 3 taken 24752 times.
|
37128 | if (backend->hw_format != AV_PIX_FMT_NONE || backend == backend_ref) |
| 311 | 33595 | continue; | |
| 312 | |||
| 313 |
2/2✓ Branch 1 taken 1768 times.
✓ Branch 2 taken 22984 times.
|
24752 | if (!av_get_cpu_flags()) { |
| 314 | /* Also test once with the existing C reference to set the baseline */ | ||
| 315 | 1768 | check_compiled(name, backend, read_op, write_op, ranges, &comp_ref, &comp_ref); | |
| 316 | } | ||
| 317 | |||
| 318 | 24752 | SwsCompiledOp comp_new = {0}; | |
| 319 | 24752 | int ret = ff_sws_ops_compile_backend(ctx, backend, &oplist, &comp_new); | |
| 320 |
2/2✓ Branch 0 taken 21219 times.
✓ Branch 1 taken 3533 times.
|
24752 | if (ret == AVERROR(ENOTSUP)) { |
| 321 | 21219 | continue; | |
| 322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3533 times.
|
3533 | } else if (ret < 0) { |
| 323 | ✗ | fail(); | |
| 324 | ✗ | goto done; | |
| 325 | } | ||
| 326 | |||
| 327 | 3533 | check_compiled(name, backend, read_op, write_op, ranges, &comp_ref, &comp_new); | |
| 328 | 3533 | ff_sws_compiled_op_unref(&comp_new); | |
| 329 | } | ||
| 330 | |||
| 331 | 12376 | done: | |
| 332 | 12376 | ff_sws_compiled_op_unref(&comp_ref); | |
| 333 | 12376 | sws_free_context(&ctx); | |
| 334 | } | ||
| 335 | |||
| 336 | #define CHECK_RANGES(NAME, RANGES, N_IN, N_OUT, IN, OUT, ...) \ | ||
| 337 | do { \ | ||
| 338 | check_ops(NAME, RANGES, (SwsOp[]) { \ | ||
| 339 | { \ | ||
| 340 | .op = SWS_OP_READ, \ | ||
| 341 | .type = IN, \ | ||
| 342 | .rw.elems = N_IN, \ | ||
| 343 | }, \ | ||
| 344 | __VA_ARGS__, \ | ||
| 345 | { \ | ||
| 346 | .op = SWS_OP_WRITE, \ | ||
| 347 | .type = OUT, \ | ||
| 348 | .rw.elems = N_OUT, \ | ||
| 349 | }, {0} \ | ||
| 350 | }); \ | ||
| 351 | } while (0) | ||
| 352 | |||
| 353 | #define MK_RANGES(R) ((const unsigned[]) { R, R, R, R }) | ||
| 354 | #define CHECK_RANGE(NAME, RANGE, N_IN, N_OUT, IN, OUT, ...) \ | ||
| 355 | CHECK_RANGES(NAME, MK_RANGES(RANGE), N_IN, N_OUT, IN, OUT, __VA_ARGS__) | ||
| 356 | |||
| 357 | #define CHECK_COMMON_RANGE(NAME, RANGE, IN, OUT, ...) \ | ||
| 358 | CHECK_RANGE(FMT("%s_p1000", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ | ||
| 359 | CHECK_RANGE(FMT("%s_p1110", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ | ||
| 360 | CHECK_RANGE(FMT("%s_p1111", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__); \ | ||
| 361 | CHECK_RANGE(FMT("%s_p1001", NAME), RANGE, 4, 4, IN, OUT, __VA_ARGS__, { \ | ||
| 362 | .op = SWS_OP_SWIZZLE, \ | ||
| 363 | .type = OUT, \ | ||
| 364 | .swizzle = SWS_SWIZZLE(0, 3, 1, 2), \ | ||
| 365 | }) | ||
| 366 | |||
| 367 | #define CHECK(NAME, N_IN, N_OUT, IN, OUT, ...) \ | ||
| 368 | CHECK_RANGE(NAME, 0, N_IN, N_OUT, IN, OUT, __VA_ARGS__) | ||
| 369 | |||
| 370 | #define CHECK_COMMON(NAME, IN, OUT, ...) \ | ||
| 371 | CHECK_COMMON_RANGE(NAME, 0, IN, OUT, __VA_ARGS__) | ||
| 372 | |||
| 373 | 14 | static void check_read_write(void) | |
| 374 | { | ||
| 375 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 376 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 377 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 56 times.
|
280 | for (int i = 1; i <= 4; i++) { |
| 378 | /* Test N->N planar read/write */ | ||
| 379 |
2/2✓ Branch 0 taken 560 times.
✓ Branch 1 taken 224 times.
|
784 | for (int o = 1; o <= i; o++) { |
| 380 | 560 | check_ops(FMT("rw_%d_%d_%s", i, o, type), NULL, (SwsOp[]) { | |
| 381 | { | ||
| 382 | .op = SWS_OP_READ, | ||
| 383 | .type = t, | ||
| 384 | .rw.elems = i, | ||
| 385 | }, { | ||
| 386 | .op = SWS_OP_WRITE, | ||
| 387 | .type = t, | ||
| 388 | .rw.elems = o, | ||
| 389 | }, {0} | ||
| 390 | }); | ||
| 391 | } | ||
| 392 | |||
| 393 | /* Test packed read/write */ | ||
| 394 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
|
224 | if (i == 1) |
| 395 | 56 | continue; | |
| 396 | |||
| 397 | 168 | check_ops(FMT("read_packed%d_%s", i, type), NULL, (SwsOp[]) { | |
| 398 | { | ||
| 399 | .op = SWS_OP_READ, | ||
| 400 | .type = t, | ||
| 401 | .rw.elems = i, | ||
| 402 | .rw.packed = true, | ||
| 403 | }, { | ||
| 404 | .op = SWS_OP_WRITE, | ||
| 405 | .type = t, | ||
| 406 | .rw.elems = i, | ||
| 407 | }, {0} | ||
| 408 | }); | ||
| 409 | |||
| 410 | 168 | check_ops(FMT("write_packed%d_%s", i, type), NULL, (SwsOp[]) { | |
| 411 | { | ||
| 412 | .op = SWS_OP_READ, | ||
| 413 | .type = t, | ||
| 414 | .rw.elems = i, | ||
| 415 | }, { | ||
| 416 | .op = SWS_OP_WRITE, | ||
| 417 | .type = t, | ||
| 418 | .rw.elems = i, | ||
| 419 | .rw.packed = true, | ||
| 420 | }, {0} | ||
| 421 | }); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | /* Test fractional reads/writes */ | ||
| 426 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14 times.
|
56 | for (int frac = 1; frac <= 3; frac++) { |
| 427 | 42 | const int bits = 8 >> frac; | |
| 428 | 42 | const int range = (1 << bits) - 1; | |
| 429 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
|
42 | if (bits == 2) |
| 430 | 14 | continue; /* no 2 bit packed formats currently exist */ | |
| 431 | |||
| 432 | 28 | check_ops(FMT("read_frac%d", frac), NULL, (SwsOp[]) { | |
| 433 | { | ||
| 434 | .op = SWS_OP_READ, | ||
| 435 | .type = U8, | ||
| 436 | .rw.elems = 1, | ||
| 437 | .rw.frac = frac, | ||
| 438 | }, { | ||
| 439 | .op = SWS_OP_WRITE, | ||
| 440 | .type = U8, | ||
| 441 | .rw.elems = 1, | ||
| 442 | }, {0} | ||
| 443 | }); | ||
| 444 | |||
| 445 | 28 | check_ops(FMT("write_frac%d", frac), MK_RANGES(range), (SwsOp[]) { | |
| 446 | { | ||
| 447 | .op = SWS_OP_READ, | ||
| 448 | .type = U8, | ||
| 449 | .rw.elems = 1, | ||
| 450 | }, { | ||
| 451 | .op = SWS_OP_WRITE, | ||
| 452 | .type = U8, | ||
| 453 | .rw.elems = 1, | ||
| 454 | .rw.frac = frac, | ||
| 455 | }, {0} | ||
| 456 | }); | ||
| 457 | } | ||
| 458 | 14 | } | |
| 459 | |||
| 460 | 14 | static void check_swap_bytes(void) | |
| 461 | { | ||
| 462 | 14 | CHECK_COMMON("swap_bytes_16", U16, U16, { | |
| 463 | .op = SWS_OP_SWAP_BYTES, | ||
| 464 | .type = U16, | ||
| 465 | }); | ||
| 466 | |||
| 467 | 14 | CHECK_COMMON("swap_bytes_32", U32, U32, { | |
| 468 | .op = SWS_OP_SWAP_BYTES, | ||
| 469 | .type = U32, | ||
| 470 | }); | ||
| 471 | 14 | } | |
| 472 | |||
| 473 | 14 | static void check_pack_unpack(void) | |
| 474 | { | ||
| 475 | const struct { | ||
| 476 | SwsPixelType type; | ||
| 477 | SwsPackOp op; | ||
| 478 | 14 | } patterns[] = { | |
| 479 | { U8, {{ 3, 3, 2 }}}, | ||
| 480 | { U8, {{ 2, 3, 3 }}}, | ||
| 481 | { U8, {{ 1, 2, 1 }}}, | ||
| 482 | {U16, {{ 5, 6, 5 }}}, | ||
| 483 | {U16, {{ 5, 5, 5 }}}, | ||
| 484 | {U16, {{ 4, 4, 4 }}}, | ||
| 485 | {U32, {{ 2, 10, 10, 10 }}}, | ||
| 486 | {U32, {{10, 10, 10, 2 }}}, | ||
| 487 | }; | ||
| 488 | |||
| 489 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 14 times.
|
126 | for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { |
| 490 | 112 | const SwsPixelType type = patterns[i].type; | |
| 491 | 112 | const SwsPackOp pack = patterns[i].op; | |
| 492 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 84 times.
|
112 | const int num = pack.pattern[3] ? 4 : 3; |
| 493 | 112 | const char *pat = FMT("%d%d%d%d", pack.pattern[0], pack.pattern[1], | |
| 494 | pack.pattern[2], pack.pattern[3]); | ||
| 495 | 112 | const int total = pack.pattern[0] + pack.pattern[1] + | |
| 496 | 112 | pack.pattern[2] + pack.pattern[3]; | |
| 497 | 112 | const unsigned ranges[4] = { | |
| 498 | 112 | (1 << pack.pattern[0]) - 1, | |
| 499 | 112 | (1 << pack.pattern[1]) - 1, | |
| 500 | 112 | (1 << pack.pattern[2]) - 1, | |
| 501 | 112 | (1 << pack.pattern[3]) - 1, | |
| 502 | }; | ||
| 503 | |||
| 504 | 112 | CHECK_RANGES(FMT("pack_%s", pat), ranges, num, 1, type, type, { | |
| 505 | .op = SWS_OP_PACK, | ||
| 506 | .type = type, | ||
| 507 | .pack = pack, | ||
| 508 | }); | ||
| 509 | |||
| 510 | 112 | CHECK_RANGE(FMT("unpack_%s", pat), UINT32_MAX >> (32 - total), 1, num, type, type, { | |
| 511 | .op = SWS_OP_UNPACK, | ||
| 512 | .type = type, | ||
| 513 | .pack = pack, | ||
| 514 | }); | ||
| 515 | } | ||
| 516 | 14 | } | |
| 517 | |||
| 518 | 1225938 | static AVRational rndq(SwsPixelType t) | |
| 519 | { | ||
| 520 | 1225938 | const unsigned num = rnd(); | |
| 521 |
2/2✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 1224594 times.
|
1225938 | if (ff_sws_pixel_type_is_int(t)) { |
| 522 | 1344 | const unsigned mask = UINT_MAX >> (32 - ff_sws_pixel_type_size(t) * 8); | |
| 523 | 1344 | return (AVRational) { num & mask, 1 }; | |
| 524 | } else { | ||
| 525 | 1224594 | const unsigned den = rnd(); | |
| 526 |
1/2✓ Branch 0 taken 1224594 times.
✗ Branch 1 not taken.
|
1224594 | return (AVRational) { num, den ? den : 1 }; |
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | 14 | static void check_clear(void) | |
| 531 | { | ||
| 532 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 533 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 534 | 56 | const int bits = ff_sws_pixel_type_size(t) * 8; | |
| 535 | |||
| 536 | /* TODO: AVRational can't fit 32 bit constants */ | ||
| 537 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
|
56 | if (bits < 32) { |
| 538 | 28 | const AVRational chroma = (AVRational) { 1 << (bits - 1), 1}; | |
| 539 | 28 | const AVRational alpha = (AVRational) { (1 << bits) - 1, 1}; | |
| 540 | 28 | const AVRational zero = (AVRational) { 0, 1}; | |
| 541 | 28 | const AVRational none = {0}; | |
| 542 | |||
| 543 | 28 | const AVRational patterns[][4] = { | |
| 544 | /* Zero only */ | ||
| 545 | { none, none, none, zero }, | ||
| 546 | { zero, none, none, none }, | ||
| 547 | /* Alpha only */ | ||
| 548 | { none, none, none, alpha }, | ||
| 549 | { alpha, none, none, none }, | ||
| 550 | /* Chroma only */ | ||
| 551 | { chroma, chroma, none, none }, | ||
| 552 | { none, chroma, chroma, none }, | ||
| 553 | { none, none, chroma, chroma }, | ||
| 554 | { chroma, none, chroma, none }, | ||
| 555 | { none, chroma, none, chroma }, | ||
| 556 | /* Alpha+chroma */ | ||
| 557 | { chroma, chroma, none, alpha }, | ||
| 558 | { none, chroma, chroma, alpha }, | ||
| 559 | { alpha, none, chroma, chroma }, | ||
| 560 | { chroma, none, chroma, alpha }, | ||
| 561 | { alpha, chroma, none, chroma }, | ||
| 562 | }; | ||
| 563 | |||
| 564 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 28 times.
|
420 | for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { |
| 565 | 392 | SwsClearOp clear = { .mask = ff_sws_comp_mask_q4(patterns[i]) }; | |
| 566 | 392 | memcpy(clear.value, patterns[i], sizeof(clear.value)); | |
| 567 | 392 | CHECK(FMT("clear_pattern_%s[%d]", type, i), 4, 4, t, t, { | |
| 568 | .op = SWS_OP_CLEAR, | ||
| 569 | .type = t, | ||
| 570 | .clear = clear, | ||
| 571 | }); | ||
| 572 | } | ||
| 573 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | } else if (!ff_sws_pixel_type_is_int(t)) { |
| 574 | /* Floating point YUV doesn't exist, only alpha needs to be cleared */ | ||
| 575 | 14 | CHECK(FMT("clear_alpha_%s", type), 4, 4, t, t, { | |
| 576 | .op = SWS_OP_CLEAR, | ||
| 577 | .type = t, | ||
| 578 | .clear.value[3] = { 0, 1 }, | ||
| 579 | .clear.mask = SWS_COMP(3), | ||
| 580 | }); | ||
| 581 | } | ||
| 582 | } | ||
| 583 | 14 | } | |
| 584 | |||
| 585 | 14 | static void check_shift(void) | |
| 586 | { | ||
| 587 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14 times.
|
56 | for (SwsPixelType t = U16; t < SWS_PIXEL_TYPE_NB; t++) { |
| 588 | 42 | const char *type = ff_sws_pixel_type_name(t); | |
| 589 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
|
42 | if (!ff_sws_pixel_type_is_int(t)) |
| 590 | 14 | continue; | |
| 591 | |||
| 592 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 28 times.
|
252 | for (int shift = 1; shift <= 8; shift++) { |
| 593 | 224 | CHECK_COMMON(FMT("lshift%d_%s", shift, type), t, t, { | |
| 594 | .op = SWS_OP_LSHIFT, | ||
| 595 | .type = t, | ||
| 596 | .shift = { shift }, | ||
| 597 | }); | ||
| 598 | |||
| 599 | 224 | CHECK_COMMON(FMT("rshift%d_%s", shift, type), t, t, { | |
| 600 | .op = SWS_OP_RSHIFT, | ||
| 601 | .type = t, | ||
| 602 | .shift = { shift }, | ||
| 603 | }); | ||
| 604 | } | ||
| 605 | } | ||
| 606 | 14 | } | |
| 607 | |||
| 608 | 14 | static void check_swizzle(void) | |
| 609 | { | ||
| 610 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 611 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 612 | static const int patterns[][4] = { | ||
| 613 | /* Pure swizzle */ | ||
| 614 | {3, 0, 1, 2}, | ||
| 615 | {3, 0, 2, 1}, | ||
| 616 | {2, 1, 0, 3}, | ||
| 617 | {3, 2, 1, 0}, | ||
| 618 | {3, 1, 0, 2}, | ||
| 619 | {3, 2, 0, 1}, | ||
| 620 | {1, 2, 0, 3}, | ||
| 621 | {1, 0, 2, 3}, | ||
| 622 | {2, 0, 1, 3}, | ||
| 623 | {2, 3, 1, 0}, | ||
| 624 | {2, 1, 3, 0}, | ||
| 625 | {1, 2, 3, 0}, | ||
| 626 | {1, 3, 2, 0}, | ||
| 627 | {0, 2, 1, 3}, | ||
| 628 | {0, 2, 3, 1}, | ||
| 629 | {0, 3, 1, 2}, | ||
| 630 | {3, 1, 2, 0}, | ||
| 631 | {0, 3, 2, 1}, | ||
| 632 | /* Luma expansion */ | ||
| 633 | {0, 0, 0, 3}, | ||
| 634 | {3, 0, 0, 0}, | ||
| 635 | {0, 0, 0, 1}, | ||
| 636 | {1, 0, 0, 0}, | ||
| 637 | }; | ||
| 638 | |||
| 639 |
2/2✓ Branch 0 taken 1232 times.
✓ Branch 1 taken 56 times.
|
1288 | for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { |
| 640 | 1232 | const int x = patterns[i][0], y = patterns[i][1], | |
| 641 | 1232 | z = patterns[i][2], w = patterns[i][3]; | |
| 642 | 1232 | CHECK(FMT("swizzle_%d%d%d%d_%s", x, y, z, w, type), 4, 4, t, t, { | |
| 643 | .op = SWS_OP_SWIZZLE, | ||
| 644 | .type = t, | ||
| 645 | .swizzle = SWS_SWIZZLE(x, y, z, w), | ||
| 646 | }); | ||
| 647 | } | ||
| 648 | } | ||
| 649 | 14 | } | |
| 650 | |||
| 651 | 14 | static void check_convert(void) | |
| 652 | { | ||
| 653 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType i = U8; i < SWS_PIXEL_TYPE_NB; i++) { |
| 654 | 56 | const char *itype = ff_sws_pixel_type_name(i); | |
| 655 | 56 | const int isize = ff_sws_pixel_type_size(i); | |
| 656 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 56 times.
|
280 | for (SwsPixelType o = U8; o < SWS_PIXEL_TYPE_NB; o++) { |
| 657 | 224 | const char *otype = ff_sws_pixel_type_name(o); | |
| 658 | 224 | const int osize = ff_sws_pixel_type_size(o); | |
| 659 | 224 | const char *name = FMT("convert_%s_%s", itype, otype); | |
| 660 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 168 times.
|
224 | if (i == o) |
| 661 | 56 | continue; | |
| 662 | |||
| 663 |
4/4✓ Branch 0 taken 98 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 84 times.
|
168 | if (isize < osize || !ff_sws_pixel_type_is_int(o)) { |
| 664 | 84 | CHECK_COMMON(name, i, o, { | |
| 665 | .op = SWS_OP_CONVERT, | ||
| 666 | .type = i, | ||
| 667 | .convert.to = o, | ||
| 668 | }); | ||
| 669 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
84 | } else if (isize > osize || !ff_sws_pixel_type_is_int(i)) { |
| 670 | 84 | uint32_t range = UINT32_MAX >> (32 - osize * 8); | |
| 671 | 84 | CHECK_COMMON_RANGE(name, range, i, o, { | |
| 672 | .op = SWS_OP_CONVERT, | ||
| 673 | .type = i, | ||
| 674 | .convert.to = o, | ||
| 675 | }); | ||
| 676 | } | ||
| 677 | } | ||
| 678 | } | ||
| 679 | |||
| 680 | /* Check expanding conversions */ | ||
| 681 | 14 | CHECK_COMMON("expand16", U8, U16, { | |
| 682 | .op = SWS_OP_CONVERT, | ||
| 683 | .type = U8, | ||
| 684 | .convert.to = U16, | ||
| 685 | .convert.expand = true, | ||
| 686 | }); | ||
| 687 | |||
| 688 | 14 | CHECK_COMMON("expand32", U8, U32, { | |
| 689 | .op = SWS_OP_CONVERT, | ||
| 690 | .type = U8, | ||
| 691 | .convert.to = U32, | ||
| 692 | .convert.expand = true, | ||
| 693 | }); | ||
| 694 | 14 | } | |
| 695 | |||
| 696 | 14 | static void check_dither(void) | |
| 697 | { | ||
| 698 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | for (SwsPixelType t = F32; t < SWS_PIXEL_TYPE_NB; t++) { |
| 699 | 14 | const char *type = ff_sws_pixel_type_name(t); | |
| 700 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (ff_sws_pixel_type_is_int(t)) |
| 701 | ✗ | continue; | |
| 702 | |||
| 703 | /* Test all sizes up to 256x256 */ | ||
| 704 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 14 times.
|
140 | for (int size_log2 = 0; size_log2 <= 8; size_log2++) { |
| 705 | 126 | const int size = 1 << size_log2; | |
| 706 | 126 | const int mask = size - 1; | |
| 707 | 126 | AVRational *matrix = av_refstruct_allocz(size * size * sizeof(*matrix)); | |
| 708 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
|
126 | if (!matrix) { |
| 709 | ✗ | fail(); | |
| 710 | ✗ | return; | |
| 711 | } | ||
| 712 | |||
| 713 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 112 times.
|
126 | if (size == 1) { |
| 714 | 14 | matrix[0] = (AVRational) { 1, 2 }; | |
| 715 | } else { | ||
| 716 |
2/2✓ Branch 0 taken 1223320 times.
✓ Branch 1 taken 112 times.
|
1223432 | for (int i = 0; i < size * size; i++) |
| 717 | 1223320 | matrix[i] = rndq(t); | |
| 718 | } | ||
| 719 | |||
| 720 | 126 | CHECK_COMMON(FMT("dither_%dx%d_%s", size, size, type), t, t, { | |
| 721 | .op = SWS_OP_DITHER, | ||
| 722 | .type = t, | ||
| 723 | .dither.size_log2 = size_log2, | ||
| 724 | .dither.matrix = matrix, | ||
| 725 | .dither.y_offset = {0, 3 & mask, 2 & mask, 5 & mask}, | ||
| 726 | }); | ||
| 727 | |||
| 728 | 126 | av_refstruct_unref(&matrix); | |
| 729 | } | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | 14 | static void check_min_max(void) | |
| 734 | { | ||
| 735 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 736 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 737 | 56 | CHECK_COMMON(FMT("min_%s", type), t, t, { | |
| 738 | .op = SWS_OP_MIN, | ||
| 739 | .type = t, | ||
| 740 | .clamp = {{ rndq(t), rndq(t), rndq(t), rndq(t) }}, | ||
| 741 | }); | ||
| 742 | |||
| 743 | 56 | CHECK_COMMON(FMT("max_%s", type), t, t, { | |
| 744 | .op = SWS_OP_MAX, | ||
| 745 | .type = t, | ||
| 746 | .clamp = {{ rndq(t), rndq(t), rndq(t), rndq(t) }}, | ||
| 747 | }); | ||
| 748 | } | ||
| 749 | 14 | } | |
| 750 | |||
| 751 | 14 | static void check_linear(void) | |
| 752 | { | ||
| 753 | static const struct { | ||
| 754 | const char *name; | ||
| 755 | uint32_t mask; | ||
| 756 | } patterns[] = { | ||
| 757 | { "luma", SWS_MASK_LUMA }, | ||
| 758 | { "alpha", SWS_MASK_ALPHA }, | ||
| 759 | { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA }, | ||
| 760 | { "dot3", 0x7 }, | ||
| 761 | { "row0", SWS_MASK_ROW(0) ^ SWS_MASK(0, 3) }, | ||
| 762 | { "diag3", SWS_MASK_DIAG3 }, | ||
| 763 | { "diag4", SWS_MASK_DIAG4 }, | ||
| 764 | { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA }, | ||
| 765 | { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 }, | ||
| 766 | { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 }, | ||
| 767 | { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA }, | ||
| 768 | }; | ||
| 769 | |||
| 770 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | for (SwsPixelType t = F32; t < SWS_PIXEL_TYPE_NB; t++) { |
| 771 | 14 | const char *type = ff_sws_pixel_type_name(t); | |
| 772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (ff_sws_pixel_type_is_int(t)) |
| 773 | ✗ | continue; | |
| 774 | |||
| 775 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 14 times.
|
168 | for (int p = 0; p < FF_ARRAY_ELEMS(patterns); p++) { |
| 776 | 154 | const uint32_t mask = patterns[p].mask; | |
| 777 | 154 | SwsLinearOp lin = { .mask = mask }; | |
| 778 | |||
| 779 |
2/2✓ Branch 0 taken 616 times.
✓ Branch 1 taken 154 times.
|
770 | for (int i = 0; i < 4; i++) { |
| 780 |
2/2✓ Branch 0 taken 3080 times.
✓ Branch 1 taken 616 times.
|
3696 | for (int j = 0; j < 5; j++) { |
| 781 |
2/2✓ Branch 0 taken 770 times.
✓ Branch 1 taken 2310 times.
|
3080 | if (mask & SWS_MASK(i, j)) { |
| 782 | 770 | lin.m[i][j] = rndq(t); | |
| 783 | } else { | ||
| 784 | 2310 | lin.m[i][j] = (AVRational) { i == j, 1 }; | |
| 785 | } | ||
| 786 | } | ||
| 787 | } | ||
| 788 | |||
| 789 | 154 | CHECK(FMT("linear_%s_%s", patterns[p].name, type), 4, 4, t, t, { | |
| 790 | .op = SWS_OP_LINEAR, | ||
| 791 | .type = t, | ||
| 792 | .lin = lin, | ||
| 793 | }); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | 14 | } | |
| 797 | |||
| 798 | 14 | static void check_scale(void) | |
| 799 | { | ||
| 800 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 801 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 802 | 56 | const int bits = ff_sws_pixel_type_size(t) * 8; | |
| 803 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 14 times.
|
56 | if (ff_sws_pixel_type_is_int(t)) { |
| 804 | 42 | const unsigned max = UINT32_MAX >> (32 - bits); | |
| 805 | |||
| 806 | /* Test fixed fast path for expansion from bits to full range */ | ||
| 807 | 42 | CHECK_COMMON_RANGE(FMT("scale_full_%s", type), 1, t, t, { | |
| 808 | .op = SWS_OP_SCALE, | ||
| 809 | .type = t, | ||
| 810 | .scale = {{ max, 1 }}, | ||
| 811 | }); | ||
| 812 | |||
| 813 | /* Ensure the result won't exceed the value range */ | ||
| 814 | 42 | const unsigned scale = rnd() & (max >> 1); | |
| 815 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | const unsigned range = max / (scale ? scale : 1); |
| 816 | 42 | CHECK_COMMON_RANGE(FMT("scale_%s", type), range, t, t, { | |
| 817 | .op = SWS_OP_SCALE, | ||
| 818 | .type = t, | ||
| 819 | .scale = {{ scale, 1 }}, | ||
| 820 | }); | ||
| 821 | } else { | ||
| 822 | 14 | CHECK_COMMON(FMT("scale_%s", type), t, t, { | |
| 823 | .op = SWS_OP_SCALE, | ||
| 824 | .type = t, | ||
| 825 | .scale = { rndq(t) }, | ||
| 826 | }); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | 14 | } | |
| 830 | |||
| 831 | 14 | static void check_filter(void) | |
| 832 | { | ||
| 833 | 14 | SwsFilterParams params = { | |
| 834 | .scaler_params = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT }, | ||
| 835 | }; | ||
| 836 | |||
| 837 | 14 | const SwsScaler scalers[] = { | |
| 838 | SWS_SCALE_POINT, | ||
| 839 | SWS_SCALE_SINC, | ||
| 840 | }; | ||
| 841 | |||
| 842 | SwsFilterWeights *filter; | ||
| 843 | |||
| 844 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | for (SwsPixelType t = U8; t < SWS_PIXEL_TYPE_NB; t++) { |
| 845 | 56 | const char *type = ff_sws_pixel_type_name(t); | |
| 846 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 56 times.
|
168 | for (int s = 0; s < FF_ARRAY_ELEMS(scalers); s++) { |
| 847 | 112 | params.scaler = scalers[s]; | |
| 848 | 112 | params.dst_size = LINES; | |
| 849 |
2/2✓ Branch 0 taken 560 times.
✓ Branch 1 taken 112 times.
|
672 | for (int h = 1; h <= LINES; h += h) { |
| 850 | 560 | params.src_size = h; | |
| 851 | 560 | int ret = ff_sws_filter_generate(NULL, ¶ms, &filter); | |
| 852 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 560 times.
|
560 | if (ret < 0) { |
| 853 | ✗ | fail(); | |
| 854 | ✗ | return; | |
| 855 | } | ||
| 856 | |||
| 857 | 560 | const char *name = filter->name; | |
| 858 |
2/2✓ Branch 0 taken 2240 times.
✓ Branch 1 taken 560 times.
|
2800 | for (int n = 1; n <= 4; n++) { |
| 859 | 2240 | check_ops(FMT("%s_filter%d_v_%dx%d_%s", name, n, PIXELS, h, type), NULL, (SwsOp[]) { | |
| 860 | { | ||
| 861 | .op = SWS_OP_READ, | ||
| 862 | .type = t, | ||
| 863 | .rw.elems = n, | ||
| 864 | .rw.filter = SWS_OP_FILTER_V, | ||
| 865 | .rw.kernel = filter, | ||
| 866 | }, { | ||
| 867 | .op = SWS_OP_WRITE, | ||
| 868 | .type = SWS_PIXEL_F32, | ||
| 869 | .rw.elems = n, | ||
| 870 | }, {0} | ||
| 871 | }); | ||
| 872 | } | ||
| 873 | |||
| 874 | 560 | av_refstruct_unref(&filter); | |
| 875 | } | ||
| 876 | |||
| 877 | 112 | params.dst_size = PIXELS; | |
| 878 |
2/2✓ Branch 0 taken 784 times.
✓ Branch 1 taken 112 times.
|
896 | for (int w = 1; w <= PIXELS; w += w) { |
| 879 | 784 | params.src_size = w; | |
| 880 | 784 | int ret = ff_sws_filter_generate(NULL, ¶ms, &filter); | |
| 881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 784 times.
|
784 | if (ret < 0) { |
| 882 | ✗ | fail(); | |
| 883 | ✗ | return; | |
| 884 | } | ||
| 885 | |||
| 886 | 784 | const char *name = filter->name; | |
| 887 |
2/2✓ Branch 0 taken 3136 times.
✓ Branch 1 taken 784 times.
|
3920 | for (int n = 1; n <= 4; n++) { |
| 888 | 3136 | check_ops(FMT("%s_filter%d_h_%dx%d_%s", name, n, w, LINES, type), NULL, (SwsOp[]) { | |
| 889 | { | ||
| 890 | .op = SWS_OP_READ, | ||
| 891 | .type = t, | ||
| 892 | .rw.elems = n, | ||
| 893 | .rw.filter = SWS_OP_FILTER_H, | ||
| 894 | .rw.kernel = filter, | ||
| 895 | }, { | ||
| 896 | .op = SWS_OP_WRITE, | ||
| 897 | .type = SWS_PIXEL_F32, | ||
| 898 | .rw.elems = n, | ||
| 899 | }, {0} | ||
| 900 | }); | ||
| 901 | } | ||
| 902 | |||
| 903 | 784 | av_refstruct_unref(&filter); | |
| 904 | } | ||
| 905 | } | ||
| 906 | } | ||
| 907 | } | ||
| 908 | |||
| 909 | 14 | void checkasm_check_sw_ops(void) | |
| 910 | { | ||
| 911 | 14 | check_read_write(); | |
| 912 | 14 | report("read_write"); | |
| 913 | 14 | check_swap_bytes(); | |
| 914 | 14 | report("swap_bytes"); | |
| 915 | 14 | check_pack_unpack(); | |
| 916 | 14 | report("pack_unpack"); | |
| 917 | 14 | check_clear(); | |
| 918 | 14 | report("clear"); | |
| 919 | 14 | check_shift(); | |
| 920 | 14 | report("shift"); | |
| 921 | 14 | check_swizzle(); | |
| 922 | 14 | report("swizzle"); | |
| 923 | 14 | check_convert(); | |
| 924 | 14 | report("convert"); | |
| 925 | 14 | check_dither(); | |
| 926 | 14 | report("dither"); | |
| 927 | 14 | check_min_max(); | |
| 928 | 14 | report("min_max"); | |
| 929 | 14 | check_linear(); | |
| 930 | 14 | report("linear"); | |
| 931 | 14 | check_scale(); | |
| 932 | 14 | report("scale"); | |
| 933 | 14 | check_filter(); | |
| 934 | 14 | report("filter"); | |
| 935 | 14 | } | |
| 936 |