FFmpeg
Loading...
Searching...
No Matches
ops.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#include "../ops_chain.h"
22
23#include "libavutil/avassert.h"
24#include "libavutil/avstring.h"
25#include "libavutil/tree.h"
26
27#include "ops_impl_conv.c"
28
29/**
30 * Check that there is no mismatch for the SwsOpExec/SwsOpImpl offset
31 * values used by ops_static.
32 * NOTE: The check is performed here since this file only ever targets
33 * aarch64, differently from ops_static which may be built on any
34 * host.
35 */
36static_assert(offsetof_exec_in == offsetof(SwsOpExec, in), "SwsOpExec layout mismatch");
37static_assert(offsetof_exec_out == offsetof(SwsOpExec, out), "SwsOpExec layout mismatch");
38static_assert(offsetof_exec_in_bump == offsetof(SwsOpExec, in_bump), "SwsOpExec layout mismatch");
39static_assert(offsetof_exec_out_bump == offsetof(SwsOpExec, out_bump), "SwsOpExec layout mismatch");
40static_assert(offsetof_impl_cont == offsetof(SwsOpImpl, cont), "SwsOpImpl layout mismatch");
41static_assert(offsetof_impl_priv == offsetof(SwsOpImpl, priv), "SwsOpImpl layout mismatch");
42
43/*********************************************************************/
44/* Forward-declare exported functions. */
45#define ENTRY(fname, ...) extern void fname(void);
46#include "ops_entries.c"
47#undef ENTRY
48
49static const struct {
50 void (*func)(void);
52} ops_entries[] = {
53#define ENTRY(fname, ...) { .func = fname, .params = __VA_ARGS__ },
54#include "ops_entries.c"
55#undef ENTRY
56};
57
58/* Look up the exported function pointer for the given parameters. */
60{
61 for (int i = 0; i < FF_ARRAY_ELEMS(ops_entries); i++)
62 if (!memcmp(p, &ops_entries[i].params, sizeof(SwsAArch64OpImplParams)))
63 return ops_entries[i].func;
64 return NULL;
65}
66
67/*********************************************************************/
69 const SwsUOp *uop, SwsImplResult *res)
70{
71 /**
72 * Compute number of full vector registers needed to pack all non-zero
73 * coefficients.
74 */
75 const int num_vregs = linear_num_vregs(p);
76 av_assert0(num_vregs <= 4);
77 void *coeffs = av_malloc(num_vregs * 16);
78 if (!coeffs)
79 return AVERROR(ENOMEM);
80
81 /**
82 * Copy non-zero coefficients, packed in sequential order, offset first.
83 * The same order must be followed in asmgen_op_linear().
84 */
85 int i_coeff = 0;
86 for (int i = 0; i < 4; i++) {
87 for (int j = 0; j < 5; j++) {
88 const int jj = (j == 0) ? 4 : (j - 1);
89 if (!(p->par.lin.zero & SWS_MASK(i, jj))) {
90 const SwsPixel px = uop->data.mat4x5[i][jj];
91 switch (p->type) {
92 case SWS_PIXEL_U8: ((uint8_t *) coeffs)[i_coeff++] = px.u8; break;
93 case SWS_PIXEL_U16: ((uint16_t *) coeffs)[i_coeff++] = px.u16; break;
94 case SWS_PIXEL_U32: ((uint32_t *) coeffs)[i_coeff++] = px.u32; break;
95 case SWS_PIXEL_F32: ((float *) coeffs)[i_coeff++] = px.f32; break;
96 }
97 }
98 }
99 }
100
101 res->priv.ptr = coeffs;
102 res->free = ff_op_priv_free;
103
104 return 0;
105}
106
107/*********************************************************************/
108static int aarch64_setup_dither(const SwsUOp *uop, SwsImplResult *res)
109{
110 res->priv.ptr = av_refstruct_ref(uop->data.ptr);
111 res->free = ff_op_priv_unref;
112 return 0;
113}
114
115/*********************************************************************/
116static int aarch64_setup(const SwsUOp *uop, const SwsAArch64OpImplParams *p,
118{
119 switch (uop->uop) {
120 case SWS_UOP_READ_BIT:
121 /* Negative shift values to perform right shift using ushl. */
122 out->priv = (SwsOpPriv) {
123 .u8 = {
124 -7, -6, -5, -4, -3, -2, -1, 0,
125 -7, -6, -5, -4, -3, -2, -1, 0,
126 }
127 };
128 break;
130 /* Shift values for ushl. */
131 out->priv = (SwsOpPriv) {
132 .u8 = {
133 7, 6, 5, 4, 3, 2, 1, 0,
134 7, 6, 5, 4, 3, 2, 1, 0,
135 }
136 };
137 break;
138 case SWS_UOP_CLEAR:
139 case SWS_UOP_MIN:
140 case SWS_UOP_MAX:
141 return ff_sws_setup_vec4(&(const SwsImplParams) { .uop = uop }, out);
142 case SWS_UOP_SCALE:
143 return ff_sws_setup_scalar(&(const SwsImplParams) { .uop = uop }, out);
144 case SWS_UOP_LINEAR:
146 return aarch64_setup_linear(p, uop, out);
147 case SWS_UOP_DITHER:
148 return aarch64_setup_dither(uop, out);
149 }
150 return 0;
151}
152
153/*********************************************************************/
156{
157 int ret;
158
159 const int cpu_flags = av_get_cpu_flags();
161 return AVERROR(ENOTSUP);
162
163 /* Use at most two full vregs during the widest precision section */
164 int block_size = (uops->pixel_size_max == 4) ? 8 : 16;
165
167 if (!chain)
168 return AVERROR(ENOMEM);
170
171 *out = (SwsCompiledOp) {
172 .priv = chain,
173 .slice_align = 1,
175 .block_size = block_size,
176 };
177
178 /* Look up kernel functions. */
179 for (int i = 0; i < uops->num_ops; i++) {
181 convert_to_aarch64_impl(&uops->ops[i], block_size, &params);
183 if (!func) {
184 ret = AVERROR(ENOTSUP);
185 goto error;
186 }
187 SwsImplResult res = { 0 };
188 ret = aarch64_setup(&uops->ops[i], &params, &res);
189 if (ret < 0)
190 goto error;
191 ret = ff_sws_op_chain_append(chain, func, res.free, &res.priv);
192 if (ret < 0)
193 goto error;
194 }
195
196 /* Look up process function. */
197 void ff_sws_process_0001_neon(void);
198 void ff_sws_process_0011_neon(void);
199 void ff_sws_process_0111_neon(void);
200 void ff_sws_process_1111_neon(void);
201
202 SwsOpFunc process_func = NULL;
203 switch (av_popcount(uops->planes_in | uops->planes_out)) {
204 case 1: process_func = (SwsOpFunc) ff_sws_process_0001_neon; break;
205 case 2: process_func = (SwsOpFunc) ff_sws_process_0011_neon; break;
206 case 3: process_func = (SwsOpFunc) ff_sws_process_0111_neon; break;
207 case 4: process_func = (SwsOpFunc) ff_sws_process_1111_neon; break;
208 }
209
210 out->func = process_func;
211 out->cpu_flags = chain->cpu_flags;
212
213 return 0;
214
215error:
217 return ret;
218}
219
220/*********************************************************************/
221static int aarch64_compile(SwsContext *ctx, const SwsOpList *ops,
223{
225 if (!uops)
226 return AVERROR(ENOMEM);
227
228 const SwsUOpFlags flags = (ctx->flags & SWS_BITEXACT) ? 0 : SWS_UOP_FLAG_FMA;
229 int ret = ff_sws_ops_translate(ctx, ops, flags, uops);
230 if (ret < 0)
231 goto error;
232
233 ret = aarch64_compile_uops(ctx, uops, out);
234
235error:
237 return ret;
238}
239
240/*********************************************************************/
242 .name = "aarch64",
243 .flags = SWS_BACKEND_AARCH64,
244 .compile = aarch64_compile,
245 .compile_uops = aarch64_compile_uops,
246 .hw_format = AV_PIX_FMT_NONE,
247};
static int aarch64_setup_dither(const SwsUOp *uop, SwsImplResult *res)
Definition ops.c:108
static int aarch64_setup(const SwsUOp *uop, const SwsAArch64OpImplParams *p, SwsImplResult *out)
Definition ops.c:116
static int aarch64_setup_linear(const SwsAArch64OpImplParams *p, const SwsUOp *uop, SwsImplResult *res)
Definition ops.c:68
static int aarch64_compile_uops(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
Definition ops.c:154
static int aarch64_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Definition ops.c:221
static const struct @070174075374214234277303002223103136214276265127 ops_entries[]
SwsAArch64OpImplParams params
Definition ops.c:51
const SwsOpBackend backend_aarch64
Definition ops.c:241
static SwsFuncPtr aarch64_lookup(const SwsAArch64OpImplParams *p)
Definition ops.c:59
static FILE * out
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define av_popcount
Definition common.h:154
#define NULL
Definition coverity.c:32
#define AVERROR(e)
Definition error.h:45
@ SWS_BACKEND_AARCH64
Chained AArch64 NEON kernels.
Definition swscale.h:119
@ SWS_BITEXACT
Definition swscale.h:178
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition jacosubdec.c:66
static atomic_int cpu_flags
Definition cpu.c:56
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
Definition cpu.c:109
#define AV_CPU_FLAG_NEON
Definition cpu.h:73
int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func, void(*free)(SwsOpPriv *), const SwsOpPriv *priv)
Definition ops_chain.c:45
int ff_sws_setup_vec4(const SwsImplParams *params, SwsImplResult *out)
Definition ops_chain.c:144
SwsOpChain * ff_sws_op_chain_alloc(void)
Copyright (C) 2025 Niklas Haas.
Definition ops_chain.c:26
void ff_sws_op_chain_free_cb(void *ptr)
Definition ops_chain.c:31
int ff_sws_setup_scalar(const SwsImplParams *params, SwsImplResult *out)
Definition ops_chain.c:129
static void ff_sws_op_chain_free(SwsOpChain *chain)
Definition ops_chain.h:96
static void ff_op_priv_unref(SwsOpPriv *priv)
Definition ops_chain.h:141
void(* SwsFuncPtr)(void)
Per-kernel execution context.
Definition ops_chain.h:70
static void ff_op_priv_free(SwsOpPriv *priv)
Definition ops_chain.h:136
void(* SwsOpFunc)(const SwsOpExec *exec, const void *priv, int bx_start, int y_start, int bx_end, int y_end)
Process a given range of pixel blocks.
static int linear_num_vregs(const SwsAArch64OpImplParams *params)
Definition ops_impl.h:73
#define offsetof_exec_out_bump
Definition ops_impl.h:91
#define offsetof_exec_in
These values will be used by ops_asmgen to access fields inside of SwsOpExec and SwsOpImpl.
Definition ops_impl.h:88
#define offsetof_exec_out
Definition ops_impl.h:89
#define offsetof_exec_in_bump
Definition ops_impl.h:90
#define offsetof_impl_priv
Definition ops_impl.h:93
#define offsetof_impl_cont
Definition ops_impl.h:92
static void convert_to_aarch64_impl(const SwsUOp *uop, int block_size, SwsAArch64OpImplParams *out)
NOTE: This file is #include'd directly by both the NEON backend and the sws_ops_aarch64 tool.
#define av_malloc(s)
Definition ops_static.c:52
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition refstruct.c:141
#define FF_ARRAY_ELEMS(a)
SwsAArch64OpImplParams describes the parameters for an SwsUOpType operation.
Definition ops_impl.h:47
Main external API structure.
Definition swscale.h:227
SwsOpPriv priv
Definition ops_chain.h:113
void(* free)(SwsOpPriv *priv)
Definition ops_chain.h:114
Compiled "chain" of operations, which can be dispatched efficiently.
Definition ops_chain.h:84
int cpu_flags
Definition ops_chain.h:89
void(* free[SWS_MAX_OPS+1])(SwsOpPriv *)
Definition ops_chain.h:87
Copyright (C) 2026 Niklas Haas.
Helper struct for representing a list of operations.
Definition ops.h:297
SwsUOp * ops
Definition uops.h:329
int pixel_size_max
Definition uops.h:335
int num_ops
Definition uops.h:330
SwsCompMask planes_in
Definition uops.h:333
SwsCompMask planes_out
Definition uops.h:334
Definition uops.h:292
SwsUOpType uop
Definition uops.h:295
SwsPixel * ptr
Definition uops.h:302
union SwsUOp::@242237116251216327057105100216205033300341206345 data
SwsPixel mat4x5[4][5]
Definition uops.h:305
static void error(const char *err)
A tree container.
Private data for each kernel.
Definition ops_chain.h:45
void * ptr
Definition ops_chain.h:49
float f32
Definition uops.h:85
uint32_t u32
Definition uops.h:84
uint8_t u8
Definition uops.h:82
uint16_t u16
Definition uops.h:83
int ff_sws_ops_translate(SwsContext *ctx, const SwsOpList *ops, SwsUOpFlags flags, SwsUOpList *uops)
Translate a list of operations down to micro-ops, which can be further optimized and then directly ex...
Definition uops.c:618
SwsUOpList * ff_sws_uop_list_alloc(void)
Definition uops.c:174
void ff_sws_uop_list_free(SwsUOpList **p_ops)
Definition uops.c:160
uint32_t SwsUOpFlags
Definition uops.h:147
@ SWS_PIXEL_F32
Definition uops.h:45
@ SWS_PIXEL_U32
Definition uops.h:44
@ SWS_PIXEL_U16
Definition uops.h:43
@ SWS_PIXEL_U8
Definition uops.h:42
#define SWS_MASK(I, J)
Definition uops.h:259
@ SWS_UOP_MAX
Definition uops.h:196
@ SWS_UOP_READ_BIT
Definition uops.h:167
@ SWS_UOP_MIN
Definition uops.h:195
@ SWS_UOP_LINEAR
Definition uops.h:204
@ SWS_UOP_LINEAR_FMA
Definition uops.h:205
@ SWS_UOP_SCALE
Definition uops.h:193
@ SWS_UOP_WRITE_BIT
Definition uops.h:173
@ SWS_UOP_DITHER
Definition uops.h:206
@ SWS_UOP_CLEAR
Definition uops.h:203
@ SWS_UOP_FLAG_FMA
Definition uops.h:150