Go to the documentation of this file.
27 #include "../ops_chain.h"
29 #include "../uops_macros.h"
49 static_assert(
sizeof(
out->priv.ptr) <=
sizeof(
int32_t[2]),
50 ">8 byte pointers not supported");
57 for (
int i = 0;
i <
filter->num_weights;
i++)
87 const int taps_align =
sizeof(
int32_t) / pixel_size;
88 const int filter_size =
filter->filter_size;
90 const size_t aligned_size =
FFALIGN(filter_size, taps_align);
91 const size_t line_size =
FFALIGN(
filter->dst_size, block_size);
93 if (aligned_size > INT_MAX)
110 const int mmsize = block_size * 2;
111 const int gather_size = mmsize /
sizeof(
int32_t);
112 for (
size_t x = 0; x < line_size; x += block_size) {
113 const int elems =
FFMIN(block_size,
filter->dst_size - x);
114 for (
int j = 0; j < filter_size; j++) {
115 const int jb = j & ~(taps_align - 1);
116 const int ji = j - jb;
117 const size_t idx_base = x * aligned_size + jb * block_size + ji;
118 for (
int i = 0;
i < elems;
i++) {
119 const int w =
filter->weights[(x +
i) * filter_size + j];
120 size_t idx = idx_base;
132 const int gather_base =
i & ~(gather_size - 1);
133 const int gather_pos =
i - gather_base;
134 const int lane_idx = gather_pos >> 2;
135 const int pos_in_lane = gather_pos & 3;
136 idx += gather_base * 4
137 + (pos_in_lane >> 1) * (mmsize / 2)
139 + (pos_in_lane & 1) * 4;
141 idx +=
i * taps_align;
154 out->priv.uptr[1] = aligned_size;
157 for (
int i = 0;
i < 4;
i++) {
159 out->over_read[
i] = (aligned_size - filter_size) * pixel_size;
195 const int taps_align = 16 / sizeof_weights;
196 const int pixels_align = 4;
197 const int filter_size =
filter->filter_size;
198 const size_t aligned_size =
FFALIGN(filter_size, taps_align);
224 for (
int x = 0; x <
filter->dst_size; x++) {
225 for (
int j = 0; j < filter_size; j++) {
226 const int xb = x & ~(pixels_align - 1);
227 const int jb = j & ~(taps_align - 1);
228 const int xi = x - xb, ji = j - jb;
229 const int w =
filter->weights[x * filter_size + j];
230 const int idx = xb * aligned_size + jb * pixels_align +
xi * taps_align + ji;
241 out->priv.uptr[1] = aligned_size * sizeof_weights;
244 for (
int i = 0;
i < 4;
i++) {
246 out->over_read[
i] = (aligned_size - filter_size) * pixel_size;
259 default:
return AVERROR(EINVAL);
268 for (
int i = 0;
i < 4;
i++)
300 #define REF_ENTRY(EXT, NAME, ...) &uop_##NAME##EXT,
301 #define DECL_ENTRY(EXT, CHECK, SETUP, NAME, ...) \
302 void ff_##NAME##EXT(void); \
303 static const SwsUOpEntry uop_##NAME##EXT = { \
304 .func = (SwsFuncPtr) ff_##NAME##EXT, \
311 #define DECL_OPS_COMMON(EXT, TYPE) \
312 SWS_FOR_STRUCT(TYPE, READ_PACKED, DECL_ENTRY, EXT, NULL, setup_rw_packed) \
313 SWS_FOR_STRUCT(TYPE, READ_NIBBLE, DECL_ENTRY, EXT, NULL, NULL) \
314 SWS_FOR_STRUCT(TYPE, READ_BIT, DECL_ENTRY, EXT, NULL, NULL) \
315 SWS_FOR_STRUCT(TYPE, READ_PALETTE, DECL_ENTRY, EXT, NULL, NULL) \
316 SWS_FOR_STRUCT(TYPE, WRITE_PACKED, DECL_ENTRY, EXT, NULL, setup_rw_packed) \
317 SWS_FOR_STRUCT(TYPE, WRITE_NIBBLE, DECL_ENTRY, EXT, NULL, NULL) \
318 SWS_FOR_STRUCT(TYPE, WRITE_BIT, DECL_ENTRY, EXT, NULL, NULL) \
319 SWS_FOR_STRUCT(TYPE, SWAP_BYTES, DECL_ENTRY, EXT, NULL, NULL) \
320 SWS_FOR_STRUCT(TYPE, EXPAND_BIT, DECL_ENTRY, EXT, NULL, NULL) \
321 SWS_FOR_STRUCT(TYPE, PERMUTE, DECL_ENTRY, EXT, NULL, NULL) \
322 SWS_FOR_STRUCT(TYPE, COPY, DECL_ENTRY, EXT, NULL, NULL) \
323 SWS_FOR_STRUCT(TYPE, SCALE, DECL_ENTRY, EXT, NULL, setup_scale) \
324 SWS_FOR_STRUCT(TYPE, ADD, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
325 SWS_FOR_STRUCT(TYPE, MIN, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
326 SWS_FOR_STRUCT(TYPE, MAX, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
327 SWS_FOR_STRUCT(TYPE, UNPACK, DECL_ENTRY, EXT, NULL, NULL) \
328 SWS_FOR_STRUCT(TYPE, PACK, DECL_ENTRY, EXT, NULL, NULL) \
329 SWS_FOR_STRUCT(TYPE, LSHIFT, DECL_ENTRY, EXT, NULL, NULL) \
330 SWS_FOR_STRUCT(TYPE, RSHIFT, DECL_ENTRY, EXT, NULL, NULL) \
331 SWS_FOR_STRUCT(TYPE, LINEAR, DECL_ENTRY, EXT, NULL, setup_linear) \
332 SWS_FOR_STRUCT(TYPE, LINEAR_FMA, DECL_ENTRY, EXT, NULL, setup_linear) \
333 SWS_FOR_STRUCT(TYPE, DITHER, DECL_ENTRY, EXT, NULL, setup_dither) \
336 #define REF_OPS_COMMON(EXT, TYPE) \
337 SWS_FOR(TYPE, READ_PACKED, REF_ENTRY, EXT) \
338 SWS_FOR(TYPE, READ_NIBBLE, REF_ENTRY, EXT) \
339 SWS_FOR(TYPE, READ_BIT, REF_ENTRY, EXT) \
340 SWS_FOR(TYPE, READ_PALETTE, REF_ENTRY, EXT) \
341 SWS_FOR(TYPE, WRITE_PACKED, REF_ENTRY, EXT) \
342 SWS_FOR(TYPE, WRITE_NIBBLE, REF_ENTRY, EXT) \
343 SWS_FOR(TYPE, WRITE_BIT, REF_ENTRY, EXT) \
344 SWS_FOR(TYPE, SWAP_BYTES, REF_ENTRY, EXT) \
345 SWS_FOR(TYPE, EXPAND_BIT, REF_ENTRY, EXT) \
346 SWS_FOR(TYPE, PERMUTE, REF_ENTRY, EXT) \
347 SWS_FOR(TYPE, COPY, REF_ENTRY, EXT) \
348 SWS_FOR(TYPE, SCALE, REF_ENTRY, EXT) \
349 SWS_FOR(TYPE, ADD, REF_ENTRY, EXT) \
350 SWS_FOR(TYPE, MIN, REF_ENTRY, EXT) \
351 SWS_FOR(TYPE, MAX, REF_ENTRY, EXT) \
352 SWS_FOR(TYPE, UNPACK, REF_ENTRY, EXT) \
353 SWS_FOR(TYPE, PACK, REF_ENTRY, EXT) \
354 SWS_FOR(TYPE, LSHIFT, REF_ENTRY, EXT) \
355 SWS_FOR(TYPE, RSHIFT, REF_ENTRY, EXT) \
356 SWS_FOR(TYPE, LINEAR, REF_ENTRY, EXT) \
357 SWS_FOR(TYPE, LINEAR_FMA, REF_ENTRY, EXT) \
358 SWS_FOR(TYPE, DITHER, REF_ENTRY, EXT) \
361 #define DECL_TABLE_U8(EXT, SIZE, FLAG) \
362 DECL_OPS_COMMON(EXT, U8) \
363 SWS_FOR_STRUCT(U8, READ_PLANAR, DECL_ENTRY, EXT, NULL, NULL) \
364 SWS_FOR_STRUCT(U8, WRITE_PLANAR, DECL_ENTRY, EXT, NULL, NULL) \
365 SWS_FOR_STRUCT(U8, CLEAR, DECL_ENTRY, EXT, NULL, setup_clear) \
367 static const SwsUOpTable uops_u8##EXT = { \
368 .cpu_flags = AV_CPU_FLAG_##FLAG, \
369 .block_size = SIZE, \
371 REF_OPS_COMMON(EXT, U8) \
372 SWS_FOR(U8, READ_PLANAR, REF_ENTRY, EXT) \
373 SWS_FOR(U8, WRITE_PLANAR, REF_ENTRY, EXT) \
374 SWS_FOR(U8, CLEAR, REF_ENTRY, EXT) \
379 #define DECL_TABLE_U16(EXT, SIZE, FLAG) \
380 DECL_OPS_COMMON(EXT, U16) \
381 SWS_FOR_STRUCT(U8, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
382 SWS_FOR_STRUCT(U16, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
383 SWS_FOR_STRUCT(U8, EXPAND_PAIR, DECL_ENTRY, EXT, NULL, NULL) \
385 static const SwsUOpTable uops_u16##EXT = { \
386 .cpu_flags = AV_CPU_FLAG_##FLAG, \
387 .block_size = SIZE, \
389 REF_OPS_COMMON(EXT, U16) \
390 SWS_FOR(U8, TO_U16, REF_ENTRY, EXT) \
391 SWS_FOR(U16, TO_U8, REF_ENTRY, EXT) \
392 SWS_FOR(U8, EXPAND_PAIR, REF_ENTRY, EXT) \
397 #define DECL_TABLE_U32(EXT, SIZE, FLAG) \
398 DECL_OPS_COMMON(EXT, U32) \
399 SWS_FOR_STRUCT(U8, TO_U32, DECL_ENTRY, EXT, NULL, NULL) \
400 SWS_FOR_STRUCT(U32, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
401 SWS_FOR_STRUCT(U16, TO_U32, DECL_ENTRY, EXT, NULL, NULL) \
402 SWS_FOR_STRUCT(U32, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
403 SWS_FOR_STRUCT(U8, EXPAND_QUAD, DECL_ENTRY, EXT, NULL, NULL) \
405 static const SwsUOpTable uops_u32##EXT = { \
406 .cpu_flags = AV_CPU_FLAG_##FLAG, \
407 .block_size = SIZE, \
409 REF_OPS_COMMON(EXT, U32) \
410 SWS_FOR(U8, TO_U32, REF_ENTRY, EXT) \
411 SWS_FOR(U32, TO_U8, REF_ENTRY, EXT) \
412 SWS_FOR(U16, TO_U32, REF_ENTRY, EXT) \
413 SWS_FOR(U32, TO_U16, REF_ENTRY, EXT) \
414 SWS_FOR(U8, EXPAND_QUAD, REF_ENTRY, EXT) \
419 #define DECL_TABLE_F32(EXT, SIZE, FLAG) \
420 DECL_OPS_COMMON(EXT, F32) \
421 SWS_FOR_STRUCT(U8, TO_F32, DECL_ENTRY, EXT, NULL, NULL) \
422 SWS_FOR_STRUCT(F32, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
423 SWS_FOR_STRUCT(U16, TO_F32, DECL_ENTRY, EXT, NULL, NULL) \
424 SWS_FOR_STRUCT(F32, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
425 SWS_FOR_STRUCT(U8, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
426 SWS_FOR_STRUCT(U16, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
427 SWS_FOR_STRUCT(F32, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
428 SWS_FOR_STRUCT(U8, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
429 check_filter_h_4x4, setup_filter_h_4x4) \
430 SWS_FOR_STRUCT(U16, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
431 check_filter_h_4x4, setup_filter_h_4x4) \
432 SWS_FOR_STRUCT(F32, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
433 check_filter_h_4x4, setup_filter_h_4x4) \
434 SWS_FOR_STRUCT(U8, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
435 SWS_FOR_STRUCT(U16, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
436 SWS_FOR_STRUCT(F32, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
437 SWS_FOR_STRUCT(U8, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
438 SWS_FOR_STRUCT(U16, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
439 SWS_FOR_STRUCT(F32, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
441 static const SwsUOpTable uops_f32##EXT = { \
442 .cpu_flags = AV_CPU_FLAG_##FLAG, \
443 .block_size = SIZE, \
445 REF_OPS_COMMON(EXT, F32) \
446 SWS_FOR(U8, TO_F32, REF_ENTRY, EXT) \
447 SWS_FOR(F32, TO_U8, REF_ENTRY, EXT) \
448 SWS_FOR(U16, TO_F32, REF_ENTRY, EXT) \
449 SWS_FOR(F32, TO_U16, REF_ENTRY, EXT) \
450 SWS_FOR(U8, READ_PLANAR_FH, REF_ENTRY, _4x4##EXT) \
451 SWS_FOR(U16, READ_PLANAR_FH, REF_ENTRY, _4x4##EXT) \
452 SWS_FOR(F32, READ_PLANAR_FH, REF_ENTRY, _4x4##EXT) \
453 SWS_FOR(U8, READ_PLANAR_FH, REF_ENTRY, EXT) \
454 SWS_FOR(U16, READ_PLANAR_FH, REF_ENTRY, EXT) \
455 SWS_FOR(F32, READ_PLANAR_FH, REF_ENTRY, EXT) \
456 SWS_FOR(U8, READ_PLANAR_FV, REF_ENTRY, EXT) \
457 SWS_FOR(U16, READ_PLANAR_FV, REF_ENTRY, EXT) \
458 SWS_FOR(F32, READ_PLANAR_FV, REF_ENTRY, EXT) \
459 SWS_FOR(U8, READ_PLANAR_FV_FMA, REF_ENTRY, EXT) \
460 SWS_FOR(U16, READ_PLANAR_FV_FMA, REF_ENTRY, EXT) \
461 SWS_FOR(F32, READ_PLANAR_FV_FMA, REF_ENTRY, EXT) \
510 static int movsize(
const int bytes,
const int mmsize)
512 return bytes <= 4 ? 4 :
531 const int mask_size = lane_aligned ? 16 : mmsize;
543 const int write_chunk = groups * par->
write_size;
544 const int num_lanes = lane_aligned ? mmsize / 16 : 1;
546 const int out_total = num_lanes * write_chunk;
552 .over_read = {
movsize(in_total, mmsize) - in_total },
553 .over_write = {
movsize(out_total, mmsize) - out_total },
556 #define ASSIGN_SHUFFLE_FUNC(CPU, EXT, NAME, ...) \
558 const SwsUOpEntry *entry = &uop_##NAME##EXT; \
559 if (!memcmp(&uop->par, &entry->par, sizeof(uop->par))) { \
560 out->func = (SwsOpFunc) entry->func; \
561 out->cpu_flags = AV_CPU_FLAG_##CPU; \
599 for (
int i = 0;
i < 4;
i++)
634 int op_block_size =
out->block_size;
644 op_block_size, chain);
650 case 1:
out->func = ff_sws_process1_x86;
break;
651 case 2:
out->func = ff_sws_process2_x86;
break;
652 case 3:
out->func = ff_sws_process3_x86;
break;
653 case 4:
out->func = ff_sws_process4_x86;
break;
static int hscale_sizeof_weight(const SwsUOp *uop)
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
static uint32_t expand32(const SwsPixelType type, const SwsPixel value)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
const SwsOpBackend backend_x86
static void normalize_clear(SwsUOp *uop)
#define EXTERNAL_FMA3(flags)
#define u(width, name, range_min, range_max)
Represents a computed filter kernel.
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
#define AV_LOG_VERBOSE
Detailed information.
void(* filter)(uint8_t *src, int stride, int qscale)
static int get_mmsize(void)
Copyright (C) 2025 Niklas Haas.
static void ff_op_priv_unref(SwsOpPriv *priv)
static int setup_linear(const SwsImplParams *params, SwsImplResult *out)
#define SWS_UOP_NAME_MAX
Generate a unique name for a SwsUOp.
#define DECL_TABLE_F32(EXT, SIZE, FLAG)
int ff_sws_shuffle_mask(const SwsUOp *uop, int8_t shuffle[], int size)
Compute a shuffle mask for pshufb-style ASM functions, by repeating the shuffle pattern for as many g...
@ SWS_BACKEND_X86
Chained x86 SIMD kernels.
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
static int setup_dither(const SwsImplParams *params, SwsImplResult *out)
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
#define SWS_COMP_ELEMS(N)
#define DECL_TABLE_U8(EXT, SIZE, FLAG)
#define SWS_FOR(TYPE, UOP, MACRO,...)
#define SWS_FOR_STRUCT(TYPE, UOP, MACRO,...)
static int compile_uops_x86(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
#define FF_ARRAY_ELEMS(a)
SwsFilterWeights * kernel
#define flags(name, subs,...)
SwsOpChain * ff_sws_op_chain_alloc(void)
Copyright (C) 2025 Niklas Haas.
int flags
Flags modifying the (de)muxer behaviour.
static int read_chunk(AVFormatContext *s)
static int setup_clear(const SwsImplParams *params, SwsImplResult *out)
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static AVFormatContext * ctx
#define EXTERNAL_AVX2(flags)
SwsAArch64OpImplParams params
#define DECL_TABLE_U16(EXT, SIZE, FLAG)
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Compiled "chain" of operations, which can be dispatched efficiently.
#define DECL_ENTRY(EXT, CHECK, SETUP, NAME,...)
static bool uop_is_type_invariant(const SwsUOpType uop)
static bool check_filter_h_4x4(const SwsImplParams *params)
#define DECL_TABLE_U32(EXT, SIZE, FLAG)
#define EXTERNAL_AVX512(flags)
SWS_DECL_FUNC(ff_sws_process1_x86)
static const SwsUOpTable *const tables[]
#define ASSIGN_SHUFFLE_FUNC(CPU, EXT, NAME,...)
static int translate_shuffle(const SwsUOp *uop, int mmsize, SwsCompiledOp *out)
#define i(width, name, range_min, range_max)
static int movsize(const int bytes, const int mmsize)
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
#define EXTERNAL_SSE4(flags)
SwsUOpList * ff_sws_uop_list_alloc(void)
void ff_sws_op_chain_free_cb(void *ptr)
static int setup_filter_h_4x4(const SwsImplParams *params, SwsImplResult *out)
static void ff_sws_op_chain_free(SwsOpChain *chain)
static const int weights[]
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
void * av_calloc(size_t nmemb, size_t size)
static void ff_op_priv_free(SwsOpPriv *priv)
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...
void ff_sws_uop_list_free(SwsUOpList **p_ops)
static int setup_rw_packed(const SwsImplParams *params, SwsImplResult *out)
Copyright (C) 2025-2026 Niklas Haas.
void ff_sws_uop_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX])
static int setup_scale(const SwsImplParams *params, SwsImplResult *out)
#define AV_CPU_FLAG_SLOW_GATHER
CPU has slow gathers.
static int setup_filter_v(const SwsImplParams *params, SwsImplResult *out)
int ff_sws_uop_lookup(SwsContext *ctx, const SwsUOpTable *const tables[], int num_tables, const SwsUOp *uop, const int block_size, SwsOpChain *chain)
"Compile" a single uop by looking it up in a list of fixed size uop tables, in decreasing order of pr...
static int compile_x86(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
#define xi(width, name, var, range_min, range_max, subs,...)
Helper struct for representing a list of operations.
Main external API structure.
#define EXTERNAL_AVX512ICL(flags)
static int setup_filter_h(const SwsImplParams *params, SwsImplResult *out)