Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libswscale/uops_tmpl.c
Line
Count
Source
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 <libavutil/bswap.h>
22
23
#include "uops_tmpl.h"
24
25
#ifndef BIT_DEPTH
26
#  define BIT_DEPTH 8
27
#endif
28
29
#if IS_FLOAT && BIT_DEPTH == 32
30
#  define PIXEL_TYPE SWS_PIXEL_F32
31
0
#  define pixel_t    float
32
0
#  define inter_t    float
33
#  define PX         F32
34
0
#  define px         f32
35
#elif BIT_DEPTH == 32
36
0
#  define PIXEL_MAX  0xFFFFFFFFu
37
0
#  define PIXEL_SWAP av_bswap32
38
0
#  define pixel_t    uint32_t
39
#  define inter_t    int64_t
40
#  define PX         U32
41
0
#  define px         u32
42
#elif BIT_DEPTH == 16
43
0
#  define PIXEL_MAX  0xFFFFu
44
0
#  define PIXEL_SWAP av_bswap16
45
0
#  define pixel_t    uint16_t
46
0
#  define inter_t    int64_t
47
#  define PX         U16
48
0
#  define px         u16
49
#elif BIT_DEPTH == 8
50
0
#  define PIXEL_MAX  0xFFu
51
0
#  define pixel_t    uint8_t
52
0
#  define inter_t    int32_t
53
#  define PX         U8
54
0
#  define px         u8
55
#else
56
#  error Invalid BIT_DEPTH
57
#endif
58
59
/*********************************
60
 * Generic read/write operations *
61
 *********************************/
62
63
DECL_READ(read_planar, const SwsCompMask mask)
64
0
{
65
0
    SWS_LOOP
66
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
67
0
        if (X) x[i] = in0[i];
68
0
        if (Y) y[i] = in1[i];
69
0
        if (Z) z[i] = in2[i];
70
0
        if (W) w[i] = in3[i];
71
0
    }
72
73
0
    if (X) iter->in[0] += SIZEOF_BLOCK;
74
0
    if (Y) iter->in[1] += SIZEOF_BLOCK;
75
0
    if (Z) iter->in[2] += SIZEOF_BLOCK;
76
0
    if (W) iter->in[3] += SIZEOF_BLOCK;
77
78
0
    CONTINUE(x, y, z, w);
79
0
}
Unexecuted instantiation: uops_backend.c:read_planar_U8
Unexecuted instantiation: uops_backend.c:read_planar_U16
Unexecuted instantiation: uops_backend.c:read_planar_U32
Unexecuted instantiation: uops_backend.c:read_planar_F32
80
81
DECL_READ(read_packed, const SwsCompMask mask)
82
0
{
83
0
    const int elems = W ? 4 : Z ? 3 : Y ? 2 : 1;
84
85
0
    SWS_LOOP
86
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
87
0
        if (X) x[i] = in0[elems * i + 0];
88
0
        if (Y) y[i] = in0[elems * i + 1];
89
0
        if (Z) z[i] = in0[elems * i + 2];
90
0
        if (W) w[i] = in0[elems * i + 3];
91
0
    }
92
93
0
    iter->in[0] += SIZEOF_BLOCK * elems;
94
0
    CONTINUE(x, y, z, w);
95
0
}
Unexecuted instantiation: uops_backend.c:read_packed_U8
Unexecuted instantiation: uops_backend.c:read_packed_U16
Unexecuted instantiation: uops_backend.c:read_packed_U32
Unexecuted instantiation: uops_backend.c:read_packed_F32
96
97
DECL_WRITE(write_planar, const SwsCompMask mask)
98
0
{
99
0
    SWS_LOOP
100
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
101
0
        if (X) out0[i] = x[i];
102
0
        if (Y) out1[i] = y[i];
103
0
        if (Z) out2[i] = z[i];
104
0
        if (W) out3[i] = w[i];
105
0
    }
106
107
0
    if (X) iter->out[0] += SIZEOF_BLOCK;
108
0
    if (Y) iter->out[1] += SIZEOF_BLOCK;
109
0
    if (Z) iter->out[2] += SIZEOF_BLOCK;
110
0
    if (W) iter->out[3] += SIZEOF_BLOCK;
111
0
}
Unexecuted instantiation: uops_backend.c:write_planar_U8
Unexecuted instantiation: uops_backend.c:write_planar_U16
Unexecuted instantiation: uops_backend.c:write_planar_U32
Unexecuted instantiation: uops_backend.c:write_planar_F32
112
113
DECL_WRITE(write_packed, const SwsCompMask mask)
114
0
{
115
0
    const int elems = W ? 4 : Z ? 3 : Y ? 2 : 1;
116
117
0
    SWS_LOOP
118
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
119
0
        if (X) out0[elems * i + 0] = x[i];
120
0
        if (Y) out0[elems * i + 1] = y[i];
121
0
        if (Z) out0[elems * i + 2] = z[i];
122
0
        if (W) out0[elems * i + 3] = w[i];
123
0
    }
124
125
0
    iter->out[0] += SIZEOF_BLOCK * elems;
126
0
}
Unexecuted instantiation: uops_backend.c:write_packed_U8
Unexecuted instantiation: uops_backend.c:write_packed_U16
Unexecuted instantiation: uops_backend.c:write_packed_U32
Unexecuted instantiation: uops_backend.c:write_packed_F32
127
128
#if BIT_DEPTH == 8
129
130
DECL_READ(read_bit, const SwsCompMask mask)
131
0
{
132
0
    av_assert2(mask == SWS_COMP_ELEMS(1));
133
134
0
    SWS_LOOP
135
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) {
136
0
        const pixel_t val = ((const pixel_t *) in0)[i >> 3];
137
0
        x[i + 0] = (val >> 7) & 1;
138
0
        x[i + 1] = (val >> 6) & 1;
139
0
        x[i + 2] = (val >> 5) & 1;
140
0
        x[i + 3] = (val >> 4) & 1;
141
0
        x[i + 4] = (val >> 3) & 1;
142
0
        x[i + 5] = (val >> 2) & 1;
143
0
        x[i + 6] = (val >> 1) & 1;
144
0
        x[i + 7] = (val >> 0) & 1;
145
0
    }
