Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libswscale/uops_backend.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/avassert.h"
22
23
#include "uops_tmpl.h"
24
25
/**
26
 * We want to disable FP contraction because this is a reference backend that
27
 * establishes a bit-exact reference result.
28
 */
29
#ifdef __clang__
30
#pragma STDC FP_CONTRACT OFF
31
#elif AV_GCC_VERSION_AT_LEAST(4, 8)
32
#pragma GCC optimize ("fp-contract=off")
33
#elif defined(_MSC_VER)
34
#pragma fp_contract (off)
35
#endif
36
37
#if AV_GCC_VERSION_AT_LEAST(4, 4)
38
#pragma GCC optimize ("finite-math-only")
39
#endif
40
41
/* Integer types */
42
#define IS_FLOAT 0
43
#  define BIT_DEPTH 8
44
#    include "uops_tmpl.c"
45
#  undef BIT_DEPTH
46
#  define BIT_DEPTH 16
47
#    include "uops_tmpl.c"
48
#  undef BIT_DEPTH
49
#  define BIT_DEPTH 32
50
#    include "uops_tmpl.c"
51
#  undef BIT_DEPTH
52
#undef IS_FLOAT
53
54
/* Floating point types */
55
#define IS_FLOAT 1
56
#  define BIT_DEPTH 32
57
#    include "uops_tmpl.c"
58
#  undef BIT_DEPTH
59
#undef IS_FLOAT
60
61
/* Expanded as new uop types are implemented in the C/template backend */
62
#define REF_ALL_UOPS(TYPE)                                  \
63
    SWS_FOR(TYPE, READ_PLANAR,    REF_ENTRY)                \
64
    SWS_FOR(TYPE, READ_PLANAR_FV, REF_ENTRY)                \
65
    SWS_FOR(TYPE, READ_PLANAR_FH, REF_ENTRY)                \
66
    SWS_FOR(TYPE, READ_PACKED,    REF_ENTRY)                \
67
    SWS_FOR(TYPE, READ_NIBBLE,    REF_ENTRY)                \
68
    SWS_FOR(TYPE, READ_BIT,       REF_ENTRY)                \
69
    SWS_FOR(TYPE, READ_PALETTE,   REF_ENTRY)                \
70
    SWS_FOR(TYPE, PERMUTE,        REF_ENTRY)                \
71
    SWS_FOR(TYPE, COPY,           REF_ENTRY)                \
72
    SWS_FOR(TYPE, WRITE_PLANAR,   REF_ENTRY)                \
73
    SWS_FOR(TYPE, WRITE_PACKED,   REF_ENTRY)                \
74
    SWS_FOR(TYPE, WRITE_NIBBLE,   REF_ENTRY)                \
75
    SWS_FOR(TYPE, WRITE_BIT,      REF_ENTRY)                \
76
    SWS_FOR(TYPE, SWAP_BYTES,     REF_ENTRY)                \
77
    SWS_FOR(TYPE, EXPAND_BIT,     REF_ENTRY)                \
78
    SWS_FOR(TYPE, EXPAND_PAIR,    REF_ENTRY)                \
79
    SWS_FOR(TYPE, EXPAND_QUAD,    REF_ENTRY)                \
80
    SWS_FOR(TYPE, TO_U8,          REF_ENTRY)                \
81
    SWS_FOR(TYPE, TO_U16,         REF_ENTRY)                \
82
    SWS_FOR(TYPE, TO_U32,         REF_ENTRY)                \
83
    SWS_FOR(TYPE, TO_F32,         REF_ENTRY)                \
84
    SWS_FOR(TYPE, SCALE,          REF_ENTRY)                \
85
    SWS_FOR(TYPE, ADD,            REF_ENTRY)                \
86
    SWS_FOR(TYPE, MIN,            REF_ENTRY)                \
87
    SWS_FOR(TYPE, MAX,            REF_ENTRY)                \
88
    SWS_FOR(TYPE, UNPACK,         REF_ENTRY)                \
89
    SWS_FOR(TYPE, PACK,           REF_ENTRY)                \
90
    SWS_FOR(TYPE, LSHIFT,         REF_ENTRY)                \
91
    SWS_FOR(TYPE, RSHIFT,         REF_ENTRY)                \
92
    SWS_FOR(TYPE, CLEAR,          REF_ENTRY)                \
93
    SWS_FOR(TYPE, LINEAR,         REF_ENTRY)                \
94
    SWS_FOR(TYPE, DITHER,         REF_ENTRY)                \
95
    /* end of macro */
