Commit Graph
3613 Commits
Author SHA1 Message Date
iSold Leo ec2a4105e2 swscale: avoid overflow in fast bilinear edge handling
The final edge clamp computes the source position using int
multiplication before shifting. With sufficiently wide inputs this
overflows, which may suppress the clamp and leave the last output
pixels interpolated with the padding byte.

Promote the multiplication to int64_t in the C, MMXEXT and VSX
implementations.

Add a regression test covering the rightmost pixel of a wide upscale,
which is wrong before this change on both the C and the MMXEXT path.

Fixes: signed integer overflow: 15 * 255918080 cannot be represented in type 'int'
Fixes: #21591
Signed-off-by: iSold Leo <s@qwqlog.com>
2026-08-05 19:34:30 +00:00
Kacper Michajłow 8f80421b2d swscale/aarch64/ops_static: fix av_assert0 on NDEBUG builds
av_assert0 suppose to run always.

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
2026-08-05 13:06:18 +00:00
Steve Lhomme 87f17b68a8 swscale/x86: use HOSTCPPFLAGS instead of CPPFLAGS for native code
Similar to 976e18fdef.
2026-08-05 11:06:22 +00:00
Niklas Haas 3df239e113 swscale/uops_macros: also generate op lists involving 3DLUTs
These may differ from the regular op lists in nontrivial ways, due to e.g.
different optimization steps being taken.

In practice, it seems this just adds the extra LUT_3D uops, but we don't
know that for sure, so better to brute force the list. That said, I do
think we can safely skip the extra backend flags in this case, at least.

Even in the worst case scenario, that would just force a fallback to the
C reference backend.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 05d8891a20 swscale/format: add SwsLut3D support to the ops list generator
The value range normalization and input range clamp will normally be
optimized away.

This commit also moves the legacy 3dlut pass to be legacy-exclusive, as the
ops code now uses the new logic. This ordering ensures that the conversion
works on every commit in isolation.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 38196645f5 swscale/graph: move 3DLUT application to the conversion pass
Instead of generating the 3DLUT and applying it right away, init_passes()
now just generates it and passes it as a parameter to add_convert_pass(),
which will forward it to the underlying implementation.

I pre-emptively moved the function to the legacy section, in anticipation
of the following commit which will make this legacy-only.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas d803957307 swscale/graph: lift SwsLut3D to SwsGraph top level
Since this depends on the overall picture parameters anyways, updating it
directly from the private setup() function was always a bit hacky. More
importantly, this needed for the ops-based 3DLUT implementation, which is
already using the pass priv pointer to store the compiled function.

Overall, simpler to just lift it to the top level and update it directly as
needed.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 4bdb4d564f swscale/uops: add SWS_UOP_LUT_3D reference implementation
The structure for the tetrahedral interpolation deviates slightly from the
naive formulation in lut3d.c; instead of branching into every separate case,
we sort the weights and offsets using a series of conditional swaps. This
actually performs identically on my end, but results in code that is much
closer to what SIMD will be doing. That should hopefully serve as a better
reference for future SIMD implementors. (Myself included)

I also reordered the dynamic tone-mapping code a bit to better indicate the
sources of live register pressure that will manifest in the real SIMD kernel.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 6c770f33c8 swscale/ops: add SWS_OP_LUT_3D and supporting code
After extensive testing, prototyping and benchmarking across a range of
systems, I determined that the optimal data layout for the SIMD 3DLUT is
essentially exactly the one we have. 16-bit integers are near optimal for
quality vs compactness, and crucially, x86 lets us load the entire packed
3DLUT entry with a single `vpgatherdq` instruction.

This dwarfs the loss from needing to cast the resulting 16-bit integers
back to f32 and renormalize.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 96e0967eca swscale/cms: fix IPT rounding error
av_round16f() was incorrectly scaling to 65534, which would correspond to
a neutral PT offset of 32767 = (1 << 15) - 1, but the code was assuming a
value of (1 << 15). To fix it, and make the PT channel correctly symmetric
around the intended neutral value, we have to map PT = +0.5 to 65536, an
unrepresentable value. This is not an issue because the PT channel values are
strictly inside some subset of [-0.5, 0.5] in practice, for real in-gamut
color values - it's already an envelope that includes quite a bit of safety
margin.