146
147
0
    iter->in[0] += SIZEOF_BLOCK >> 3;
148
0
    CONTINUE(x, y, z, w);
149
0
}
150
151
DECL_READ(read_nibble, const SwsCompMask mask)
152
0
{
153
0
    av_assert2(mask == SWS_COMP_ELEMS(1));
154
155
0
    SWS_LOOP
156
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i += 2) {
157
0
        const pixel_t val = in0[i >> 1];
158
0
        x[i + 0] = val >> 4;  /* high nibble */
159
0
        x[i + 1] = val & 0xF; /* low nibble */
160
0
    }
161
162
0
    iter->in[0] += SIZEOF_BLOCK >> 1;
163
0
    CONTINUE(x, y, z, w);
164
0
}
165
166
DECL_READ(read_palette, const SwsCompMask mask)
167
0
{
168
0
    av_assert2(mask == SWS_COMP_ELEMS(4));
169
170
0
    SWS_LOOP
171
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
172
0
        const pixel_t index = in0[i];
173
0
        const pixel_t *value = &in1[index * 4];
174
0
        x[i] = value[0];
175
0
        y[i] = value[1];
176
0
        z[i] = value[2];
177
0
        w[i] = value[3];
178
0
    }
179
180
0
    iter->in[0] += SIZEOF_BLOCK;
181
0
    CONTINUE(x, y, z, w);
182
0
}
183
184
DECL_WRITE(write_bit, const SwsCompMask mask)
185
0
{
186
0
    av_assert2(mask == SWS_COMP_ELEMS(1));
187
188
0
    SWS_LOOP
189
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) {
190
0
        out0[i >> 3] = x[i + 0] << 7 |
191
0
                       x[i + 1] << 6 |
192
0
                       x[i + 2] << 5 |
193
0
                       x[i + 3] << 4 |
194
0
                       x[i + 4] << 3 |
195
0
                       x[i + 5] << 2 |
196
0
                       x[i + 6] << 1 |
197
0
                       x[i + 7];
198
0
    }
199
200
0
    iter->out[0] += SIZEOF_BLOCK >> 3;
201
0
}
202
203
DECL_WRITE(write_nibble, const SwsCompMask mask)
204
0
{
205
0
    av_assert2(mask == SWS_COMP_ELEMS(1));
206
207
0
    SWS_LOOP
208
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i += 2)
209
0
        out0[i >> 1] = x[i] << 4 | x[i + 1];
210
211
0
    iter->out[0] += SIZEOF_BLOCK >> 1;
212
0
}
213
214
#endif /* BIT_DEPTH == 8 */
215
216
SWS_FOR(PX, READ_PLANAR,    DECL_IMPL_READ,     read_planar)
217
SWS_FOR(PX, READ_PACKED,    DECL_IMPL_READ,     read_packed)
218
SWS_FOR(PX, READ_NIBBLE,    DECL_IMPL_READ,     read_nibble)
219
SWS_FOR(PX, READ_BIT,       DECL_IMPL_READ,     read_bit)
220
SWS_FOR(PX, READ_PALETTE,   DECL_IMPL_READ,     read_palette)
221
SWS_FOR(PX, WRITE_PLANAR,   DECL_IMPL_WRITE,    write_planar)
222
SWS_FOR(PX, WRITE_PACKED,   DECL_IMPL_WRITE,    write_packed)
223
SWS_FOR(PX, WRITE_NIBBLE,   DECL_IMPL_WRITE,    write_nibble)
224
SWS_FOR(PX, WRITE_BIT,      DECL_IMPL_WRITE,    write_bit)
225
226
SWS_FOR_STRUCT(PX, READ_PLANAR,     DECL_ENTRY)
227
SWS_FOR_STRUCT(PX, READ_PACKED,     DECL_ENTRY)
228
SWS_FOR_STRUCT(PX, READ_NIBBLE,     DECL_ENTRY)
229
SWS_FOR_STRUCT(PX, READ_BIT,        DECL_ENTRY)
230
SWS_FOR_STRUCT(PX, READ_PALETTE,    DECL_ENTRY)
231
SWS_FOR_STRUCT(PX, WRITE_PLANAR,    DECL_ENTRY)
232
SWS_FOR_STRUCT(PX, WRITE_PACKED,    DECL_ENTRY)
233
SWS_FOR_STRUCT(PX, WRITE_NIBBLE,    DECL_ENTRY)
234
SWS_FOR_STRUCT(PX, WRITE_BIT,       DECL_ENTRY)
235
236
/*****************************
237
 * Scaling / filtering reads *
238
 *****************************/
