h264: qpel single-axis quarter-pel — mc10/mc30/mc01/mc03 (CPU/NEON) #17
Reference in New Issue
Block a user
Delete Branch "noether/h264-qpel-quarter-axis"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes 4 single-axis quarter-pel positions in one PR. Each is a half-pel lowpass clipped to u8 then L2 rounded-averaged with an integer-aligned source pixel per H.264 §8.4.2.2.1. mc10/mc30 differ only in which integer column they avg with; mc01/mc03 same for rows. Putting them together is justified by that uniformity.
Macros (
DEFINE_QPEL_CPU_DISPATCH,DEFINE_QPEL_DISPATCH,DEFINE_QPEL_RECIPE) collapse ~150 LOC of repetition. Generic test harness viarun_quarter_axis_qpel()collapses 4 hand-rolled tests into one.All 4 positions PASS 2048/2048 bytes bit-exact first try.
Kernel enums MC10=19, MC30=20, MC01=21, MC03=22 → CPU. After this PR: 7 of 16 qpel positions covered. Remaining 9 are the off-axis combinations (mc11/12/13/21/23/31/32/33 — each combines 2D lowpass intermediate with L2 against a 1D output).
Closes the 4 single-axis quarter-pel positions in one PR. Each is a half-pel lowpass clipped to u8 followed by L2 rounded-average with an integer-aligned source pixel per H.264 §8.4.2.2.1: mc10 ¼-H ("a" pos): clip255(mc20(s)) avg src[r,c] mc30 ¾-H ("c" pos): clip255(mc20(s)) avg src[r,c+1] mc01 ¼-V ("d" pos): clip255(mc02(s)) avg src[r,c] mc03 ¾-V ("n" pos): clip255(mc02(s)) avg src[r+1,c] The mc10/mc30 pair and mc01/mc03 pair only differ in WHICH integer source pixel they average with — the half-pel computation is the same. Putting them in one PR is justified by that uniformity. Scope: - 4 new kernel enums: MC10=19, MC30=20, MC01=21, MC03=22 → CPU. - 4 NEON externs for the vendored ff_put_h264_qpel8_mc{10,30,01,03}_neon. - 4 CPU dispatch wrappers via DEFINE_QPEL_CPU_DISPATCH macro (collapses ~50 LOC of repetition). - 4 public dispatch fns via DEFINE_QPEL_DISPATCH macro. - 4 recipe wrappers via DEFINE_QPEL_RECIPE macro. - tests/h264_qpel8_quarter_axis_ref.c covers all four via shared hpel_h() / hpel_v() inlines + per-mode L2 average. - Test refactor: generic run_quarter_axis_qpel() harness exercises all 4 positions through a single helper (~50 LOC for 4 tests vs ~200 if each was hand-rolled). Verified on hertz: $ ./build/test_api_h264 | tail -8 H.264 deblock chroma h intra: 256/256 bytes bit-exact (100.0000%) H.264 qpel mc20: 1024/1024 bytes bit-exact (100.0000%) H.264 qpel mc02: 2048/2048 bytes bit-exact (100.0000%) H.264 qpel mc22: 2048/2048 bytes bit-exact (100.0000%) H.264 qpel mc10: 2048/2048 bytes bit-exact (100.0000%) H.264 qpel mc30: 2048/2048 bytes bit-exact (100.0000%) H.264 qpel mc01: 2048/2048 bytes bit-exact (100.0000%) H.264 qpel mc03: 2048/2048 bytes bit-exact (100.0000%) All 4 new positions bit-exact PASS first try. Coverage matrix update: put_ mc00 mc10 mc20 mc30 mc01 — ✓ — ✓ mc11 — — ✓ — ← this row mc21 — — — — mc31 — — — — mc02 — — ✓ — ← mc02 + mc22 anchor mc03 — — ✓ — After this PR: 7 of 16 single-axis + diagonal positions done. Remaining 9 are the off-axis quarter-pel combinations (mc11/mc12/mc13/mc21/mc23/mc31/mc32/mc33) — each combines a 2D lowpass intermediate with L2 averaging against a 1D-lowpass output. Next PR scope. Why no QPU shaders: same R-band logic as the prior CPU additions. At ~10 ns per 8x8 NEON block, all 16 qpel positions together would land in ~1.3 ms/frame at 1080p worst case — comfortably inside the 33 ms budget. QPU shader for mc20 already exists (cycle 9 / v3d_h264_qpel_mc20.spv); the other 15 follow once a clear perf reason emerges.