Coverage Report

Created: 2026-08-17 07:50

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
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
static inline av_const int ff_sws_pixel_type_size(SwsPixelType type)
51
0
{
52
0
    switch (type) {
53
0
    case SWS_PIXEL_U8:  return sizeof(uint8_t);
54
0
    case SWS_PIXEL_U16: return sizeof(uint16_t);
55
0
    case SWS_PIXEL_U32: return sizeof(uint32_t);
56
0
    case SWS_PIXEL_F32: return sizeof(float);
57
0
    case SWS_PIXEL_NONE: break;
58
0
    case SWS_PIXEL_TYPE_NB: break;
59
0
    }
60
0
    return 0;
61
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
62
63
static inline av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
64
0
{
65
0
    switch (type) {
66
0
    case SWS_PIXEL_U8:
67
0
    case SWS_PIXEL_U16:
68
0
    case SWS_PIXEL_U32:
69
0
        return true;
70
0
    case SWS_PIXEL_F32:
71
0
        return false;
72
0
    case SWS_PIXEL_NONE:
73
0
    case SWS_PIXEL_TYPE_NB: break;
74
0
    }
75
0
    return false;
76
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
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
0
#define SWS_COMP(X) (1 << (X))
98
0
#define SWS_COMP_TEST(mask, X) (!!((mask) & SWS_COMP(X)))
99
#define SWS_COMP_INV(mask) ((mask) ^ SWS_COMP_ALL)
100
0
#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
0
    (((X) ? SWS_COMP(0) : 0) |      \
104
0
     ((Y) ? SWS_COMP(1) : 0) |      \
105
0
     ((Z) ? SWS_COMP(2) : 0) |      \
106
0
     ((W) ? SWS_COMP(3) : 0))
107
};
108
109
110
0
#define ff_sws_comp_mask_str(mask) ff_sws_comp_mask_print(mask, (char[5]){0})
111
static inline char *ff_sws_comp_mask_print(SwsCompMask mask, char buf[5])
112
0
{
113
0
    char *ptr = buf;
114
0
    for (int c = 0; c < 4; c++) {
115
0
        if (SWS_COMP_TEST(mask, c))
116
0
            *ptr++ = "xyzw"[c];
117
0
    }
118
0
    *ptr = '\0';
119
0
    return buf;
120
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
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
0
#define SWS_MASK(I, J)  (1 << (5 * (I) + (J)))
232
#define SWS_MASK_OFF(I) SWS_MASK(I, 4)
233
0
#define SWS_MASK_ROW(I) (0x1F << (5 * (I)))
234
0
#define SWS_MASK_COL(J) (0x8421 << J)
235
0
#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
static inline int ff_sws_uop_cmp_v(const void *a, const void *b)
290
0
{
291
0
    return ff_sws_uop_cmp(a, b);
292
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
293
294
/**
295
 * Generate a unique name for a SwsUOp.
296
 */
297
0
#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