239
240
DECL_SETUP(setup_filter_v, params, out)
241
0
{
242
0
    if (params->uop->par.filter.type != SWS_PIXEL_F32)
243
0
        return AVERROR(ENOTSUP);
244
245
0
    const SwsFilterWeights *filter = params->uop->data.kernel;
246
0
    static_assert(sizeof(out->priv.ptr) <= sizeof(int32_t[2]),
247
0
                  ">8 byte pointers not supported");
248
249
    /* Pre-convert weights to float */
250
0
    float *weights = av_calloc(filter->num_weights, sizeof(float));
251
0
    if (!weights)
252
0
        return AVERROR(ENOMEM);
253
254
0
    for (int i = 0; i < filter->num_weights; i++)
255
0
        weights[i] = (float) filter->weights[i] / SWS_FILTER_SCALE;
256
257
0
    out->priv.ptr = weights;
258
0
    out->priv.i32[2] = filter->filter_size;
259
0
    out->free = ff_op_priv_free;
260
0
    return 0;
261
0
}
Unexecuted instantiation: uops_backend.c:setup_filter_v_U8
Unexecuted instantiation: uops_backend.c:setup_filter_v_U16
Unexecuted instantiation: uops_backend.c:setup_filter_v_F32
Unexecuted instantiation: uops_backend.c:setup_filter_v_U32
262
263
/* Fully general vertical planar filter case */
264
DECL_READ(read_planar_fv, const SwsCompMask mask, const SwsPixelType type)
265
0
{
266
0
    av_assert2(type == SWS_PIXEL_F32);
267
0
    const SwsOpExec *exec = iter->exec;
268
0
    const float *restrict weights = impl->priv.ptr;
269
0
    const int filter_size = impl->priv.i32[2];
270
0
    weights += filter_size * iter->y;
271
272
0
    block_t xs, ys, zs, ws;
273
0
    if (X) memset(&xs.f32, 0, sizeof(xs.f32));
274
0
    if (Y) memset(&ys.f32, 0, sizeof(ys.f32));
275
0
    if (Z) memset(&zs.f32, 0, sizeof(zs.f32));
276
0
    if (W) memset(&ws.f32, 0, sizeof(ws.f32));
277
278
0
    for (int j = 0; j < filter_size; j++) {
279
0
        const float weight = weights[j];
280
281
0
        SWS_LOOP
282
0
        for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
283
0
            if (X) xs.f32[i] += weight * in0[i];
284
0
            if (Y) ys.f32[i] += weight * in1[i];
285
0
            if (Z) zs.f32[i] += weight * in2[i];
286
0
            if (W) ws.f32[i] += weight * in3[i];
287
0
        }
288
289
0
        if (X) in0 = bump_ptr(in0, exec->in_stride[0]);
290
0
        if (Y) in1 = bump_ptr(in1, exec->in_stride[1]);
291
0
        if (Z) in2 = bump_ptr(in2, exec->in_stride[2]);
292
0
        if (W) in3 = bump_ptr(in3, exec->in_stride[3]);
293
0
    }
294
295
0
    if (X) iter->in[0] += SIZEOF_BLOCK;
296
0
    if (Y) iter->in[1] += SIZEOF_BLOCK;
297
0
    if (Z) iter->in[2] += SIZEOF_BLOCK;
298
0
    if (W) iter->in[3] += SIZEOF_BLOCK;
299
300
0
    CONTINUE(&xs, &ys, &zs, &ws);
301
0
}
Unexecuted instantiation: uops_backend.c:read_planar_fv_U8
Unexecuted instantiation: uops_backend.c:read_planar_fv_U16
Unexecuted instantiation: uops_backend.c:read_planar_fv_F32
Unexecuted instantiation: uops_backend.c:read_planar_fv_U32
302
303
DECL_SETUP(setup_filter_h, params, out)
304
0
{
305
0
    if (params->uop->par.filter.type != SWS_PIXEL_F32)
306
0
        return AVERROR(ENOTSUP);
307
308
0
    SwsFilterWeights *filter = params->uop->data.kernel;
309
0
    out->priv.ptr = av_refstruct_ref(filter->weights);
310
0
    out->priv.i32[2] = filter->filter_size;
311
0
    out->free = ff_op_priv_unref;
312
0
    return 0;
313
0
}
Unexecuted instantiation: uops_backend.c:setup_filter_h_U8
Unexecuted instantiation: uops_backend.c:setup_filter_h_U16
Unexecuted instantiation: uops_backend.c:setup_filter_h_F32
Unexecuted instantiation: uops_backend.c:setup_filter_h_U32
314
315
/* Fully general horizontal planar filter case */
316
DECL_READ(read_planar_fh, const SwsCompMask mask, const SwsPixelType type)
317
0
{
318
0
    av_assert2(type == SWS_PIXEL_F32);
319
0
    const SwsOpExec *exec = iter->exec;
320
0
    const int *restrict weights = impl->priv.ptr;
321
0
    const int filter_size = impl->priv.i32[2];
322
0
    const float scale = 1.0f / SWS_FILTER_SCALE;
323
0
    const int xpos = iter->x;
324
0
    weights += filter_size * iter->x;
325
326
0
    block_t xs, ys, zs, ws;
327
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
328
0
        const int offset = exec->in_offset_x[xpos + i];
329
0
        pixel_t *start0 = bump_ptr(in0, offset);
330
0
        pixel_t *start1 = bump_ptr(in1, offset);
331
0
        pixel_t *start2 = bump_ptr(in2, offset);
332
0
        pixel_t *start3 = bump_ptr(in3, offset);
333
334
0
        inter_t sx = 0, sy = 0, sz = 0, sw = 0;
335
0
        for (int j = 0; j < filter_size; j++) {
336
0
            const int weight = weights[j];
337
0
            if (X) sx += weight * start0[j];
338
0
            if (Y) sy += weight * start1[j];
339
0
            if (Z) sz += weight * start2[j];
340
0
            if (W) sw += weight * start3[j];
341
0
        }
342
343
0
        if (X) xs.f32[i] = (float) sx * scale;
344
0
        if (Y) ys.f32[i] = (float) sy * scale;
345
0
        if (Z) zs.f32[i] = (float) sz * scale;
346
0
        if (W) ws.f32[i] = (float) sw * scale;
347
348
0
        weights += filter_size;
349
0
    }
