Repository navigation
fix(sycl): correct libvmaf_sycl zero-copy VMAF on QSV-decoded 10-bit input - #1081
Merged
lusoris merged 3 commits intoAug 30, 2026
Merged
Conversation
11 tasks done
Merged
3 of 6 tasks
lusoris
added a commit
that referenced
this pull request
Aug 30, 2026
…cker digest batching (#1127) No PR merged on this repository between 2026-06-29 and 2026-08-30. master was green on all 26 required checks the whole time; the blocker was a self-reinforcing loop in the merge gate. Required Checks Aggregator polls until every sibling workflow on the SHA reaches a terminal state, and treats a sibling still queued/in_progress at the deadline as a failure. The deadline was 90 minutes — itself a remediation after a 30-minute deadline "failed every PR" on 2026-05-09. A two-month Renovate backlog then opened ~44 concurrent dependency PRs, the queue again outran the deadline, and aggregators expired with no failing check (job 89636653774 ran 90m14s and died on "Build — Ubuntu gcc (CPU) + DNN: in_progress; CodeQL: queued; ShellCheck + shfmt: queued"). Because the aggregator is required, the expiry blocks the merge, which keeps the queue deep, which causes the next expiry. Two coordinated changes, one per half of the loop: - Deadline 90 -> 240 minutes, timeout-minutes 100 -> 250. The job only polls the checks API, so a longer ceiling costs a runner slot rather than compute; the hosted-runner hard cap is 360 minutes. - Batch Docker digest/pin refreshes into one Renovate PR. This was the only dependency class without a grouping rule, so ~11 base images each opened a separate PR and a separate full CI matrix run. ADR-1123. Note the allocator returned 1121, which collides with contributor PR #1081 — scripts/adr/next-free.sh queries origin only and cannot see ADR files on contributor forks. 1121 was released and 1123 claimed by hand. Co-authored-by: Lusoris <lusoris@pm.me> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
lusoris
pushed a commit
to Tualua/vmafx
that referenced
this pull request
Aug 30, 2026
Netflix shipped VMAF v1 in libvmaf v3.2.0 (June 2026): still a libsvm nu-SVR fusion, but VIF is removed and CAMBI (banding) + speed_chroma (chroma) become core features; ADM/motion move to adm3/motion3. Six built-in models for 1080p@3H / phone@5H / 4K@1.5H / 4K@3H (last on a [0,110] range) + HFR variants; Netflix recommends 10-bit measurement even for 8-bit SDR. Adds a cited research digest and ADR-1122 deciding to adopt v1 as an opt-in generation (v0.6.1 stays default), with the port scope: build in the JSONs, fix SYCL cambi/speed_chroma (now core, currently failing on Arc A380), handle the [0,110] range end-to-end, plumb CAMBI enc params, and add new v1 golden refs in separate tests (v0.6.1 golden pairs untouched). Aligns with the zero-copy 10-bit work (ADR-1121, PR VMAFx#1081). Refs ADR-1122. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YCP4JCoduujJgccDRGvNKv
lusoris
added a commit
that referenced
this pull request
Aug 30, 2026
* docs(vmaf): research digest + ADR-1122 for VMAF v1 model port Netflix shipped VMAF v1 in libvmaf v3.2.0 (June 2026): still a libsvm nu-SVR fusion, but VIF is removed and CAMBI (banding) + speed_chroma (chroma) become core features; ADM/motion move to adm3/motion3. Six built-in models for 1080p@3H / phone@5H / 4K@1.5H / 4K@3H (last on a [0,110] range) + HFR variants; Netflix recommends 10-bit measurement even for 8-bit SDR. Adds a cited research digest and ADR-1122 deciding to adopt v1 as an opt-in generation (v0.6.1 stays default), with the port scope: build in the JSONs, fix SYCL cambi/speed_chroma (now core, currently failing on Arc A380), handle the [0,110] range end-to-end, plumb CAMBI enc params, and add new v1 golden refs in separate tests (v0.6.1 golden pairs untouched). Aligns with the zero-copy 10-bit work (ADR-1121, PR #1081). Refs ADR-1122. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YCP4JCoduujJgccDRGvNKv * docs(adr): satisfy markdownlint on the VMAF v1 research digest and ADR-1122 Formatting only — no content or conclusions changed. - table delimiter rows to the repo's "compact" pipe style (MD060) - `text` language on the feature_names fence (MD040) - backtick the viewing-condition identifiers `1080p@3H` / `phone@5H` / `4K@1.5H` / `4K@3H`; MD034 read the dot in `4K@1.5H` as a TLD and flagged it as a bare URL. Backticks are also more correct — these are technical identifiers, not prose. - angle-bracket the maintainer e-mail (MD034) markdownlint-cli2 over the PR's changed files now reports 0 issues. Note for anyone repeating this: `markdownlint-cli2 --fix` is unsafe here per ADR-0864. It rewrote `4K@1.5H` to `<4K@1.5H>`, silently corrupting the text. The autofix output was reverted and the fixes above applied by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Lusoris <lusoris@pm.me>
lusoris
force-pushed
the
fix/sycl-qsv-zerocopy-p010-normalize
branch
from
August 30, 2026 14:42
b502d0c to
6049056
Compare
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
Maintainer fixup on the contributor's branch so the two failing gates pass. Pre-Commit (Formatters + Basic Checks) was red because the branch's SYCL sources had 19 clang-format violations against the repo's .clang-format -- verified by running clang-format --dry-run --Werror over the three files as they stand in 83af211. Reformatted; the hunks are pure reflow (argument packing and a ternary joined onto one line), no semantic change. Markdown lint was red for four separate rules: - Both SYCL research digests get the house '<!-- markdownlint-disable MD013 MD060 -->' directive. 95 of the 544 docs under docs/research/ already carry exactly that pair; digests embed fixed-width tool output and evidence tables that 80 columns and the compact table style cannot represent. - sycl-zero-copy-nan-diagnosis.md: tag the sample-rows fence as 'text' (MD040) and promote the bold 'hyp 1' line under '## Verdict' to a real '###' heading (MD036). - ADR-1121: wrap the Deciders email in angle brackets (MD034). No prose was reflowed and no content changed. ADR-0864 warns that 'markdownlint --fix' rewrites content in this tree, so every markdown edit here is by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lusoris
force-pushed
the
fix/sycl-qsv-zerocopy-p010-normalize
branch
from
August 30, 2026 14:44
6049056 to
ce95142
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
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