fix(sycl): correct libvmaf_sycl zero-copy VMAF on QSV-decoded 10-bit input - #1081
Open
Tualua wants to merge 2 commits into
Open
fix(sycl): correct libvmaf_sycl zero-copy VMAF on QSV-decoded 10-bit input#1081Tualua wants to merge 2 commits into
Tualua wants to merge 2 commits into
Conversation
Document the fix for the libvmaf_sycl zero-copy NaN bug on QSV-decoded 10-bit pairs. Two root causes: a shared QSV/VA surface pool (cross-decoder contamination) and a P010/P012 MSB/LSB pixel-range mismatch. Lands ahead of the implementing commit per CLAUDE.md rule 8. - ADR-1121 via _index_fragments + _order.txt (README regenerated by concat-adr-index.sh) - research digest: two-bug investigation - docs/backends/sycl/overview.md: separate-session decode contract, P010 normalization, VMAF_SYCL_IMPORT_DEBUG env knob - core/src/sycl/AGENTS.md: normalize-on-all-import-paths invariant - changelog.d/fixed fragment; docs/rebase-notes.md entry - docs/state.md: close T-SYCL-ZEROCOPY-P010-NAN-2026-06-30 Refs ADR-1121. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YCP4JCoduujJgccDRGvNKv
…input libvmaf_sycl returned VMAF=nan with ~130x integer_motion on QSV-decoded 10-bit pairs. Root cause (ADR-1121) was two independent bugs, neither in the orchestration loop: - P010/P012 MSB/LSB mismatch (the NaN + 64x motion). VA-API delivers 10/12-bit luma MSB-aligned (V_MSB = V_LSB << (16-bpc)); the CPU path gets >>6 via FFmpeg's P010LE->YUV420P10LE, the SYCL import did not. Apply the >>(16-bpc) shift in the import: fused into the Tile4 / Y-tiled de-tile store (each sample shifted as written -- no extra kernel, no second full-plane pass; the QSV/DG2 hot path), with a standalone launch_p010_normalize() kernel only on the rare LINEAR D2D / readback fallbacks (no per-sample store to fuse into). No-op for 8-bit NV12. - Shared QSV/VA surface pool (the cross-frame contamination). Fixed by the separate-per-decoder-QSV-session invocation contract (documented in docs/backends/sycl/overview.md); libvmaf cannot observe FFmpeg session topology from inside the filter, so it is not enforced in code. No DMA-BUF coherency sync: a DMA_BUF_IOCTL_SYNC(READ) flush was tried and removed -- proven insufficient for the contamination, and its SYNC_START is a blocking decoder-fence wait that serialised decode->compute and cut 4K throughput with zero correctness benefit. Defaults the zero-copy path to direct SYCL dispatch instead of the combined graph. The graph (ADR-0483) is a net throughput loss on the VA-import path -- byte-identical output, but the per-frame de-tile import plus the graph compute-barrier serialise decode->compute, ~15-25% slower at 4K. vmaf_sycl_select_strategy() gains a va_import_path flag (passed state->has_imported), returning DIRECT after the env-override checks so an explicit VMAF_SYCL_USE_GRAPH=1 / VMAF_SYCL_DISPATCH=...:graph still wins. Users no longer need the deprecated VMAF_SYCL_NO_GRAPH=1. This change carries the supporting SYCL plumbing: the double-buffer slot toggle + upload-slot getters, and the env-gated VMAF_SYCL_CHECKSUM D2H probe + VMAF_SYCL_IMPORT_DEBUG logging used to diagnose the bug (kept as permanent diagnostics; resolved once at init via the vmaf_sycl_import_debug_enabled() accessor). Pre-existing clang-tidy debt in the touched dmabuf_import.cpp is cleaned (const-correctness on two Level Zero queue pointers + ze_result_t) per ADR-0141. Verified on Intel Arc A380 (Shadow's Edge 4K HEVC->AV1): 0 NaN, SYCL VMAF 97.2350 vs CPU oracle 97.2337 over 500 frames, integer_motion2 max 26.69, and byte-identical across repeated runs (deterministic). Netflix golden assertions untouched. Refs ADR-1121. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YCP4JCoduujJgccDRGvNKv
11 tasks
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
Fixes the
libvmaf_syclFFmpeg zero-copy filter returningVMAF score: nan(withinteger_motion~130× too high) on QSV-decoded 10-bit pairs on Intel Arc. A fresh investigation found two independent root causes — neither in the orchestration loop blamed by the prior FIX-01 attempt (which was verified incomplete): a shared QSV/VA surface pool (cross-decoder contamination) and raw P010 MSB-aligned pixels imported without the LSB normalization the CPU path gets for free. See ADR-1121.Type
fix— bug fixsycl/cuda/simd— backend-specificRoot cause & fix
-hwaccel_device, FFmpeg gives both decoders onemfxSession/VA surface pool; their distinctmfxFrameSurface1wrappers map to the sameVASurfaceIDs, so HEVCref[N±1]overwrites the surface AV1 wrotedis[N]into (sycl_dis[N]==sycl_ref[N±1]). Fix (FIX-03): require a separate-init_hw_device qsv=…per decoder — a documented usage contract (libvmaf can't see FFmpeg session topology from inside the filter).V_MSB = V_LSB << (16−bpc)); the CPU path gets>>6via FFmpeg'sP010LE→YUV420P10LE, the SYCL import did not. Fix (FIX-04): apply the>>(16−bpc)shift in the import — fused into the Tile4/Y-tiled de-tile store on the QSV/DG2 hot path (each sample shifted as written; no extra kernel, no second pass) and a standalonelaunch_p010_normalize()kernel only on the rare LINEAR/readback fallbacks (no-op for 8-bit).DMA_BUF_IOCTL_SYNC(READ)flush was tried and removed — proven insufficient for the contamination, and itsSYNC_STARTis a blocking decoder-fence wait that serialised decode→compute and cut 4K throughput with zero correctness benefit. (vaSyncSurface()+ the in-order queue already order decode→de-tile.)Checklist
make format && make lintgreen locally (clang-tidy on touched SYCL TUs in-container)..c/.cpp/.h— none added; existing fork files edited (headers intact).docs/adr/_index_fragments/1121-*.md+ appended to_order.txt(README regenerated viaconcat-adr-index.sh).Bug-status hygiene (ADR-0165)
docs/state.mdupdated —T-SYCL-ZEROCOPY-P010-NAN-2026-06-30added to Recently closed.Netflix golden-data gate
assertAlmostEqual(...). The bug is in the fork-added SYCL VA-import path; the CPU metric engine and golden pairs are untouched. (The fork D-03 oracle baseline was rebased to the de-contaminated value 97.2350 in.planningverification artifacts only — not Netflix golden data.)Cross-backend numerical results
Performance: the zero-copy path now defaults to direct SYCL dispatch — the
combined graph (ADR-0483) is a net throughput loss on VA-import (byte-identical
output, but the per-frame de-tile import + graph compute-barrier serialise
decode→compute, ~15–25% slower at 4K; ~33→42 fps on Arc A380).
select_strategygains a
va_import_pathflag (after the env checks, soVMAF_SYCL_USE_GRAPH=1still forces graph); users no longer need the deprecated
VMAF_SYCL_NO_GRAPH=1.Secondary: the MSB→LSB shift is fused into the de-tile kernel (no extra GPU pass)
and the
DMA_BUF_IOCTL_SYNCblocking flush was removed. Default-dispatch outputis byte-identical to graph mode (sha256 match) — zero numeric change.
Deep-dive deliverables (ADR-0108)
docs/research/2026-06-30-sycl-qsv-zerocopy-two-bug-investigation.md.## Alternatives considered(normalize-in-import vs in-kernel vs force-readback vs auto-detect-session vs ioctl-as-fix).AGENTS.mdinvariant note —core/src/sycl/AGENTS.md: normalize on all import paths; FIX-02 is hardening not the fix; D-03 de-contaminated targets.changelog.d/fixed/1121-sycl-qsv-zerocopy-p010-normalization.md.docs/rebase-notes.md→fix/sycl-qsv-zerocopy-p010-normalize(no ffmpeg-patch impact; invariants listed).Reproducer
Known follow-ups
mfxSessiontopology). Thelibvmaf_syclfilter could log a one-time hint if it detects a shared VA pool — deferred.meson_options.txt/LIBVMAFContextdelta); the separate-session pattern is an ffmpeg invocation, not avf_libvmaf.cchange.🤖 Generated with Claude Code
https://claude.ai/code/session_01YCP4JCoduujJgccDRGvNKv