350
351
0
    CONTINUE(&xs, &ys, &zs, &ws);
352
0
}
Unexecuted instantiation: uops_backend.c:read_planar_fh_U8
Unexecuted instantiation: uops_backend.c:read_planar_fh_U16
Unexecuted instantiation: uops_backend.c:read_planar_fh_F32
Unexecuted instantiation: uops_backend.c:read_planar_fh_U32
353
354
SWS_FOR(PX, READ_PLANAR_FV, DECL_IMPL_READ, read_planar_fv)
355
SWS_FOR(PX, READ_PLANAR_FH, DECL_IMPL_READ, read_planar_fh)
356
SWS_FOR_STRUCT(PX, READ_PLANAR_FV, DECL_ENTRY, .setup = fn(setup_filter_v) )
357
SWS_FOR_STRUCT(PX, READ_PLANAR_FH, DECL_ENTRY, .setup = fn(setup_filter_h) )
358
359
/***************************
360
 * Permutation and copying *
361
 ***************************/
362
363
DECL_FUNC(permute, const SwsCompMask mask, int num_moves,
364
          int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5,
365
          int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5)
366
0
{
367
0
    const int8_t dst[SWS_UOP_MOVE_MAX] = { d0, d1, d2, d3, d4, d5 };
368
0
    const int8_t src[SWS_UOP_MOVE_MAX] = { s0, s1, s2, s3, s4, s5 };
369
370
0
    pixel_t *ptr[5] = { NULL, x, y, z, w };
371
0
    for (int n = 0; n < num_moves; n++)
372
0
        ptr[dst[n] + 1] = ptr[src[n] + 1];
373
374
    /* The unneeded registers may still alias the used ones, so point them
375
     * back at the stack to avoid collisions */
376
0
    block_t xx, yy, zz, ww;
377
0
    CONTINUE(X ? ptr[1] : xx.px,
378
0
             Y ? ptr[2] : yy.px,
379
0
             Z ? ptr[3] : zz.px,
380
0
             W ? ptr[4] : ww.px);
381
0
}
Unexecuted instantiation: uops_backend.c:permute_U8
Unexecuted instantiation: uops_backend.c:permute_U16
Unexecuted instantiation: uops_backend.c:permute_U32
Unexecuted instantiation: uops_backend.c:permute_F32
382
383
DECL_FUNC(copy, const SwsCompMask mask, int num_moves,
384
          int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5,
385
          int8_t s0, int8_t s1, int8_t s2, int8_t s3, int8_t s4, int8_t s5)
386
0
{
387
0
    const size_t block_size = SWS_BLOCK_SIZE * sizeof(pixel_t);
388
0
    const int8_t dst[SWS_UOP_MOVE_MAX] = { d0, d1, d2, d3, d4, d5 };
389
0
    const int8_t src[SWS_UOP_MOVE_MAX] = { s0, s1, s2, s3, s4, s5 };
390
391
0
    block_t data[5];
392
0
    memcpy(&data[1].px, x, block_size);
393
0
    memcpy(&data[2].px, y, block_size);
394
0
    memcpy(&data[3].px, z, block_size);
395
0
    memcpy(&data[4].px, w, block_size);
396
397
0
    for (int n = 0; n < num_moves; n++)
398
0
        data[dst[n] + 1] = data[src[n] + 1];
399
400
0
    memcpy(x, &data[1].px, block_size);
401
0
    memcpy(y, &data[2].px, block_size);
402
0
    memcpy(z, &data[3].px, block_size);
403
0
    memcpy(w, &data[4].px, block_size);
404
405
0
    CONTINUE(x, y, z, w);
406
0
}
Unexecuted instantiation: uops_backend.c:copy_U8
Unexecuted instantiation: uops_backend.c:copy_U16
Unexecuted instantiation: uops_backend.c:copy_U32
Unexecuted instantiation: uops_backend.c:copy_F32
407
408
SWS_FOR(PX, PERMUTE, DECL_IMPL, permute)
409
SWS_FOR(PX, COPY,    DECL_IMPL, copy)
410
SWS_FOR_STRUCT(PX, PERMUTE, DECL_ENTRY)
411
SWS_FOR_STRUCT(PX, COPY,    DECL_ENTRY)
412
413
/*********************
414
 * Format conversion *
415
 *********************/