Similarly, av_round16f() is also the wrong tool for the I/RGB channels,
because it incorrectly scaled those to 65534, an off by one of the intended
unorm16 full range peak of 65535. This silently resulted in e.g. RGBA64
true white (65535) not round-tripping through the 3DLUT.

Fix both by splitting this helper into two separate helpers, each of them
fixed to the correct, intended value range.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas e43517c1d1 swscale/lut3d: simplify and hard-code 3DLUT format
The ops-based 3DLUT approach will take care of appropriately normalizing
the input to the expected domain; so the format choice no longer matters here
except for the lut3d_apply() function, which will only be used by the legacy
reference code path. So we can just continue hard-coding the format there.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 6a56bd0362 swscale/lut3d: use refstruct for 3D LUT allocations
Needed anyways for the upcoming SWS_OP_LUT_3D.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 69f0fa91d4 swscale/lut3d: pad 3DLUT to eliminate over-read
Instead of clamping in the application function. Trivial simplicity gain
for the SIMD code.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas ea8fb1b71e swscale/lut3d: alignment (cosmetic)
Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas d0bf8cff9f swscale/aarch64: reject unknown ops by default
Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 0ff884dabe swscale/csputils: remove unused struct
Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 327319bb7b swscale/ops: remove SwsLinearOp.mask
This was originally introduced to make matching linear ops against
implementations faster. However, since this is now handled on the uops
level, there is no more reason to carry this metadata on the ops level.

Simplifies a lot of places in the code. It will simplify even more, once
the linear optimizations are moved to the uops level.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 6321b53809 swscale/ops: solve for component dependencies
Needed to determine reverse dependencies of different input planes, for
appropriately splitting op lists involving subsampled planes.

Generates benign diffs that just reflect the new addition, e.g.:

 yuva444p 16x16 -> rgb24 16x16:
   [ u8 ===X] SWS_OP_READ         : 3 elem(s) planar >> 0
     min: {0 0 0 _}, max: {255 255 255 _}
+    inputs: {x y z _}, outputs: {xyz yz xy _}
   [ u8 ===X] SWS_OP_CONVERT      : u8 -> f32
     min: {0 0 0 _}, max: {255 255 255 _}
+    inputs: {x y z _}, outputs: {xyz yz xy _}
   [f32 ...X] SWS_OP_LINEAR       : matrix3+off3 [[85/73 0 1.596027 0 -222.921566] [85/73 -0.391762 -0.812968 0 135.575295] [85/73 2.017232 0 0 -276.835851] [0 0 0 1 0]]
     min: {-222.921566 -171.630839 -276.835851 _}, max: {480.983073 432.493103 534.476153 _}
+    inputs: {xz xyz xy _}, outputs: {x y z _}
   [f32 ...X] SWS_OP_DITHER       : 16x16 matrix + {0 3 2 -1}
     min: {-222.919612 -171.628886 -276.833898 _}, max: {481.981120 433.491150 535.474200 _}
+    inputs: {xz xyz xy _}, outputs: {x y z _}
   [f32 ...X] SWS_OP_MAX          : {0 0 0 _} <= x
     min: {0 0 0 _}, max: {481.981120 433.491150 535.474200 _}
+    inputs: {xz xyz xy _}, outputs: {x y z _}
   [f32 ...X] SWS_OP_MIN          : x <= {255 255 255 _}
     min: {0 0 0 _}, max: {255 255 255 _}
+    inputs: {xz xyz xy _}, outputs: {x y z _}
   [f32 +++X] SWS_OP_CONVERT      : f32 -> u8
     min: {0 0 0 _}, max: {255 255 255 _}
+    inputs: {xz xyz xy _}, outputs: {x y z _}
   [ u8 XXXX] SWS_OP_WRITE        : 3 elem(s) packed >> 0
     ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas fc94457bb7 swscale/ops: refactor comp flags propagation slightly
Introduce a unified FORWARD() helper macro that can be used for any type of
op, whether it is independent per component or more complex. By initializing
every op to the same IDENTITY state, we can leverage the monoid property to
make this work for naive propagations as well.