96
97
static const SwsUOpTable uop_table = {
98
    .block_size = SWS_BLOCK_SIZE,
99
    .entries = {
100
        REF_ALL_UOPS(U8)
101
        REF_ALL_UOPS(U16)
102
        REF_ALL_UOPS(U32)
103
        REF_ALL_UOPS(F32)
104
        NULL
105
    },
106
};
107
108
static void process(const SwsOpExec *exec, const void *priv,
109
                    const int bx_start, const int y_start,
110
                    int bx_end, int y_end)
111
0
{
112
0
    const SwsOpChain *chain = priv;
113
0
    const SwsOpImpl *impl = chain->impl;
114
0
    block_t x, y, z, w; /* allocate enough space for any intermediate */
115
116
0
    SwsOpIter iterdata;
117
0
    SwsOpIter *iter = &iterdata; /* for CONTINUE() macro to work */
118
0
    iter->exec = exec;
119
0
    for (int i = 0; i < 4; i++) {
120
0
        iter->in[i]  = (uintptr_t) exec->in[i];
121
0
        iter->out[i] = (uintptr_t) exec->out[i];
122
0
    }
123
124
0
    for (iter->y = y_start; iter->y < y_end; iter->y++) {
125
0
        for (int block = bx_start; block < bx_end; block++) {
126
0
            iter->x = block * SWS_BLOCK_SIZE;
127
0
            CONTINUE(&x, &y, &z, &w);
128
0
        }
129
130
0
        const int y_bump = exec->in_bump_y ? exec->in_bump_y[iter->y] : 0;
131
0
        for (int i = 0; i < 4; i++) {
132
0
            iter->in[i]  += exec->in_bump[i] + y_bump * exec->in_stride[i];
133
0
            iter->out[i] += exec->out_bump[i];
134
0
        }
135
0
    }
136
0
}
137
138
static int compile_uops_c(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
139
0
{
140
0
    int ret;
141
142
0
    SwsOpChain *chain = ff_sws_op_chain_alloc();
143
0
    if (!chain)
144
0
        return AVERROR(ENOMEM);
145
146
0
    av_assert0(uops->num_ops > 0);
147
0
    for (int i = 0; i < uops->num_ops; i++) {
148
0
        const SwsUOpTable *table = &uop_table;
149
0
        ret = ff_sws_uop_lookup(ctx, &table, 1, &uops->ops[i],
150
0
                                SWS_BLOCK_SIZE, chain);
151
0
        if (ret < 0)
152
0
            goto fail;
153
0
    }
154
155
0
    *out = (SwsCompiledOp) {
156
0
        .slice_align = 1,
157
0
        .block_size  = SWS_BLOCK_SIZE,
158
0
        .cpu_flags   = chain->cpu_flags,
159
0
        .priv        = chain,
160
0
        .free        = ff_sws_op_chain_free_cb,
161
0
        .func        = process,
162
0
    };
163
164
0
    memcpy(out->over_read,  chain->over_read,  sizeof(out->over_read));
165
0
    memcpy(out->over_write, chain->over_write, sizeof(out->over_write));
166
167
0
    av_log(ctx, AV_LOG_DEBUG, "Compiled micro-ops:\n");
168
0
    for (int i = 0; i < uops->num_ops; i++) {
169
0
        char name[SWS_UOP_NAME_MAX];
170
0
        ff_sws_uop_name(&uops->ops[i], name);
171
0
        av_log(ctx, AV_LOG_DEBUG, "    %s\n", name);
172
0
    }
173
174
0
    return 0;
175
176
0
fail:
177
0
    ff_sws_op_chain_free(chain);
178
0
    return ret;
179
0
}
180
181
static int compile_c(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
182
0
{
183
0
    SwsUOpList *uops = ff_sws_uop_list_alloc();
184
0
    if (!uops)
185
0
        return AVERROR(ENOMEM);
186
187
0
    int ret = ff_sws_ops_translate(ctx, ops, 0, uops);
188
0
    if (ret < 0)
189
0
        goto fail;
190
191
0
    ret = compile_uops_c(ctx, uops, out);
192
193
0
fail:
194
0
    ff_sws_uop_list_free(&uops);
195
0
    return ret;
196
0
}
197
198
const SwsOpBackend backend_c = {
199
    .name           = "c",
200
    .flags          = SWS_BACKEND_C,
201
    .compile        = compile_c,
202
    .compile_uops   = compile_uops_c,
203
    .hw_format      = AV_PIX_FMT_NONE,
204
};