416
417
#define DECL_CAST(DST, dst)                                                     \
418
    DECL_FUNC(to_##dst, const SwsCompMask mask)                                 \
419
0
    {                                                                           \
420
0
        block_t xx, yy, zz, ww;                                                 \
421
0
                                                                                \
422
0
        SWS_LOOP                                                                \
423
0
        for (int i = 0; i < SWS_BLOCK_SIZE; i++) {                              \
424
0
            if (X) xx.dst[i] = x[i];                                            \
425
0
            if (Y) yy.dst[i] = y[i];                                            \
426
0
            if (Z) zz.dst[i] = z[i];                                            \
427
0
            if (W) ww.dst[i] = w[i];                                            \
428
0
        }                                                                       \
429
0
                                                                                \
430
0
        CONTINUE(&xx, &yy, &zz, &ww);                                           \
431
0
    }                                                                           \
Unexecuted instantiation: uops_backend.c:to_u16_U8
Unexecuted instantiation: uops_backend.c:to_u32_U8
Unexecuted instantiation: uops_backend.c:to_f32_U8
Unexecuted instantiation: uops_backend.c:to_u8_U16
Unexecuted instantiation: uops_backend.c:to_u32_U16
Unexecuted instantiation: uops_backend.c:to_f32_U16
Unexecuted instantiation: uops_backend.c:to_u16_U32
Unexecuted instantiation: uops_backend.c:to_f32_U32
Unexecuted instantiation: uops_backend.c:to_u8_F32
Unexecuted instantiation: uops_backend.c:to_u16_F32
Unexecuted instantiation: uops_backend.c:to_u32_F32
Unexecuted instantiation: uops_backend.c:to_u8_U8
Unexecuted instantiation: uops_backend.c:to_u16_U16
Unexecuted instantiation: uops_backend.c:to_u8_U32
Unexecuted instantiation: uops_backend.c:to_u32_U32
Unexecuted instantiation: uops_backend.c:to_f32_F32
432
                                                                                \
433
    SWS_FOR(PX, TO_##DST, DECL_IMPL, to_##dst)                                  \
434
    SWS_FOR_STRUCT(PX, TO_##DST, DECL_ENTRY)
435
436
DECL_CAST(U8,  u8)
437
DECL_CAST(U16, u16)
438
DECL_CAST(U32, u32)
439
DECL_CAST(F32, f32)
440
441
/********************
442
 * Bit manipulation *
443
 ********************/
444
445
#if !IS_FLOAT
446
DECL_FUNC(lshift, const SwsCompMask mask, const uint8_t amount)
447
0
{
448
0
    SWS_LOOP
449
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
450
0
        if (X) x[i] <<= amount;
451
0
        if (Y) y[i] <<= amount;
452
0
        if (Z) z[i] <<= amount;
453
0
        if (W) w[i] <<= amount;
454
0
    }
455
456
0
    CONTINUE(x, y, z, w);
457
0
}
Unexecuted instantiation: uops_backend.c:lshift_U16
Unexecuted instantiation: uops_backend.c:lshift_U32
Unexecuted instantiation: uops_backend.c:lshift_U8
458
459
DECL_FUNC(rshift, const SwsCompMask mask, const uint8_t amount)
460
0
{
461
0
    SWS_LOOP
462
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
463
0
        if (X) x[i] >>= amount;
464
0
        if (Y) y[i] >>= amount;
465
0
        if (Z) z[i] >>= amount;
466
0
        if (W) w[i] >>= amount;
467
0
    }
468
469
0
    CONTINUE(x, y, z, w);
470
0
}
Unexecuted instantiation: uops_backend.c:rshift_U16
Unexecuted instantiation: uops_backend.c:rshift_U8
Unexecuted instantiation: uops_backend.c:rshift_U32
471
#endif
472
473
SWS_FOR(PX, LSHIFT, DECL_IMPL, lshift)
474
SWS_FOR(PX, RSHIFT, DECL_IMPL, rshift)
475
476
SWS_FOR_STRUCT(PX, LSHIFT, DECL_ENTRY)
477
SWS_FOR_STRUCT(PX, RSHIFT, DECL_ENTRY)
478
479
#ifdef PIXEL_SWAP
480
DECL_FUNC(swap_bytes, const SwsCompMask mask)
481
0
{
482
0
    SWS_LOOP
483
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
484
0
        if (X) x[i] = PIXEL_SWAP(x[i]);
485
0
        if (Y) y[i] = PIXEL_SWAP(y[i]);
486
0
        if (Z) z[i] = PIXEL_SWAP(z[i]);
487
0
        if (W) w[i] = PIXEL_SWAP(w[i]);
488
0
    }
489
490
0
    CONTINUE(x, y, z, w);
491
0
}
Unexecuted instantiation: uops_backend.c:swap_bytes_U16
Unexecuted instantiation: uops_backend.c:swap_bytes_U32
492
#endif /* PIXEL_SWAP */
493
494
SWS_FOR(PX, SWAP_BYTES, DECL_IMPL, swap_bytes)
495
SWS_FOR_STRUCT(PX, SWAP_BYTES, DECL_ENTRY)
496
497
#ifdef PIXEL_MAX
498
DECL_FUNC(expand_bit, const SwsCompMask mask)
499
0
{
500
0
    SWS_LOOP
501
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
502
0
        if (X) x[i] = x[i] ? PIXEL_MAX : 0;
503
0
        if (Y) y[i] = y[i] ? PIXEL_MAX : 0;
504
0
        if (Z) z[i] = z[i] ? PIXEL_MAX : 0;
505
0
        if (W) w[i] = w[i] ? PIXEL_MAX : 0;
506
0
    }
507
508
0
    CONTINUE(x, y, z, w);
509
0
}
Unexecuted instantiation: uops_backend.c:expand_bit_U8
Unexecuted instantiation: uops_backend.c:expand_bit_U16
Unexecuted instantiation: uops_backend.c:expand_bit_U32
510
#endif
511
512
#if BIT_DEPTH == 8
513
DECL_FUNC(expand_pair, const SwsCompMask mask)
514
0
{
515
0
    block_t x16, y16, z16, w16;
516
517
0
    SWS_LOOP
518
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
519
0
        if (X) x16.u16[i] = x[i] << 8 | x[i];
520
0
        if (Y) y16.u16[i] = y[i] << 8 | y[i];
521
0
        if (Z) z16.u16[i] = z[i] << 8 | z[i];
522
0
        if (W) w16.u16[i] = w[i] << 8 | w[i];
523
0
    }
524
525
0
    CONTINUE(&x16, &y16, &z16, &w16);
526
0
}
527
528
DECL_FUNC(expand_quad, const SwsCompMask mask)
529
0
{
530
0
    block_t x32, y32, z32, w32;
531
0
532
0
    SWS_LOOP
533
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
534
0
        if (X) x32.u32[i] = (uint32_t) x[i] << 24 | x[i] << 16 | x[i] << 8 | x[i];
535
0
        if (Y) y32.u32[i] = (uint32_t) y[i] << 24 | y[i] << 16 | y[i] << 8 | y[i];
536
0
        if (Z) z32.u32[i] = (uint32_t) z[i] << 24 | z[i] << 16 | z[i] << 8 | z[i];
537
0
        if (W) w32.u32[i] = (uint32_t) w[i] << 24 | w[i] << 16 | w[i] << 8 | w[i];
538
0
    }
