FFmpeg
Loading...
Searching...
No Matches
sw_ops.c
Go to the documentation of this file.
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"
25#include "libavutil/refstruct.h"
26
27#include "libswscale/filters.h"
29#include "libswscale/uops.h"
31
32#include "checkasm.h"
33
34enum {
35 MAX_UOPS = 3, /* read, op, write */
37 PIXELS = 64,
38 LINES = 16,
39};
40
41typedef struct Test {
42 const char *name;
45
46 /* Extra metadata for the test harness */
47 SwsPixelType type_in; /* data format to fill */
48 SwsPixelType type_out; /* data format to compare */
49 SwsCompMask planes_in; /* planes to fill */
50 SwsCompMask planes_out; /* planes to compare */
51 int pixel_bits_in; /* read pixel stride */
52 int pixel_bits_out; /* write pixel stride */
53 unsigned ranges[NB_PLANES]; /* pixel range to fill */
54} Test;
55
56#define FMT(fmt, ...) tprintf((char[256]) {0}, 256, fmt, __VA_ARGS__)
57static const char *tprintf(char buf[], size_t size, const char *fmt, ...)
58{
59 va_list ap;
60 va_start(ap, fmt);
61 vsnprintf(buf, size, fmt, ap);
62 va_end(ap);
63 return buf;
64}
65
66static float rndf(void)
67{
68 union { uint32_t u; float f; } x;
69 do {
70 x.u = rnd();
71 } while (!isnormal(x.f));
72 return x.f;
73}
74
76{
77 switch (type) {
78 case SWS_PIXEL_U8: return (SwsPixel) { .u8 = val };
79 case SWS_PIXEL_U16: return (SwsPixel) { .u16 = val };
80 case SWS_PIXEL_U32: return (SwsPixel) { .u32 = val };
81 case SWS_PIXEL_F32: return (SwsPixel) { .f32 = val };
82 default: return (SwsPixel) {0};
83 }
84}
85
87{
88 switch (type) {
89 case SWS_PIXEL_U8: return (SwsPixel) { .u8 = rnd() & 0xFF };
90 case SWS_PIXEL_U16: return (SwsPixel) { .u16 = rnd() & 0xFFFF };
91 case SWS_PIXEL_U32: return (SwsPixel) { .u32 = rnd() };
92 case SWS_PIXEL_F32: return (SwsPixel) { .f32 = rndf() };
93 default: return (SwsPixel) {0};
94 }
95}
96
97static void fill32f(float *line, int num, unsigned range)
98{
99 const float scale = (float) range / UINT32_MAX;
100 for (int i = 0; i < num; i++)
101 line[i] = range ? scale * rnd() : rndf();
102}
103
104static void fill32(uint32_t *line, int num, unsigned range)
105{
106 for (int i = 0; i < num; i++)
107 line[i] = (range && range < UINT_MAX) ? rnd() % (range + 1) : rnd();
108}
109
110static void fill16(uint16_t *line, int num, unsigned range)
111{
112 if (!range) {
113 fill32((uint32_t *) line, AV_CEIL_RSHIFT(num, 1), 0);
114 } else {
115 for (int i = 0; i < num; i++)
116 line[i] = rnd() % (range + 1);
117 }
118}
119
120static void fill8(uint8_t *line, int num, unsigned range)
121{
122 if (!range) {
123 fill32((uint32_t *) line, AV_CEIL_RSHIFT(num, 2), 0);
124 } else {
125 for (int i = 0; i < num; i++)
126 line[i] = rnd() % (range + 1);
127 }
128}
129
131{
132 switch (ff_sws_pixel_type_size(type)) {
133 case 1: return SWS_PIXEL_U8;
134 case 2: return SWS_PIXEL_U16;
135 case 4: return SWS_PIXEL_U32;
136 default: break;
137 }
138
139 av_unreachable("Invalid pixel type!");
140 return SWS_PIXEL_NONE;
141}
142
143static void check_compiled(const Test *test,
144 const SwsCompiledOp *comp_ref,
145 const SwsCompiledOp *comp_new)
146{
147 /**
148 * We can't use `check_func()` alone because the actual function pointer
149 * may be a wrapper or entry point shared by multiple implementations.
150 * Solve it by hashing in the active CPU flags as well.
151 */
152 uintptr_t id = (uintptr_t) comp_new->func;
153 id ^= (id << 6) + (id >> 2) + 0x9e3779b97f4a7c15 + comp_new->cpu_flags;
154 if (!check_key(id, "%s", test->name))
155 return;
156
157 declare_func(void, const SwsOpExec *, const void *, int bx, int y, int bx_end, int y_end);
158
159 static DECLARE_ALIGNED_64(char, src0)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])];
160 static DECLARE_ALIGNED_64(char, src1)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])];
161 static DECLARE_ALIGNED_64(char, dst0)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])];
162 static DECLARE_ALIGNED_64(char, dst1)[NB_PLANES][LINES][PIXELS * sizeof(uint32_t[4])];
163
164 av_assert0(PIXELS % comp_new->block_size == 0);
165 for (int p = 0; p < NB_PLANES; p++) {
166 void *plane = src0[p];
167 if (!SWS_COMP_TEST(test->planes_in, p)) {
168 memset(plane, 0, sizeof(src0[p]));
169 continue;
170 }
171
172 switch (test->type_in) {
173 case SWS_PIXEL_U8:
174 fill8(plane, sizeof(src0[p]) / sizeof(uint8_t), test->ranges[p]);
175 break;
176 case SWS_PIXEL_U16:
177 fill16(plane, sizeof(src0[p]) / sizeof(uint16_t), test->ranges[p]);
178 break;
179 case SWS_PIXEL_U32:
180 fill32(plane, sizeof(src0[p]) / sizeof(uint32_t), test->ranges[p]);
181 break;
182 case SWS_PIXEL_F32:
183 fill32f(plane, sizeof(src0[p]) / sizeof(uint32_t), test->ranges[p]);
184 break;
185 }
186 }
187
188 memcpy(src1, src0, sizeof(src0));
189 memset(dst0, 0, sizeof(dst0));
190 memset(dst1, 0, sizeof(dst1));
191
192 const int read_size = PIXELS * test->pixel_bits_in >> 3;
193 const int write_size = PIXELS * test->pixel_bits_out >> 3;
194
195 SwsOpExec exec = {0};
196 exec.width = PIXELS;
197 exec.height = exec.slice_h = LINES;
198 for (int i = 0; i < NB_PLANES; i++) {
199 exec.in_stride[i] = sizeof(src0[i][0]);
200 exec.out_stride[i] = sizeof(dst0[i][0]);
201 exec.in_bump[i] = exec.in_stride[i] - read_size;
202 exec.out_bump[i] = exec.out_stride[i] - write_size;
203 }
204
205 int32_t in_bump_y[LINES];
206 int32_t in_offset_x[PIXELS];
207 const SwsUOp *read_op = &test->uops[0];
208 switch (read_op->uop) {
210 exec.in_bump[1] = exec.in_stride[1] = 0;
211 static_assert(sizeof(src0[1]) >= sizeof(uint32_t[256]), "palette plane too small");
212 break;
214 const int *offsets = read_op->data.kernel->offsets;
215 for (int y = 0; y < LINES - 1; y++)
216 in_bump_y[y] = offsets[y + 1] - offsets[y] - 1;
217 in_bump_y[LINES - 1] = 0;
218 exec.in_bump_y = in_bump_y;
219 break;
220 }
222 const int *offsets = read_op->data.kernel->offsets;
223 for (int x = 0; x < PIXELS; x++)
224 in_offset_x[x] = offsets[x] * test->pixel_bits_in >> 3;
225 exec.in_offset_x = in_offset_x;
226 }
227 }
228
229 for (int i = 0; i < NB_PLANES; i++) {
230 exec.in[i] = (void *) src0[i];
231 exec.out[i] = (void *) dst0[i];
232 exec.block_size_in[i] = comp_ref->block_size * test->pixel_bits_in >> 3;
233 exec.block_size_out[i] = comp_ref->block_size * test->pixel_bits_out >> 3;
234 }
235 checkasm_call(comp_ref->func, &exec, comp_ref->priv, 0, 0, PIXELS / comp_ref->block_size, LINES);
236
237 for (int i = 0; i < NB_PLANES; i++) {
238 exec.in[i] = (void *) src1[i];
239 exec.out[i] = (void *) dst1[i];
240 exec.block_size_in[i] = comp_new->block_size * test->pixel_bits_in >> 3;
241 exec.block_size_out[i] = comp_new->block_size * test->pixel_bits_out >> 3;
242 }
243 checkasm_call_checked(comp_new->func, &exec, comp_new->priv, 0, 0, PIXELS / comp_new->block_size, LINES);
244
245 for (int i = 0; i < NB_PLANES; i++) {
246 if (!SWS_COMP_TEST(test->planes_out, i))
247 continue;
248
249 const char *desc = FMT("%s[%d]", test->name, i);
250 const int stride = sizeof(dst0[i][0]);
251 switch (test->type_out) {
252 case SWS_PIXEL_U8:
253 checkasm_check(uint8_t, (void *) dst0[i], stride,
254 (void *) dst1[i], stride,
255 write_size, LINES, desc);
256 break;
257 case SWS_PIXEL_U16:
258 checkasm_check(uint16_t, (void *) dst0[i], stride,
259 (void *) dst1[i], stride,
260 write_size >> 1, LINES, desc);
261 break;
262 case SWS_PIXEL_U32:
263 checkasm_check(uint32_t, (void *) dst0[i], stride,
264 (void *) dst1[i], stride,
265 write_size >> 2, LINES, desc);
266 break;
267 case SWS_PIXEL_F32:
268 checkasm_check(float_ulp, (void *) dst0[i], stride,
269 (void *) dst1[i], stride,
270 write_size >> 2, LINES, desc, 0);
271 break;
272 }
273 }
274
275 bench(comp_new->func, &exec, comp_new->priv, 0, 0, PIXELS / comp_new->block_size, LINES);
276}
277
278static void run_test(const Test *test)
279{
281 if (!ctx)
282 return;
283 ctx->flags = SWS_BITEXACT;
284
285 /* Generate dummy uop list on-stack */
286 SwsUOpList oplist = {
287 .ops = (SwsUOp *) test->uops,
288 .num_ops = test->num_uops,
289
290 /* Less efficient, but works universally */
291 .planes_in = SWS_COMP_ALL,
292 .planes_out = SWS_COMP_ALL,
293 };
294
295 for (int i = 0; i < test->num_uops; i++) {
296 const int pixel_size = ff_sws_pixel_type_size(test->uops[i].type);
297 if (pixel_size > oplist.pixel_size_max)
298 oplist.pixel_size_max = pixel_size;
299 }
300
301 static const SwsOpBackend *backend_ref;
302 if (!backend_ref) {
303 for (int n = 0; ff_sws_op_backends[n]; n++) {
304 if (!strcmp(ff_sws_op_backends[n]->name, "c")) {
305 backend_ref = ff_sws_op_backends[n];
306 break;
307 }
308 }
309 av_assert0(backend_ref);
310 }
311
312 /* Always compile `ops` using the C backend as a reference */
313 SwsCompiledOp comp_ref = {0};
314 int ret = backend_ref->compile_uops(ctx, &oplist, &comp_ref);
315 if (ret < 0) {
316 av_assert0(ret != AVERROR(ENOTSUP));
317 fail();
318 goto done;
319 }
320
321 /* Check with the C backend to establish a reference */
322 check_compiled(test, &comp_ref, &comp_ref);
323
324 /* Iterate over every other backend, and test it against the C reference */
325 for (int n = 0; ff_sws_op_backends[n]; n++) {
326 const SwsOpBackend *backend = ff_sws_op_backends[n];
327 if (backend->hw_format != AV_PIX_FMT_NONE || backend == backend_ref)
328 continue;
329 if (!backend->compile_uops)
330 continue;
331
332 SwsCompiledOp comp_new = {0};
333 int ret = backend->compile_uops(ctx, &oplist, &comp_new);
334 if (ret == AVERROR(ENOTSUP)) {
335 continue;
336 } else if (ret < 0) {
337 fail();
338 goto done;
339 }
340
341 /* Distinguish backends from each other even with same CPU flags */
343 check_compiled(test, &comp_ref, &comp_new);
344 ff_sws_compiled_op_unref(&comp_new);
345 }
346
347done:
348 ff_sws_compiled_op_unref(&comp_ref);
350}
351
352static void check_uop(const char *name, const SwsUOp *uop,
353 SwsCompMask mask_in, SwsCompMask mask_out,
354 const unsigned ranges[NB_PLANES])
355{
356 Test t = {
357 .name = name,
358 .type_in = uop->type,
359 .type_out = uop->type,
360 };
361
362 for (int i = 0; ranges && i < NB_PLANES; i++)
363 t.ranges[i] = ranges[i];
364
365 /* uops with non-standard output type conversions */
366 switch (uop->uop) {
367 case SWS_UOP_TO_U8: t.type_out = SWS_PIXEL_U8; break;
368 case SWS_UOP_TO_U16: t.type_out = SWS_PIXEL_U16; break;
369 case SWS_UOP_TO_U32: t.type_out = SWS_PIXEL_U32; break;
370 case SWS_UOP_TO_F32: t.type_out = SWS_PIXEL_F32; break;
375 t.type_out = uop->par.filter.type;
376 break;
377 }
378
379 /* Set up read/write metadata for rw uops */
380 const int bits_in = ff_sws_pixel_type_size(t.type_in) * 8;
381 const int bits_out = ff_sws_pixel_type_size(t.type_out) * 8;
382 switch (uop->uop) {
386 t.planes_in = uop->mask;
387 t.pixel_bits_in = bits_in;
388 break;
390 t.planes_out = uop->mask;
391 t.pixel_bits_out = bits_out;
392 break;
395 t.pixel_bits_in = bits_in * SWS_COMP_COUNT(uop->mask);
396 break;
399 t.pixel_bits_out = bits_out * SWS_COMP_COUNT(uop->mask);
400 break;
403 t.pixel_bits_in = 4;
404 break;
407 t.pixel_bits_out = 4;
408 break;
409 case SWS_UOP_READ_BIT:
411 t.pixel_bits_in = 1;
412 break;
415 t.pixel_bits_out = 1;
416 break;
419 t.pixel_bits_in = 8; /* size of index */
420 break;
421 }
422
423 /* Add read uop if needed */
424 if (!t.planes_in) {
425 t.planes_in = mask_in;
426 t.pixel_bits_in = bits_in;
427 t.uops[t.num_uops++] = (SwsUOp) {
428 .type = pixel_type_to_int(t.type_in),
429 .uop = SWS_UOP_READ_PLANAR,
430 .mask = SWS_COMP_ALL, /* extra planes are zero'd */
431 };
432 }
433
434 /* Add the UOp itself */
435 t.uops[t.num_uops++] = *uop;
436
437 /* Add write uop if needed */
438 if (!t.planes_out) {
439 t.planes_out = mask_out;
440 t.pixel_bits_out = bits_out;
441 t.uops[t.num_uops++] = (SwsUOp) {
442 .type = pixel_type_to_int(t.type_out),
444 .mask = SWS_COMP_ALL, /* extra planes are ignored */
445 };
446 }
447
448 run_test(&t);
449}
450
451static void check_range(const char *name, const SwsUOp *uop,
452 const unsigned ranges[NB_PLANES])
453{
454 /* Test all planes to ensure data remains untouched */
455 check_uop(name, uop, SWS_COMP_ALL, SWS_COMP_ALL, ranges);
456}
457
458static void check_simple(const char *name, const SwsUOp *uop)
459{
460 check_range(name, uop, NULL);
461}
462
463static void check_scalar(const char *name, SwsUOp *uop)
464{
465 uop->data.scalar = rndpx(uop->type);
466 check_simple(name, uop);
467}
468
469static void check_vec4(const char *name, SwsUOp *uop)
470{
471 for (int i = 0; i < 4; i++)
472 uop->data.vec4[i] = rndpx(uop->type);
473
474 check_simple(name, uop);
475}
476
477#define MK_RANGES(R) ((const unsigned[]) { R, R, R, R })
478
479static void check_read(const char *name, SwsUOp *uop)
480{
481 check_uop(name, uop, uop->mask, uop->mask, NULL);
482}
483
484static void check_write(const char *name, const SwsUOp *uop)
485{
486 const int frac = uop->uop == SWS_UOP_WRITE_BIT ? 3 :
487 uop->uop == SWS_UOP_WRITE_NIBBLE ? 1 : 0;
488 const int bits = 8 >> frac;
489 const unsigned range = (1 << bits) - 1;
490 check_uop(name, uop, uop->mask, uop->mask, MK_RANGES(range));
491}
492
493static void check_filter(const char *name, SwsUOp *uop)
494{
495 const bool is_vert = uop->uop == SWS_UOP_READ_PLANAR_FV;
496
497 SwsFilterParams par = {
498 .scaler_params = { SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT },
499 .dst_size = is_vert ? LINES : PIXELS,
500 };
501
502 const SwsScaler scalers[] = {
505 };
506
507 for (int s = 0; s < FF_ARRAY_ELEMS(scalers); s++) {
508 par.scaler = scalers[s];
509
510 for (par.src_size = 1; par.src_size <= par.dst_size; par.src_size <<= 1) {
511 if (ff_sws_filter_generate(NULL, &par, &uop->data.kernel) < 0) {
512 fail();
513 return;
514 }
515
516 char desc[256];
517 snprintf(desc, sizeof(desc), "%s_%s_%d", name,
518 uop->data.kernel->name, par.src_size);
519
520 check_read(desc, uop);
522 }
523 }
524}
525
526static void check_swizzle(const char *name, const SwsUOp *uop)
527{
528 /* Only check data equality in needed components; since the others
529 * could either remain untouched or contain garbage */
530 check_uop(name, uop, SWS_COMP_ALL, uop->mask, NULL);
531}
532
533static void check_expand_bit(const char *name, const SwsUOp *uop)
534{
535 check_range(name, uop, MK_RANGES(1));
536}
537
538static void check_cast(const char *name, const SwsUOp *uop)
539{
541 switch (uop->uop) {
542 case SWS_UOP_TO_U8: dst = SWS_PIXEL_U8; break;
543 case SWS_UOP_TO_U16: dst = SWS_PIXEL_U16; break;
544 case SWS_UOP_TO_U32: dst = SWS_PIXEL_U32; break;
545 case SWS_UOP_TO_F32: dst = SWS_PIXEL_F32; break;
548 default: return;
549 }
550
551 const int isize = ff_sws_pixel_type_size(uop->type);
552 const int osize = ff_sws_pixel_type_size(dst);
553 unsigned range = UINT32_MAX >> (32 - osize * 8);
554 if (isize < osize || !ff_sws_pixel_type_is_int(dst))
555 range = 0;
556
557 check_uop(name, uop, uop->mask, uop->mask, MK_RANGES(range));
558}
559
560static void check_scale(const char *name, SwsUOp *uop)
561{
562 const int bits = ff_sws_pixel_type_size(uop->type) * 8;
563 const unsigned max = UINT32_MAX >> (32 - bits);
564 SwsPixel scale = uop->data.scalar = rndpx(uop->type);
565 unsigned range = 0;
566
567 /* Ensure the result won't exceed the value range */
568 switch (uop->type) {
569 case SWS_PIXEL_U8: range = max / (scale.u8 ? scale.u8 : 1); break;
570 case SWS_PIXEL_U16: range = max / (scale.u16 ? scale.u16 : 1); break;
571 case SWS_PIXEL_U32: range = max / (scale.u32 ? scale.u32 : 1); break;
572 }
573
575}
576
577static void check_unpack(const char *name, const SwsUOp *uop)
578{
579 const uint8_t *pat = uop->par.pack.pattern;
580 const int total = pat[0] + pat[1] + pat[2] + pat[3];
581 const unsigned range = UINT32_MAX >> (32 - total);
582
583 check_uop(name, uop, SWS_COMP(0), uop->mask, MK_RANGES(range));
584}
585
586static void check_pack(const char *name, const SwsUOp *uop)
587{
588 const uint8_t *pat = uop->par.pack.pattern;
589 const unsigned ranges[4] = {
590 (1 << pat[0]) - 1, (1 << pat[1]) - 1,
591 (1 << pat[2]) - 1, (1 << pat[3]) - 1,
592 };
593
594 check_uop(name, uop, uop->mask, SWS_COMP(0), ranges);
595}
596
597static void check_linear(const char *name, SwsUOp *uop)
598{
599 const SwsLinearUOp *par = &uop->par.lin;
600 for (int i = 0; i < 4; i++) {
601 for (int j = 0; j < 5; j++) {
602 if (par->zero & SWS_MASK(i, j))
603 uop->data.mat4[i][j] = constpx(uop->type, 0);
604 else if (par->one & SWS_MASK(i, j))
605 uop->data.mat4[i][j] = constpx(uop->type, 1);
606 else
607 uop->data.mat4[i][j] = rndpx(uop->type);
608 }
609 }
610
611 check_simple(name, uop);
612}
613
614static void check_dither(const char *name, SwsUOp *uop)
615{
617
618 const int size = 1 << uop->par.dither.size_log2;
619 const int height = ff_sws_dither_height(&uop->par.dither);
621 if (!matrix) {
622 fail();
623 return;
624 }
625
626 for (int i = 0; i < size * size; i++)
627 matrix[i] = rndpx(uop->type);
628 memcpy(matrix + size * size, matrix,
629 size * (height - size) * sizeof(*matrix));
630
631 uop->data.ptr = matrix;
632 check_simple(name, uop);
633
635}
636
637static void check_lut_3d(const char *name, SwsUOp *uop)
638{
639 SwsLut3D *lut3d = ff_sws_lut3d_alloc();
640 if (!lut3d) {
641 fail();
642 return;
643 }
644
645 checkasm_init(&lut3d->input, sizeof(lut3d->input));
646
647 if (uop->par.lut3d.dynamic) {
648 checkasm_init(&lut3d->tone_map, sizeof(lut3d->tone_map));
649 checkasm_init(&lut3d->output, sizeof(lut3d->output));
650 lut3d->dynamic = true;
651
652 /* Prevent out-of-bounds read from IPT values with abs(PT) > 0.5 */
653 for (int i = 0; i < FF_ARRAY_ELEMS(lut3d->tone_map); i++)
654 lut3d->tone_map[i].y = FFMIN(lut3d->tone_map[i].y, 1 << 15);
655 }
656
657 uop->data.lut3d = lut3d;
659
660 av_refstruct_unref(&lut3d);
661}
662
663#define CHECK_FUNCTION(CHECK, NAME, ...) \
664 CHECK(#NAME, &(SwsUOp) { __VA_ARGS__ });
665
666#define CHECK_FOR(UOP, CHECK) \
667 SWS_FOR_STRUCT(U8, UOP, CHECK_FUNCTION, CHECK) \
668 SWS_FOR_STRUCT(U16, UOP, CHECK_FUNCTION, CHECK) \
669 SWS_FOR_STRUCT(U32, UOP, CHECK_FUNCTION, CHECK) \
670 SWS_FOR_STRUCT(F32, UOP, CHECK_FUNCTION, CHECK) \
671 report(#UOP)
672
674{
675 CHECK_FOR(READ_PLANAR, check_read);
676 CHECK_FOR(READ_PLANAR_FH, check_filter);
677 CHECK_FOR(READ_PLANAR_FV, check_filter);
678 CHECK_FOR(READ_PACKED, check_read);
679 CHECK_FOR(READ_NIBBLE, check_read);
680 CHECK_FOR(READ_BIT, check_read);
681 CHECK_FOR(READ_PALETTE, check_read);
682 CHECK_FOR(WRITE_PLANAR, check_write);
683 CHECK_FOR(WRITE_PACKED, check_write);
684 CHECK_FOR(WRITE_NIBBLE, check_write);
685 CHECK_FOR(WRITE_BIT, check_write);
686 CHECK_FOR(PERMUTE, check_swizzle);
688 CHECK_FOR(SWAP_BYTES, check_simple);
689 CHECK_FOR(EXPAND_BIT, check_expand_bit);
690 CHECK_FOR(EXPAND_PAIR, check_cast);
691 CHECK_FOR(EXPAND_QUAD, check_cast);
692 CHECK_FOR(TO_U8, check_cast);
693 CHECK_FOR(TO_U16, check_cast);
694 CHECK_FOR(TO_U32, check_cast);
695 CHECK_FOR(TO_F32, check_cast);
700 CHECK_FOR(UNPACK, check_unpack);
701 CHECK_FOR(PACK, check_pack);
702 CHECK_FOR(LSHIFT, check_simple);
706 CHECK_FOR(DITHER, check_dither);
707 CHECK_FOR(LUT_3D, check_lut_3d);
708}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
int32_t
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define COPY(src, name)
#define MAX
Definition blend_modes.c:46
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
#define bench(...)
Definition checkasm.h:138
#define rnd
Definition checkasm.h:136
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define RSHIFT(a, b)
Definition common.h:56
#define NULL
Definition coverity.c:32
#define max(a, b)
#define SCALE(c)
Definition dcadata.c:7338
#define ADD(a, b)
static const char * checkasm_get_cpu_suffix(void)
Get the suffix for the current CPU flag, or "c" if none.
Definition checkasm.h:350
static const uint8_t bits[8]
Definition fastaudio.c:100
int ff_sws_filter_generate(void *log, const SwsFilterParams *params, SwsFilterWeights **out)
Generate a filter kernel for the given parameters.
Definition filters.c:187
#define declare_func
Definition test.h:489
#define fail
Definition test.h:479
#define check_key
Definition test.h:482
#define AVERROR(e)
Definition error.h:45
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition utils.c:1032
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition utils.c:2321
#define SWS_PARAM_DEFAULT
Definition swscale.h:456
SwsScaler
Definition swscale.h:96
@ SWS_SCALE_POINT
nearest neighbor (point sampling)
Definition swscale.h:100
@ SWS_SCALE_SINC
unwindowed sinc
Definition swscale.h:103
@ SWS_BITEXACT
Definition swscale.h:178
CHECKASM_API void checkasm_init(void *buf, size_t bytes)
Initialize a buffer with pathological test patterns.
Definition utils.c:431
static const int offsets[]
Definition hevc_pel.c:34
cl_device_type type
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition intra.c:278
#define u(width, name, range_min, range_max)
Definition cbs_apv.c:68
const char * desc
Definition libsvtav1.c:83
@ INPUT_LUT_SIZE
Definition lut3d.h:36
SwsLut3D * ff_sws_lut3d_alloc(void)
Allocates a refstruct.
Definition lut3d.c:33
#define FFMIN(a, b)
Definition macros.h:49
enum AVColorRange range
#define DECLARE_ALIGNED_64(t, v)
const SwsOpBackend *const ff_sws_op_backends[]
Definition ops.c:42
void ff_sws_compiled_op_unref(SwsCompiledOp *comp)
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
#define checkasm_call_checked(func,...)
Definition aarch64.h:93
const char * name
Definition qsvenc.c:142
#define MIN(a, b)
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition refstruct.c:120
static void * av_refstruct_allocz(size_t size)
Equivalent to av_refstruct_alloc_ext(size, 0, NULL, NULL)
Definition refstruct.h:105
#define FF_ARRAY_ELEMS(a)
#define vsnprintf
Definition snprintf.h:36
#define snprintf
Definition snprintf.h:34
SwsOpFunc func
Main external API structure.
Definition swscale.h:227
uint8_t size_log2
Definition uops.h:239
int src_size
The relative sizes of the input and output images.
Definition filters.h:57
SwsScaler scaler
The filter kernel and parameters to use.
Definition filters.h:49
SwsPixelType type
Definition uops.h:197
char name[16]
Extra metadata about the filter, used to inform the optimizer / range tracker about the filter's beha...
Definition filters.h:119
int * offsets
The computed source pixel positions for each row of the filter.
Definition filters.h:105
uint32_t zero
Definition uops.h:225
uint32_t one
Definition uops.h:224
int dynamic
Definition uops.h:243
Append a set of operations for applying a gamut/tone mapping 3D LUT to the pixels.
Definition lut3d.h:50
v3u16_t output[OUTPUT_LUT_SIZE_PT][OUTPUT_LUT_SIZE_PT][OUTPUT_LUT_SIZE_I]
Definition lut3d.h:56
v3u16_t input[INPUT_LUT_SIZE][INPUT_LUT_SIZE][INPUT_LUT_SIZE]
Definition lut3d.h:55
bool dynamic
Definition lut3d.h:52
v2u16_t tone_map[TONE_LUT_SIZE+1]
Definition lut3d.h:59
const char * name
int(* compile_uops)(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
Alternative to compile that takes a list of micro-ops directly.
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
Copyright (C) 2026 Niklas Haas.
int32_t block_size_out[4]
ptrdiff_t out_stride[4]
uint8_t * out[4]
int32_t * in_offset_x
Pixel offset map; for horizontal scaling, in bytes.
const uint8_t * in[4]
int32_t height
int32_t slice_h
ptrdiff_t in_stride[4]
int32_t width
int32_t block_size_in[4]
ptrdiff_t in_bump[4]
Pointer bump, difference between stride and processed line size.
ptrdiff_t out_bump[4]
int32_t * in_bump_y
Line bump; determines how many additional lines to advance (after incrementing normally to the next l...
uint8_t pattern[4]
Definition uops.h:215
int pixel_size_max
Definition uops.h:307
Definition uops.h:264
SwsPixel scalar
Definition uops.h:275
SwsCompMask mask
Definition uops.h:268
SwsUOpType uop
Definition uops.h:267
SwsUOpParams par
Definition uops.h:269
const SwsLut3D * lut3d
Definition uops.h:279
SwsFilterWeights * kernel
Definition uops.h:273
SwsPixel mat4[4][5]
Definition uops.h:277
SwsPixel * ptr
Definition uops.h:274
union SwsUOp::@242237116251216327057105100216205033300341206345 data
SwsPixelType type
Definition uops.h:266
SwsPixel vec4[4]
Definition uops.h:276
Definition sw_ops.c:41
int pixel_bits_out
Definition sw_ops.c:52
SwsPixelType type_out
Definition sw_ops.c:48
SwsCompMask planes_in
Definition sw_ops.c:49
SwsPixelType type_in
Definition sw_ops.c:47
SwsUOp uops[MAX_UOPS]
Definition sw_ops.c:43
int num_uops
Definition sw_ops.c:44
SwsCompMask planes_out
Definition sw_ops.c:50
unsigned ranges[NB_PLANES]
Definition sw_ops.c:53
const char * name
Definition sw_ops.c:42
int pixel_bits_in
Definition sw_ops.c:51
Definition idctdsp.c:35
const char * name
Definition idctdsp.c:36
uint16_t y
Definition csputils.h:69
#define stride
static void fill16(uint16_t *line, int num, unsigned range)
Definition sw_ops.c:110
static void fill8(uint8_t *line, int num, unsigned range)
Definition sw_ops.c:120
static void check_expand_bit(const char *name, const SwsUOp *uop)
Definition sw_ops.c:533
static void check_lut_3d(const char *name, SwsUOp *uop)
Definition sw_ops.c:637
#define CHECK_FOR(UOP, CHECK)
Definition sw_ops.c:666
static void check_scalar(const char *name, SwsUOp *uop)
Definition sw_ops.c:463
static void fill32f(float *line, int num, unsigned range)
Definition sw_ops.c:97
static void check_write(const char *name, const SwsUOp *uop)
Definition sw_ops.c:484
static SwsPixel rndpx(SwsPixelType type)
Definition sw_ops.c:86
static void check_uop(const char *name, const SwsUOp *uop, SwsCompMask mask_in, SwsCompMask mask_out, const unsigned ranges[NB_PLANES])
Definition sw_ops.c:352
static void run_test(const Test *test)
Definition sw_ops.c:278
static float rndf(void)
Definition sw_ops.c:66
static void check_filter(const char *name, SwsUOp *uop)
Definition sw_ops.c:493
static void check_vec4(const char *name, SwsUOp *uop)
Definition sw_ops.c:469
void checkasm_check_sw_ops(void)
Definition sw_ops.c:673
static void check_read(const char *name, SwsUOp *uop)
Definition sw_ops.c:479
static void check_dither(const char *name, SwsUOp *uop)
Definition sw_ops.c:614
static void check_linear(const char *name, SwsUOp *uop)
Definition sw_ops.c:597
#define MK_RANGES(R)
Definition sw_ops.c:477
@ LINES
Definition sw_ops.c:38
@ NB_PLANES
Definition sw_ops.c:36
@ MAX_UOPS
Definition sw_ops.c:35
static void check_scale(const char *name, SwsUOp *uop)
Definition sw_ops.c:560
static void check_simple(const char *name, const SwsUOp *uop)
Definition sw_ops.c:458
static void check_pack(const char *name, const SwsUOp *uop)
Definition sw_ops.c:586
static void check_swizzle(const char *name, const SwsUOp *uop)
Definition sw_ops.c:526
static void check_unpack(const char *name, const SwsUOp *uop)
Definition sw_ops.c:577
static SwsPixelType pixel_type_to_int(const SwsPixelType type)
Definition sw_ops.c:130
static void check_cast(const char *name, const SwsUOp *uop)
Definition sw_ops.c:538
static void check_range(const char *name, const SwsUOp *uop, const unsigned ranges[NB_PLANES])
Definition sw_ops.c:451
static const char * tprintf(char buf[], size_t size, const char *fmt,...)
Definition sw_ops.c:57
static SwsPixel constpx(SwsPixelType type, int val)
Definition sw_ops.c:75
static void fill32(uint32_t *line, int num, unsigned range)
Definition sw_ops.c:104
static void check_compiled(const Test *test, const SwsCompiledOp *comp_ref, const SwsCompiledOp *comp_new)
Definition sw_ops.c:143
#define FMT(fmt,...)
Definition sw_ops.c:56
#define checkasm_call(func,...)
Call a function with signal handling.
Definition test.h:252
CHECKASM_API CheckasmKey CHECKASM_API void checkasm_set_func_variant(const char *id,...) CHECKASM_PRINTF(1
Set a custom variant identifier for the next checkasm_check_func() call.
#define src1
Definition h264pred.c:141
#define src0
Definition h264pred.c:140
#define PIXELS
static AVFormatContext * ctx
Definition movenc.c:49
#define height
Definition dsp.h:89
int size
SwsDitherUOp dither
Definition uops.h:260
SwsFilterUOp filter
Definition uops.h:254
SwsLut3DUOp lut3d
Definition uops.h:261
SwsLinearUOp lin
Definition uops.h:259
SwsPackUOp pack
Definition uops.h:257
int ff_sws_dither_height(const SwsDitherUOp *dither)
Computes (1 << size_log2) + MAX(y_offset).
Definition uops.c:232
@ SWS_COMP_ALL
Definition uops.h:96
SwsPixelType
Definition uops.h:39
@ SWS_PIXEL_F32
Definition uops.h:44
@ SWS_PIXEL_U32
Definition uops.h:43
@ SWS_PIXEL_U16
Definition uops.h:42
@ SWS_PIXEL_NONE
Definition uops.h:40
@ SWS_PIXEL_U8
Definition uops.h:41
#define SWS_COMP(X)
Definition uops.h:97
#define SWS_COMP_TEST(mask, X)
Definition uops.h:98
#define SWS_COMP_ELEMS(N)
Definition uops.h:100
#define SWS_MASK(I, J)
Definition uops.h:231
@ SWS_UOP_TO_U8
Definition uops.h:159
@ SWS_UOP_EXPAND_QUAD
Definition uops.h:158
@ SWS_UOP_READ_PLANAR
Definition uops.h:133
@ SWS_UOP_WRITE_PLANAR
Definition uops.h:142
@ SWS_UOP_READ_NIBBLE
Definition uops.h:138
@ SWS_UOP_READ_BIT
Definition uops.h:139
@ SWS_UOP_WRITE_NIBBLE
Definition uops.h:144
@ SWS_UOP_READ_PLANAR_FH
Definition uops.h:134
@ SWS_UOP_WRITE_PACKED
Definition uops.h:143
@ SWS_UOP_WRITE_BIT
Definition uops.h:145
@ SWS_UOP_READ_PACKED
Definition uops.h:137
@ SWS_UOP_EXPAND_PAIR
Definition uops.h:157
@ SWS_UOP_TO_U16
Definition uops.h:160
@ SWS_UOP_READ_PALETTE
Definition uops.h:140
@ SWS_UOP_READ_PLANAR_FV
Definition uops.h:135
@ SWS_UOP_TO_U32
Definition uops.h:161
@ SWS_UOP_TO_F32
Definition uops.h:162
#define SWS_COMP_COUNT(mask)
Definition uops.h:101
static av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition uops.h:63
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:93
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:50
#define NB_PLANES
Definition vf_geq.c:41
#define LINEAR
#define CLEAR(destin)
Definition wavpackenc.c:50