Repository navigation
fix(sycl): return from vmaf_sycl_upload_plane only after its copy has completed - #2102
Merged
Merged
Conversation
lusoris
force-pushed
the
fix/sycl-upload-plane-fence
branch
from
October 5, 2026 20:08
3fafbee to
7f7c11a
Compare
…t INT64_MAX scores (#2190) * fix(adm): sum the scale-0 contrast-masking rows unsigned so a row past INT64_MAX scores The integer ADM masking reduction adds, per row, the non-negative cubes of the CSF-weighted coefficients above their threshold, and the CPU, its AVX2 / AVX-512 rows and the CUDA, HIP and SYCL twins summed a scale-0 row in int64. Compared with itself, a 31-32 or 63-64 pixel wide picture with full-range reference detail (core/test/adm_cm_row_overflow_frame.h) takes one row to 1.044 / 1.021 INT64_MAX at the default weights: the sum wrapped, the numerator was NaN and the frame failed with "invalid ADM reduction". A horizontal or vertical CSF weight above 38,400 does the same at 16K. Scale 0 now sums its rows and its frame unsigned (adm_cm_round_row_total_s0(), adm_cm_fold_s0(), uint64_t rows in every backend; the GPU hosts read the scale-0 slots as uint64_t), which holds every row at the default weights (0.52 of 2^64 at worst) and up to an h/v weight of about 45,200. Below 2^63 the values keep their bits. Scales 1-3 keep their signed sums. The weights between 45,200 and the ADR-1472 limit of 46,603 are left open as T-ADM-CM-SCALE0-ROW-UINT64-WEIGHT-BUDGET. The CUDA and HIP scale 1-3 decouple also narrowed the gain product (|o| up to 1.45e9 times the limit of 100) to int32 before bounding it by t, an undefined conversion the devices' saturation hid; they now bound the double product with fmin / fmax and narrow once, as the CPU does. test_integer_adm_cm_row_unsigned (8, 10, 16 bit; SIMD == scalar) and the new row case of test_gpu_adm_tiny_frames fail on master and pass on the CPU, CUDA, HIP and SYCL; the fold and gain contracts pin both forms; the Netflix golden gate passes. Closes T-ADM-CM-SCALE0-ROW-INT64-OVERFLOW-2026-10-05. Closes T-GPU-ADM-S123-GAIN-PRODUCT-NARROWING-2026-10-05.
…filters after a mid-run error (#2115) * fix(ffmpeg): print no pooled score from the libvmaf and libvmaf_cuda filters after a mid-run error Upstream FFmpeg's libvmaf and libvmaf_cuda filters share one uninit(). After a failed picture copy or vmaf_read_pictures(), the run exited non-zero, but uninit() still pooled the frames read before the error and printed a VMAF score line. frame_cnt had already counted the failed frame, so the pooling usually failed and the line showed an uninitialised value: "VMAF score: 0.000000" for both filters in the dev container. The error line named neither the frame nor the error. As the maintainer decided, new series patch 0021 makes these filters follow the rule libvmaf_sycl and libvmaf_metal follow since ADR-1761 (ADR-1768): - one error names the filter, the step, the frame and the error; - the frame is freed and the filter records the stop; - frame_cnt advances only after a successful read; - uninit() prints no pooled score and writes no report after a stop, a failed flush or a failed pooled score. The divergence from upstream is deliberate and is kept on every series refresh. ffmpeg-patches/test/check-libvmaf-no-score-after-error.sh injects the errors through the LD_PRELOAD shim. The shim is renamed fault_inject_libvmaf.c and now injects vmaf_read_pictures() failures too. The script runs the CPU filter, and libvmaf_cuda on the RTX 4090. With this branch's series, 17 of 17 checks pass; the previous FFmpeg fails 6. core/test/test_ffmpeg_libvmaf_stop_contract.py checks the series without a device. * docs: regenerate the indexes and the citation map after rebasing
* ci(workflows): do not cancel master push runs by concurrency A push to master no longer cancels the runs of the previous master commit. The concurrency group of every push-to-master workflow carries github.sha on master and cancel-in-progress stays on for pull request refs. Publish, release-please, Scorecard and the Pages deploy job stay serialised and are listed with reasons in a new contract test. The Required Checks Aggregator takes the same form, so re-running an old master head cannot cancel the newest one. * ci(workflows): type the master concurrency contract test * test(ffmpeg): update workflow concurrency group expectation for master push * docs: regenerate the indexes and the citation map after rebasing
… completed (#2102) * fix(sycl): return from vmaf_sycl_upload_plane only after its copy has completed vmaf_sycl_upload_plane() enqueued its host-to-device copy on the copy queue and returned. Nothing ordered that copy before the frame's compute on the other queues: sycl_apply_input_barriers() waits on last_upload_event, which this function never set. The caller was also free to release the source while the copy still read it; the Windows D3D11 import unmaps its staging texture right after the call. On an Arc A380, eight 3840x2160 frames uploaded this way and read at once with psnr_sycl were all wrong (psnr_y 4.9 to 6.1 where the CPU gives about 7.1), on three of three runs. Recording the copy's event for the compute barrier, without waiting, still left six of eight wrong. The function now orders the copy behind the slot's previous readers, as vmaf_sycl_shared_frame_upload() does (ADR-1369), and waits for the copy before returning. All eight frames now equal the CPU on three of three runs (test_sycl_zero_copy_model_gate, test_upload_plane_orders_compute). The test's other cases no longer wait on the copy queue themselves. common.cpp, touched, is brought to zero clang-tidy findings: its four getenv() calls read through the thread-safe snapshot helper vmaf_gpu_dispatch_env_get() (ADR-0488).
lusoris
force-pushed
the
fix/sycl-upload-plane-fence
branch
from
October 5, 2026 21:42
7f7c11a to
d61f34b
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
vmaf_sycl_upload_plane()returned with its host-to-device copy still in flight. Nothing ordered that copy before the frame's compute, which runs on other queues:sycl_apply_input_barriers()waits onlast_upload_event, which this function never set. The caller could also free the source while the copy was still reading it; the Windows D3D11 import unmaps its staging texture right after the call. On an Arc A380, every 3840x2160 frame uploaded this way and read at once scored the wrong pixels.The function now orders the copy behind the slot's previous readers and waits for it before returning. This closes
T-SYCL-UPLOAD-PLANE-NO-COMPUTE-FENCE-2026-10-05, which #2075 opened (now on master).What reproduced (A380, xe)
test_sycl_zero_copy_model_gate, new casetest_upload_plane_orders_compute: 8 frames of 3840x2160 that change every frame, uploaded withvmaf_sycl_upload_plane(), read at once bypsnr_sycl(enable_chroma=false), compared with the CPUpsnr. The test frees its source pictures right after the read, as a caller may.%.17g)psnr_y4.9 to 6.1 where the CPU gives 7.04 to 7.15)The test's other cases (576x324) were right before the fix too, because their copies finish first. Their explicit
vmaf_sycl_wait_copy_queue()is gone, so every case now runs without a wait of the caller's own.What changed
core/src/sycl/common.cpp::vmaf_sycl_upload_plane():sycl_fence_slot_readers()first (asvmaf_sycl_shared_frame_upload()does, ADR-1369), thenlast_ev.wait_and_throw()before returning.common.cpp, touched, is brought from 4 to 0 sycl-lane clang-tidy findings. Its fourgetenv()calls (VMAF_SYCL_PROFILE,VMAF_SYCL_TIMING,VMAF_SYCL_IMPORT_DEBUG,VMAF_SYCL_CHECKSUM) now read through the thread-safe snapshotvmaf_gpu_dispatch_env_get()(ADR-0488). The scoped baseline was tightened in the dev container.libvmaf_sycl.hcomment,docs/api/gpu.mdanddocs/backends/sycl/zero-copy.mdstate that the call returns after the copy.Verification (A380; SYCL build with
dg2-g11AOT)test_sycl_zero_copy_model_gatefast+gpu+syclteststest_vmaf_sycl_threads,test_vmaf_feature_backend_sycl(slow)--suite fastwithoutgpuscripts/dev/tidy-lane.sh --write --only core/src/sycl/common.cpp sycl(dev container)common.cpp4 → 0, tightened; the test file stays at 0Not verified: the Windows D3D11 path, which calls this function (no Windows GPU host).
Deep-dive deliverables (ADR-0108)
core/src/sycl/AGENTS.md("vmaf_sycl_upload_plane()returns after its copy completed")changelog.d/fixed/sycl-upload-plane-waits-for-copy.mddocs/rebase-notes.md, "vmaf_sycl_upload_plane waits for its copy (2026-10-05)"Reproducer