539
0
540
0
    CONTINUE(&x32, &y32, &z32, &w32);
541
0
}
542
#endif /* BIT_DEPTH == 8 */
543
544
SWS_FOR(PX, EXPAND_BIT,  DECL_IMPL, expand_bit)
545
SWS_FOR(PX, EXPAND_PAIR, DECL_IMPL, expand_pair)
546
SWS_FOR(PX, EXPAND_QUAD, DECL_IMPL, expand_quad)
547
SWS_FOR_STRUCT(PX, EXPAND_BIT,  DECL_ENTRY)
548
SWS_FOR_STRUCT(PX, EXPAND_PAIR, DECL_ENTRY)
549
SWS_FOR_STRUCT(PX, EXPAND_QUAD, DECL_ENTRY)
550
551
/*************************
552
 * Packing and unpacking *
553
 ************************/
554
555
#if !IS_FLOAT
556
DECL_FUNC(unpack, const SwsCompMask mask,
557
                  const uint8_t bx, const uint8_t by,
558
                  const uint8_t bz, const uint8_t bw)
559
0
{
560
0
    const uint8_t sx = bw + bz + by;
561
0
    const uint8_t sy = bw + bz;
562
0
    const uint8_t sz = bw;
563
0
    const uint8_t sw = 0;
564
565
0
    const pixel_t mx = (1 << bx) - 1;
566
0
    const pixel_t my = (1 << by) - 1;
567
0
    const pixel_t mz = (1 << bz) - 1;
568
0
    const pixel_t mw = (1 << bw) - 1;
569
570
0
    SWS_LOOP
571
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
572
0
        const pixel_t val = x[i];
573
0
        if (X) x[i] = (val >> sx) & mx;
574
0
        if (Y) y[i] = (val >> sy) & my;
575
0
        if (Z) z[i] = (val >> sz) & mz;
576
0
        if (W) w[i] = (val >> sw) & mw;
577
0
    }
578
579
0
    CONTINUE(x, y, z, w);
580
0
}
Unexecuted instantiation: uops_backend.c:unpack_U8
Unexecuted instantiation: uops_backend.c:unpack_U16
Unexecuted instantiation: uops_backend.c:unpack_U32
581
582
DECL_FUNC(pack, const SwsCompMask mask,
583
                const uint8_t bx, const uint8_t by,
584
                const uint8_t bz, const uint8_t bw)
585
0
{
586
0
    const uint8_t sx = bw + bz + by;
587
0
    const uint8_t sy = bw + bz;
588
0
    const uint8_t sz = bw;
589
0
    const uint8_t sw = 0;
590
591
0
    SWS_LOOP
592
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
593
0
        pixel_t val = 0;
594
0
        if (X) val |= x[i] << sx;
595
0
        if (Y) val |= y[i] << sy;
596
0
        if (Z) val |= z[i] << sz;
597
0
        if (W) val |= w[i] << sw;
598
0
        x[i] = val;
599
0
    }
600
601
0
    CONTINUE(x, y, z, w);
602
0
}
Unexecuted instantiation: uops_backend.c:pack_U8
Unexecuted instantiation: uops_backend.c:pack_U16
Unexecuted instantiation: uops_backend.c:pack_U32
603
#endif /* !IS_FLOAT */
604
605
SWS_FOR(PX, UNPACK, DECL_IMPL, unpack)
606
SWS_FOR(PX, PACK,   DECL_IMPL, pack)
607
SWS_FOR_STRUCT(PX, UNPACK,  DECL_ENTRY)
608
SWS_FOR_STRUCT(PX, PACK,    DECL_ENTRY)
609
610
/***********************
611
 * Pixel data clearing *
612
 ***********************/
613
614
#ifdef PIXEL_MAX
615
DECL_FUNC(clear, const SwsCompMask mask, const SwsCompMask one,
616
                 const SwsCompMask zero)
617
0
{
618
0
    #define ONE(N)  SWS_COMP_TEST(one, N)
619
0
    #define ZERO(N) SWS_COMP_TEST(zero, N)
620
0
    const pixel_t cx = ONE(0) ? PIXEL_MAX : ZERO(0) ? 0 : impl->priv.px[0];
621
0
    const pixel_t cy = ONE(1) ? PIXEL_MAX : ZERO(1) ? 0 : impl->priv.px[1];
622
0
    const pixel_t cz = ONE(2) ? PIXEL_MAX : ZERO(2) ? 0 : impl->priv.px[2];
623
0
    const pixel_t cw = ONE(3) ? PIXEL_MAX : ZERO(3) ? 0 : impl->priv.px[3];
624
625
0
    SWS_LOOP
626
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
627
0
        if (X) x[i] = cx;
628
0
        if (Y) y[i] = cy;
629
0
        if (Z) z[i] = cz;
630
0
        if (W) w[i] = cw;
631
0
    }
632
633
0
    CONTINUE(x, y, z, w);
634
0
}
Unexecuted instantiation: uops_backend.c:clear_U8
Unexecuted instantiation: uops_backend.c:clear_U16
Unexecuted instantiation: uops_backend.c:clear_U32
635
#endif
636
637
SWS_FOR(PX, CLEAR, DECL_IMPL, clear)
638
SWS_FOR_STRUCT(PX, CLEAR, DECL_ENTRY, .setup = ff_sws_setup_vec4)
639
640
/*************************
641
 * Arithmetic operations *
642
 *************************/
