perf: NEON emitFlat encoder + int32 reversible IDWT pipeline#401
Merged
Conversation
Port the AVX2 deferred-drain pattern to the ARM NEON cleanup encoder. Instead of calling emitBits() per quad (which forces an overflow check on every 4-lane emit), accumulate (v_corr, m) pairs into flat arrays and drain once per line-pair through emitFlat(). The 4-wide prefix-sum fast path inside emitFlat batches four consecutive values into Creg when their total bit-width fits in 64 bits, avoiding per-value overflow checks. Lossless 8K 12-bit single-thread encode: 0.67 s → 0.51 s (≈24%). Codestreams are bitwise identical to baseline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
77a46d0 to
0a9d285
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves HTJ2K performance on ARM by deferring MagSgn emission in the NEON cleanup encoder, and fixes lossless reversible (5/3) round-trip correctness by adding an int32-based IDWT decode pipeline that mirrors the int32 FDWT encoder path.
Changes:
- Add a NEON
emitFlat()MagSgn drain path and update the NEON cleanup encoder to batch (v_corr, m) emission per line-pair. - Introduce int32 reversible 5/3 IDWT primitives (scalar/NEON/AVX2/AVX-512/WASM) and a
use_i32streaming-IDWT mode for lossless decode. - Thread a
dequant_i32flag through codeblock/subband decode and update dequantize/finalize/MCT glue to consume int32 samples where applicable.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| source/core/transform/idwt.cpp | Wires use_i32 into streaming IDWT steps and adds an int32 horizontal row-inplace path. |
| source/core/transform/idwt_wasm.cpp | Adds WASM SIMD int32 rev53 filter + vertical lifting steps. |
| source/core/transform/idwt_neon.cpp | Adds NEON int32 rev53 filter + vertical lifting steps. |
| source/core/transform/idwt_avx512.cpp | Adds AVX-512 int32 rev53 filter + vertical lifting steps. |
| source/core/transform/idwt_avx2.cpp | Adds AVX2 int32 rev53 filter + vertical lifting steps. |
| source/core/transform/dwt.hpp | Declares new int32 IDWT entrypoints and adds idwt_2d_state::use_i32 + init param. |
| source/core/coding/subband_row_buf.hpp | Adds dequant_i32 flag to subband row buffer state. |
| source/core/coding/subband_row_buf.cpp | Propagates dequant_i32 into decode tasks/codeblocks. |
| source/core/coding/ht_block_encoding_neon.hpp | Adds state_MS_enc::emitFlat() for deferred MagSgn draining. |
| source/core/coding/ht_block_encoding_neon.cpp | Switches NEON cleanup encode MagSgn emission to batched emitFlat(). |
| source/core/coding/ht_block_decoding.cpp | Adds templated fused dequant store-to-int32 option and dequant_i32 plumbing. |
| source/core/coding/ht_block_decoding_wasm.cpp | Adds templated fused dequant store-to-int32 option and dequant_i32 plumbing (WASM). |
| source/core/coding/ht_block_decoding_neon.cpp | Adds templated fused dequant store-to-int32 option and dequant_i32 plumbing (NEON). |
| source/core/coding/ht_block_decoding_avx2.cpp | Adds templated fused dequant store-to-int32 option and dequant_i32 plumbing (AVX2). |
| source/core/coding/coding_units.hpp | Adds dequant_i32 to j2k_codeblock. |
| source/core/coding/coding_units.cpp | Enables i32 pipeline for reversible line decode; adds int32→float conversions for finalize/MCT paths. |
| source/core/coding/block_dequant.hpp | Extends j2k_dequant() API with dequant_i32 flag. |
| source/core/coding/block_dequant.cpp | Adds scalar reversible dequant that can store int32 into band buffer. |
| source/core/coding/block_dequant_neon.cpp | Adds NEON reversible dequant that can store int32 into band buffer. |
| source/core/coding/block_dequant_avx512.cpp | Adds AVX-512 reversible dequant that can store int32 into band buffer. |
| source/core/coding/block_dequant_avx2.cpp | Adds AVX2 reversible dequant that can store int32 into band buffer. |
| source/core/coding/block_decoding.cpp | Passes block->dequant_i32 into j2k_dequant(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0a9d285 to
583c1c6
Compare
583c1c6 to
07301a3
Compare
07301a3 to
ff9ca52
Compare
ff9ca52 to
950b6b2
Compare
Add an int32 IDWT pipeline for lossless 5/3 decode that matches the
int32 FDWT encoder. The float IDWT cannot correctly invert the int32
FDWT due to integer-vs-floor(float) rounding divergence in compound
lifting expressions, breaking the lossless encode-decode round-trip.
Primitives (all backends: NEON, AVX2, AVX-512, WASM SIMD, scalar):
- idwt_1d_filtr_rev53_i32: horizontal 1D int32 IDWT
- idwt_rev_ver_{lp,hp}_step_i32: vertical lifting steps
- idwt_1d_row_inplace_i32: in-place horizontal IDWT for ring buffer
Pipeline wiring:
- dequant_i32 flag on j2k_codeblock and j2k_subband_row_buf propagates
to both the standalone dequantize() and the fused dequant inside
ht_cleanup_decode, storing raw int32 instead of float in band_buf
- Fused dequant uses template<bool StoreI32> (if constexpr) across all
backends — zero inner-loop branching
- Finalize step reads int32 directly from ring buffer instead of
converting in-place (which would corrupt the ring buffer for the
IDWT's vertical lifting neighbors)
- MCT path uses scratch buffers for the int32-to-float conversion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
950b6b2 to
0b398db
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
emitBits()per quad. 25% single-threaded lossless encode speedup on 4K 12-bit (183 ms → 138 ms).ht_cleanup_decodeand standalonedequantize()use atemplate<bool StoreI32>approach (if constexpr) for zero inner-loop branching. The finalize step reads int32 directly from the ring buffer to avoid in-place corruption of the IDWT vertical lifting neighbors.Benchmarks (4K ElephantDream 4096x2160, Zen 5)
Test plan