FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/uops_backend.c
Date: 2026-08-30 18:45:47
Exec Total Coverage
Lines: 48 50 96.0%
Functions: 3 3 100.0%
Branches: 21 24 87.5%

Line Branch Exec 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 SWS_FOR(TYPE, LUT_3D, REF_ENTRY) \
96 /* end of macro */
97
98 static const SwsUOpTable uop_table = {
99 .block_size = SWS_BLOCK_SIZE,
100 .entries = {
101 REF_ALL_UOPS(U8)
102 REF_ALL_UOPS(U16)
103 REF_ALL_UOPS(U32)
104 REF_ALL_UOPS(F32)
105 NULL
106 },
107 };
108
109 10642 static void process(const SwsOpExec *exec, const void *priv,
110 const int bx_start, const int y_start,
111 int bx_end, int y_end)
112 {
113 10642 const SwsOpChain *chain = priv;
114 10642 const SwsOpImpl *impl = chain->impl;
115 block_t x, y, z, w; /* allocate enough space for any intermediate */
116
117 SwsOpIter iterdata;
118 10642 SwsOpIter *iter = &iterdata; /* for CONTINUE() macro to work */
119 10642 iter->exec = exec;
120
2/2
✓ Branch 0 taken 42568 times.
✓ Branch 1 taken 10642 times.
53210 for (int i = 0; i < 4; i++) {
121 42568 iter->in[i] = (uintptr_t) exec->in[i];
122 42568 iter->out[i] = (uintptr_t) exec->out[i];
123 }
124
125
2/2
✓ Branch 0 taken 807440 times.
✓ Branch 1 taken 10642 times.
818082 for (iter->y = y_start; iter->y < y_end; iter->y++) {
126
2/2
✓ Branch 0 taken 2374752 times.
✓ Branch 1 taken 807440 times.
3182192 for (int block = bx_start; block < bx_end; block++) {
127 2374752 iter->x = block * SWS_BLOCK_SIZE;
128 2374752 CONTINUE(&x, &y, &z, &w);
129 }
130
131
2/2
✓ Branch 0 taken 176192 times.
✓ Branch 1 taken 631248 times.
807440 const int y_bump = exec->in_bump_y ? exec->in_bump_y[iter->y] : 0;
132
2/2
✓ Branch 0 taken 3229760 times.
✓ Branch 1 taken 807440 times.
4037200 for (int i = 0; i < 4; i++) {
133 3229760 iter->in[i] += exec->in_bump[i] + y_bump * exec->in_stride[i];
134 3229760 iter->out[i] += exec->out_bump[i];
135 }
136 }
137 10642 }
138
139 16971 static int compile_uops_c(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
140 {
141 int ret;
142
143 16971 SwsOpChain *chain = ff_sws_op_chain_alloc();
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16971 times.
16971 if (!chain)
145 return AVERROR(ENOMEM);
146
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16971 times.
16971 av_assert0(uops->num_ops > 0);
148
2/2
✓ Branch 0 taken 74830 times.
✓ Branch 1 taken 16967 times.
91797 for (int i = 0; i < uops->num_ops; i++) {
149 74830 const SwsUOpTable *table = &uop_table;
150 74830 ret = ff_sws_uop_lookup(ctx, &table, 1, &uops->ops[i],
151 SWS_BLOCK_SIZE, chain);
152
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 74826 times.
74830 if (ret < 0)
153 4 goto fail;
154 }
155
156 16967 *out = (SwsCompiledOp) {
157 .slice_align = 1,
158 .block_size = SWS_BLOCK_SIZE,
159 16967 .cpu_flags = chain->cpu_flags,
160 .priv = chain,
161 .free = ff_sws_op_chain_free_cb,
162 .func = process,
163 };
164
165 16967 memcpy(out->over_read, chain->over_read, sizeof(out->over_read));
166 16967 memcpy(out->over_write, chain->over_write, sizeof(out->over_write));
167
168 16967 av_log(ctx, AV_LOG_DEBUG, "Compiled micro-ops:\n");
169
2/2
✓ Branch 0 taken 74818 times.
✓ Branch 1 taken 16967 times.
91785 for (int i = 0; i < uops->num_ops; i++) {
170 char name[SWS_UOP_NAME_MAX];
171 74818 ff_sws_uop_name(&uops->ops[i], name);
172 74818 av_log(ctx, AV_LOG_DEBUG, " %s\n", name);
173 }
174
175 16967 return 0;
176
177 4 fail:
178 4 ff_sws_op_chain_free(chain);
179 4 return ret;
180 }
181
182 40005 static int compile_c(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
183 {
184 40005 SwsUOpList *uops = ff_sws_uop_list_alloc();
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40005 times.
40005 if (!uops)
186 return AVERROR(ENOMEM);
187
188 40005 int ret = ff_sws_ops_translate(ctx, ops, 0, uops);
189
2/2
✓ Branch 0 taken 31994 times.
✓ Branch 1 taken 8011 times.
40005 if (ret < 0)
190 31994 goto fail;
191
192 8011 ret = compile_uops_c(ctx, uops, out);
193
194 40005 fail:
195 40005 ff_sws_uop_list_free(&uops);
196 40005 return ret;
197 }
198
199 const SwsOpBackend backend_c = {
200 .name = "c",
201 .flags = SWS_BACKEND_C,
202 .compile = compile_c,
203 .compile_uops = compile_uops_c,
204 .hw_format = AV_PIX_FMT_NONE,
205 };
206