Skip to content

svac3: AVX2 and NEON kernels for the transform, motion compensation and deblocking - #8

Merged
widgetii merged 1 commit into
masterfrom
svac3-simd
Oct 29, 2026
Merged

widgetii merged 1 commit into
masterfrom
svac3-simd

Conversation

@widgetii

Copy link
Copy Markdown
Member

First SIMD pass: the hot sample-processing kernels gain AVX2 (x86-64) and NEON (AArch64) versions behind a dispatch table. Bit-exact by construction and by test: every SIMD kernel gives the C reference's output bits.

Structure

  • svac3_dsp.h: a kernel table, svac3_dsp() picks the set:
    • svac3_dsp_c, the reference; the previous code moved here unchanged in arithmetic;
    • x86/svac3_dsp_avx2.c, built with -mavx2 and used when __builtin_cpu_supports("avx2");
    • arm/svac3_dsp_neon.c, always used on AArch64.
  • -DSVAC3D_SIMD=OFF builds the C set only. MSVC builds never get the AVX2 set, which needs GCC/Clang.

Kernels

Kernel What it covers
matmul the inverse DCT2's two passes as 16-bit matrix products with exact 32-bit sums: AVX2 madd on row pairs, NEON vmlal. Its callers keep the zero-row/column bounds
add_block prediction plus residual, clipped, for blocks inside the picture
mc_h, mc_v, mc_hv 8-tap luma and 4-tap chroma interpolation where every reference sample is inside the plane: 16-bit horizontal sums, 32-bit vertical in 2-D. Blocks near the picture edge keep the clamping C path
deblock 8 lines across one edge in 8 lanes: Bs decisions as lane masks, every filter computed and selected per lane, vertical edges through an 8x8 byte transpose. Filter type 1 stays in C

Widths that are not a multiple of 8 go to C.

Deblocking driver: the edge test, the inter Bs-0 rule, the QP average and α/β are now computed once per 4×4 unit pair (4 luma or 2 chroma lines) instead of per line. That alone speeds up the C path. Edges 8 samples apart touch disjoint samples, so batching them changes nothing.

Checks

  • test_dsp (new, in ctest) runs every SIMD kernel against C on random inputs. It covers:
    • matmul: every transform size, random depths, both operand ranges;
    • interpolation: all three shapes, both tap sets, extreme samples, and widths that fall back to C;
    • deblocking: smooth and stepped edges so every Bs branch fires, both orientations, luma and chroma, disabled groups, filter type 1, short runs.
  • Lab machines:
    • Core i9-13900 (AVX2) and Cortex-X925 (NEON) each agree with C on 200,000 iterations of every kernel group;
    • all 25 ctest tests are bit-exact on both;
    • both are clean under ASan+UBSan.

Speed: one core, best of 5, master against this branch:

stream i9-13900 Cortex-X925
1080p CBR, 90 pictures 1.33 → 0.92 s (1.45×) 0.96 → 0.47 s (2.04×)
1080p fixed QP 22 (entropy-bound) 1.32× 1.44×
1080p SmartP 1.77× 2.04×
1080p, 9 patches 1.69× 1.94×

The x86 host was loaded during the runs (load average around 30), so its numbers are the noisier ones.

Left for a next pass:

  • intra prediction, now the largest kernel left;
  • SAO;
  • the entropy decoder, which bounds the high-bitrate stream and is serial by nature.

…nd deblocking

The sample-processing kernels move behind a table, svac3_dsp: a C
reference, an AVX2 set chosen at run time on x86-64 CPUs that have it, and
a NEON set on AArch64. -DSVAC3D_SIMD=OFF builds the C set only.

- matmul: the inverse DCT2's two passes as 16-bit matrix products with
  32-bit sums (madd on AVX2, vmlal on NEON)
- add_block: prediction plus residual, for blocks inside the picture
- mc_h / mc_v / mc_hv: 8-tap luma and 4-tap chroma interpolation where
  every reference sample lies inside the plane (16-bit horizontal sums,
  32-bit vertical); edge blocks keep the clamping C path
- deblock: 8 lines across one edge in 8 lanes, the Bs decision as lane
  masks and the filters selected per lane, vertical edges through an 8x8
  byte transpose; filter type 1 stays in C

The deblocking driver now works per 4x4 unit pair: the edge test, the
inter Bs-0 rule, the QPs and alpha/beta are found once per 4 luma (2
chroma) lines rather than per line, which also speeds up the C path.

test_dsp compares every SIMD kernel with C on random inputs (all three
interpolation shapes, both tap sets, widths that fall back to C, every Bs
branch, both edge orientations); the corpus stays bit-exact.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add AVX2 and NEON kernels to SVAC3 decoding

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add CPU-selected AVX2 and NEON kernels for transform, motion compensation, residual addition, and
 deblocking.
