FFmpeg
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 #include "libavutil/tree.h"
27 
28 #include "ops.h"
29 #include "ops_internal.h"
30 #include "uops.h"
31 
32 int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b)
33 {
34  if (a->type != b->type)
35  return (int) a->type - b->type;
36  if (a->uop != b->uop)
37  return (int) a->uop - b->uop;
38  if (a->mask != b->mask)
39  return (int) a->mask - b->mask;
40  return memcmp(&a->par, &b->par, sizeof(a->par));
41 }
42 
43 static const struct {
44  char full[32];
45  char abbr[32];
47 #define UOP_NAME(OP, ABBR) [OP] = { #OP, ABBR }
48  UOP_NAME(SWS_UOP_INVALID, "invalid"),
49  UOP_NAME(SWS_UOP_READ_PLANAR, "read_planar"),
50  UOP_NAME(SWS_UOP_READ_PLANAR_FH, "read_planar_fh"),
51  UOP_NAME(SWS_UOP_READ_PLANAR_FV, "read_planar_fv"),
52  UOP_NAME(SWS_UOP_READ_PLANAR_FV_FMA, "read_planar_fv_fma"),
53  UOP_NAME(SWS_UOP_READ_PACKED, "read_packed"),
54  UOP_NAME(SWS_UOP_READ_NIBBLE, "read_nibble"),
55  UOP_NAME(SWS_UOP_READ_BIT, "read_bit"),
56  UOP_NAME(SWS_UOP_READ_PALETTE, "read_palette"),
57  UOP_NAME(SWS_UOP_WRITE_PLANAR, "write_planar"),
58  UOP_NAME(SWS_UOP_WRITE_PACKED, "write_packed"),
59  UOP_NAME(SWS_UOP_WRITE_NIBBLE, "write_nibble"),
60  UOP_NAME(SWS_UOP_WRITE_BIT, "write_bit"),
61  UOP_NAME(SWS_UOP_PERMUTE, "permute"),
62  UOP_NAME(SWS_UOP_COPY, "copy"),
63  UOP_NAME(SWS_UOP_MOVE, "move"),
64  UOP_NAME(SWS_UOP_SWAP_BYTES, "swap_bytes"),
65  UOP_NAME(SWS_UOP_EXPAND_BIT, "expand_bit"),
66  UOP_NAME(SWS_UOP_EXPAND_PAIR, "expand_pair"),
67  UOP_NAME(SWS_UOP_EXPAND_QUAD, "expand_quad"),
68  UOP_NAME(SWS_UOP_TO_U8, "to_u8"),
69  UOP_NAME(SWS_UOP_TO_U16, "to_u16"),
70  UOP_NAME(SWS_UOP_TO_U32, "to_u32"),
71  UOP_NAME(SWS_UOP_TO_F32, "to_f32"),
72  UOP_NAME(SWS_UOP_SCALE, "scale"),
73  UOP_NAME(SWS_UOP_LINEAR, "linear"),
74  UOP_NAME(SWS_UOP_LINEAR_FMA, "linear_fma"),
75  UOP_NAME(SWS_UOP_ADD, "add"),
76  UOP_NAME(SWS_UOP_MIN, "min"),
77  UOP_NAME(SWS_UOP_MAX, "max"),
78  UOP_NAME(SWS_UOP_UNPACK, "unpack"),
79  UOP_NAME(SWS_UOP_PACK, "pack"),
80  UOP_NAME(SWS_UOP_LSHIFT, "lshift"),
81  UOP_NAME(SWS_UOP_RSHIFT, "rshift"),
82  UOP_NAME(SWS_UOP_CLEAR, "clear"),
83  UOP_NAME(SWS_UOP_DITHER, "dither"),
84 #undef UOP_NAME
85 };
86 
87 static const struct {
88  char full[16];
89  char prefix[8];
91  [SWS_PIXEL_NONE] = { "SWS_PIXEL_NONE", "" },
92  [SWS_PIXEL_U8] = { "SWS_PIXEL_U8", "U8_" },
93  [SWS_PIXEL_U16] = { "SWS_PIXEL_U16", "U16_" },
94  [SWS_PIXEL_U32] = { "SWS_PIXEL_U32", "U32_" },
95  [SWS_PIXEL_F32] = { "SWS_PIXEL_F32", "F32_" },
96 };
97 
99 {
100  av_assert1(val.den != 0);
101  switch (type) {
102  case SWS_PIXEL_U8: return (SwsPixel) { .u8 = val.num / val.den };
103  case SWS_PIXEL_U16: return (SwsPixel) { .u16 = val.num / val.den };
104  case SWS_PIXEL_U32: return (SwsPixel) { .u32 = val.num / val.den };
105  case SWS_PIXEL_F32: return (SwsPixel) { .f32 = (float) val.num / val.den };
106  case SWS_PIXEL_NONE:
107  case SWS_PIXEL_TYPE_NB: break;
108  }
109 
110  av_unreachable("Invalid pixel type!");
111  return (SwsPixel) {0};
112 }
113 
114 #define Q2PIXEL(val) pixel_from_q64(op->type, val)
115 
117 {
118  switch (ff_sws_pixel_type_size(type)) {
119  case 1: return val.u8 == UINT8_MAX;
120  case 2: return val.u16 == UINT16_MAX;
121  case 4: return val.u32 == UINT32_MAX;
122  default: break;
123  }
124 
125  av_unreachable("Invalid pixel type!");
126  return false;
127 }
128 
129 void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX])
130 {
131  AVBPrint bp;
133 
134  if (op->type != SWS_PIXEL_NONE)
135  av_bprintf(&bp, "%s_", ff_sws_pixel_type_name(op->type));
136  av_bprintf(&bp, "%s", uop_names[op->uop].abbr);
137 
138  if (op->mask)
139  av_bprintf(&bp, "_%s", ff_sws_comp_mask_str(op->mask));
140 
141  const SwsUOpParams *par = &op->par;
142  switch (op->uop) {
146  av_bprintf(&bp, "_%s", ff_sws_pixel_type_name(par->filter.type));
147  break;
148  case SWS_UOP_LSHIFT:
149  case SWS_UOP_RSHIFT:
150  av_bprintf(&bp, "_%u", par->shift.amount);
151  break;
152  case SWS_UOP_PERMUTE:
153  av_bprint_chars(&bp, '_', 1);
154  for (int i = 0; i < 4; i++)
155  av_bprint_chars(&bp, "xyzw"[par->swizzle.in[i]], 1);
156  break;
157  case SWS_UOP_COPY:
158  av_bprint_chars(&bp, '_', 1);
159  for (int i = 0; i < 4; i++) {
160  if (SWS_COMP_TEST(op->mask, i))
161  av_bprint_chars(&bp, "xyzw"[par->swizzle.in[i]], 1);
162  }
163  break;
164  case SWS_UOP_MOVE:
165  av_bprint_chars(&bp, '_', 1);
166  for (int i = 0; i < par->move.num_moves; i++)
167  av_bprint_chars(&bp, "txyzw"[par->move.dst[i] + 1], 1);
168  av_bprint_chars(&bp, '_', 1);
169  for (int i = 0; i < par->move.num_moves; i++)
170  av_bprint_chars(&bp, "txyzw"[par->move.src[i] + 1], 1);
171  break;
172  case SWS_UOP_PACK:
173  case SWS_UOP_UNPACK:
174  av_bprint_chars(&bp, '_', 1);
175  for (int i = 0; i < 4 && par->pack.pattern[i]; i++)
176  av_bprintf(&bp, "%x", par->pack.pattern[i]);
177  break;
178  case SWS_UOP_CLEAR:
179  av_bprint_chars(&bp, '_', 1);
180  for (int i = 0; i < 4; i++) {
181  if (!SWS_COMP_TEST(op->mask, i))
182  continue;
183  else if (SWS_COMP_TEST(par->clear.one, i))
184  av_bprint_chars(&bp, '1', 1);
185  else if (SWS_COMP_TEST(par->clear.zero, i))
186  av_bprint_chars(&bp, '0', 1);
187  else
188  av_bprint_chars(&bp, 'x', 1);
189  }
190  break;
191  case SWS_UOP_LINEAR:
192  case SWS_UOP_LINEAR_FMA:
193  for (int i = 0; i < 4; i++) {
194  if (!SWS_COMP_TEST(op->mask, i))
195  continue;
196  av_bprint_chars(&bp, '_', 1);
197  for (int j = 0; j < 5; j++) {
198  if (par->lin.one & SWS_MASK(i, j))
199  av_bprint_chars(&bp, '1', 1);
200  else if (par->lin.zero & SWS_MASK(i, j))
201  av_bprint_chars(&bp, '0', 1);
202  else if (par->lin.exact & SWS_MASK(i, j))
203  av_bprint_chars(&bp, 'X', 1);
204  else
205  av_bprint_chars(&bp, 'x', 1);
206  }
207  }
208  break;
209  case SWS_UOP_DITHER:
210  for (int i = 0; i < 4; i++) {
211  if (SWS_COMP_TEST(op->mask, i))
212  av_bprintf(&bp, "_%d", par->dither.y_offset[i]);
213  }
214  const unsigned size = 1u << par->dither.size_log2;
215  av_bprintf(&bp, "_%ux%u", size, size);
216  break;
217  }
218 
220 }
221 
222 static int generate_entry_struct(void *opaque, void *key)
223 {
224  const SwsUOp *ref = opaque;
225  const SwsUOp *uop = key;
226  AVBPrint *bp = ref->data.opaque;
227  char name[SWS_UOP_NAME_MAX];
228  ff_sws_uop_name(uop, name);
229  av_bprintf(bp, " \\\n MACRO(__VA_ARGS__, %-40s", name);
230  av_bprintf(bp, ", .type = %-13s, .uop = %-24s, .mask = 0x%x",
231  pixel_types[uop->type].full, uop_names[uop->uop].full, uop->mask);
232 
233  const SwsUOpParams *par = &uop->par;
234  switch (uop->uop) {
238  av_bprintf(bp, ", .par.filter.type = %s", pixel_types[par->filter.type].full);
239  break;
240  case SWS_UOP_LSHIFT:
241  case SWS_UOP_RSHIFT:
242  av_bprintf(bp, ", .par.shift.amount = %u", par->shift.amount);
243  break;
244  case SWS_UOP_PERMUTE:
245  case SWS_UOP_COPY:
246  av_bprintf(bp, ", .par.swizzle.in = {%d, %d, %d, %d}",
247  par->swizzle.in[0], par->swizzle.in[1],
248  par->swizzle.in[2], par->swizzle.in[3]);
249  break;
250  case SWS_UOP_MOVE:
251  av_bprintf(bp, ", .par.move.num_moves = %d", par->move.num_moves);
252  av_bprintf(bp, ", .par.move.dst = {%d, %d, %d, %d, %d, %d}",
253  par->move.dst[0], par->move.dst[1], par->move.dst[2],
254  par->move.dst[3], par->move.dst[4], par->move.dst[5]);
255  av_bprintf(bp, ", .par.move.src = {%d, %d, %d, %d, %d, %d}",
256  par->move.src[0], par->move.src[1], par->move.src[2],
257  par->move.src[3], par->move.src[4], par->move.src[5]);
258  break;
259  case SWS_UOP_PACK:
260  case SWS_UOP_UNPACK:
261  av_bprintf(bp, ", .par.pack.pattern = {%d, %d, %d, %d}",
262  par->pack.pattern[0], par->pack.pattern[1],
263  par->pack.pattern[2], par->pack.pattern[3]);
264  break;
265  case SWS_UOP_CLEAR:
266  av_bprintf(bp, ", .par.clear.one = 0x%x, .par.clear.zero = 0x%x",
267  par->clear.one, par->clear.zero);
268  break;
269  case SWS_UOP_LINEAR:
270  case SWS_UOP_LINEAR_FMA:
271  av_bprintf(bp, ", .par.lin.one = 0x%x, .par.lin.zero = 0x%x",
272  par->lin.one, par->lin.zero);
273  if (uop->uop == SWS_UOP_LINEAR_FMA)
274  av_bprintf(bp, ", .par.lin.exact = 0x%x", par->lin.exact);
275  break;
276  case SWS_UOP_DITHER:
277  av_bprintf(bp, ", .par.dither = { .y_offset = {%u, %u, %u, %u}, .size_log2 = %u }",
278  par->dither.y_offset[0], par->dither.y_offset[1],
279  par->dither.y_offset[2], par->dither.y_offset[3],
280  par->dither.size_log2);
281  break;
282  }
283 
284  av_bprintf(bp, ")");
285  return 0;
286 }
287 
288 static int generate_entry_args(void *opaque, void *key)
289 {
290  const SwsUOp *ref = opaque;
291  const SwsUOp *uop = key;
292  AVBPrint *bp = ref->data.opaque;
293  char name[SWS_UOP_NAME_MAX];
294  ff_sws_uop_name(uop, name);
295  av_bprintf(bp, " \\\n MACRO(__VA_ARGS__, %-40s, %-13s, %-24s, 0x%x",
296  name, pixel_types[uop->type].full, uop_names[uop->uop].full, uop->mask);
297 
298  const SwsUOpParams *par = &uop->par;
299  switch (uop->uop) {
303  av_bprintf(bp, ", %s", pixel_types[par->filter.type].full);
304  break;
305  case SWS_UOP_LSHIFT:
306  case SWS_UOP_RSHIFT:
307  av_bprintf(bp, ", %u", par->shift.amount);
308  break;
309  case SWS_UOP_PERMUTE:
310  case SWS_UOP_COPY:
311  av_bprintf(bp, ", %d, %d, %d, %d",
312  par->swizzle.in[0], par->swizzle.in[1],
313  par->swizzle.in[2], par->swizzle.in[3]);
314  break;
315  case SWS_UOP_MOVE:
316  av_bprintf(bp, ", %d", par->move.num_moves);
317  av_bprintf(bp, ", %d, %d, %d, %d, %d, %d",
318  par->move.dst[0], par->move.dst[1], par->move.dst[2],
319  par->move.dst[3], par->move.dst[4], par->move.dst[5]);
320  av_bprintf(bp, ", %d, %d, %d, %d, %d, %d",
321  par->move.src[0], par->move.src[1], par->move.src[2],
322  par->move.src[3], par->move.src[4], par->move.src[5]);
323  break;
324  case SWS_UOP_PACK:
325  case SWS_UOP_UNPACK:
326  av_bprintf(bp, ", %d, %d, %d, %d",
327  par->pack.pattern[0], par->pack.pattern[1],
328  par->pack.pattern[2], par->pack.pattern[3]);
329  break;
330  case SWS_UOP_CLEAR:
331  av_bprintf(bp, ", 0x%05x, 0x%05x", par->clear.one, par->clear.zero);
332  break;
333  case SWS_UOP_LINEAR:
334  case SWS_UOP_LINEAR_FMA:
335  av_bprintf(bp, ", 0x%05x, 0x%05x", par->lin.one, par->lin.zero);
336  if (uop->uop == SWS_UOP_LINEAR_FMA)
337  av_bprintf(bp, ", 0x%05x", par->lin.exact);
338  break;
339  case SWS_UOP_DITHER:
340  av_bprintf(bp, ", %u, %u, %u, %u, %u",
341  par->dither.y_offset[0], par->dither.y_offset[1],
342  par->dither.y_offset[2], par->dither.y_offset[3],
343  par->dither.size_log2);
344  break;
345  }
346 
347  av_bprintf(bp, ")");
348  return 0;
349 }
350 
351 static void uop_uninit(SwsUOp *uop)
352 {
353  switch (uop->uop) {
354  case SWS_UOP_DITHER:
355  av_refstruct_unref(&uop->data.ptr);
356  break;
361  break;
362  }
363 
364  *uop = (SwsUOp) {0};
365 }
366 
368 {
369  SwsUOpList *ops = *p_ops;
370  if (!ops)
371  return;
372 
373  for (int i = 0; i < ops->num_ops; i++)
374  uop_uninit(&ops->ops[i]);
375 
376  av_freep(&ops->ops);
377  av_free(ops);
378  *p_ops = NULL;
379 }
380 
382 {
383  return av_mallocz(sizeof(SwsUOpList));
384 }
385 
387 {
388  if (!av_dynarray2_add((void **) &uops->ops, &uops->num_ops,
389  sizeof(*uop), (uint8_t *) uop))
390  {
391  uop_uninit(uop);
392  return AVERROR(ENOMEM);
393  }
394 
395  *uop = (SwsUOp) {0};
396  return 0;
397 }
398 
400 {
401  int max_offset = 0;
402  for (int i = 0; i < 4; i++)
403  max_offset = FFMAX(max_offset, dither->y_offset[i]);
404  return (1 << dither->size_log2) + max_offset;
405 }
406 
408 {
409  switch (ff_sws_pixel_type_size(type)) {
410  case 1: return SWS_PIXEL_U8;
411  case 2: return SWS_PIXEL_U16;
412  case 4: return SWS_PIXEL_U32;
413  default: break;
414  }
415 
416  av_unreachable("Invalid pixel type!");
417  return SWS_PIXEL_NONE;
418 }
419 
420 static bool exact_product_f32(float a, float b)
421 {
422  volatile float prod = a * b;
423  volatile float result = b ? prod / b : 0.0f;
424  return !b || result == a;
425 }
426 
428  const SwsComps *comps, int idx)
429 {
430  const AVRational64 minq = comps->min[idx];
431  const AVRational64 maxq = comps->max[idx];
433  return true;
434  else if (!minq.den || !maxq.den)
435  return false; /* unknown bounds */
436 
437  const SwsPixel min = pixel_from_q64(type, minq);
438  const SwsPixel max = pixel_from_q64(type, maxq);
439  switch (type) {
440  case SWS_PIXEL_F32:
441  return exact_product_f32(coef.f32, min.f32) &&
442  exact_product_f32(coef.f32, max.f32);
443  }
444 
445  av_unreachable("Invalid pixel type!");
446  return false;
447 }
448 
450 {
451  if (!(flags & SWS_UOP_FLAG_FMA))
452  return false;
453  if (!(ctx->flags & SWS_BITEXACT))
454  return true;
455  if (!ff_sws_pixel_type_is_int(op->type))
456  return false;
457 
458  const int bits = ff_sws_pixel_type_size(op->type) * 8;
459  const uint64_t max_val = UINT64_MAX >> (64 - bits);
460 
461  /* Maximum value representable losslessly as float. Note that this is
462  * currently true only for U8, but that may change if we ever update the
463  * value of SWS_FILTER_SCALE. */
464  return max_val * SWS_FILTER_SCALE <= (1 << 22);
465 }
466 
468  const SwsOp *op)
469 {
470  SwsUOp uop = {
471  .type = op->type,
472  .mask = SWS_COMP_MASK(op->rw.elems > 0, op->rw.elems > 1,
473  op->rw.elems > 2, op->rw.elems > 3),
474  };
475 
476  /* Non-filtered reads don't care about the exact pixel contents */
477  if (!op->rw.filter.op)
478  uop.type = pixel_type_to_int(op->type);
479 
480  const bool is_read = op->op == SWS_OP_READ;
481  if (op->rw.filter.op) {
482  if (op->op == SWS_OP_WRITE || op->rw.frac || op->rw.mode != SWS_RW_PLANAR)
483  return AVERROR(ENOTSUP);
484  uop.par.filter.type = op->rw.filter.type;
485  uop.data.kernel = av_refstruct_ref(op->rw.filter.kernel);
486  if (op->rw.filter.op == SWS_OP_FILTER_H) {
488  } else if (check_filter_fma(ctx, flags, op)) {
490  } else {
492  }
493  } else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1) {
494  if (op->rw.frac)
495  return AVERROR(ENOTSUP);
496  uop.uop = is_read ? SWS_UOP_READ_PACKED : SWS_UOP_WRITE_PACKED;
497  } else if (op->rw.mode == SWS_RW_PALETTE) {
498  if (op->rw.frac || !is_read)
499  return AVERROR(ENOTSUP);
501  } else if (op->rw.frac == 3) {
502  uop.uop = is_read ? SWS_UOP_READ_BIT : SWS_UOP_WRITE_BIT;
503  } else if (op->rw.frac == 1) {
504  uop.uop = is_read ? SWS_UOP_READ_NIBBLE : SWS_UOP_WRITE_NIBBLE;
505  } else {
506  av_assert0(!op->rw.frac);
507  uop.uop = is_read ? SWS_UOP_READ_PLANAR : SWS_UOP_WRITE_PLANAR;
508  }
509 
510  return ff_sws_uop_list_append(ops, &uop);
511 }
512 
513 static int count_idx(const int *arr, size_t size, int val)
514 {
515  int num = 0;
516  for (size_t i = 0; i < size; i++) {
517  if (arr[i] == val)
518  num++;
519  }
520 
521  return num;
522 }
523 
524 static int translate_move(SwsUOpList *ops, const SwsOp *op)
525 {
526  SwsUOp uop = {
527  .uop = SWS_UOP_MOVE,
528  .type = pixel_type_to_int(op->type),
529  };
530  SwsMoveUOp *par = &uop.par.move;
531 
532  /* Mask of components that are not yet satisfied */
534  for (int i = 0; i < 4; i++) {
535  if (op->swizzle.in[i] == i)
536  todo &= ~SWS_COMP(i);
537  }
538 
539  /* Mask of components whose value is required for the final output */
540  SwsCompMask needed = 0;
541  for (int i = 0; i < 4; i++) {
542  if (SWS_OP_NEEDED(op, i))
543  needed |= SWS_COMP(op->swizzle.in[i]);
544  }
545 
546  /* Current mapping of registers to components */
547  int idx[4 + 1] = { 0, 1, 2, 3, -1 }; /* +1 for tmp */
548 
549  /* Decompose the swizzle mask into a series of register-register moves */
550  while (todo) {
551  int dst = -1, src = -1;
552 
553  /* Find next unsatisfied dst <- src move that doesn't clobber a value */
554  for (dst = 0; dst < 4; dst++) {
555  if (!SWS_COMP_TEST(todo, dst))
556  continue; /* already satisfied */
557  const int cur = idx[dst];
558  if (count_idx(idx, FF_ARRAY_ELEMS(idx), cur) == 1 && SWS_COMP_TEST(needed, cur))
559  continue; /* clobbers last remaining, still-needed value */
560  for (src = 0; src < FF_ARRAY_ELEMS(idx); src++) {
561  if (idx[src] == op->swizzle.in[dst]) {
562  /* Prevent read-after-write dependency. */
563  if (par->num_moves > 0 && src == par->dst[par->num_moves - 1])
564  src = par->src[par->num_moves - 1];
565  break;
566  }
567  }
568  av_assert1(src < FF_ARRAY_ELEMS(idx));
569  todo &= ~SWS_COMP(dst);
570  break;
571  }
572 
573  if (dst == 4) {
574  /* Stuck in a cycle, break it by saving to the scratch register */
575  dst = 4;
576  for (src = 0; src < 4; src++) {
577  if (SWS_COMP_TEST(todo, src)) {
578  needed &= ~SWS_COMP(idx[src]);
579  break;
580  }
581  }
582  av_assert1(src < 4);
583  }
584 
586  par->dst[par->num_moves] = dst > 3 ? -1 : dst;
587  par->src[par->num_moves] = src > 3 ? -1 : src;
588  par->num_moves++;
589  idx[dst] = idx[src];
590  }
591 
592  return ff_sws_uop_list_append(ops, &uop);
593 }
594 
596 {
597  if (flags & SWS_UOP_FLAG_MOVE)
598  return translate_move(ops, op);
599 
600  SwsUOp uop = {
601  .type = pixel_type_to_int(op->type),
602  .uop = SWS_UOP_PERMUTE,
603  .par.swizzle.in = {0, 1, 2, 3},
604  };
605 
607  SwsCompMask seen = 0;
608  for (int i = 0; i < 4; i++) {
609  if (!SWS_COMP_TEST(needed, i))
610  continue;
611  const int src = op->swizzle.in[i];
612  if (SWS_COMP_TEST(seen, src))
613  uop.uop = SWS_UOP_COPY; /* Swizzle mask contains duplicates */
614  seen |= SWS_COMP(src);
615  uop.par.swizzle.in[i] = src;
616  }
617 
618  if (uop.uop == SWS_UOP_PERMUTE) {
619  /* Prevent overlap by moving unused components to unseen indices */
620  for (int i = 0; i < 4; i++) {
621  if (SWS_COMP_TEST(needed, i))
622  continue;
623 
624  /* Prefer identity mapping if possible */
625  int unused = i;
626  if (SWS_COMP_TEST(seen, i)) {
627  for (int j = 0; j < 4; j++) {
628  if (!SWS_COMP_TEST(seen, j)) {
629  unused = j;
630  break;
631  }
632  }
633  }
634 
635  uop.par.swizzle.in[i] = unused;
636  seen |= SWS_COMP(unused);
637  }
638  }
639 
640  if (uop.uop == SWS_UOP_COPY) {
641  /* Remove remaining trivial / identity components from the mask */
642  for (int i = 0; i < 4; i++) {
643  if (uop.par.swizzle.in[i] == i)
644  needed &= ~SWS_COMP(i);
645  }
646 
647  uop.mask = needed;
648  }
649 
650  return ff_sws_uop_list_append(ops, &uop);
651 }
652 
653 static int translate_dither_op(SwsUOpList *ops, const SwsOp *op)
654 {
655  SwsUOp uop = {
656  .type = op->type,
657  .uop = SWS_UOP_DITHER,
658  .par.dither.size_log2 = op->dither.size_log2,
659  };
660 
661  if (op->dither.size_log2 == 0) {
662  /* Constant offset */
663  const SwsPixel val = Q2PIXEL(op->dither.matrix[0]);
664  uop.uop = SWS_UOP_ADD;
665  for (int i = 0; i < 4; i++) {
666  if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0)
667  continue;
668  uop.mask |= SWS_COMP(i);
669  uop.data.vec4[i] = val;
670  }
671 
672  return ff_sws_uop_list_append(ops, &uop);
673  }
674 
675  const int size = 1 << op->dither.size_log2;
676  for (int i = 0; i < 4; i++) {
677  if (!SWS_OP_NEEDED(op, i) || op->dither.y_offset[i] < 0)
678  continue;
679  const uint8_t off = op->dither.y_offset[i] & (size - 1);
680  uop.mask |= SWS_COMP(i);
681  uop.par.dither.y_offset[i] = off;
682  }
683 
684  /* Allocate extra rows to allow over-reading for row offsets. Note that
685  * y_offset is currently never larger than 5, so the extra space needed
686  * for this over-allocation is bounded by 5 * size * sizeof(float),
687  * typically 320 bytes for a 16x16 dither matrix. */
688  const int stride = size * sizeof(SwsPixel);
689  const int num_rows = ff_sws_dither_height(&uop.par.dither);
690  SwsPixel *matrix = uop.data.ptr = av_refstruct_allocz(num_rows * stride);
691  if (!matrix)
692  return AVERROR(ENOMEM);
693 
694  for (int i = 0; i < size * size; i++)
695  matrix[i] = Q2PIXEL(op->dither.matrix[i]);
696  memcpy(&matrix[size * size], matrix, (num_rows - size) * stride);
697 
698  return ff_sws_uop_list_append(ops, &uop);
699 }
700 
702  SwsUOpFlags flags, const SwsOp *op,
703  const SwsComps *input)
704 {
705  SwsUOp uop = {
706  .type = op->type,
707  .uop = SWS_UOP_LINEAR,
708  };
709 
710  const bool bitexact = ctx->flags & SWS_BITEXACT;
711  uint32_t exact = 0;
712 
713  for (int i = 0; i < 4; i++) {
714  if (SWS_OP_NEEDED(op, i) && (op->lin.mask & SWS_MASK_ROW(i)))
715  uop.mask |= SWS_COMP(i);
716  bool nonzero = (op->lin.m[i][4].num != 0);
717  for (int j = 0; j < 5; j++) {
718  const AVRational64 k = op->lin.m[i][j];
719  const SwsPixel px = Q2PIXEL(k);
720  uop.data.mat4[i][j] = px;
721  if (k.num == 0)
722  uop.par.lin.zero |= SWS_MASK(i, j);
723  else if (j < 4 && k.num == k.den)
724  uop.par.lin.one |= SWS_MASK(i, j);
725  else if (j < 4 && nonzero && (!bitexact || exact_prod(uop.type, px, input, j)))
726  exact |= SWS_MASK(i, j);
727  if (k.num != 0)
728  nonzero = true;
729  }
730  }
731 
732  if (flags & SWS_UOP_FLAG_FMA) {
733  /* multiplication by 1 and 0 are always exact by definition */
734  uop.uop = SWS_UOP_LINEAR_FMA;
735  uop.par.lin.exact = exact | uop.par.lin.zero | uop.par.lin.one;
736  }
737 
738  return ff_sws_uop_list_append(ops, &uop);
739 }
740 
742 {
743  if (factor.den != 1)
744  return false;
745 
746  switch (type) {
747  case SWS_PIXEL_U8: return factor.num == UINT8_MAX;
748  case SWS_PIXEL_U16: return factor.num == UINT16_MAX;
749  case SWS_PIXEL_U32: return factor.num == UINT32_MAX;
750  case SWS_PIXEL_F32: return false;
751  case SWS_PIXEL_NONE:
752  case SWS_PIXEL_TYPE_NB: break;
753  }
754 
755  av_unreachable("Invalid pixel type!");
756  return false;
757 }
758 
760  const SwsOp *op, const SwsComps *input)
761 {
762  switch (op->op) {
763  case SWS_OP_FILTER_H:
764  case SWS_OP_FILTER_V:
765  return AVERROR(ENOTSUP); /* always handled by subpass splitting */
766  case SWS_OP_READ:
767  case SWS_OP_WRITE:
768  return translate_rw_op(ctx, uops, flags, op);
769  case SWS_OP_SWIZZLE:
770  return translate_swizzle(uops, flags, op);
771  case SWS_OP_DITHER:
772  return translate_dither_op(uops, op);
773  case SWS_OP_LINEAR:
774  return translate_linear_op(ctx, uops, flags, op, input);
775  default:
776  break;
777  }
778 
779  /* Default handling for "simple" ops */
780  SwsUOp uop = {
781  .type = op->type,
782  .uop = SWS_UOP_INVALID,
783  .mask = ff_sws_comp_mask_needed(op),
784  };
785 
786  switch (op->op) {
787  case SWS_OP_CONVERT:
788  if (op->convert.expand) {
789  av_assert0(op->type == SWS_PIXEL_U8);
790  switch (op->convert.to) {
791  case SWS_PIXEL_U16: uop.uop = SWS_UOP_EXPAND_PAIR; break;
792  case SWS_PIXEL_U32: uop.uop = SWS_UOP_EXPAND_QUAD; break;
793  }
794  } else {
795  switch (op->convert.to) {
796  case SWS_PIXEL_U8: uop.uop = SWS_UOP_TO_U8; break;
797  case SWS_PIXEL_U16: uop.uop = SWS_UOP_TO_U16; break;
798  case SWS_PIXEL_U32: uop.uop = SWS_UOP_TO_U32; break;
799  case SWS_PIXEL_F32: uop.uop = SWS_UOP_TO_F32; break;
800  }
801  }
802  break;
803  case SWS_OP_UNPACK:
804  case SWS_OP_PACK:
805  uop.uop = op->op == SWS_OP_PACK ? SWS_UOP_PACK : SWS_UOP_UNPACK;
806  uop.mask = 0;
807  for (int i = 0; i < 4 && op->pack.pattern[i]; i++) {
808  uop.par.pack.pattern[i] = op->pack.pattern[i];
809  uop.mask |= SWS_COMP(i);
810  }
811  break;
812  case SWS_OP_LSHIFT:
813  case SWS_OP_RSHIFT:
815  uop.par.shift.amount = op->shift.amount;
816  break;
817  case SWS_OP_CLEAR:
818  uop.uop = SWS_UOP_CLEAR;
819  uop.type = pixel_type_to_int(op->type);
820  uop.mask &= op->clear.mask;
821  for (int i = 0; i < 4; i++) {
822  if (!SWS_COMP_TEST(op->clear.mask, i))
823  continue;
824  const AVRational64 v = op->clear.value[i];
825  const SwsPixel px = Q2PIXEL(op->clear.value[i]);
826  uop.data.vec4[i] = px;
827  if (v.num == 0)
828  uop.par.clear.zero |= SWS_COMP(i);
829  else if (pixel_is_1s(op->type, px))
830  uop.par.clear.one |= SWS_COMP(i);
831  }
832  break;
833  case SWS_OP_SCALE:
834  if (is_expand_bit(op->type, op->scale.factor)) {
835  uop.uop = SWS_UOP_EXPAND_BIT;
836  } else {
837  uop.uop = SWS_UOP_SCALE;
838  uop.data.scalar = Q2PIXEL(op->scale.factor);
839  }
840  break;
841  case SWS_OP_MIN:
842  case SWS_OP_MAX:
843  uop.uop = op->op == SWS_OP_MIN ? SWS_UOP_MIN : SWS_UOP_MAX;
844  uop.mask &= ff_sws_comp_mask_q4(op->clamp.limit);
845  for (int i = 0; i < 4; i++) {
846  if (SWS_COMP_TEST(uop.mask, i))
847  uop.data.vec4[i] = Q2PIXEL(op->clamp.limit[i]);
848  }
849  break;
850  case SWS_OP_SWAP_BYTES:
851  uop.uop = SWS_UOP_SWAP_BYTES;
852  uop.type = pixel_type_to_int(op->type);
853  break;
854  default:
855  return AVERROR(ENOTSUP);
856  }
857 
859  return ff_sws_uop_list_append(uops, &uop);
860 }
861 
864 {
865  SwsComps input = ops->comps_src;
866  for (int i = 0; i < ops->num_ops; i++) {
867  int ret = translate_op(ctx, uops, flags, &ops->ops[i], &input);
868  if (ret < 0)
869  return ret;
870  input = ops->ops[i].comps;
871  }
872  return 0;
873 }
874 
875 static int register_uop(struct AVTreeNode **root, const SwsUOp *uop)
876 {
877  SwsUOp *key = av_memdup(uop, sizeof(*uop));
878  if (!key)
879  return AVERROR(ENOMEM);
880  memset(&key->data, 0, sizeof(key->data));
881 
882  struct AVTreeNode *node = av_tree_node_alloc();
883  if (!node) {
884  av_free(key);
885  return AVERROR(ENOMEM);
886  }
887 
888  av_tree_insert(root, key, ff_sws_uop_cmp_v, &node);
889  if (node) {
890  av_free(node);
891  av_free(key);
892  }
893  return 0;
894 }
895 
897 {
899  if (!uops)
900  return AVERROR(ENOMEM);
901 
902  int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
903  if (ret < 0)
904  goto fail;
905 
906  struct AVTreeNode **root = ctx->opaque;
907  for (int i = 0; i < uops->num_ops; i++) {
908  ret = register_uop(root, &uops->ops[i]);
909  if (ret < 0)
910  goto fail;
911  }
912 
913 fail:
914  ff_sws_uop_list_free(&uops);
915  return ret;
916 }
917 
918 static const SwsUOpFlags uop_flags[] = {
919  0,
920  SWS_UOP_FLAG_FMA | SWS_UOP_FLAG_MOVE, /* x86 backend */
921 };
922 
923 static int register_uops(SwsContext *ctx, const SwsOpList *ops,
925 {
926  for (int i = 0; i < FF_ARRAY_ELEMS(uop_flags); i++) {
927  int ret = register_flags(ctx, ops, uop_flags[i]);
928  if (ret < 0)
929  return ret;
930  }
931 
932  *out = (SwsCompiledOp) {0}; /* dummy value, will be immediately freed */
933  return 0;
934 }
935 
936 /* Dummy backend that just registers all seen uops */
937 static const SwsOpBackend backend_uops = {
938  .name = "uops_gen",
939  .compile = register_uops,
940 };
941 
942 static int register_all_uops(SwsContext *ctx, void *graph, SwsOpList *ops)
943 {
944  /* ff_sws_compile_pass() takes over ownership of `ops` */
946  if (!copy)
947  return AVERROR(ENOMEM);
948 
950  return ff_sws_compile_pass(graph, &backend_uops, &copy, flags, NULL, NULL);
951 }
952 
953 static const SwsFlags flags[] = {
954  0,
955  SWS_ACCURATE_RND, /* may insert extra 1x1 dither ops (for accurate rounding) */
956  SWS_BITEXACT, /* prevents some FMA optimizations */
958 };
959 
960 /* Limit the range of av_tree_enumerate() to only matching uop and type */
961 static int enum_type(void *opaque, void *elem)
962 {
963  const SwsUOp *a = opaque, *b = elem;
964  if (a->type != b->type)
965  return (int) b->type - a->type;
966  if (a->uop != b->uop)
967  return (int) b->uop - a->uop;
968  return 0;
969 }
970 
971 static int free_uop_key(void *opaque, void *key)
972 {
973  av_free(key);
974  return 0;
975 }
976 
977 int ff_sws_uops_macros_gen(char **out_str)
978 {
979  int ret;
980  struct AVTreeNode *root = NULL;
981 
982  AVBPrint bprint, *const bp = &bprint;
984 
985  /* Allocate dummy graph and context for ff_sws_compile_pass() */
986  SwsGraph *graph = ff_sws_graph_alloc();
987  if (!graph)
988  return AVERROR(ENOMEM);
989 
990  SwsContext *ctx = graph->ctx = sws_alloc_context();
991  if (!ctx) {
992  ret = AVERROR(ENOMEM);
993  goto fail;
994  }
995 
996  /* Use this to plumb the tree state through all the layers of abstraction */
997  ctx->opaque = &root;
998  ctx->scaler = SWS_SCALE_BILINEAR; /* cheaper to generate filter kernels */
999 
1000  /* Register all unique uops over every relevant combination of flags */
1001  for (int i = 0; i < FF_ARRAY_ELEMS(flags); i++) {
1002  ctx->flags = flags[i];
1005  if (ret < 0)
1006  goto fail;
1007  }
1008 
1009  /**
1010  * Additionally make sure planar reads/writes are always available for all
1011  * formats, because checkasm depends on them to be able to verify the
1012  * input/output of any other operations.
1013  */
1016  continue;
1017  for (int elems = 1; elems <= 4; elems++) {
1018  for (int rw = 0; rw < 2; rw++) {
1019  SwsUOp uop = {
1020  .type = type,
1022  .mask = SWS_COMP_ELEMS(elems),
1023  };
1024 
1025  ret = register_uop(&root, &uop);
1026  if (ret < 0)
1027  goto fail;
1028  }
1029  }
1030  }
1031 
1032  #define BPRINT_STR(str) av_bprint_append_data(bp, str, strlen(str))
1033  BPRINT_STR(
1034 "/**\n"
1035 " * This file is automatically generated. Do not edit manually.\n"
1036 " * To regenerate, run: make fate-sws-uops-macros GEN=1\n"
1037 " */\n"
1038 "\n"
1039 "#ifndef SWSCALE_UOPS_MACROS_H\n"
1040 "#define SWSCALE_UOPS_MACROS_H\n"
1041 "\n"
1042 "/**\n"
1043 " * Boilerplate helper macros, for template-based backends. These will be\n"
1044 " * instantiated like this, with parameters in struct order:\n"
1045 " * MACRO(__VA_ARGS__, NAME, UOP, TYPE, MASK, [PARAMS,])\n"
1046 " * The _STRUCT variants pass all arguments in C struct syntax, while the\n"
1047 " * plain variants give them as separate C values (e.g. for use in calls)\n"
1048 " */\n"
1049 "#define SWS_GLUE3(x, y, z) x ## _ ## y ## _ ## z\n"
1050 "#define SWS_FOR(TYPE, UOP, MACRO, ...) \\\n"
1051 " SWS_GLUE3(SWS_FOR, TYPE, UOP)(MACRO, __VA_ARGS__)\n"
1052 "#define SWS_FOR_STRUCT(TYPE, UOP, MACRO, ...) \\\n"
1053 " SWS_GLUE3(SWS_FOR_STRUCT, TYPE, UOP)(MACRO, __VA_ARGS__)\n"
1054 "\n");
1055 
1056  SwsUOp key = { .data.opaque = bp };
1057  for (key.type = SWS_PIXEL_NONE + 1; key.type < SWS_PIXEL_TYPE_NB; key.type++) {
1058  for (key.uop = SWS_UOP_INVALID + 1; key.uop < SWS_UOP_TYPE_NB; key.uop++) {
1059  const char *macro = uop_names[key.uop].full + sizeof("SWS_UOP_") - 1;
1060  const char *prefix = pixel_types[key.type].prefix;
1061  av_bprintf(bp, "#define SWS_FOR_%s%s(MACRO, ...)", prefix, macro);
1063  av_bprintf(bp, "\n");
1064  av_bprintf(bp, "#define SWS_FOR_STRUCT_%s%s(MACRO, ...)", prefix, macro);
1066  av_bprintf(bp, "\n");
1067  }
1068  }
1069 
1070  BPRINT_STR("\n#endif /* SWSCALE_UOPS_MACROS_H */");
1071  ret = av_bprint_finalize(bp, out_str);
1072 
1073 fail:
1074  av_bprint_finalize(bp, NULL);
1076  av_tree_destroy(root);
1077  ff_sws_graph_free(&graph);
1079  return ret;
1080 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:39
factor
static const int factor[16]
Definition: vf_pp7.c:98
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
SWS_UOP_SCALE
@ SWS_UOP_SCALE
Definition: uops.h:135
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:42
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:123
Q2PIXEL
#define Q2PIXEL(val)
Definition: uops.c:114
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
SwsUOpParams::move
SwsMoveUOp move
Definition: uops.h:214
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:47
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:45
pixel_types
static const struct @587 pixel_types[SWS_PIXEL_TYPE_NB]
ff_sws_op_list_duplicate
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
Definition: ops.c:657
SWS_RW_PLANAR
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
Definition: ops.h:100
free_uop_key
static int free_uop_key(void *opaque, void *key)
Definition: uops.c:971
out
static FILE * out
Definition: movenc.c:55
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:284
ff_sws_uop_cmp_v
static int ff_sws_uop_cmp_v(const void *a, const void *b)
Definition: uops.h:244
SWS_UOP_RSHIFT
@ SWS_UOP_RSHIFT
Definition: uops.h:144
SWS_PIXEL_NONE
@ SWS_PIXEL_NONE
Definition: uops.h:39
av_tree_insert
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:59
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:51
SWS_SCALE_BILINEAR
@ SWS_SCALE_BILINEAR
bilinear filtering
Definition: swscale.h:98
SwsClearUOp::zero
SwsCompMask zero
Definition: uops.h:182
SwsUOp::data
union SwsUOp::@589 data
matrix
Definition: vc1dsp.c:43
full
char full[32]
Definition: uops.c:44
ff_sws_comp_mask_q4
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition: ops.c:131
ops.h
u
#define u(width, name, range_min, range_max)
Definition: cbs_apv.c:68
AVTreeNode::elem
void * elem
Definition: tree.c:28
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:59
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:178
av_dynarray2_add
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:343
b
#define b
Definition: input.c:43
SWS_UOP_MOVE_MAX
#define SWS_UOP_MOVE_MAX
Definition: uops.h:168
SWS_UOP_LINEAR_FMA
@ SWS_UOP_LINEAR_FMA
Definition: uops.h:147
SWS_UOP_MAX
@ SWS_UOP_MAX
Definition: uops.h:138
translate_rw_op
static int translate_rw_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op)
Definition: uops.c:467
ff_sws_uop_cmp
int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b)
Copyright (C) 2026 Niklas Haas.
Definition: uops.c:32
max
#define max(a, b)
Definition: cuda_runtime.h:33
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
SWS_COMP_MASK
#define SWS_COMP_MASK(X, Y, Z, W)
Definition: uops.h:74
av_tree_node_alloc
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
SwsUOpParams::swizzle
SwsSwizzleUOp swizzle
Definition: uops.h:213
SWS_UOP_LSHIFT
@ SWS_UOP_LSHIFT
Definition: uops.h:143
SwsLinearUOp::one
uint32_t one
Definition: uops.h:186
SWS_UOP_TYPE_NB
@ SWS_UOP_TYPE_NB
Definition: uops.h:151
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:134
SWS_UOP_NAME_MAX
#define SWS_UOP_NAME_MAX
Generate a unique name for a SwsUOp.
Definition: uops.h:252
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:71
av_tree_enumerate
void av_tree_enumerate(AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem))
Apply enu(opaque, &elem) to all the elements in the tree in a given range.
Definition: tree.c:155
check_filter_fma
static bool check_filter_fma(SwsContext *ctx, SwsUOpFlags flags, const SwsOp *op)
Definition: uops.c:449
ff_sws_graph_alloc
SwsGraph * ff_sws_graph_alloc(void)
Allocate an empty SwsGraph.
Definition: graph.c:817
ff_sws_comp_mask_needed
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition: ops.c:154
SwsMoveUOp::num_moves
int num_moves
Definition: uops.h:169
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:304
enum_type
static int enum_type(void *opaque, void *elem)
Definition: uops.c:961
SwsMoveUOp
Definition: uops.h:166
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: uops.h:71
av_bprint_init_for_buffer
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
SWS_UOP_TO_U16
@ SWS_UOP_TO_U16
Definition: uops.h:130
SwsOpList::num_ops
int num_ops
Definition: ops.h:267
SWS_UOP_PACK
@ SWS_UOP_PACK
Definition: uops.h:142
SwsShiftUOp::amount
uint8_t amount
Definition: uops.h:159
SWS_UOP_PERMUTE
@ SWS_UOP_PERMUTE
Definition: uops.h:120
SwsUOpParams::pack
SwsPackUOp pack
Definition: uops.h:215
SWS_UOP_EXPAND_BIT
@ SWS_UOP_EXPAND_BIT
Definition: uops.h:126
translate_move
static int translate_move(SwsUOpList *ops, const SwsOp *op)
Definition: uops.c:524
UOP_NAME
#define UOP_NAME(OP, ABBR)
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:86
val
static double val(void *priv, double ch)
Definition: aeval.c:77
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
SwsUOpParams
Definition: uops.h:210
SWS_COMP_ELEMS
#define SWS_COMP_ELEMS(N)
Definition: uops.h:73
SwsFilterUOp::type
SwsPixelType type
Definition: uops.h:155
refstruct.h
av_refstruct_allocz
static void * av_refstruct_allocz(size_t size)
Equivalent to av_refstruct_alloc_ext(size, 0, NULL, NULL)
Definition: refstruct.h:105
SWS_UOP_COPY
@ SWS_UOP_COPY
Definition: uops.h:121
SWS_UOP_INVALID
@ SWS_UOP_INVALID
Definition: uops.h:102
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:101
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:55
avassert.h
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
SWS_UOP_WRITE_NIBBLE
@ SWS_UOP_WRITE_NIBBLE
Definition: uops.h:116
SWS_UOP_READ_PALETTE
@ SWS_UOP_READ_PALETTE
Definition: uops.h:112
uop_flags
static const SwsUOpFlags uop_flags[]
Definition: uops.c:918
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:237
SwsUOp::kernel
SwsFilterWeights * kernel
Definition: uops.h:230
float
float
Definition: af_crystalizer.c:122
SWS_UOP_MOVE
@ SWS_UOP_MOVE
Definition: uops.h:122
SwsFlags
SwsFlags
Definition: swscale.h:131
dither
static const uint16_t dither[8][8]
Definition: vf_gradfun.c:46
SwsUOp::uop
SwsUOpType uop
Definition: uops.h:224
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1465
SWS_FILTER_SCALE
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition: filters.h:40
backend_uops
static const SwsOpBackend backend_uops
Definition: uops.c:937
SWS_UOP_WRITE_PLANAR
@ SWS_UOP_WRITE_PLANAR
Definition: uops.h:114
op
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
bits
uint8_t bits
Definition: vp3data.h:128
SWS_UOP_TO_F32
@ SWS_UOP_TO_F32
Definition: uops.h:132
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
SWS_UOP_MIN
@ SWS_UOP_MIN
Definition: uops.h:137
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:53
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:61
SWS_UOP_READ_PACKED
@ SWS_UOP_READ_PACKED
Definition: uops.h:109
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:58
count_idx
static int count_idx(const int *arr, size_t size, int val)
Definition: uops.c:513
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:62
SwsPixel::f32
float f32
Definition: uops.h:57
AVFormatContext::opaque
void * opaque
User data.
Definition: avformat.h:1878
key
const char * key
Definition: hwcontext_opencl.c:189
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpBackend
Definition: ops_dispatch.h:133
uop_names
static const struct @586 uop_names[SWS_UOP_TYPE_NB]
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:46
prefix
char prefix[8]
Definition: uops.c:89
register_flags
static int register_flags(SwsContext *ctx, const SwsOpList *ops, SwsUOpFlags flags)
Definition: uops.c:896
fail
#define fail
Definition: test.h:478
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
NULL
#define NULL
Definition: coverity.c:32
SwsUOp::mat4
SwsPixel mat4[4][5]
Definition: uops.h:234
SWS_PIXEL_TYPE_NB
@ SWS_PIXEL_TYPE_NB
Definition: uops.h:44
SwsUOpParams::shift
SwsShiftUOp shift
Definition: uops.h:212
flags
static const SwsFlags flags[]
Definition: uops.c:953
translate_swizzle
static int translate_swizzle(SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op)
Definition: uops.c:595
av_unreachable
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition: avassert.h:116
SwsMoveUOp::dst
int8_t dst[SWS_UOP_MOVE_MAX]
Definition: uops.h:172
AVTreeNode
Definition: tree.c:26
SwsClearUOp::one
SwsCompMask one
Definition: uops.h:181
SWS_UOP_FLAG_MOVE
@ SWS_UOP_FLAG_MOVE
Definition: uops.h:98
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:63
SWS_UOP_READ_NIBBLE
@ SWS_UOP_READ_NIBBLE
Definition: uops.h:110
SWS_UOP_ADD
@ SWS_UOP_ADD
Definition: uops.h:136
generate_entry_struct
static int generate_entry_struct(void *opaque, void *key)
Definition: uops.c:222
translate_dither_op
static int translate_dither_op(SwsUOpList *ops, const SwsOp *op)
Definition: uops.c:653
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
SwsPixelType
SwsPixelType
Definition: uops.h:38
pixel_is_1s
static bool pixel_is_1s(SwsPixelType type, SwsPixel val)
Definition: uops.c:116
SwsUOp::par
SwsUOpParams par
Definition: uops.h:226
SWS_UOP_TO_U32
@ SWS_UOP_TO_U32
Definition: uops.h:131
exact_prod
static bool exact_prod(SwsPixelType type, SwsPixel coef, const SwsComps *comps, int idx)
Definition: uops.c:427
ff_sws_graph_free
void ff_sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition: graph.c:907
SwsUOp
Definition: uops.h:221
SWS_UOP_WRITE_BIT
@ SWS_UOP_WRITE_BIT
Definition: uops.h:117
uop_uninit
static void uop_uninit(SwsUOp *uop)
Definition: uops.c:351
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
SWS_OP_FLAG_SPLIT_MEMCPY
@ SWS_OP_FLAG_SPLIT_MEMCPY
Definition: ops_dispatch.h:173
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1043
SWS_UOP_READ_PLANAR_FV_FMA
@ SWS_UOP_READ_PLANAR_FV_FMA
Definition: uops.h:108
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsLinearUOp::zero
uint32_t zero
Definition: uops.h:187
SwsUOp::mask
SwsCompMask mask
Definition: uops.h:225
SwsDitherUOp::size_log2
uint8_t size_log2
Definition: uops.h:201
size
int size
Definition: twinvq_data.h:10344
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:48
AVRational64
64-bit Rational number (pair of numerator and denominator).
Definition: rational64.h:52
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:40
SWS_UOP_UNPACK
@ SWS_UOP_UNPACK
Definition: uops.h:141
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:70
tree.h
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: uops.h:42
av_refstruct_ref
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition: refstruct.c:140
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: uops.h:195
SwsPixel
Definition: uops.h:51
SwsOp::comps
SwsComps comps
Metadata about the operation's input/output components.
Definition: ops.h:234
register_uop
static int register_uop(struct AVTreeNode **root, const SwsUOp *uop)
Definition: uops.c:875
ff_sws_uops_macros_gen
int ff_sws_uops_macros_gen(char **out_str)
Generate a set of boilerplate C preprocessor macros for describing and programmatically iterating ove...
Definition: uops.c:977
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
ff_sws_uop_list_alloc
SwsUOpList * ff_sws_uop_list_alloc(void)
Definition: uops.c:381
av_refstruct_unref
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
register_all_uops
static int register_all_uops(SwsContext *ctx, void *graph, SwsOpList *ops)
Definition: uops.c:942
SWS_UOP_TO_U8
@ SWS_UOP_TO_U8
Definition: uops.h:129
exact_product_f32
static bool exact_product_f32(float a, float b)
Definition: uops.c:420
SWS_UOP_READ_PLANAR
@ SWS_UOP_READ_PLANAR
Definition: uops.h:105
SwsOpList::ops
SwsOp * ops
Definition: ops.h:266
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: uops.h:40
needed
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is needed
Definition: filter_design.txt:212
SWS_UOP_SWAP_BYTES
@ SWS_UOP_SWAP_BYTES
Definition: uops.h:125
SwsUOp::scalar
SwsPixel scalar
Definition: uops.h:232
ops_internal.h
SWS_UOP_LINEAR
@ SWS_UOP_LINEAR
Definition: uops.h:146
ff_sws_enum_op_lists
int ff_sws_enum_op_lists(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
Helper function to enumerate over all possible (optimized) operation lists, under the current set of ...
Definition: ops.c:1052
SwsOp
Definition: ops.h:210
SwsUOpParams::lin
SwsLinearUOp lin
Definition: uops.h:217
SwsPackUOp::pattern
uint8_t pattern[4]
Definition: uops.h:177
abbr
char abbr[32]
Definition: uops.c:45
SwsUOp::type
SwsPixelType type
Definition: uops.h:223
AVRational64::den
int64_t den
Denominator.
Definition: rational64.h:54
pixel_type_to_int
static SwsPixelType pixel_type_to_int(const SwsPixelType type)
Definition: uops.c:407
ff_sws_ops_translate
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:862
ret
ret
Definition: filter_design.txt:187
is_expand_bit
static bool is_expand_bit(SwsPixelType type, AVRational64 factor)
Definition: uops.c:741
BPRINT_STR
#define BPRINT_STR(str)
SwsComps::min
AVRational64 min[4]
Definition: ops.h:87
SwsUOpList::num_ops
int num_ops
Definition: uops.h:257
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:54
SwsCompiledOp
Definition: ops_dispatch.h:100
ff_sws_uop_list_free
void ff_sws_uop_list_free(SwsUOpList **p_ops)
Definition: uops.c:367
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:102
SwsUOp::ptr
SwsPixel * ptr
Definition: uops.h:231
SwsComps
Definition: ops.h:82
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:56
SwsLinearUOp::exact
uint32_t exact
Definition: uops.h:190
SWS_OP_SWAP_BYTES
@ SWS_OP_SWAP_BYTES
Definition: ops.h:41
ff_sws_uop_name
void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX])
Definition: uops.c:129
SwsDitherUOp::y_offset
uint8_t y_offset[4]
Definition: uops.h:200
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
px
#define px
Definition: uops_tmpl.c:54
SwsUOpList
Definition: uops.h:255
SwsUOp::vec4
SwsPixel vec4[4]
Definition: uops.h:233
ff_sws_uop_list_append
int ff_sws_uop_list_append(SwsUOpList *uops, SwsUOp *uop)
Definition: uops.c:386
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend, SwsOpList **pops, int flags, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
Definition: ops_dispatch.c:751
generate_entry_args
static int generate_entry_args(void *opaque, void *key)
Definition: uops.c:288
SWS_UOP_DITHER
@ SWS_UOP_DITHER
Definition: uops.h:148
SWS_UOP_WRITE_PACKED
@ SWS_UOP_WRITE_PACKED
Definition: uops.h:115
SwsDitherUOp
Definition: uops.h:199
SwsUOpParams::dither
SwsDitherUOp dither
Definition: uops.h:218
mem.h
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:122
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: uops.h:43
SWS_UOP_READ_PLANAR_FV
@ SWS_UOP_READ_PLANAR_FV
Definition: uops.h:107
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
uops.h
SWS_UOP_EXPAND_QUAD
@ SWS_UOP_EXPAND_QUAD
Definition: uops.h:128
SwsUOpFlags
uint32_t SwsUOpFlags
Definition: uops.h:94
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AVRational64::num
int64_t num
Numerator.
Definition: rational64.h:53
SwsComps::max
AVRational64 max[4]
Definition: ops.h:87
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:52
SWS_UOP_READ_PLANAR_FH
@ SWS_UOP_READ_PLANAR_FH
Definition: uops.h:106
sws_free_context
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition: utils.c:2381
SwsMoveUOp::src
int8_t src[SWS_UOP_MOVE_MAX]
Definition: uops.h:173
SwsUOpParams::filter
SwsFilterUOp filter
Definition: uops.h:211
translate_linear_op
static int translate_linear_op(SwsContext *ctx, SwsUOpList *ops, SwsUOpFlags flags, const SwsOp *op, const SwsComps *input)
Definition: uops.c:701
SWS_UOP_FLAG_FMA
@ SWS_UOP_FLAG_FMA
Definition: uops.h:97
ff_sws_dither_height
int ff_sws_dither_height(const SwsDitherUOp *dither)
Computes (1 << size_log2) + MAX(y_offset).
Definition: uops.c:399
translate_op
static int translate_op(SwsContext *ctx, SwsUOpList *uops, SwsUOpFlags flags, const SwsOp *op, const SwsComps *input)
Definition: uops.c:759
SWS_ACCURATE_RND
@ SWS_ACCURATE_RND
Force bit-exact output.
Definition: swscale.h:177
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:130
SWS_UOP_READ_BIT
@ SWS_UOP_READ_BIT
Definition: uops.h:111
stride
#define stride
Definition: h264pred_template.c:536
SWS_UOP_CLEAR
@ SWS_UOP_CLEAR
Definition: uops.h:145
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:265
SwsContext
Main external API structure.
Definition: swscale.h:227
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: uops.h:41
SWS_MASK
#define SWS_MASK(I, J)
Definition: uops.h:193
SWS_OP_FLAG_DRY_RUN
@ SWS_OP_FLAG_DRY_RUN
Definition: ops_dispatch.h:170
SwsSwizzleUOp::in
uint8_t in[4]
Definition: uops.h:163
SwsUOpParams::clear
SwsClearUOp clear
Definition: uops.h:216
SwsUOpList::ops
SwsUOp * ops
Definition: uops.h:256
src
#define src
Definition: vp8dsp.c:248
SWS_UOP_EXPAND_PAIR
@ SWS_UOP_EXPAND_PAIR
Definition: uops.h:127
register_uops
static int register_uops(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Definition: uops.c:923
pixel_from_q64
static SwsPixel pixel_from_q64(SwsPixelType type, AVRational64 val)
Definition: uops.c:98
ff_sws_comp_mask_str
#define ff_sws_comp_mask_str(mask)
Definition: uops.h:82
min
float min
Definition: vorbis_enc_data.h:429