Skip to content

svac3: AVX2 and NEON kernels for angular intra prediction and SAO - #9

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

widgetii merged 1 commit into
masterfrom
svac3-simd2

Conversation

@widgetii

Copy link
Copy Markdown
Member

The follow-up to #8: the two kernels it left out, intra prediction and SAO. Bit-exact like the rest: every SIMD kernel gives the C reference's output bits.

Angular intra prediction

  • In the modes that read a single reference line (xySign < 0), every sample of a row (xyAxis 0), or of a column (xyAxis 1), has the same fractional position and the same integer shift.
  • So the row is a 4-tap filter along that line: the new ipred_row kernel, with 32-bit sums. Columns are computed as rows and transposed.
  • The reference lines are now int16_t and padded with their last sample, so the kernel never clamps. The padding is exactly what rr() / cc() return past 2M / 2N. It reaches as far as the steepest mode goes from a 64-sample block: 176 samples past it, checked against svac3_dir_tab.
  • Modes whose rows switch between the top and left lines (xySign > 0) stay per sample.

SAO

  • Works on whole regions instead of per sample with bounds checks.
  • Band offset is a 32-entry lookup: two pshufb halves on AVX2, tbl with two registers on NEON.
  • Edge offset finds the class as sign(c − a) + sign(c − b) and looks it up in a 5-entry table, the same four cases as before.
  • Edge offset runs over the region whose two neighbours are inside the picture. The samples outside it were already left unchanged, and still are.

Checks

  • test_dsp (6 kernel groups now) covers:
    • every MIPF filter table and fractional offset, widths that fall back to C, and extreme samples;
    • every edge direction and random band tables, on smooth and on noisy content.
  • On the lab machines:
    • Core i9-13900 (AVX2) and Cortex-X925 (NEON) each agree with C on 200,000 iterations of every group;
    • ctest is 25/25 bit-exact on both;
    • NEON is clean under ASan+UBSan.

Speed: one core, best of 5, master (with #8) against this branch:

stream i9-13900 Cortex-X925
1080p CBR 1.11 → 0.84 s (1.32×) 0.47 → 0.44 s (1.07×)
1080p fixed QP 22 (intra-heavy) 0.30 → 0.16 s (1.88×) 0.16 → 0.09 s (1.78×)
1080p SmartP 1.12× 1.09×
1080p, 9 patches 1.07× 1.13×

The x86 host is shared and was loaded, so its numbers are the noisier ones. After this, the high-bitrate stream is bound by the entropy decoder (parse_srcc_block, decide), which is serial.

Angular intra modes that read one reference line (xySign < 0, 5.4.8.1.4.2)
now predict a row (or a column, for xyAxis 1) at a time: every sample of it
has the same fractional position, so the row is a 4-tap filter along the
line, ipred_row. The reference lines are padded with their last sample out
to what the steepest mode reaches, which is what rr() and cc() clamp to.
Modes that switch between the two lines within a row stay per sample.

SAO now works on whole regions: band offset with a 32-entry table, edge
offset with the class sign(c - a) + sign(c - b) looked up in a 5-entry one,
over the region whose neighbours lie in the picture (the samples outside it
are left as they are, as before). AVX2 uses pshufb for the tables, NEON
tbl.

test_dsp covers both: every MIPF filter and offset, widths that fall back
to C, extreme samples; every edge direction and band table, on smooth and
noisy content.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add AVX2 and NEON kernels for angular prediction and SAO

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add bit-exact AVX2 and NEON kernels for angular intra prediction and SAO.
• Dispatch row and region operations to SIMD, retaining C fallbacks and picture-edge behavior.
• Extend DSP equivalence tests and document the resulting performance gains.
Diagram

graph TD
  Recon["Angular prediction"] --> DSP["DSP dispatch"] --> AVX2["AVX2 kernels"]
  SAO["SAO regions"] --> DSP --> NEON["NEON kernels"]
  DSP --> C["C kernels"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Predict columns directly without transposing
  • ➕ Avoids the temporary prediction block and transpose pass.
  • ➖ Strided reference reads or scatter writes complicate SIMD and may cost more than the transpose.

Recommendation: Keep row-oriented prediction with a transpose for columns: it shares one contiguous four-tap kernel across both axes and keeps the SIMD implementations straightforward. Consider direct column kernels only if profiling shows the transpose is a significant cost.

Files changed (8) +358 / -28

Enhancement (6) +300 / -25
svac3_dsp_neon.cAdd NEON prediction-row and SAO kernels +86/-0

Add NEON prediction-row and SAO kernels

• Implements four-tap prediction with 32-bit accumulators and vectorized SAO band and edge lookups. Uses C kernels for unsupported row widths and region tails, then registers the new NEON functions.

source/svac3/arm/svac3_dsp_neon.c

svac3_dsp.cProvide C reference kernels for prediction and SAO +33/-0

Provide C reference kernels for prediction and SAO

• Adds scalar four-tap prediction, edge-class lookup, and band-offset region kernels. Registers them as the C DSP implementations and SIMD fallbacks.

source/svac3/svac3_dsp.c

svac3_dsp.hExtend the DSP interface with prediction and SAO operations +14/-0

Extend the DSP interface with prediction and SAO operations

• Defines function pointers for prediction rows and SAO edge and band regions. Documents their sample, lookup-table, and neighbor-offset contracts.

source/svac3/svac3_dsp.h

svac3_loopfilter.cProcess SAO through picture-bounded DSP regions +17/-23

Process SAO through picture-bounded DSP regions

• Replaces per-sample SAO loops with DSP region calls. Builds compact band and edge tables and restricts edge processing to samples whose neighbors are inside the picture, leaving excluded samples unchanged.

source/svac3/svac3_loopfilter.c

svac3_recon.cRoute single-reference angular modes through row prediction +39/-2

Route single-reference angular modes through row prediction

• Stores reference samples as padded 16-bit lines so row kernels can read past the original line end without per-tap clamps. Predicts eligible modes by row, or predicts columns as rows and transposes them; modes that switch reference lines retain their per-sample path.

source/svac3/svac3_recon.c

svac3_dsp_avx2.cAdd AVX2 prediction-row and SAO kernels +111/-0

Add AVX2 prediction-row and SAO kernels

• Implements 32-bit four-tap prediction and vectorized SAO edge-class and band-table lookups. Falls back to C for unsupported widths and region tails, then registers the AVX2 functions.

source/svac3/x86/svac3_dsp_avx2.c

Tests (1) +55 / -1
test_dsp.cCompare prediction and SAO kernels against C +55/-1

Compare prediction and SAO kernels against C

• Adds randomized equivalence checks for prediction filters, offsets, widths, and extreme samples, plus SAO edge directions and band tables on smooth and noisy inputs. Expands the DSP test run from four to six kernel groups.

tests/test_dsp.c

Documentation (1) +3 / -2
README.mdDocument new SIMD coverage and throughput +3/-2

Document new SIMD coverage and throughput

• Adds angular intra prediction and SAO to the documented SIMD kernels. Revises single-core throughput figures and notes the serial entropy-decoder bottleneck at high bit rates.

README.md

@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 3e7945a into master Oct 29, 2026
5 checks passed
@widgetii
widgetii deleted the svac3-simd2 branch October 29, 2026 06:00
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