FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/uops.h
Date: 2026-08-26 01:27:24
Exec Total Coverage
Lines: 21 27 77.8%
Functions: 4 4 100.0%
Branches: 10 15 66.7%

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