FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/uops.h
Date: 2026-10-19 01:23:10
Exec Total Coverage
Lines: 32 43 74.4%
Functions: 6 6 100.0%
Branches: 17 25 68.0%

Line Branch Exec Source
1 /**
2 * Copyright (C) 2025 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
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 #ifndef SWSCALE_UOPS_H
22 #define SWSCALE_UOPS_H
23
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27
28 /***************************************************************************
29 * Note: This header must be usable at build time, to generate asm sources *
30 ***************************************************************************/
31
32 #include "libavutil/attributes.h"
33 #include "rational64.h"
34
35 typedef struct SwsContext SwsContext;
36 typedef struct SwsFilterWeights SwsFilterWeights;
37 typedef struct SwsLut3D SwsLut3D;
38 typedef struct SwsOpList SwsOpList;
39
40 typedef enum SwsPixelType {
41 SWS_PIXEL_NONE = 0,
42 SWS_PIXEL_U8,
43 SWS_PIXEL_U16,
44 SWS_PIXEL_U32,
45 SWS_PIXEL_F32,
46 SWS_PIXEL_TYPE_NB
47 } SwsPixelType;
48
49 const char *ff_sws_pixel_type_name(SwsPixelType type);
50
51 23551762 static inline av_const int ff_sws_pixel_type_size(SwsPixelType type)
52 {
53
4/7
✓ Branch 0 taken 3849715 times.
✓ Branch 1 taken 9933387 times.
✓ Branch 2 taken 1590733 times.
✓ Branch 3 taken 8177927 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
23551762 switch (type) {
54 3849715 case SWS_PIXEL_U8: return sizeof(uint8_t);
55 9933387 case SWS_PIXEL_U16: return sizeof(uint16_t);
56 1590733 case SWS_PIXEL_U32: return sizeof(uint32_t);
57 8177927 case SWS_PIXEL_F32: return sizeof(float);
58 ✗ case SWS_PIXEL_NONE: break;
59 ✗ case SWS_PIXEL_TYPE_NB: break;
60 }
61 ✗ return 0;
62 }
63
64 141691531 static inline av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
65 {
66
2/4
✓ Branch 0 taken 100073943 times.
✓ Branch 1 taken 41617588 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
141691531 switch (type) {
67 100073943 case SWS_PIXEL_U8:
68 case SWS_PIXEL_U16:
69 case SWS_PIXEL_U32:
70 100073943 return true;
71 41617588 case SWS_PIXEL_F32:
72 41617588 return false;
73 ✗ case SWS_PIXEL_NONE:
74 ✗ case SWS_PIXEL_TYPE_NB: break;
75 }
76 ✗ return false;
77 }
78
79 typedef union SwsPixel {
80 char data[4];
81
82 uint8_t u8;
83 uint16_t u16;
84 uint32_t u32;
85 float f32;
86 } SwsPixel;
87
88 /* Ensures (SwsPixel) {0} is properly initialized to all zeros */
89 static_assert(sizeof(SwsPixel) == sizeof(char[4]), "SwsPixel size mismatch");
90
91 156521686 static inline SwsPixel ff_sws_pixel_from_q64(SwsPixelType type, AVRational64 val)
92 {
93
4/6
✓ Branch 0 taken 105360 times.
✓ Branch 1 taken 220351 times.
✓ Branch 2 taken 42126 times.
✓ Branch 3 taken 156153849 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
156521686 switch (type) {
94 156521686 case SWS_PIXEL_U8: return (SwsPixel) { .u8 = val.num / val.den };
95 220351 case SWS_PIXEL_U16: return (SwsPixel) { .u16 = val.num / val.den };
96 42126 case SWS_PIXEL_U32: return (SwsPixel) { .u32 = val.num / val.den };
97 156153849 case SWS_PIXEL_F32: return (SwsPixel) { .f32 = (float) val.num / val.den };
98 ✗ case SWS_PIXEL_NONE:
99 ✗ case SWS_PIXEL_TYPE_NB: break;
100 }
101 ✗ return (SwsPixel) {0};
102 }
103
104 322552 static inline bool ff_sws_pixel_is_1s(SwsPixelType type, SwsPixel val)
105 {
106
3/4
✓ Branch 0 taken 51886 times.
✓ Branch 1 taken 139250 times.
✓ Branch 2 taken 131416 times.
✗ Branch 3 not taken.
322552 switch (ff_sws_pixel_type_size(type)) {
107 51886 case 1: return val.u8 == UINT8_MAX;
108 139250 case 2: return val.u16 == UINT16_MAX;
109 131416 case 4: return val.u32 == UINT32_MAX;
110 ✗ default: break;
111 }
112 ✗ return false;
113 }
114
115 /**
116 * Bit-mask of components. Exact meaning depends on the usage context.
117 */
118 typedef uint8_t SwsCompMask;
119 enum {
120 SWS_COMP_NONE = 0,
121 SWS_COMP_ALL = 0xF,
122 #define SWS_COMP(X) (1 << (X))
123 #define SWS_COMP_TEST(mask, X) (!!((mask) & SWS_COMP(X)))
124 #define SWS_COMP_INV(mask) ((mask) ^ SWS_COMP_ALL)
125 #define SWS_COMP_ELEMS(N) ((1 << (N)) - 1)
126 #define SWS_COMP_COUNT(mask) (av_popcount((mask) & SWS_COMP_ALL))
127 #define SWS_COMP_MASK(X, Y, Z, W) \
128 (((X) ? SWS_COMP(0) : 0) | \
129 ((Y) ? SWS_COMP(1) : 0) | \
130 ((Z) ? SWS_COMP(2) : 0) | \
131 ((W) ? SWS_COMP(3) : 0))
132 };
133
134
135 #define ff_sws_comp_mask_str(mask) ff_sws_comp_mask_print(mask, (char[5]){0})
136 37141679 static inline char *ff_sws_comp_mask_print(SwsCompMask mask, char buf[5])
137 {
138 37141679 char *ptr = buf;
139
2/2
✓ Branch 0 taken 148566716 times.
✓ Branch 1 taken 37141679 times.
185708395 for (int c = 0; c < 4; c++) {
140
2/2
✓ Branch 0 taken 53491665 times.
✓ Branch 1 taken 95075051 times.
148566716 if (SWS_COMP_TEST(mask, c))
141 53491665 *ptr++ = "xyzw"[c];
142 }
143 37141679 *ptr = '\0';
144 37141679 return buf;
145 }
146
147 typedef uint32_t SwsUOpFlags;
148 typedef enum SwsUOpFlagBits {
149 SWS_UOP_FLAG_NONE = 0,
150 SWS_UOP_FLAG_FMA = (1 << 0), /* platform supports FMA ops */
151 SWS_UOP_FLAG_PSHUFB = (1 << 1), /* platform supports pshufb equivalent */
152 SWS_UOP_FLAG_EXPAND_BIT = (1 << 2), /* backend implements SWS_UOP_EXPAND_BIT */
153 SWS_UOP_FLAG_READ_PALETTE = (1 << 3), /* backend implements SWS_UOP_READ_PALETTE */
154 SWS_UOP_FLAG_ADD = (1 << 4), /* backend implements SWS_UOP_ADD */
155 } SwsUOpFlagBits;
156
157 typedef enum SwsUOpType {
158 SWS_UOP_INVALID = 0,
159
160 /* Read/write uops; mask = components to read/write */
161 SWS_UOP_READ_PLANAR, /* simple planar byte-aligned read */
162 SWS_UOP_READ_PLANAR_FH, /* planar read with horizontal filter */
163 SWS_UOP_READ_PLANAR_FV, /* planar read with vertical filter */
164 SWS_UOP_READ_PLANAR_FV_FMA,
165 SWS_UOP_READ_PACKED, /* simple packed byte-aligned read */
166 SWS_UOP_READ_NIBBLE, /* fractional read (4 bits) from single plane */
167 SWS_UOP_READ_BIT, /* fractional read (1 bit) from single plane */
168 SWS_UOP_READ_PALETTE, /* indexed read from palette in plane 1 */
169
170 SWS_UOP_WRITE_PLANAR, /* simple planar byte-aligned write */
171 SWS_UOP_WRITE_PACKED, /* simple packed byte-aligned write */
172 SWS_UOP_WRITE_NIBBLE, /* fractional write (4 bits) to single plane */
173 SWS_UOP_WRITE_BIT, /* fractional write (1 bit) to single plane */
174
175 /* Packed shuffle / gather uops */
176 SWS_UOP_RW_SHUFFLE, /* in-place (packed) indexed shuffle/gather */
177
178 /* Data rearrangement uops; mask = needed or trivial components */
179 SWS_UOP_PERMUTE, /* permute pointers (no duplicates) */
180 SWS_UOP_COPY, /* permute data (may contain duplicates) */
181
182 /* Data conversion / manipulation uops; mask = affected components */
183 SWS_UOP_SWAP_BYTES, /* swap byte order in components */
184 SWS_UOP_EXPAND_BIT, /* expand low-order bit to all bits in type */
185 SWS_UOP_EXPAND_PAIR, /* expand bytes in pairs (16 bit) */
186 SWS_UOP_EXPAND_QUAD, /* expand bytes in quads (32 bit) */
187 SWS_UOP_TO_U8, /* cast pixel values to SWS_PIXEL_U8 */
188 SWS_UOP_TO_U16, /* cast pixel values to SWS_PIXEL_U16 */
189 SWS_UOP_TO_U32, /* cast pixel values to SWS_PIXEL_U32 */
190 SWS_UOP_TO_F32, /* cast pixel values to SWS_PIXEL_F32 */
191
192 /* Arithmetic uops */
193 SWS_UOP_SCALE, /* multiply masked components by scalar */
194 SWS_UOP_ADD, /* add vec4 to masked components */
195 SWS_UOP_MIN, /* min(x, vec4) on masked components */
196 SWS_UOP_MAX, /* max(x, vec4) on masked components */
197
198 /* Identical to corresponding SwsOpType */
199 SWS_UOP_UNPACK, /* mask = nonzero components in pack pattern */
200 SWS_UOP_PACK, /* mask = nonzero components in pack pattern */
201 SWS_UOP_LSHIFT, /* mask = components to shift */
202 SWS_UOP_RSHIFT, /* mask = components to shift */
203 SWS_UOP_CLEAR, /* mask = components to clear */
204 SWS_UOP_LINEAR, /* mask = non-trivial output rows */
205 SWS_UOP_LINEAR_FMA, /* with SWS_UOP_FLAG_FMA */
206 SWS_UOP_DITHER, /* mask = components to dither */
207 SWS_UOP_LUT_3D, /* mask = needed output components */
208
209 /* Platform-specific uops would go here */
210 SWS_UOP_TYPE_NB,
211 } SwsUOpType;
212
213 typedef struct SwsShuffleUOp {
214 uint8_t clear_value; /* value to clear elements with negative indices to */
215 uint8_t read_size; /* input bytes per iteration */
216 uint8_t write_size; /* output bytes per iteration */
217 } SwsShuffleUOp;
218
219 typedef struct SwsShuffleMask {
220 int8_t mask[16]; /* shuffle index mask, or -1 to clear bytes (to `clear_value`) */
221 uint8_t pixels; /* number of pixels per iteration */
222 } SwsShuffleMask;
223
224 typedef struct SwsFilterUOp {
225 SwsPixelType type; /* pixel type to store result as */
226 } SwsFilterUOp;
227
228 typedef struct SwsShiftUOp {
229 uint8_t amount;
230 } SwsShiftUOp;
231
232 typedef struct SwsMoveUOp {
233 /* The worst case number of moves (for two independent cycles) */
234 #define SWS_UOP_MOVE_MAX 6
235 int num_moves;
236
237 /* This may involve a temporary register (index -1) */
238 int8_t dst[SWS_UOP_MOVE_MAX]; /* destination register index */
239 int8_t src[SWS_UOP_MOVE_MAX]; /* source register index */
240 } SwsMoveUOp;
241
242 typedef struct SwsPackUOp {
243 uint8_t pattern[4]; /* bit depth pattern, from MSB to LSB */
244 } SwsPackUOp;
245
246 typedef struct SwsClearUOp {
247 SwsCompMask one; /* mask of coefficients equal to all 1s */
248 SwsCompMask zero; /* mask of coefficients equal to all 0s */
249 } SwsClearUOp;
250
251 typedef struct SwsLinearUOp {
252 uint32_t one; /* mask of coefficients equal to one */
253 uint32_t zero; /* mask of coefficients equal to zero */
254
255 /* for SWS_UOP_LINEAR_FMA only */
256 uint32_t exact; /* mask of coefficients whose product is exact */
257 } SwsLinearUOp;
258
259 #define SWS_MASK(I, J) (1 << (5 * (I) + (J)))
260 #define SWS_MASK_OFF(I) SWS_MASK(I, 4)
261 #define SWS_MASK_ROW(I) (0x1F << (5 * (I)))
262 #define SWS_MASK_COL(J) (0x8421 << J)
263 #define SWS_MASK_DIAG4 (0x41041)
264
265 typedef struct SwsDitherUOp {
266 uint8_t y_offset[4];
267 uint8_t size_log2;
268 } SwsDitherUOp;
269
270 typedef struct SwsLut3DUOp {
271 int dynamic;
272 } SwsLut3DUOp;
273
274 /**
275 * Computes (1 << size_log2) + MAX(y_offset). The dither matrix attached to
276 * the SwsUOp is always pre-padded to this number of lines.
277 */
278 int ff_sws_dither_height(const SwsDitherUOp *dither);
279
280 typedef union SwsUOpParams {
281 SwsShuffleUOp shuffle; /* for SWS_UOP_RW_SHUFFLE */
282 SwsFilterUOp filter; /* for SWS_UOP_READ_*_FV/FH */
283 SwsShiftUOp shift;
284 SwsMoveUOp move; /* for SWS_UOP_PERMUTE and SWS_UOP_COPY */
285 SwsPackUOp pack;
286 SwsClearUOp clear;
287 SwsLinearUOp lin;
288 SwsDitherUOp dither;
289 SwsLut3DUOp lut3d;
290 } SwsUOpParams;
291
292 typedef struct SwsUOp {
293 /* These fields uniquely identify the uop implementation */
294 SwsPixelType type;
295 SwsUOpType uop;
296 SwsCompMask mask;
297 SwsUOpParams par;
298
299 /* Constant data for this uop; not part of the unique identifier */
300 union {
301 SwsFilterWeights *kernel; /* refstruct */
302 SwsPixel *ptr; /* refstruct */
303 SwsPixel scalar;
304 SwsPixel vec4[4];
305 SwsPixel mat4x5[4][5]; /* row major */
306 SwsShuffleMask shuffle; /* for SWS_UOP_RW_SHUFFLE */
307 const SwsLut3D *lut3d; /* for SWS_UOP_LUT_3D; refstruct */
308 void *opaque; /* reserved for internal use */
309 } data;
310 } SwsUOp;
311
312 /**
313 * Compare two SwsUOps for equality (excluding constant data).
314 */
315 int ff_sws_uop_cmp(const SwsUOp *a, const SwsUOp *b);
316
317 58128857 static inline int ff_sws_uop_cmp_v(const void *a, const void *b)
318 {
319 58128857 return ff_sws_uop_cmp(a, b);
320 }
321
322 /**
323 * Generate a unique name for a SwsUOp.
324 */
325 #define SWS_UOP_NAME_MAX 64
326 void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX]);
327
328 typedef struct SwsUOpList {
329 SwsUOp *ops;
330 int num_ops;
331
332 /* Additional metadata for implementations */
333 SwsCompMask planes_in; /* mask of planes read from */
334 SwsCompMask planes_out; /* mask of planes written to */
335 int pixel_size_max; /* size of largest pixel type seen in any uop */
336 } SwsUOpList;
337
338 SwsUOpList *ff_sws_uop_list_alloc(void);
339 void ff_sws_uop_list_free(SwsUOpList **ops);
340 void ff_sws_uop_list_remove_at(SwsUOpList *uops, int index, int count);
341
342 /* Takes over ownership of `uop` and sets it to {0}, even on failure. */
343 int ff_sws_uop_list_append(SwsUOpList *uops, SwsUOp *uop);
344
345 /**
346 * Called internally by ff_sws_ops_translate().
347 */
348 int ff_sws_uop_list_optimize(SwsContext *ctx, SwsUOpFlags flags, SwsUOpList *uops);
349
350 /**
351 * Translate a list of operations down to micro-ops, which can be further
352 * optimized and then directly executed by backends.
353 *
354 * Return 0 or a negative error code.
355 */
356 int ff_sws_ops_translate(SwsContext *ctx, const SwsOpList *ops,
357 SwsUOpFlags flags, SwsUOpList *uops);
358
359 /**
360 * Compute a shuffle mask for `pshufb`-style ASM functions, by repeating
361 * the shuffle pattern for as many groups as will fit.
362 *
363 * @param uop An operation of type SWS_UOP_RW_SHUFFLE.
364 * @param shuffle The output shuffle index mask (or -1 to clear bytes).
365 * @param size The maximum size (in bytes) of the output shuffle mask.
366 *
367 * @return the number of groups on success, or a negative error code.
368 *
369 * @note The shuffle mask is already pre-expanded to fill up to 16 bytes,
370 * so this is only needed for larger shuffle instructions (e.g. vpermb).
371 */
372 int ff_sws_shuffle_mask(const SwsUOp *uop, int8_t shuffle[], int size);
373
374 #endif
375