Coverage Report

Created: 2026-10-28 07:09

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