643
644
DECL_FUNC(scale, const SwsCompMask mask)
645
0
{
646
0
    const pixel_t scale = impl->priv.px[0];
647
648
0
    SWS_LOOP
649
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
650
0
        if (X) x[i] *= scale;
651
0
        if (Y) y[i] *= scale;
652
0
        if (Z) z[i] *= scale;
653
0
        if (W) w[i] *= scale;
654
0
    }
655
656
0
    CONTINUE(x, y, z, w);
657
0
}
Unexecuted instantiation: uops_backend.c:scale_U8
Unexecuted instantiation: uops_backend.c:scale_U16
Unexecuted instantiation: uops_backend.c:scale_U32
Unexecuted instantiation: uops_backend.c:scale_F32
658
659
DECL_FUNC(add, const SwsCompMask mask)
660
0
{
661
0
    SWS_LOOP
662
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
663
0
        if (X) x[i] += impl->priv.px[0];
664
0
        if (Y) y[i] += impl->priv.px[1];
665
0
        if (Z) z[i] += impl->priv.px[2];
666
0
        if (W) w[i] += impl->priv.px[3];
667
0
    }
668
669
0
    CONTINUE(x, y, z, w);
670
0
}
Unexecuted instantiation: uops_backend.c:add_F32
Unexecuted instantiation: uops_backend.c:add_U8
Unexecuted instantiation: uops_backend.c:add_U16
Unexecuted instantiation: uops_backend.c:add_U32
671
672
DECL_FUNC(min, const SwsCompMask mask)
673
0
{
674
0
    SWS_LOOP
675
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
676
0
        if (X) x[i] = FFMIN(x[i], impl->priv.px[0]);
677
0
        if (Y) y[i] = FFMIN(y[i], impl->priv.px[1]);
678
0
        if (Z) z[i] = FFMIN(z[i], impl->priv.px[2]);
679
0
        if (W) w[i] = FFMIN(w[i], impl->priv.px[3]);
680
0
    }
681
682
0
    CONTINUE(x, y, z, w);
683
0
}
Unexecuted instantiation: uops_backend.c:min_F32
Unexecuted instantiation: uops_backend.c:min_U8
Unexecuted instantiation: uops_backend.c:min_U16
Unexecuted instantiation: uops_backend.c:min_U32
684
685
DECL_FUNC(max, const SwsCompMask mask)
686
0
{
687
0
    SWS_LOOP
688
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
689
0
        if (X) x[i] = FFMAX(x[i], impl->priv.px[0]);
690
0
        if (Y) y[i] = FFMAX(y[i], impl->priv.px[1]);
691
0
        if (Z) z[i] = FFMAX(z[i], impl->priv.px[2]);
692
0
        if (W) w[i] = FFMAX(w[i], impl->priv.px[3]);
693
0
    }
694
695
0
    CONTINUE(x, y, z, w);
696
0
}
Unexecuted instantiation: uops_backend.c:max_F32
Unexecuted instantiation: uops_backend.c:max_U8
Unexecuted instantiation: uops_backend.c:max_U16
Unexecuted instantiation: uops_backend.c:max_U32
697
698
SWS_FOR(PX, SCALE, DECL_IMPL, scale)
699
SWS_FOR(PX, ADD,   DECL_IMPL, add)
700
SWS_FOR(PX, MIN,   DECL_IMPL, min)
701
SWS_FOR(PX, MAX,   DECL_IMPL, max)
702
SWS_FOR_STRUCT(PX, SCALE, DECL_ENTRY, .setup = ff_sws_setup_scalar )
703
SWS_FOR_STRUCT(PX, ADD,   DECL_ENTRY, .setup = ff_sws_setup_vec4 )
704
SWS_FOR_STRUCT(PX, MIN,   DECL_ENTRY, .setup = ff_sws_setup_vec4 )
705
SWS_FOR_STRUCT(PX, MAX,   DECL_ENTRY, .setup = ff_sws_setup_vec4 )
706
707
/*************
708
 * Dithering *
709
 *************/
710
711
DECL_SETUP(setup_dither, params, out)
712
0
{
713
0
    const SwsUOp *uop = params->uop;
714
0
    const SwsDitherUOp *dither = &uop->par.dither;
715
0
    const int size = 1 << dither->size_log2;
716
0
    if (size >= SWS_BLOCK_SIZE) {
717
        /* No extra padding needed */
718
0
        out->priv.ptr = av_refstruct_ref(uop->data.ptr);
719
0
        out->free = ff_op_priv_unref;
720
0
        return 0;
721
0
    }
722
723
0
    const int stride = FFMAX(size, SWS_BLOCK_SIZE);
724
0
    const int height = ff_sws_dither_height(dither);
725
0
    pixel_t *matrix = av_malloc(sizeof(pixel_t) * height * stride);
726
0
    if (!matrix)
727
0
        return AVERROR(ENOMEM);
728
0
    out->priv.ptr = matrix;
729
0
    out->free = ff_op_priv_free;
730
731
    /* Pad to multiple of block size. We don't need extra padding for the
732
     * height because ff_sws_dither_height() already includes any padding
733
     * necessary for the y_offset */
734
0
    for (int y = 0; y < height; y++) {
735
0
        pixel_t *row = &matrix[y * stride];
736
0
        for (int x = 0; x < size; x++)
737
0
            row[x] = uop->data.ptr[y * size + x].px;
738
0
        for (int x = size; x < stride; x++)
739
0
            row[x] = row[x % size];
740
0
    }
741
742
0
    return 0;
743
0
}
Unexecuted instantiation: uops_backend.c:setup_dither_F32
Unexecuted instantiation: uops_backend.c:setup_dither_U8
Unexecuted instantiation: uops_backend.c:setup_dither_U16
Unexecuted instantiation: uops_backend.c:setup_dither_U32
744
745
DECL_FUNC(dither, const SwsCompMask mask,
746
                  const uint8_t off0, const uint8_t off1,
747
                  const uint8_t off2, const uint8_t off3,
748
                  const uint8_t size_log2)