As an aside, we also properly zero out the unrelated fields when discarding
a component (i.e. marking it as GARBAGE).

This will make a couple of up-coming refactors a bit easier.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Niklas Haas 08c90c60f7 swscale/ops: fix merge_comp_flags() for SWS_COMP_SWAPPED
This violates the documentation (monoid property).

It's a bit arbitrary whether to consider this an OR-type or AND-type flag,
since mixing swapped and non-swapped components is almost surely a bug, but
keeping it as an OR-type makes sure such cases at least show up in the
result.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Niklas Haas <git@haasn.dev>
2026-08-03 09:32:30 +00:00
Ramiro Polla c61690153c swscale/aarch64: split ops_static.c out of ops_asmgen.c
ops_asmgen.c contains common aarch64 asm generation code that will be
used by CPS backend and the JIT backend.

The standalone tool with CPS-specific code is now ops_static.c.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla e69c1d87f2 swscale/aarch64/ops_asmgen: populate operands matrix in asmgen_setup_linear()
This will serve multiple purposes:
- Allow JIT code to populate operands from a deduplicated data pool;
- Simplify the future implementation of integer linear operation, since
  mul/mla take full vector registers as coefficients, and not elements.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla bc06af02c6 swscale/aarch64/ops_asmgen: use different value for vtmp register index
Use vtmp register index relative to the current matrix column instead
of reusing the position of the value from the packed data.

The i_coeff and derived values will be removed in the following commit.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla a1fcb227ae swscale/aarch64/ops_asmgen: reword annotations for linear operation
Refer to offset[i] or coeff[i][j] instead of position of the value from
the packed data.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla ecbb883014 swscale/aarch64/ops_asmgen: move save_mask setup out of asmgen_op_linear() and into asmgen_setup_linear()
The save_mask setup makes copies of input data that would be clobbered
by the linear operation itself. This setup is not entirely necessary
with JIT, since we may have separate input and output vector registers,
so the code is moved into the setup function which will be CPS-only.

This doubles the amount of temp registers needed, since they must all
be copied before both loops.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 132187cdbb swscale/aarch64/ops_asmgen: increase the number of temp vectors to 12
This change is done separately from the next commit (which uses the new
temp vectors in the linear op) to make it easier to track changes to
ops_neon.gen.S.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 1b66342df2 swscale/aarch64/ops_asmgen: split input/output vector banks into separate register variables
For CPS these will continue being the same vector register numbers,
because of the fixed ABI, but for JIT we will be able to use different
input/output vector registers to implicitly perform swizzles.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 940e4b29e1 swscale/aarch64/ops_asmgen: split vector init from reshaping
This changes nothing for the CPS code, but will allow the JIT compiler
to allocate and reorder vector registers without them being affected by
reshaping.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 12a0191744 swscale/aarch64/ops_asmgen: setup frame for each function
Currently this is redundant, since all CPS functions share the same
frame.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 0096b48825 swscale/aarch64/ops_asmgen: load values from exec before performing setup
This changes little for the current CPS code, which has fairly simple
setup code. But in JIT we will factor out much more code from the main
loop into the setup section.

This also frees up the register used by exec (x0) earlier on, so it may
be reused earlier in JIT code.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 25ee9a4218 swscale/aarch64/ops_asmgen: use more (but simpler) loops for exec load generation
Same behaviour, just looks neater.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 28a47aea66 swscale/aarch64/ops_asmgen: pass both input and output masks to asmgen_process()
Currently, for CPS code, both masks are the same, similar to how the C
and x86 backends do it.

But the JIT compiler will have more precise input and output masks.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 90a8749bf3 swscale/aarch64/ops_asmgen: split cps code out of asmgen_process()
The asmgen_process() function is now more generic, which will allow us
to use it from the JIT compiler.