• Retain C fallbacks for unsupported CPUs, picture edges, and unsupported kernel cases.
• Batch deblocking parameters per unit pair and test SIMD outputs against the C reference.
Diagram

graph TD
  Recon["Reconstruction"] --> DSP{"CPU dispatch"} --> C["C reference"]
  Inter["Motion compensation"] --> DSP
  Deblock["Deblocking driver"] --> DSP
  DSP --> AVX2["AVX2 kernels"]
  DSP --> NEON["NEON kernels"]
Loading
High-Level Assessment

The shared table with a portable C reference is appropriate for this first SIMD pass: it keeps architecture selection separate from decoder logic and gives unsupported cases a direct fallback. Per-kernel dispatch was considered, but adds selection complexity without a current need for independently selected ISA tiers.

Files changed (12) +1278 / -158

Enhancement (7) +1078 / -156
svac3_dsp_neon.cImplement AArch64 NEON sample kernels +265/-0

Implement AArch64 NEON sample kernels

• Adds NEON matrix multiplication, residual addition, interpolation, and eight-line deblocking. Unsupported widths, short runs, and filter type 1 use the C reference.

source/svac3/arm/svac3_dsp_neon.c

svac3_dsp.cProvide portable kernels and CPU selection +207/-0

Provide portable kernels and CPU selection

• Introduces the C implementations of the dispatched kernels and selects AVX2 at runtime, NEON on AArch64, or C otherwise.

source/svac3/svac3_dsp.c

svac3_dsp.hDefine the SVAC3 kernel table +59/-0

Define the SVAC3 kernel table

• Declares kernel signatures and their input contracts, plus accessors for the selected, C-reference, and available SIMD tables.

source/svac3/svac3_dsp.h

svac3_inter.cRoute in-bounds interpolation through DSP +32/-2

Route in-bounds interpolation through DSP

• Uses dispatched interpolation for reference blocks whose taps remain inside the plane, and copies integer-position blocks directly. Retains the clamping path near picture boundaries.

source/svac3/svac3_inter.c

svac3_loopfilter.cBatch deblocking edges and parameters +51/-136

Batch deblocking edges and parameters

• Moves per-line filter work to the DSP table and computes edge eligibility, QP averages, and thresholds once per 4×4 unit pair. Submits runs of up to eight luma or chroma lines to the selected kernel.

source/svac3/svac3_loopfilter.c

svac3_recon.cDispatch inverse transforms and block addition +38/-18

Dispatch inverse transforms and block addition

• Expresses the inverse transform as two dispatched matrix products and fast-paths all-zero coefficients. Routes in-picture residual addition through DSP while preserving partial-picture handling.

source/svac3/svac3_recon.c

svac3_dsp_avx2.cImplement x86-64 AVX2 sample kernels +426/-0

Implement x86-64 AVX2 sample kernels

• Adds AVX2 implementations for the transform, residual addition, interpolation, and eight-line deblocking. Uses the C reference for unsupported widths, short deblocking runs, and filter type 1.

source/svac3/x86/svac3_dsp_avx2.c

Tests (2) +173 / -0
CMakeLists.txtRegister the DSP comparison test +4/-0

Register the DSP comparison test

• Builds test_dsp against svac3d and registers it with CTest.

CMakeLists.txt

test_dsp.cCompare SIMD kernels against C +169/-0

Compare SIMD kernels against C

• Adds randomized output comparisons across transform dimensions, residual addition, interpolation taps and shapes, and deblocking orientations and modes. Exits successfully without comparisons when no SIMD implementation is available.

tests/test_dsp.c

Documentation (1) +10 / -0
README.mdDocument SIMD selection and performance +10/-0

Document SIMD selection and performance

• Describes AVX2 and NEON availability, the C-only build option, bit-exactness checks, and representative decode rates.

README.md

Other (2) +17 / -2
ci.ymlLink DSP kernels into the patch fuzzer +1/-1

Link DSP kernels into the patch fuzzer

• Adds the new DSP source to the CI patch-fuzzer build so its decoder dependencies continue to link.

.github/workflows/ci.yml

CMakeLists.txtMake SVAC3 SIMD builds architecture-aware +16/-1

Make SVAC3 SIMD builds architecture-aware

• Adds the SVAC3D_SIMD option and conditionally includes the AVX2 or NEON source. Applies -mavx2 only to its source file and excludes that implementation on MSVC.

source/CMakeLists.txt

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@widgetii
widgetii merged commit 97dd28a into master Oct 29, 2026
5 checks passed
@widgetii
widgetii deleted the svac3-simd branch October 29, 2026 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant