FFmpeg
Loading...
Searching...
No Matches
uops.c
Go to the documentation of this file.
1/**
2 * Copyright (C) 2026 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <stdbool.h>
22
23#include "libavutil/avassert.h"
24#include "libavutil/mem.h"
25#include "libavutil/refstruct.h"
26
27#include "ops.h"
28#include "uops.h"
29#include "uops_list.h"
30
31int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b)
32{
33 if (a->type != b->type)
34 return (int) a->type - b->type;
35 if (a->uop != b->uop)
36 return (int) a->uop - b->uop;
37 if (a->mask != b->mask)
38 return (int) a->mask - b->mask;
39 return memcmp(&a->par, &b->par, sizeof(a->par));
40}
41
42static const struct {
43 char abbr[32];
45#define UOP_NAME(OP, ABBR) [OP] = { ABBR },
47#undef UOP_NAME
48};
49
51{
52 av_assert1(val.den != 0);
53 switch (type) {
54 case SWS_PIXEL_U8: return (SwsPixel) { .u8 = val.num / val.den };
55 case SWS_PIXEL_U16: return (SwsPixel) { .u16 = val.num / val.den };
56 case SWS_PIXEL_U32: return (SwsPixel) { .u32 = val.num / val.den };
57 case SWS_PIXEL_F32: return (SwsPixel) { .f32 = (float) val.num / val.den };
58 case SWS_PIXEL_NONE:
59 case SWS_PIXEL_TYPE_NB: break;
60 }
61
62 av_unreachable("Invalid pixel type!");
63 return (SwsPixel) {0};
64}
65
66#define Q2PIXEL(val) pixel_from_q64(op->type, val)
67
69{
71 case 1: return val.u8 == UINT8_MAX;
72 case 2: return val.u16 == UINT16_MAX;
73 case 4: return val.u32 == UINT32_MAX;
74 default: break;
75 }
76
77 av_unreachable("Invalid pixel type!");
78 return false;
79}
80
82{
83 AVBPrint bp;
85
86 if (op->type != SWS_PIXEL_NONE)
87 av_bprintf(&bp, "%s_", ff_sws_pixel_type_name(op->type));
88 av_bprintf(&bp, "%s", uop_names[op->uop].abbr);
89
90 if (op->mask)
91 av_bprintf(&bp, "_%s", ff_sws_comp_mask_str(op->mask));
92
93 const SwsUOpParams *par = &op->par;
94 switch (op->uop) {
99 break;
101 av_bprintf(&bp, "_%x_%u_%u", par->shuffle.clear_value,
103 break;
104 case SWS_UOP_LSHIFT:
105 case SWS_UOP_RSHIFT:
106 av_bprintf(&bp, "_%u", par->shift.amount);
107 break;
108 case SWS_UOP_PERMUTE:
109 case SWS_UOP_COPY:
110 av_bprint_chars(&bp, '_', 1);
111 for (int i = 0; i < par->move.num_moves; i++)
112 av_bprint_chars(&bp, "txyzw"[par->move.dst[i] + 1], 1);
113 av_bprint_chars(&bp, '_', 1);
114 for (int i = 0; i < par->move.num_moves; i++)
115 av_bprint_chars(&bp, "txyzw"[par->move.src[i] + 1], 1);
116 break;
117 case SWS_UOP_PACK:
118 case SWS_UOP_UNPACK:
119 av_bprint_chars(&bp, '_', 1);
120 for (int i = 0; i < 4 && par->pack.pattern[i]; i++)
121 av_bprintf(&bp, "%x", par->pack.pattern[i]);
122 break;
123 case SWS_UOP_CLEAR:
124 av_bprint_chars(&bp, '_', 1);
125 for (int i = 0; i < 4; i++) {
126 if (!SWS_COMP_TEST(op->mask, i))
127 continue;
128 else if (SWS_COMP_TEST(par->clear.one, i))
129 av_bprint_chars(&bp, '1', 1);
130 else if (SWS_COMP_TEST(par->clear.zero, i))
131 av_bprint_chars(&bp, '0', 1);
132 else
133 av_bprint_chars(&bp, 'x', 1);
134 }
135 break;
136 case SWS_UOP_LINEAR:
138 for (int i = 0; i < 4; i++) {
139 if (!SWS_COMP_TEST(op->mask, i))
140 continue;
141 av_bprint_chars(&bp, '_', 1);
142 for (int j = 0; j < 5; j++) {
143 if (par->lin.one & SWS_MASK(i, j))
144 av_bprint_chars(&bp, '1', 1);
145 else if (par->lin.zero & SWS_MASK(i, j))
146 av_bprint_chars(&bp, '0', 1);
147 else if (par->lin.exact & SWS_MASK(i, j))
148 av_bprint_chars(&bp, 'X', 1);
149 else
150 av_bprint_chars(&bp, 'x', 1);
151 }
152 }
153 break;
154 case SWS_UOP_DITHER:
155 for (int i = 0; i < 4; i++) {
156 if (SWS_COMP_TEST(op->mask, i))
157 av_bprintf(&bp, "_%d", par->dither.y_offset[i]);
158 }
159 const unsigned size = 1u << par->dither.size_log2;
160 av_bprintf(&bp, "_%ux%u", size, size);
161 break;
162 case SWS_UOP_LUT_3D:
163 av_bprintf(&bp, "_%s", par->lut3d.dynamic ? "dynamic" : "static");
164 break;
165 }
166
168}
169
170static void uop_uninit(SwsUOp *uop)
171{
172 switch (uop->uop) {
173 case SWS_UOP_DITHER:
175 break;
180 break;
181 case SWS_UOP_LUT_3D:
183 break;
184 }
185
186 *uop = (SwsUOp) {0};
187}
188
190{
191 SwsUOpList *ops = *p_ops;
192 if (!ops)
193 return;
194
195 for (int i = 0; i < ops->num_ops; i++)
196 uop_uninit(&ops->ops[i]);
197
198 av_freep(&ops->ops);
199 av_free(ops);
200 *p_ops = NULL;
201}
202
204{
205 return av_mallocz(sizeof(SwsUOpList));
206}
207
209{
210 if (!av_dynarray2_add((void **) &uops->ops, &uops->num_ops,
211 sizeof(*uop), (uint8_t *) uop))
212 {
213 uop_uninit(uop);
214 return AVERROR(ENOMEM);
215 }
216
217 *uop = (SwsUOp) {0};
218 return 0;
219}
220
221void ff_sws_uop_list_remove_at(SwsUOpList *uops, int index, int count)
222{
223 const int end = uops->num_ops - count;
224 av_assert2(index >= 0 && count >= 0 && index + count <= uops->num_ops);
225 for (int i = 0; i < count; i++)
226 uop_uninit(&uops->ops[index + i]);
227 for (int i = index; i < end; i++)
228 uops->ops[i] = uops->ops[i + count];
229 uops->num_ops = end;
230}
231
233{
234 int max_offset = 0;
235 for (int i = 0; i < 4; i++)
236 max_offset = FFMAX(max_offset, dither->y_offset[i]);
237 return (1 << dither->size_log2) + max_offset;
238}
239
241{
242 switch (ff_sws_pixel_type_size(type)) {
243 case 1: return SWS_PIXEL_U8;
244 case 2: return SWS_PIXEL_U16;
245 case 4: return SWS_PIXEL_U32;
246 default: break;
247 }
248
249 av_unreachable("Invalid pixel type!");
250 return SWS_PIXEL_NONE;
251}
252
253static bool exact_product_f32(float a, float b)
254{
255 volatile float prod = a * b;
256 volatile float result = b ? prod / b : 0.0f;
257 return !b || result == a;
258}
259
261 const SwsComps *comps, int idx)
262{
263 const AVRational64 minq = comps->min[idx];
264 const AVRational64 maxq = comps->max[idx];
266 return true;
267 else if (!minq.den || !maxq.den)
268 return false; /* unknown bounds */
269
270 const SwsPixel min = pixel_from_q64(type, minq);
271 const SwsPixel max = pixel_from_q64(type, maxq);
272 switch (type) {
273 case SWS_PIXEL_F32:
274 return exact_product_f32(coef.f32, min.f32) &&
275 exact_product_f32(coef.f32, max.f32);
276 }
277
278 av_unreachable("Invalid pixel type!");
279 return false;
280}
281
283{
284 if (!(flags & SWS_UOP_FLAG_FMA))
285 return false;
286 if (!(ctx->flags & SWS_BITEXACT))
287 return true;
288 if (!ff_sws_pixel_type_is_int(op->type))
289 return false;
290
291 const int bits = ff_sws_pixel_type_size(op->type) * 8;
292 const uint64_t max_val = UINT64_MAX >> (64 - bits);
293
294 /* Maximum value representable losslessly as float. Note that this is
295 * currently true only for U8, but that may change if we ever update the
296 * value of SWS_FILTER_SCALE. */
297 return max_val * SWS_FILTER_SCALE <= (1 << 22);
298}
299
301 const SwsOp *op)
302{
303 SwsUOp uop = {
304 .type = op->type,
305 .mask = SWS_COMP_MASK(op->rw.elems > 0, op->rw.elems > 1,
306 op->rw.elems > 2, op->rw.elems > 3),
307 };
308
309 /* Non-filtered reads don't care about the exact pixel contents */
310 if (!op->rw.filter.op)
311 uop.type = pixel_type_to_int(op->type);
312
313 const bool is_read = op->op == SWS_OP_READ;
314 if (op->rw.filter.op) {
315 if (op->op == SWS_OP_WRITE || op->rw.frac || op->rw.mode != SWS_RW_PLANAR)
316 return AVERROR(ENOTSUP);
317 uop.par.filter.type = op->rw.filter.type;
318 uop.data.kernel = av_refstruct_ref(op->rw.filter.kernel);
319 if (op->rw.filter.op == SWS_OP_FILTER_H) {
321 } else if (check_filter_fma(ctx, flags, op)) {
323 } else {
325 }
326 } else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1) {
327 if (op->rw.frac)
328 return AVERROR(ENOTSUP);
330 } else if (op->rw.mode == SWS_RW_PALETTE) {
331 if (op->rw.frac || !is_read)
332 return AVERROR(ENOTSUP);
334 } else if (op->rw.frac == 3) {
335 uop.uop = is_read ? SWS_UOP_READ_BIT : SWS_UOP_WRITE_BIT;
336 } else if (op->rw.frac == 1) {
338 } else {
339 av_assert0(!op->rw.frac);
341 }
342
343 const int planes = ff_sws_rw_op_planes(op);
344 if (op->op == SWS_OP_READ) {
346 } else {
348 }
349
350 return ff_sws_uop_list_append(ops, &uop);
351}
352
353static int count_idx(const int *arr, size_t size, int val)
354{
355 int num = 0;
356 for (size_t i = 0; i < size; i++) {
357 if (arr[i] == val)
358 num++;
359 }
360
361 return num;
362}
363
364static int translate_swizzle(SwsUOpList *ops, const SwsOp *op)
365{
366 SwsUOp uop = {
367 .uop = SWS_UOP_PERMUTE,
368 .type = pixel_type_to_int(op->type),
370 };
371 SwsMoveUOp *par = &uop.par.move;
372
373 /* Mask of components that are not yet satisfied */
374 SwsCompMask todo = uop.mask;
375 for (int i = 0; i < 4; i++) {
376 if (op->swizzle.in[i] == i)
377 todo &= ~SWS_COMP(i);
378 }
379
380 /* Mask of components whose value is required for the final output */
381 SwsCompMask needed = 0;
382 for (int i = 0; i < 4; i++) {
383 if (SWS_OP_NEEDED(op, i))
384 needed |= SWS_COMP(op->swizzle.in[i]);
385 }
386
387 /* Current mapping of registers to components */
388 int idx[4 + 1] = { 0, 1, 2, 3, -1 }; /* +1 for tmp */
389
390 /* Decompose the swizzle mask into a series of register-register moves */
391 while (todo) {
392 int dst = -1, src = -1;
393
394 /* Find next unsatisfied dst <- src move that doesn't clobber a value */
395 for (dst = 0; dst < 4; dst++) {
396 if (!SWS_COMP_TEST(todo, dst))
397 continue; /* already satisfied */
398 const int cur = idx[dst];
399 if (count_idx(idx, FF_ARRAY_ELEMS(idx), cur) == 1 && SWS_COMP_TEST(needed, cur))
400 continue; /* clobbers last remaining, still-needed value */
401 for (src = 0; src < FF_ARRAY_ELEMS(idx); src++) {
402 if (idx[src] == op->swizzle.in[dst]) {
403 /* Prevent read-after-write dependency. */
404 if (par->num_moves > 0 && src == par->dst[par->num_moves - 1])
405 src = par->src[par->num_moves - 1];
406 break;
407 }
408 }
410 todo &= ~SWS_COMP(dst);
411 break;
412 }
413
414 if (dst == 4) {
415 /* Stuck in a cycle, break it by saving to the scratch register */
416 dst = 4;
417 for (src = 0; src < 4; src++) {
418 if (SWS_COMP_TEST(todo, src)) {
419 needed &= ~SWS_COMP(idx[src]);
420 break;
421 }
422 }
423 av_assert1(src < 4);
424 }
425
427 par->dst[par->num_moves] = dst > 3 ? -1 : dst;
428 par->src[par->num_moves] = src > 3 ? -1 : src;
429 par->num_moves++;
430 idx[dst] = idx[src];
431 }
432
433 /* Check for duplicates in the final register map */
434 SwsCompMask seen = 0;
435 for (int i = 0; i < 4; i++) {
436 if (!SWS_COMP_TEST(uop.mask, i))
437 continue;
438 av_assert2(idx[i] >= 0); /* should be no tmp register */
439 const SwsCompMask bit = SWS_COMP(idx[i]);
440 if (seen & bit) {
441 uop.uop = SWS_UOP_COPY;
442 break;
443 }
444 seen |= bit;
445 }
446
447 /* Add any extra unused components to the mask, to prevent generating
448 * duplicate uops like permute_xyz_txy_xyt and permute_xyzw_txy_xyt */
449 for (int i = 0; i < 4; i++) {
450 const SwsCompMask bit = SWS_COMP(i);
451 if (!(seen & bit) && idx[i] == i)
452 uop.mask |= bit;
453 }
454
455 return ff_sws_uop_list_append(ops, &uop);
456}
457
458static int translate_dither_op(SwsUOpList *ops, const SwsOp *op)
459{
460 SwsUOp uop = {
461 .type = op->type,
462 .uop = SWS_UOP_DITHER,
463 .par.dither.size_log2 = op->dither.size_log2,
464 };
465
466 if (op->dither.size_log2 == 0) {
467 /* Constant offset */
468 const SwsPixel val = Q2PIXEL(op->dither.matrix[0]);
469 uop.uop = SWS_UOP_ADD;
470 for (int i = 0; i < 4; i++) {
471 if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0)
472 continue;
473 uop.mask |= SWS_COMP(i);
474 uop.data.vec4[i] = val;
475 }
476
477 return ff_sws_uop_list_append(ops, &uop);
478 }
479
480 const int size = 1 << op->dither.size_log2;
481 for (int i = 0; i < 4; i++) {
482 if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0)
483 continue;
484 const uint8_t off = op->dither.y_offset[i] & (size - 1);
485 uop.mask |= SWS_COMP(i);
486 uop.par.dither.y_offset[i] = off;
487 }
488
489 /* Allocate extra rows to allow over-reading for row offsets. Note that
490 * y_offset is currently never larger than 5, so the extra space needed
491 * for this over-allocation is bounded by 5 * size * sizeof(float),
492 * typically 320 bytes for a 16x16 dither matrix. */
493 const int stride = size * sizeof(SwsPixel);
494 const int num_rows = ff_sws_dither_height(&uop.par.dither);
495 SwsPixel *matrix = uop.data.ptr = av_refstruct_allocz(num_rows * stride);
496 if (!matrix)
497 return AVERROR(ENOMEM);
498
499 for (int i = 0; i < size * size; i++)
500 matrix[i] = Q2PIXEL(op->dither.matrix[i]);
501 memcpy(&matrix[size * size], matrix, (num_rows - size) * stride);
502
503 return ff_sws_uop_list_append(ops, &uop);
504}
505
507 SwsUOpFlags flags, const SwsOp *op,
508 const SwsComps *input)
509{
510 SwsUOp uop = {
511 .type = op->type,
512 .uop = SWS_UOP_LINEAR,
513 };
514
515 const uint32_t mask = ff_sws_linear_mask(&op->lin);
516 const bool bitexact = ctx->flags & SWS_BITEXACT;
517 uint32_t exact = 0;
518
519 for (int i = 0; i < 4; i++) {
520 if (!SWS_OP_NEEDED(op, i) || !(mask & SWS_MASK_ROW(i))) {
521 uop.par.lin.zero |= SWS_MASK_ROW(i);
522 continue;
523 }
524 uop.mask |= SWS_COMP(i);
525 bool nonzero = (op->lin.m[i][4].num != 0);
526 for (int j = 0; j < 5; j++) {
527 const AVRational64 k = op->lin.m[i][j];
528 const SwsPixel px = Q2PIXEL(k);
529 uop.data.mat4[i][j] = px;
530 if (k.num == 0)
531 uop.par.lin.zero |= SWS_MASK(i, j);
532 else if (j < 4 && k.num == k.den)
533 uop.par.lin.one |= SWS_MASK(i, j);
534 else if (j < 4 && nonzero && (!bitexact || exact_prod(uop.type, px, input, j)))
535 exact |= SWS_MASK(i, j);
536 if (k.num != 0)
537 nonzero = true;
538 }
539 }
540
541 if (flags & SWS_UOP_FLAG_FMA) {
542 /* multiplication by 1 and 0 are always exact by definition */
544 uop.par.lin.exact = exact | uop.par.lin.zero | uop.par.lin.one;
545 }
546
547 return ff_sws_uop_list_append(ops, &uop);
548}
549
551{
552 if (factor.den != 1)
553 return false;
554
555 switch (type) {
556 case SWS_PIXEL_U8: return factor.num == UINT8_MAX;
557 case SWS_PIXEL_U16: return factor.num == UINT16_MAX;
558 case SWS_PIXEL_U32: return factor.num == UINT32_MAX;
559 case SWS_PIXEL_F32: return false;
560 case SWS_PIXEL_NONE:
561 case SWS_PIXEL_TYPE_NB: break;
562 }
563
564 av_unreachable("Invalid pixel type!");
565 return false;
566}
567
569 const SwsOp *op, const SwsComps *input)
570{
571 switch (op->op) {
572 case SWS_OP_FILTER_H:
573 case SWS_OP_FILTER_V:
574 return AVERROR(ENOTSUP); /* always handled by subpass splitting */
575 case SWS_OP_READ:
576 case SWS_OP_WRITE:
577 return translate_rw_op(ctx, uops, flags, op);
578 case SWS_OP_SWIZZLE:
579 return translate_swizzle(uops, op);
580 case SWS_OP_DITHER:
581 return translate_dither_op(uops, op);
582 case SWS_OP_LINEAR:
583 return translate_linear_op(ctx, uops, flags, op, input);
584 default:
585 break;
586 }
587
588 /* Default handling for "simple" ops */
589 SwsUOp uop = {
590 .type = op->type,
591 .uop = SWS_UOP_INVALID,
593 };
594
595 switch (op->op) {
596 case SWS_OP_CONVERT:
597 if (op->convert.expand) {
598 av_assert0(op->type == SWS_PIXEL_U8);
599 switch (op->convert.to) {
600 case SWS_PIXEL_U16: uop.uop = SWS_UOP_EXPAND_PAIR; break;
601 case SWS_PIXEL_U32: uop.uop = SWS_UOP_EXPAND_QUAD; break;
602 }
603 } else {
604 switch (op->convert.to) {
605 case SWS_PIXEL_U8: uop.uop = SWS_UOP_TO_U8; break;
606 case SWS_PIXEL_U16: uop.uop = SWS_UOP_TO_U16; break;
607 case SWS_PIXEL_U32: uop.uop = SWS_UOP_TO_U32; break;
608 case SWS_PIXEL_F32: uop.uop = SWS_UOP_TO_F32; break;
609 }
610 }
611 break;
612 case SWS_OP_UNPACK:
613 case SWS_OP_PACK:
615 uop.mask = 0;
616 for (int i = 0; i < 4 && op->pack.pattern[i]; i++) {
617 uop.par.pack.pattern[i] = op->pack.pattern[i];
618 if (op->op == SWS_OP_PACK || SWS_OP_NEEDED(op, i))
619 uop.mask |= SWS_COMP(i);
620 }
621 break;
622 case SWS_OP_LSHIFT:
623 case SWS_OP_RSHIFT:
625 uop.par.shift.amount = op->shift.amount;
626 break;
627 case SWS_OP_CLEAR:
628 uop.uop = SWS_UOP_CLEAR;
629 uop.type = pixel_type_to_int(op->type);
630 uop.mask &= op->clear.mask;
631 for (int i = 0; i < 4; i++) {
632 if (!SWS_COMP_TEST(op->clear.mask, i))
633 continue;
634 const AVRational64 v = op->clear.value[i];
635 const SwsPixel px = Q2PIXEL(op->clear.value[i]);
636 uop.data.vec4[i] = px;
637 if (v.num == 0)
638 uop.par.clear.zero |= SWS_COMP(i);
639 else if (pixel_is_1s(op->type, px))
640 uop.par.clear.one |= SWS_COMP(i);
641 }
642 break;
643 case SWS_OP_SCALE:
644 if (is_expand_bit(op->type, op->scale.factor)) {
646 } else {
647 uop.uop = SWS_UOP_SCALE;
648 uop.data.scalar = Q2PIXEL(op->scale.factor);
649 }
650 break;
651 case SWS_OP_MIN:
652 case SWS_OP_MAX:
653 uop.uop = op->op == SWS_OP_MIN ? SWS_UOP_MIN : SWS_UOP_MAX;
654 uop.mask &= ff_sws_comp_mask_q4(op->clamp.limit);
655 for (int i = 0; i < 4; i++) {
656 if (SWS_COMP_TEST(uop.mask, i))
657 uop.data.vec4[i] = Q2PIXEL(op->clamp.limit[i]);
658 }
659 break;
662 uop.type = pixel_type_to_int(op->type);
663 break;
664 case SWS_OP_LUT_3D:
665 uop.uop = SWS_UOP_LUT_3D;
666 uop.par.lut3d.dynamic = op->lut3d.dynamic;
667 uop.data.lut3d = av_refstruct_ref_c(op->lut3d.lut);
668 break;
669 default:
670 return AVERROR(ENOTSUP);
671 }
672
674 return ff_sws_uop_list_append(uops, &uop);
675}
676
679{
680 SwsComps input = ops->comps_src;
681 for (int i = 0; i < ops->num_ops; i++) {
682 const SwsOp *op = &ops->ops[i];
683 const int pixel_size = ff_sws_pixel_type_size(op->type);
684 if (pixel_size > uops->pixel_size_max)
685 uops->pixel_size_max = pixel_size;
686
687 int ret = translate_op(ctx, uops, flags, op, &input);
688 if (ret < 0)
689 return ret;
690 input = ops->ops[i].comps;
691 }
692
693 return ff_sws_uop_list_optimize(ctx, flags, uops);
694}
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
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition avassert.h:68
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
#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
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define bit(string, value)
Definition cbs_mpeg2.c:56
#define NULL
Definition coverity.c:32
#define min(a, b)
#define max(a, b)
static const uint8_t bits[8]
Definition fastaudio.c:100
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition bprint.c:130
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition bprint.c:85
#define AVERROR(e)
Definition error.h:45
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition mem.c:341
@ SWS_BITEXACT
Definition swscale.h:178
int index
Definition gxfenc.c:90
int a
cl_device_type type
#define b
Definition input.c:43
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition anm.c:76
static const int factor[16]
Definition vf_pp7.c:98
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition filters.h:40
static const struct @257111027162314367033347246032313251342043035002 planes[]
static const uint16_t mask[17]
Definition lzw.c:38
#define FFMAX(a, b)
Definition macros.h:47
Memory handling functions.
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition ops.c:802
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition ops.c:123
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition ops.c:56
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition ops.c:100
int ff_sws_rw_op_planes(const SwsOp *op)
Return the number of planes involved in a read/write operation.
Definition ops.c:133
@ SWS_OP_RSHIFT
Definition ops.h:49
@ SWS_OP_SWIZZLE
Definition ops.h:43
@ SWS_OP_LSHIFT
Definition ops.h:48
@ SWS_OP_FILTER_V
Definition ops.h:64
@ SWS_OP_SCALE
Definition ops.h:56
@ SWS_OP_FILTER_H
Definition ops.h:63
@ SWS_OP_WRITE
Definition ops.h:41
@ SWS_OP_READ
Definition ops.h:40
@ SWS_OP_CLEAR
Definition ops.h:52
@ SWS_OP_SWAP_BYTES
Definition ops.h:42
@ SWS_OP_MIN
Definition ops.h:54
@ SWS_OP_UNPACK
Definition ops.h:46
@ SWS_OP_LINEAR
Definition ops.h:59
@ SWS_OP_PACK
Definition ops.h:47
@ SWS_OP_DITHER
Definition ops.h:60
@ SWS_OP_MAX
Definition ops.h:55
@ SWS_OP_LUT_3D
Definition ops.h:67
@ SWS_OP_CONVERT
Definition ops.h:53
@ SWS_RW_PALETTE
Definition ops.h:109
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
Definition ops.h:107
@ SWS_RW_PACKED
Definition ops.h:108
#define SWS_OP_NEEDED(op, idx)
Definition ops.h:265
int ff_sws_uop_list_optimize(SwsContext *ctx, SwsUOpFlags flags, SwsUOpList *uops)
Called internally by ff_sws_ops_translate().
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
const void * av_refstruct_ref_c(const void *obj)
Analog of av_refstruct_ref(), but for constant objects.
Definition refstruct.c:149
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition refstruct.c:140
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)
64-bit Rational number (pair of numerator and denominator).
Definition rational64.h:52
int64_t num
Numerator.
Definition rational64.h:53
int64_t den
Denominator.
Definition rational64.h:54
SwsCompMask one
Definition uops.h:219
SwsCompMask zero
Definition uops.h:220
Definition ops.h:86
AVRational64 min[4]
Definition ops.h:91
AVRational64 max[4]
Definition ops.h:91
Main external API structure.
Definition swscale.h:227
uint8_t size_log2
Definition uops.h:239
uint8_t y_offset[4]
Definition uops.h:238
SwsPixelType type
Definition uops.h:197
uint32_t zero
Definition uops.h:225
uint32_t one
Definition uops.h:224
uint32_t exact
Definition uops.h:228
int dynamic
Definition uops.h:243
int8_t src[SWS_UOP_MOVE_MAX]
Definition uops.h:211
int num_moves
Definition uops.h:207
int8_t dst[SWS_UOP_MOVE_MAX]
Definition uops.h:210
Helper struct for representing a list of operations.
Definition ops.h:293
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition ops.h:312
SwsOp * ops
Definition ops.h:294
int num_ops
Definition ops.h:295
Definition ops.h:237
SwsComps comps
Metadata about the operation's input/output components.
Definition ops.h:262
uint8_t pattern[4]
Definition uops.h:215
uint8_t amount
Definition uops.h:201
uint8_t write_size
Definition uops.h:188
uint8_t read_size
Definition uops.h:187
uint8_t clear_value
Definition uops.h:186
SwsUOp * ops
Definition uops.h:301
int pixel_size_max
Definition uops.h:307
int num_ops
Definition uops.h:302
SwsCompMask planes_in
Definition uops.h:305
SwsCompMask planes_out
Definition uops.h:306
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
#define stride
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
#define src
Definition vp8dsp.c:248
int size
float f32
Definition uops.h:84
SwsMoveUOp move
Definition uops.h:256
SwsClearUOp clear
Definition uops.h:258
SwsDitherUOp dither
Definition uops.h:260
SwsFilterUOp filter
Definition uops.h:254
SwsLut3DUOp lut3d
Definition uops.h:261
SwsShuffleUOp shuffle
Definition uops.h:253
SwsLinearUOp lin
Definition uops.h:259
SwsShiftUOp shift
Definition uops.h:255
SwsPackUOp pack
Definition uops.h:257
char abbr[32]
Definition uops.c:43
int ff_sws_ops_translate(SwsContext *ctx, const SwsOpList *ops, SwsUOpFlags flags, SwsUOpList *uops)
Translate a list of operations down to micro-ops, which can be further optimized and then directly ex...
Definition uops.c:677
int ff_sws_dither_height(const SwsDitherUOp *dither)
Computes (1 << size_log2) + MAX(y_offset).
Definition uops.c:232
static bool check_filter_fma(SwsContext *ctx, SwsUOpFlags flags, const SwsOp *op)
Definition uops.c:282
static void uop_uninit(SwsUOp *uop)
Definition uops.c:170
int ff_sws_uop_list_append(SwsUOpList *uops, SwsUOp *uop)
Definition uops.c:208
static SwsPixel pixel_from_q64(SwsPixelType type, AVRational64 val)
Definition uops.c:50
#define UOP_NAME(OP, ABBR)
static bool exact_prod(SwsPixelType type, SwsPixel coef, const SwsComps *comps, int idx)
Definition uops.c:260
void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX])
Definition uops.c:81
static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op, const SwsComps *input)
Definition uops.c:506
int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b)
Copyright (C) 2026 Niklas Haas.
Definition uops.c:31
static bool pixel_is_1s(SwsPixelType type, SwsPixel val)
Definition uops.c:68
static int translate_dither_op(SwsUOpList *ops, const SwsOp *op)
Definition uops.c:458
SwsUOpList * ff_sws_uop_list_alloc(void)
Definition uops.c:203
void ff_sws_uop_list_free(SwsUOpList **p_ops)
Definition uops.c:189
#define Q2PIXEL(val)
Definition uops.c:66
static int translate_swizzle(SwsUOpList *ops, const SwsOp *op)
Definition uops.c:364
static int translate_rw_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op)
Definition uops.c:300
void ff_sws_uop_list_remove_at(SwsUOpList *uops, int index, int count)
Definition uops.c:221
static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags, const SwsOp *op, const SwsComps *input)
Definition uops.c:568
static int count_idx(const int *arr, size_t size, int val)
Definition uops.c:353
static const struct @145311200363243152256244361015041277337174162300 uop_names[SWS_UOP_TYPE_NB]
static bool is_expand_bit(SwsPixelType type, AVRational64 factor)
Definition uops.c:550
static SwsPixelType pixel_type_to_int(const SwsPixelType type)
Definition uops.c:240
static bool exact_product_f32(float a, float b)
Definition uops.c:253
uint32_t SwsUOpFlags
Definition uops.h:122
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_TYPE_NB
Definition uops.h:45
@ SWS_PIXEL_NONE
Definition uops.h:40
@ SWS_PIXEL_U8
Definition uops.h:41
#define SWS_COMP(X)
Definition uops.h:97
#define ff_sws_comp_mask_str(mask)
Definition uops.h:110
#define SWS_UOP_MOVE_MAX
Definition uops.h:206
#define SWS_MASK_ROW(I)
Definition uops.h:233
#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_PACK
Definition uops.h:172
@ SWS_UOP_PERMUTE
Definition uops.h:151
@ 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_MAX
Definition uops.h:168
@ SWS_UOP_READ_BIT
Definition uops.h:139
@ SWS_UOP_SWAP_BYTES
Definition uops.h:155
@ SWS_UOP_MIN
Definition uops.h:167
@ SWS_UOP_LINEAR
Definition uops.h:176
@ SWS_UOP_RSHIFT
Definition uops.h:174
@ SWS_UOP_COPY
Definition uops.h:152
@ SWS_UOP_WRITE_NIBBLE
Definition uops.h:144
@ SWS_UOP_INVALID
Definition uops.h:130
@ SWS_UOP_LINEAR_FMA
Definition uops.h:177
@ SWS_UOP_READ_PLANAR_FH
Definition uops.h:134
@ SWS_UOP_SCALE
Definition uops.h:165
@ SWS_UOP_WRITE_PACKED
Definition uops.h:143
@ SWS_UOP_WRITE_BIT
Definition uops.h:145
@ SWS_UOP_READ_PLANAR_FV_FMA
Definition uops.h:136
@ SWS_UOP_READ_PACKED
Definition uops.h:137
@ SWS_UOP_LUT_3D
Definition uops.h:179
@ SWS_UOP_EXPAND_PAIR
Definition uops.h:157
@ SWS_UOP_TO_U16
Definition uops.h:160
@ SWS_UOP_DITHER
Definition uops.h:178
@ SWS_UOP_ADD
Definition uops.h:166
@ SWS_UOP_TYPE_NB
Definition uops.h:182
@ SWS_UOP_CLEAR
Definition uops.h:175
@ SWS_UOP_READ_PALETTE
Definition uops.h:140
@ SWS_UOP_EXPAND_BIT
Definition uops.h:156
@ SWS_UOP_READ_PLANAR_FV
Definition uops.h:135
@ SWS_UOP_TO_U32
Definition uops.h:161
@ SWS_UOP_RW_SHUFFLE
Definition uops.h:148
@ SWS_UOP_UNPACK
Definition uops.h:171
@ SWS_UOP_TO_F32
Definition uops.h:162
@ SWS_UOP_LSHIFT
Definition uops.h:173
#define SWS_COMP_MASK(X, Y, Z, W)
Definition uops.h:102
@ SWS_UOP_FLAG_FMA
Definition uops.h:125
#define SWS_UOP_NAME_MAX
Generate a unique name for a SwsUOp.
Definition uops.h:297
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 UOPS_LIST(ENTRY)
This file is part of FFmpeg.
Definition uops_list.h:23
static const uint16_t dither[8][8]
Definition vf_gradfun.c:46