The naming of the function, along with the setup code and main loop,
are moved to asmgen_process_cps().

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 7ee8947b2c swscale/aarch64/ops_asmgen: split asmgen_setup_*() out of asmgen_op_*()
This paves the way for performing operation setup differently for the
JIT backend, which will have constant values factored out of the loop.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla d99e656ee0 swscale/aarch64/ops_asmgen: pass SwsAArch64OpRegs as a separate argument to asmgen_op_*()
This will help the JIT compiler by letting us provide a separate set of
registers for each operation.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 98e536f4d3 swscale/aarch64/ops_asmgen: split reshape_all_vectors() into vector register classes
This reduces some unnecessary vector reshaping, and also makes the
intention clearer at the call-sites.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 97590dbd48 swscale/aarch64/ops_asmgen: split constant vector registers out of temp
This makes each vector register's purpose clearer, and will let the JIT
compiler later factor loading of constant values out of the main loop.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 154791b150 swscale/aarch64/ops_asmgen: add IMPL_PRIV helper for offset operand
This reduces the line length for instructions that access impl->priv.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla af0d56b00e swscale/aarch64/ops_asmgen: use RasmOp directly when generating masks for SWS_UOP_UNPACK
There is no need to pack the vector register usage for this function.
This change creates holes in the usage of const vector registers, but
populates the RasmOp const array directly, which will help for the
implementation of the JIT compiler.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 2a9665b7c9 swscale/aarch64/ops_asmgen: use arrangement specifiers for vector registers with known size
This way, we don't depend on the RasmOp having been correctly reshaped
prior to being used.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla d34ed6ce40 swscale/aarch64/ops_asmgen: use and/orr arrangement specifier helpers from rasm
This way, we don't depend on the RasmOp having been correctly reshaped
prior to being used.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla e418d44c1e swscale/aarch64/rasm: add extra helpers for instructions that take all 16b operands
Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Ramiro Polla 53f1b3dd09 swscale/aarch64/rasm: fill AArch64VecViews by value
Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-22 14:07:37 +00:00
Andreas Rheinhardt 68c94ed330 av{codec,filter}/x86: Remove unnecessary asm.h inclusions
asm.h is only for inline assembly.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2026-07-22 14:52:57 +02:00
Andreas Rheinhardt f8c4828c0f avutil/x86/asm: Remove HAVE_[67]REGS, use HAVE_X86_[67]REGS directly
This allows to remove the asm.h inclusion from x86/mathops.h
and therefore from hundreds of files which don't need it.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2026-07-22 14:52:57 +02:00
Ramiro Polla 82c1a01142 swscale/tests/sws_ops_aarch64: pretty-print entries in ops_entries.c
This makes them all neatly aligned.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-19 15:07:03 +02:00
Ramiro Polla 19cc66f02f swscale/aarch64/ops: use SwsUOpParams for SwsAArch64OpImplParams's parameter fields
This is one more step to eventually replace the parameter fields in
SwsAArch64OpImplParams by generic structs from libswscale/uops.h.

The function names and ordering in ops_entries.c is maintained to
simplify the gradual move to uops.h.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-19 15:07:03 +02:00
Ramiro Polla 0536c93b32 swscale/aarch64/ops: use SwsCompMask for SwsAArch64OpImplParams.mask
This is one more step to eventually replace the parameter fields in
SwsAArch64OpImplParams by generic structs from libswscale/uops.h.

The function names and ordering in ops_entries.c is maintained to
simplify the gradual move to uops.h.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-19 15:07:03 +02:00
Ramiro Polla 353b8297a5 swscale/aarch64/ops: use SwsDitherUOp for SwsAArch64OpImplParams.dither
This is one more step to eventually replace the parameter fields in
SwsAArch64OpImplParams by generic structs from libswscale/uops.h.

The function names and ordering in ops_entries.c is maintained to
simplify the gradual move to uops.h.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-19 15:07:03 +02:00
Ramiro Polla 4a33d2ce2c swscale/aarch64/ops: use SwsLinearUOp for SwsAArch64OpImplParams.linear
This is one more step to eventually replace the parameter fields in
SwsAArch64OpImplParams by generic structs from libswscale/uops.h.

The function names and ordering in ops_entries.c is maintained to
simplify the gradual move to uops.h.

Sponsored-by: Sovereign Tech Fund
Signed-off-by: Ramiro Polla <ramiro.polla@gmail.com>
2026-07-19 15:07:03 +02:00