FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/uops_backend.c
Date: 2026-10-20 22:17:59
Exec Total Coverage
Lines: 49 51 96.1%
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 defined(__GNUC__)
32 #pragma GCC optimize ("fp-contract=off")
33 #elif defined(_MSC_VER)
34 #pragma fp_contract (off)
35 #endif
36
37 #if defined(__GNUC__) && !defined(__clang__)
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 79238 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 79238 const SwsOpChain *chain = priv;
114 79238 const SwsOpImpl *impl = chain->impl;
115 block_t x, y, z, w; /* allocate enough space for any intermediate */
116
117 SwsOpIter iterdata;
118 79238 SwsOpIter *iter = &iterdata; /* for CONTINUE() macro to work */
119 79238 iter->exec = exec;
120
2/2
✓ Branch 0 taken 316952 times.
✓ Branch 1 taken 79238 times.
396190 for (int i = 0; i < 4; i++) {
121 316952 iter->in[i] = (uintptr_t) exec->in[i];
122 316952 iter->out[i] = (uintptr_t) exec->out[i];
123 }
124
125
2/2
✓ Branch 0 taken 7386608 times.
✓ Branch 1 taken 79238 times.
7465846 for (iter->y = y_start; iter->y < y_end; iter->y++) {
126
2/2
✓ Branch 0 taken 22102656 times.
✓ Branch 1 taken 7386608 times.
29489264 for (int block = bx_start; block < bx_end; block++) {
127 22102656 iter->x = block * SWS_BLOCK_SIZE;
128 22102656 CONTINUE(&x, &y, &z, &w);
129 }
130
131
2/2
✓ Branch 0 taken 1617216 times.
✓ Branch 1 taken 5769392 times.
7386608 const int y_bump = exec->in_bump_y ? exec->in_bump_y[iter->y] : 0;
132
2/2
✓ Branch 0 taken 29546432 times.
✓ Branch 1 taken 7386608 times.
36933040 for (int i = 0; i < 4; i++) {
133 29546432 iter->in[i] += exec->in_bump[i] + y_bump * exec->in_stride[i];
134 29546432 iter->out[i] += exec->out_bump[i];
135 }
136 }
137 79238 }
138
139 85706 static int compile_uops_c(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
140 {
141 int ret;
142
143 85706 SwsOpChain *chain = ff_sws_op_chain_alloc();
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85706 times.
85706 if (!chain)
145 ✗ return AVERROR(ENOMEM);
146
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85706 times.
85706 av_assert0(uops->num_ops > 0);
148
2/2
✓ Branch 0 taken 437681 times.
✓ Branch 1 taken 85699 times.
523380 for (int i = 0; i < uops->num_ops; i++) {
149 437681 const SwsUOpTable *table = &uop_table;
150 437681 ret = ff_sws_uop_lookup(ctx, &table, 1, &uops->ops[i],
151 SWS_BLOCK_SIZE, chain);
152
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 437674 times.
437681 if (ret < 0)
153 7 goto fail;
154 }
155
156 85699 *out = (SwsCompiledOp) {
157 .slice_align = 1,
158 .block_size = SWS_BLOCK_SIZE,
159 85699 .cpu_flags = chain->cpu_flags,
160 .priv = chain,
161 .free = ff_sws_op_chain_free_cb,
162 .func = process,
163 };
164
165 85699 memcpy(out->over_read, chain->over_read, sizeof(out->over_read));
166 85699 memcpy(out->over_write, chain->over_write, sizeof(out->over_write));
167
168 85699 av_log(ctx, AV_LOG_DEBUG, "Compiled micro-ops:\n");
169
2/2
✓ Branch 0 taken 437660 times.
✓ Branch 1 taken 85699 times.
523359 for (int i = 0; i < uops->num_ops; i++) {
170 char name[SWS_UOP_NAME_MAX];
171 437660 ff_sws_uop_name(&uops->ops[i], name);
172 437660 av_log(ctx, AV_LOG_DEBUG, " %s\n", name);
173 }
174
175 85699 return 0;
176
177 7 fail:
178 7 ff_sws_op_chain_free(chain);
179 7 return ret;
180 }
181
182 110829 static int compile_c(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
183 {
184 110829 SwsUOpList *uops = ff_sws_uop_list_alloc();
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110829 times.
110829 if (!uops)
186 ✗ return AVERROR(ENOMEM);
187
188 110829 const SwsUOpFlags flags = SWS_UOP_FLAG_EXPAND_BIT
189 | SWS_UOP_FLAG_READ_PALETTE
190 | SWS_UOP_FLAG_ADD;
191 110829 int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
192
2/2
✓ Branch 0 taken 34251 times.
✓ Branch 1 taken 76578 times.
110829 if (ret < 0)
193 34251 goto fail;
194
195 76578 ret = compile_uops_c(ctx, uops, out);
196
197 110829 fail:
198 110829 ff_sws_uop_list_free(&uops);
199 110829 return ret;
200 }
201
202 const SwsOpBackend backend_c = {
203 .name = "c",
204 .flags = SWS_BACKEND_C,
205 .compile = compile_c,
206 .compile_uops = compile_uops_c,
207 .hw_format = AV_PIX_FMT_NONE,
208 };
209