749
0
{
750
0
    const int size   = 1 << size_log2;
751
0
    const int stride = FFMAX(size, SWS_BLOCK_SIZE);
752
753
0
    const pixel_t *matrix = impl->priv.ptr;
754
0
    matrix += (iter->y & (size - 1)) * stride;
755
0
    matrix += (iter->x & (size - 1)) & ~(SWS_BLOCK_SIZE - 1);
756
757
0
    const pixel_t *const row0 = &matrix[off0 * stride];
758
0
    const pixel_t *const row1 = &matrix[off1 * stride];
759
0
    const pixel_t *const row2 = &matrix[off2 * stride];
760
0
    const pixel_t *const row3 = &matrix[off3 * stride];
761
762
0
    SWS_LOOP
763
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
764
0
        if (X) x[i] += row0[i];
765
0
        if (Y) y[i] += row1[i];
766
0
        if (Z) z[i] += row2[i];
767
0
        if (W) w[i] += row3[i];
768
0
    }
769
770
0
    CONTINUE(x, y, z, w);
771
0
}
Unexecuted instantiation: uops_backend.c:dither_F32
Unexecuted instantiation: uops_backend.c:dither_U8
Unexecuted instantiation: uops_backend.c:dither_U16
Unexecuted instantiation: uops_backend.c:dither_U32
772
773
SWS_FOR(PX, DITHER, DECL_IMPL, dither)
774
SWS_FOR_STRUCT(PX, DITHER, DECL_ENTRY, .setup = fn(setup_dither) )
775
776
/*********************
777
 * Linear operations *
778
 *********************/
779
780
typedef struct {
781
    /* Stored in split form for convenience */
782
    pixel_t m[4][4];
783
    pixel_t k[4];
784
} fn(LinCoeffs);
785
786
DECL_SETUP(setup_linear, params, out)
787
0
{
788
0
    const SwsUOp *uop = params->uop;
789
0
    fn(LinCoeffs) c;
790
791
0
    for (int i = 0; i < 4; i++) {
792
0
        for (int j = 0; j < 4; j++)
793
0
            c.m[i][j] = uop->data.mat4[i][j].px;
794
0
        c.k[i] = uop->data.mat4[i][4].px;
795
0
    }
796
797
0
    out->priv.ptr = av_memdup(&c, sizeof(c));
798
0
    out->free = ff_op_priv_free;
799
0
    return out->priv.ptr ? 0 : AVERROR(ENOMEM);
800
0
}
Unexecuted instantiation: uops_backend.c:setup_linear_F32
Unexecuted instantiation: uops_backend.c:setup_linear_U8
Unexecuted instantiation: uops_backend.c:setup_linear_U16
Unexecuted instantiation: uops_backend.c:setup_linear_U32
801
802
/**
803
 * Fully general case for a 5x5 linear affine transformation. Should never be
804
 * called without constant `mask`. This function will compile down to the
805
 * appropriately optimized version for the required subset of operations when
806
 * called with a constant mask.
807
 */
808
DECL_FUNC(linear, const SwsCompMask mask, const uint32_t one, const uint32_t zero)
809
0
{
810
0
    const fn(LinCoeffs) c = *(const fn(LinCoeffs) *) impl->priv.ptr;
811
812
0
    SWS_LOOP
813
0
    for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
814
0
        const pixel_t xx = x[i];
815
0
        const pixel_t yy = y[i];
816
0
        const pixel_t zz = z[i];
817
0
        const pixel_t ww = w[i];
818
819
0
#define LIN_VAL(I, J, val) \
820
0
    ((one & SWS_MASK(I, J)) ? (val) : c.m[I][J] * (val))
821
822
0
#define LIN_ROW(I, var) do {                                    \
823
0
    var[i] = (zero & SWS_MASK(I, 4)) ? 0 : c.k[I];              \
824
0
    if (!(zero & SWS_MASK(I, 0))) var[i] += LIN_VAL(I, 0, xx);  \
825
0
    if (!(zero & SWS_MASK(I, 1))) var[i] += LIN_VAL(I, 1, yy);  \
826
0
    if (!(zero & SWS_MASK(I, 2))) var[i] += LIN_VAL(I, 2, zz);  \
827
0
    if (!(zero & SWS_MASK(I, 3))) var[i] += LIN_VAL(I, 3, ww);  \
828
0
} while (0)
829
830
0
        if (X) LIN_ROW(0, x);
831
0
        if (Y) LIN_ROW(1, y);
832
0
        if (Z) LIN_ROW(2, z);
833
0
        if (W) LIN_ROW(3, w);
834
0
    }
835
836
0
    CONTINUE(x, y, z, w);
837
0
}
Unexecuted instantiation: uops_backend.c:linear_F32
Unexecuted instantiation: uops_backend.c:linear_U8
Unexecuted instantiation: uops_backend.c:linear_U16
Unexecuted instantiation: uops_backend.c:linear_U32
838
839
SWS_FOR(PX, LINEAR, DECL_IMPL, linear)
840
SWS_FOR_STRUCT(PX, LINEAR, DECL_ENTRY, .setup = fn(setup_linear) )
841
842
#undef PIXEL_MAX
843
#undef PIXEL_SWAP
844
#undef pixel_t
845
#undef inter_t
846
#undef block_t
847
#undef PX
848
#undef px