FFmpeg
Loading...
Searching...
No Matches
ops_impl_conv.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 Ramiro Polla
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/**
22 * NOTE: This file is #include'd directly by both the NEON backend and
23 * the sws_ops_aarch64 tool.
24 */
25
26#include "libavutil/error.h"
27#include "libavutil/rational.h"
28#include "libswscale/ops.h"
29
30#include "ops_impl.h"
31
32static void swizzle_emit(SwsAArch64OpImplParams *out, uint8_t dst, uint8_t src)
33{
34 int idx = out->par.move.num_moves++;
35 out->par.move.dst[idx] = dst;
36 out->par.move.src[idx] = src;
37}
38
40{
41 SwsSwizzleOp swizzle = {
42 .in = {
43 op->swizzle.in[0],
44 op->swizzle.in[1],
45 op->swizzle.in[2],
46 op->swizzle.in[3],
47 }
48 };
49
50 /* Compute used vectors (src and dst) */
51 uint8_t src_used[4] = { 0 };
52 bool done[4] = { true, true, true, true };
53 LOOP(out->mask, dst) {
54 uint8_t src = swizzle.in[dst];
55 src_used[src]++;
56 done[dst] = false;
57 }
58
59 /* First perform unobstructed copies. */
60 for (bool progress = true; progress; ) {
61 progress = false;
62 for (int dst = 0; dst < 4; dst++) {
63 if (done[dst] || src_used[dst])
64 continue;
65 uint8_t src = swizzle.in[dst];
67 src_used[src]--;
68 done[dst] = true;
69 progress = true;
70 }
71 }
72
73 /* Then swap and rotate remaining operations. */
74 for (int dst = 0; dst < 4; dst++) {
75 if (done[dst])
76 continue;
77
78 swizzle_emit(out, -1, dst);
79
80 uint8_t cur_dst = dst;
81 uint8_t src = swizzle.in[cur_dst];
82 while (src != dst) {
83 swizzle_emit(out, cur_dst, src);
84 done[cur_dst] = true;
85 cur_dst = src;
86 src = swizzle.in[cur_dst];
87 }
88
89 swizzle_emit(out, cur_dst, -1);
90 done[cur_dst] = true;
91 }
92}
93
94/**
95 * Convert SwsOp to a SwsAArch64OpImplParams. Read the comments regarding
96 * SwsAArch64OpImplParams in ops_impl.h for more information.
97 */
98static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n,
99 int block_size, SwsAArch64OpImplParams *out)
100{
101 const SwsOp *op = &ops->ops[n];
102
103 out->block_size = block_size;
104
105 /**
106 * Most SwsOp work on fields described by SWS_OP_NEEDED().
107 * The few that don't will override this field later.
108 */
109 out->mask = 0;
110 for (int i = 0; i < 4; i++) {
111 if (SWS_OP_NEEDED(op, i))
112 out->mask |= SWS_COMP(i);
113 }
114
115 out->type = op->type;
116
117 /* Map SwsOpType to SwsUOpType */
118 switch (op->op) {
119 case SWS_OP_READ:
120 if (op->rw.filter.op)
121 return AVERROR(ENOTSUP);
122 /**
123 * The different types of read operations have been split into
124 * their own SwsUOpType to simplify the implementation.
125 */
126 if (op->rw.frac == 1)
128 else if (op->rw.frac == 3)
129 out->uop = SWS_UOP_READ_BIT;
130 else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1)
132 else if (op->rw.mode == SWS_RW_PACKED || op->rw.mode == SWS_RW_PLANAR)
134 else
135 return AVERROR(ENOTSUP);
136 break;
137 case SWS_OP_WRITE:
138 if (op->rw.filter.op)
139 return AVERROR(ENOTSUP);
140 /**
141 * The different types of write operations have been split into
142 * their own SwsUOpType to simplify the implementation.
143 */
144 if (op->rw.frac == 1)
146 else if (op->rw.frac == 3)
147 out->uop = SWS_UOP_WRITE_BIT;
148 else if (op->rw.mode == SWS_RW_PACKED && op->rw.elems > 1)
150 else if (op->rw.mode == SWS_RW_PACKED || op->rw.mode == SWS_RW_PLANAR)
152 else
153 return AVERROR(ENOTSUP);
154 break;
155 case SWS_OP_SWAP_BYTES: out->uop = SWS_UOP_SWAP_BYTES; break;
156 case SWS_OP_SWIZZLE: {
157 /**
158 * Detect whether copies are needed or if a simple permute is
159 * enough.
160 */
161 out->uop = SWS_UOP_PERMUTE;
162 SwsCompMask seen = 0;
163 LOOP(out->mask, i) {
164 uint8_t src = op->swizzle.in[i];
165 if (seen & SWS_COMP(src)) {
166 out->uop = SWS_UOP_COPY;
167 break;
168 }
169 seen |= SWS_COMP(src);
170 }
171 break;
172 }
173 case SWS_OP_UNPACK: out->uop = SWS_UOP_UNPACK; break;
174 case SWS_OP_PACK: out->uop = SWS_UOP_PACK; break;
175 case SWS_OP_LSHIFT: out->uop = SWS_UOP_LSHIFT; break;
176 case SWS_OP_RSHIFT: out->uop = SWS_UOP_RSHIFT; break;
177 case SWS_OP_CLEAR: out->uop = SWS_UOP_CLEAR; break;
178 case SWS_OP_CONVERT:
179 if (op->convert.expand) {
180 switch (op->convert.to) {
181 case SWS_PIXEL_U16: out->uop = SWS_UOP_EXPAND_PAIR; break;
182 case SWS_PIXEL_U32: out->uop = SWS_UOP_EXPAND_QUAD; break;
183 }
184 } else {
185 switch (op->convert.to) {
186 case SWS_PIXEL_U8: out->uop = SWS_UOP_TO_U8; break;
187 case SWS_PIXEL_U16: out->uop = SWS_UOP_TO_U16; break;
188 case SWS_PIXEL_U32: out->uop = SWS_UOP_TO_U32; break;
189 case SWS_PIXEL_F32: out->uop = SWS_UOP_TO_F32; break;
190 }
191 }
192 break;
193 case SWS_OP_MIN:
194 case SWS_OP_MAX:
195 out->uop = (op->op == SWS_OP_MIN) ? SWS_UOP_MIN : SWS_UOP_MAX;
196 out->mask &= ff_sws_comp_mask_q4(op->clamp.limit);
197 break;
198 case SWS_OP_SCALE: out->uop = SWS_UOP_SCALE; break;
199 case SWS_OP_LINEAR:
200 out->uop = (ctx->flags & SWS_BITEXACT)
203 break;
204 case SWS_OP_DITHER: out->uop = SWS_UOP_DITHER; break;
205 default:
206 return AVERROR(ENOTSUP);
207 }
208
209 switch (out->uop) {
210 case SWS_UOP_READ_BIT:
218 switch (op->rw.elems) {
219 case 1: out->mask = SWS_COMP_ELEMS(1); break;
220 case 2: out->mask = SWS_COMP_ELEMS(2); break;
221 case 3: out->mask = SWS_COMP_ELEMS(3); break;
222 case 4: out->mask = SWS_COMP_ELEMS(4); break;
223 };
224 break;
225 case SWS_UOP_PERMUTE:
226 case SWS_UOP_COPY:
227 /* Recompute mask taking identity swizzle into account */
228 out->mask = 0;
229 for (int i = 0; i < 4; i++) {
230 if (SWS_OP_NEEDED(op, i) && op->swizzle.in[i] != i)
231 out->mask |= SWS_COMP(i);
232 }
234 /* The element size and type don't matter. */
235 out->block_size = block_size * ff_sws_pixel_type_size(op->type);
236 out->type = SWS_PIXEL_U8;
237 break;
238 case SWS_UOP_UNPACK:
239 for (int i = 0; i < 4; i++)
240 out->par.pack.pattern[i] = op->pack.pattern[i];
241 break;
242 case SWS_UOP_PACK:
243 out->mask = 0;
244 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
245 out->mask |= SWS_COMP(i);
246 for (int i = 0; i < 4; i++)
247 out->par.pack.pattern[i] = op->pack.pattern[i];
248 break;
249 case SWS_UOP_LSHIFT:
250 case SWS_UOP_RSHIFT:
251 out->par.shift.amount = op->shift.amount;
252 break;
253 case SWS_UOP_CLEAR:
254 out->mask = 0;
255 for (int i = 0; i < 4; i++) {
256 if (op->clear.mask & SWS_COMP(i)) {
257 out->mask |= SWS_COMP(i);
258 if (op->clear.value[i].num == 0) {
259 out->par.clear.zero |= SWS_COMP(i);
260 } else {
261 uint32_t val = op->clear.value[i].num / op->clear.value[i].den;
262 if ((op->type == SWS_PIXEL_U8 && val == UINT8_MAX) ||
263 (op->type == SWS_PIXEL_U16 && val == UINT16_MAX) ||
264 (op->type == SWS_PIXEL_U32 && val == UINT32_MAX))
265 out->par.clear.one |= SWS_COMP(i);
266 }
267 }
268 }
269 break;
270 case SWS_UOP_LINEAR:
272 out->mask = 0;
273 const uint32_t lin_mask = ff_sws_linear_mask(&op->lin);
274 for (int i = 0; i < 4; i++) {
275 if (!SWS_OP_NEEDED(op, i) || !(lin_mask & SWS_MASK_ROW(i))) {
276 for (int j = 0; j < 5; j++)
277 out->par.lin.zero |= SWS_MASK(i, j);
278 continue;
279 }
280 out->mask |= SWS_COMP(i);
281 for (int j = 0; j < 5; j++) {
282 const AVRational64 k = op->lin.m[i][j];
283 if (j < 4 && k.num == k.den)
284 out->par.lin.one |= SWS_MASK(i, j);
285 else if (k.num == 0)
286 out->par.lin.zero |= SWS_MASK(i, j);
287 }
288 }
289 break;
290 case SWS_UOP_DITHER:
291 out->mask = SWS_COMP_MASK(op->dither.y_offset[0] >= 0,
292 op->dither.y_offset[1] >= 0,
293 op->dither.y_offset[2] >= 0,
294 op->dither.y_offset[3] >= 0);
295 LOOP(out->mask, i) {
296 out->par.dither.y_offset[i] = op->dither.y_offset[i];
297 }
298 out->par.dither.size_log2 = op->dither.size_log2;
299 break;
300 }
301
302 switch (out->uop) {
303 case SWS_UOP_READ_BIT:
312 case SWS_UOP_CLEAR:
313 /* Only the element size matters, not the type. */
314 if (out->type == SWS_PIXEL_F32)
315 out->type = SWS_PIXEL_U32;
316 break;
317 }
318
319 return 0;
320}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
static FILE * out
static AVFormatContext * ctx
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
error code definitions
#define AVERROR(e)
Definition error.h:45
@ SWS_BITEXACT
Definition swscale.h:178
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition anm.c:76
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition ops.c:802
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition ops.c:100
@ SWS_OP_RSHIFT
Definition ops.h:49
@ SWS_OP_SWIZZLE
Definition ops.h:43
@ SWS_OP_LSHIFT
Definition ops.h:48
@ SWS_OP_SCALE
Definition ops.h:56
@ SWS_OP_WRITE
Definition ops.h:41
@ SWS_OP_READ
Definition ops.h:40
@ SWS_OP_CLEAR
Definition ops.h:52
@ SWS_OP_SWAP_BYTES
Definition ops.h:42
@ SWS_OP_MIN
Definition ops.h:54
@ SWS_OP_UNPACK
Definition ops.h:46
@ SWS_OP_LINEAR
Definition ops.h:59
@ SWS_OP_PACK
Definition ops.h:47
@ SWS_OP_DITHER
Definition ops.h:60
@ SWS_OP_MAX
Definition ops.h:55
@ SWS_OP_CONVERT
Definition ops.h:53
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
Definition ops.h:107
@ SWS_RW_PACKED
Definition ops.h:108
#define SWS_OP_NEEDED(op, idx)
Definition ops.h:265
#define LOOP(mask, idx)
Definition ops_impl.h:56
static void swizzle_emit(SwsAArch64OpImplParams *out, uint8_t dst, uint8_t src)
NOTE: This file is #include'd directly by both the NEON backend and the sws_ops_aarch64 tool.
static void convert_swizzle_to_moves(const SwsOp *op, SwsAArch64OpImplParams *out)
static int convert_to_aarch64_impl(SwsContext *ctx, const SwsOpList *ops, int n, int block_size, SwsAArch64OpImplParams *out)
Convert SwsOp to a SwsAArch64OpImplParams.
Utilities for rational number calculation.
64-bit Rational number (pair of numerator and denominator).
Definition rational64.h:52
int64_t num
Numerator.
Definition rational64.h:53
int64_t den
Denominator.
Definition rational64.h:54
SwsAArch64OpImplParams describes the parameters for an SwsUOpType operation.
Definition ops_impl.h:47
Main external API structure.
Definition swscale.h:227
Helper struct for representing a list of operations.
Definition ops.h:293
SwsOp * ops
Definition ops.h:294
Definition ops.h:237
uint8_t in[4]
Definition ops.h:155
#define src
Definition vp8dsp.c:248
@ SWS_PIXEL_F32
Definition uops.h:44
@ SWS_PIXEL_U32
Definition uops.h:43
@ SWS_PIXEL_U16
Definition uops.h:42
@ SWS_PIXEL_U8
Definition uops.h:41
#define SWS_COMP(X)
Definition uops.h:97
#define SWS_MASK_ROW(I)
Definition uops.h:233
#define SWS_COMP_ELEMS(N)
Definition uops.h:100
#define SWS_MASK(I, J)
Definition uops.h:231
@ SWS_UOP_TO_U8
Definition uops.h:159
@ SWS_UOP_PACK
Definition uops.h:172
@ SWS_UOP_PERMUTE
Definition uops.h:151
@ SWS_UOP_EXPAND_QUAD
Definition uops.h:158
@ SWS_UOP_READ_PLANAR
Definition uops.h:133
@ SWS_UOP_WRITE_PLANAR
Definition uops.h:142
@ SWS_UOP_READ_NIBBLE
Definition uops.h:138
@ SWS_UOP_MAX
Definition uops.h:168
@ SWS_UOP_READ_BIT
Definition uops.h:139
@ SWS_UOP_SWAP_BYTES
Definition uops.h:155
@ SWS_UOP_MIN
Definition uops.h:167
@ SWS_UOP_LINEAR
Definition uops.h:176
@ SWS_UOP_RSHIFT
Definition uops.h:174
@ SWS_UOP_COPY
Definition uops.h:152
@ SWS_UOP_WRITE_NIBBLE
Definition uops.h:144
@ SWS_UOP_LINEAR_FMA
Definition uops.h:177
@ SWS_UOP_SCALE
Definition uops.h:165
@ SWS_UOP_WRITE_PACKED
Definition uops.h:143
@ SWS_UOP_WRITE_BIT
Definition uops.h:145
@ SWS_UOP_READ_PACKED
Definition uops.h:137
@ SWS_UOP_EXPAND_PAIR
Definition uops.h:157
@ SWS_UOP_TO_U16
Definition uops.h:160
@ SWS_UOP_DITHER
Definition uops.h:178
@ SWS_UOP_CLEAR
Definition uops.h:175
@ SWS_UOP_TO_U32
Definition uops.h:161
@ SWS_UOP_UNPACK
Definition uops.h:171
@ SWS_UOP_TO_F32
Definition uops.h:162
@ SWS_UOP_LSHIFT
Definition uops.h:173
#define SWS_COMP_MASK(X, Y, Z, W)
Definition uops.h:102
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:93
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:50