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;
89 const int block_size =
params->table->block_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;
194 const int block_size =
params->table->block_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) \
312SWS_FOR_STRUCT(TYPE, READ_PACKED, DECL_ENTRY, EXT, NULL, setup_rw_packed) \
313SWS_FOR_STRUCT(TYPE, READ_NIBBLE, DECL_ENTRY, EXT, NULL, NULL) \
314SWS_FOR_STRUCT(TYPE, READ_BIT, DECL_ENTRY, EXT, NULL, NULL) \
315SWS_FOR_STRUCT(TYPE, READ_PALETTE, DECL_ENTRY, EXT, NULL, NULL) \
316SWS_FOR_STRUCT(TYPE, WRITE_PACKED, DECL_ENTRY, EXT, NULL, setup_rw_packed) \
317SWS_FOR_STRUCT(TYPE, WRITE_NIBBLE, DECL_ENTRY, EXT, NULL, NULL) \
318SWS_FOR_STRUCT(TYPE, WRITE_BIT, DECL_ENTRY, EXT, NULL, NULL) \
319SWS_FOR_STRUCT(TYPE, SWAP_BYTES, DECL_ENTRY, EXT, NULL, NULL) \
320SWS_FOR_STRUCT(TYPE, EXPAND_BIT, DECL_ENTRY, EXT, NULL, NULL) \
321SWS_FOR_STRUCT(TYPE, PERMUTE, DECL_ENTRY, EXT, NULL, NULL) \
322SWS_FOR_STRUCT(TYPE, COPY, DECL_ENTRY, EXT, NULL, NULL) \
323SWS_FOR_STRUCT(TYPE, SCALE, DECL_ENTRY, EXT, NULL, setup_scale) \
324SWS_FOR_STRUCT(TYPE, ADD, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
325SWS_FOR_STRUCT(TYPE, MIN, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
326SWS_FOR_STRUCT(TYPE, MAX, DECL_ENTRY, EXT, NULL, ff_sws_setup_vec4) \
327SWS_FOR_STRUCT(TYPE, UNPACK, DECL_ENTRY, EXT, NULL, NULL) \
328SWS_FOR_STRUCT(TYPE, PACK, DECL_ENTRY, EXT, NULL, NULL) \
329SWS_FOR_STRUCT(TYPE, LSHIFT, DECL_ENTRY, EXT, NULL, NULL) \
330SWS_FOR_STRUCT(TYPE, RSHIFT, DECL_ENTRY, EXT, NULL, NULL) \
331SWS_FOR_STRUCT(TYPE, LINEAR, DECL_ENTRY, EXT, NULL, setup_linear) \
332SWS_FOR_STRUCT(TYPE, LINEAR_FMA, DECL_ENTRY, EXT, NULL, setup_linear) \
333SWS_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) \
362DECL_OPS_COMMON(EXT, U8) \
363SWS_FOR_STRUCT(U8, READ_PLANAR, DECL_ENTRY, EXT, NULL, NULL) \
364SWS_FOR_STRUCT(U8, WRITE_PLANAR, DECL_ENTRY, EXT, NULL, NULL) \
365SWS_FOR_STRUCT(U8, CLEAR, DECL_ENTRY, EXT, NULL, setup_clear) \
367static 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) \
380DECL_OPS_COMMON(EXT, U16) \
381SWS_FOR_STRUCT(U8, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
382SWS_FOR_STRUCT(U16, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
383SWS_FOR_STRUCT(U8, EXPAND_PAIR, DECL_ENTRY, EXT, NULL, NULL) \
385static 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) \
398DECL_OPS_COMMON(EXT, U32) \
399SWS_FOR_STRUCT(U8, TO_U32, DECL_ENTRY, EXT, NULL, NULL) \
400SWS_FOR_STRUCT(U32, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
401SWS_FOR_STRUCT(U16, TO_U32, DECL_ENTRY, EXT, NULL, NULL) \
402SWS_FOR_STRUCT(U32, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
403SWS_FOR_STRUCT(U8, EXPAND_QUAD, DECL_ENTRY, EXT, NULL, NULL) \
405static 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) \
420DECL_OPS_COMMON(EXT, F32) \
421SWS_FOR_STRUCT(U8, TO_F32, DECL_ENTRY, EXT, NULL, NULL) \
422SWS_FOR_STRUCT(F32, TO_U8, DECL_ENTRY, EXT, NULL, NULL) \
423SWS_FOR_STRUCT(U16, TO_F32, DECL_ENTRY, EXT, NULL, NULL) \
424SWS_FOR_STRUCT(F32, TO_U16, DECL_ENTRY, EXT, NULL, NULL) \
425SWS_FOR_STRUCT(U8, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
426SWS_FOR_STRUCT(U16, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
427SWS_FOR_STRUCT(F32, READ_PLANAR_FH, DECL_ENTRY, EXT, NULL, setup_filter_h) \
428SWS_FOR_STRUCT(U8, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
429 check_filter_h_4x4, setup_filter_h_4x4) \
430SWS_FOR_STRUCT(U16, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
431 check_filter_h_4x4, setup_filter_h_4x4) \
432SWS_FOR_STRUCT(F32, READ_PLANAR_FH, DECL_ENTRY, _4x4##EXT, \
433 check_filter_h_4x4, setup_filter_h_4x4) \
434SWS_FOR_STRUCT(U8, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
435SWS_FOR_STRUCT(U16, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
436SWS_FOR_STRUCT(F32, READ_PLANAR_FV, DECL_ENTRY, EXT, NULL, setup_filter_v) \
437SWS_FOR_STRUCT(U8, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
438SWS_FOR_STRUCT(U16, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
439SWS_FOR_STRUCT(F32, READ_PLANAR_FV_FMA, DECL_ENTRY, EXT, NULL, setup_filter_v) \
441static 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) \
510static int movsize(
const int bytes,
const int mmsize)
512 return bytes <= 4 ? 4 :
531 const int mask_size = lane_aligned ? 16 : mmsize;
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;
SwsAArch64OpImplParams params
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
#define flags(name, subs,...)
#define i(width, name, range_min, range_max)
#define xi(width, name, var, range_min, range_max, subs,...)
static int read_chunk(AVFormatContext *s)
static const OptionGroupDef groups[]
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_VERBOSE
Detailed information.
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
@ SWS_BACKEND_X86
Chained x86 SIMD kernels.
static const int weights[]
static atomic_int cpu_flags
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
#define AV_CPU_FLAG_SLOW_GATHER
CPU has slow gathers.
#define EXTERNAL_AVX512ICL(flags)
#define EXTERNAL_FMA3(flags)
#define EXTERNAL_SSE4(flags)
#define EXTERNAL_AVX512(flags)
#define EXTERNAL_AVX2(flags)
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
static const uint16_t mask[17]
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
const SwsOpBackend backend_x86
SwsOpChain * ff_sws_op_chain_alloc(void)
Copyright (C) 2025 Niklas Haas.
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...
void ff_sws_op_chain_free_cb(void *ptr)
static void ff_sws_op_chain_free(SwsOpChain *chain)
static void ff_op_priv_unref(SwsOpPriv *priv)
static void ff_op_priv_free(SwsOpPriv *priv)
#define SWS_DECL_FUNC(NAME)
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...
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
#define FF_ARRAY_ELEMS(a)
Main external API structure.
Represents a computed filter kernel.
Compiled "chain" of operations, which can be dispatched efficiently.
Helper struct for representing a list of operations.
Copyright (C) 2025 Niklas Haas.
SwsFilterWeights * kernel
union SwsUOp::@242237116251216327057105100216205033300341206345 data
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
static AVFormatContext * ctx
static const uint8_t *const tables[]
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_name(const SwsUOp *op, char buf[SWS_UOP_NAME_MAX])
SwsUOpList * ff_sws_uop_list_alloc(void)
void ff_sws_uop_list_free(SwsUOpList **p_ops)
#define SWS_COMP_ELEMS(N)
#define SWS_UOP_NAME_MAX
Generate a unique name for a SwsUOp.
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
#define SWS_FOR(TYPE, UOP, MACRO,...)
#define SWS_FOR_STRUCT(TYPE, UOP, MACRO,...)
#define DECL_ENTRY(SETUP, NAME,...)
static int setup_clear(const SwsImplParams *params, SwsImplResult *out)
static int movsize(const int bytes, const int mmsize)
#define ASSIGN_SHUFFLE_FUNC(CPU, EXT, NAME,...)
static int hscale_sizeof_weight(const SwsUOp *uop)
static int setup_filter_h_4x4(const SwsImplParams *params, SwsImplResult *out)
static bool uop_is_type_invariant(const SwsUOpType uop)
static int compile_uops_x86(SwsContext *ctx, const SwsUOpList *uops, SwsCompiledOp *out)
static uint32_t expand32(const SwsPixelType type, const SwsPixel value)
static int compile_x86(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
#define DECL_TABLE_U8(EXT, SIZE, FLAG)
#define DECL_TABLE_U16(EXT, SIZE, FLAG)
static int setup_linear(const SwsImplParams *params, SwsImplResult *out)
static int setup_scale(const SwsImplParams *params, SwsImplResult *out)
static int setup_filter_v(const SwsImplParams *params, SwsImplResult *out)
#define DECL_TABLE_U32(EXT, SIZE, FLAG)
static void normalize_clear(SwsUOp *uop)
static bool check_filter_h_4x4(const SwsImplParams *params)
static int setup_dither(const SwsImplParams *params, SwsImplResult *out)
static int translate_shuffle(const SwsUOp *uop, int mmsize, SwsCompiledOp *out)
static int setup_filter_h(const SwsImplParams *params, SwsImplResult *out)
#define DECL_TABLE_F32(EXT, SIZE, FLAG)
static int setup_rw_packed(const SwsImplParams *params, SwsImplResult *out)
Copyright (C) 2025-2026 Niklas Haas.
static int get_mmsize(void)