Skip to content

fix(hip): stage the luma plane onto the device before the ADM DWT2 launch - #1370

Draft
lusoris wants to merge 3 commits into
masterfrom
fix/hip-integer-adm-picture-staging
Draft

fix(hip): stage the luma plane onto the device before the ADM DWT2 launch#1370
lusoris wants to merge 3 commits into
masterfrom
fix/hip-integer-adm-picture-staging

Conversation

@lusoris

@lusoris lusoris commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

integer_adm_hip faulted the GPU on the first frame and killed the process:

Memory access fault by GPU node-1 on address 0x556905b5a000.
Reason: Page not present or supervisor privilege.

Tracked as T-HIP-INTEGER-ADM-GPU-PAGE-FAULT-2026-09-05; reproduced here on a gfx1030.

Running the test under AMD_SERIALIZE_KERNEL=3 HIP_LAUNCH_BLOCKING=1 AMD_LOG_LEVEL=3 named the offender as the very first kernel launched, adm_dwt2_8_vert_hori_kernel_4_16_32768_128_8_uint8_t, and put the faulting address in the host heap range — the tell that a host pointer reached a device kernel.

It did. extract_fex_hip passed ref_pic->data[0] and dis_pic->data[0] straight into dwt2_8_device_hip / dwt2_16_device_hip, but the HIP backend is host-pic (ADR-0530), so those are HOST pointers. The CUDA twin needs no staging because vmaf_cuda_picture_* hands it device memory already — the HIP port inherited the CUDA call shape without the thing that made it valid. integer_psnr_hip already stages correctly via its ref_in / dis_in buffers, which is exactly why test_hip_psnr_parity passed while the ADM test cored.

Fixed by allocating a per-side device staging buffer for the scale-0 luma plane in init_fex_hip and copying the host plane across with hipMemcpy2DAsync before the DWT2 launch. The staged rows are tightly packed, so the element stride handed to the kernel becomes w rather than the picture's stride.

on gfx1030 before after
test_hip_adm_parity GPU coredump (process killed) 3/3 passing
HIP parity suite 16 pass / 2 fail 17 pass / 1 fail
vmaf --backend hip --feature adm_hip process killed integer_adm2 = 0.962084

The one remaining HIP failure is test_hip_ssim_parity (4.53e-03), the separately-tracked T-GAP-HIP-INTEGER-SSIM-FLOAT-KERNEL-DEFERRED-2026-09-02 — an 11-tap float Gaussian where the CPU uses a 9-tap int64 kernel, formally deferred under ADR-0564. Untouched here.

Also in this PR: HIP large-fixture parity variants (ADR-1206)

With the ADM extractor able to run, the 960x540 sweep that found the SYCL bug (#1369) could finally run on HIP too. Result on gfx1030: 16 pass, 0 fail, 1 skip — no new HIP defects, which is a useful negative result.

Two tests are handled explicitly rather than silently:

  • float_ssim_hip is a documented v1 scale=1-only extractor; its large variant records that contract as a skip, and still fails loudly if the twin ever stops refusing.
  • test_hip_ssim_parity is excluded from the list: its divergence is the ADR-0564-deferred 11-tap float Gaussian, so a second fixture would only re-report a deferred gap at another resolution.

Metal is now the only family without large-fixture variants — no Apple hardware here to verify against.

Type

  • fix — bug fix
  • sycl / cuda / simd — backend-specific (HIP)

Checklist

  • Commits follow Conventional Commits.
  • make format && make lint is green locally (pre-commit run --files clean; assertion-density, check-copyright, check-state-md-rows pass).
  • Unit tests pass: meson test -C build — HIP parity suite 17/1 on a gfx1030; the failure is the pre-existing deferred ssim gap.
  • If I touched any SIMD/GPU code path, I ran /cross-backend-diff and the worst ULP is ≤ 2 — equivalent done directly: test_hip_adm_parity compares CPU vs HIP at places=4 and now passes, where it previously could not run at all.
  • If I touched a feature extractor with SIMD/GPU twins, I either updated every twin or listed the gap — only the HIP twin was broken; CUDA/SYCL/Metal receive device pictures or already stage.
  • If I added a new .c / .h — no new source files.
  • If this is a breaking change — not breaking. The extractor previously crashed; it now returns scores.
  • If this PR adds an ADR, the row lives in docs/adr/_index_fragments/ — index in sync.

Bug-status hygiene (ADR-0165)

  • docs/state.md updated — T-HIP-INTEGER-ADM-GPU-PAGE-FAULT-2026-09-05 moved to Recently closed; it also closes the second half of T-GAP-HIP-INTEGER-ADM-PICTURE-STAGING-DEFERRED-2026-09-02.

Netflix golden-data gate (ADR-0024)

  • I did not modify any assertAlmostEqual(...) score in the Netflix golden Python tests.
  • If I believe a golden value must change — none does. The golden gate is CPU-only; this is a HIP-only change.

Deep-dive deliverables (ADR-0108)

  • Research digest — no digest needed: the diagnosis is one serialized-kernel run that named the faulting kernel plus one read of the call site, both recorded in ADR-1211's Context.
  • Decision matrix## Alternatives considered in ADR-1211, including making the whole HIP backend device-pic and disabling the extractor with .flags = 0, and why both were rejected.
  • AGENTS.md invariant note — added to core/src/hip/AGENTS.md.
  • Reproducer / smoke-test command — below.
  • CHANGELOG fragmentchangelog.d/fixed/hip-integer-adm-picture-staging.md.
  • Rebase notedocs/rebase-notes.md, "ADR-1211 — HIP is host-pic; device kernels need staged input".

Reproducer

Needs a ROCm device. Note -Denable_hipcc=true — without it the HIP picture allocator is an -ENOSYS stub and every HIP extractor fails with problem reading pictures for an unrelated reason.

meson setup build core -Denable_hip=true -Denable_hipcc=true -Denable_cuda=false -Denable_sycl=false
ninja -C build
meson test -C build test_hip_adm_parity

On master the process dies with Memory access fault by GPU node-1; on this branch the test is 3/3.

Known follow-ups

  • The staging copy is followed by a hipStreamSynchronize for correctness on this first cut; overlapping it with the existing ref/dis events is a performance follow-up.
  • If more HIP extractors come to need device input, making the HIP backend device-pic (as CUDA is) becomes the better shape than per-extractor staging — see the ADR's alternatives table.

🤖 Generated with Claude Code

lusoris pushed a commit that referenced this pull request Sep 6, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris pushed a commit that referenced this pull request Sep 7, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the fix/hip-integer-adm-picture-staging branch from d1e33ff to 73eaca0 Compare September 7, 2026 06:54
lusoris pushed a commit that referenced this pull request Sep 7, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the fix/hip-integer-adm-picture-staging branch 2 times, most recently from feff236 to f6b3809 Compare September 7, 2026 09:16
lusoris pushed a commit that referenced this pull request Sep 7, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the fix/hip-integer-adm-picture-staging branch from f6b3809 to 07ef118 Compare September 7, 2026 10:18
Lusoris and others added 3 commits September 7, 2026 13:14
…unch

integer_adm_hip faulted the GPU on the first frame and killed the process:

  Memory access fault by GPU node-1 on address 0x556905b5a000.
  Reason: Page not present or supervisor privilege.

Running the test under AMD_SERIALIZE_KERNEL=3 HIP_LAUNCH_BLOCKING=1
AMD_LOG_LEVEL=3 named the offender as the very first kernel launched,
adm_dwt2_8_vert_hori_kernel_4_16_32768_128_8_uint8_t, and put the faulting
address in the host heap range — the tell that a host pointer reached a device
kernel.

It did. extract_fex_hip passed ref_pic->data[0] and dis_pic->data[0] straight
into dwt2_8_device_hip / dwt2_16_device_hip, but the HIP backend is host-pic
(ADR-0530), so those are HOST pointers. The CUDA twin needs no staging because
vmaf_cuda_picture_* hands it device memory already; the HIP port inherited the
CUDA call shape without the thing that made it valid. integer_psnr_hip already
staged correctly via ref_in / dis_in, which is exactly why test_hip_psnr_parity
passed while the ADM test cored.

Fixed by allocating a per-side device staging buffer for the scale-0 luma plane
in init_fex_hip and copying the host plane across with hipMemcpy2DAsync before
the DWT2 launch. The staged rows are tightly packed, so the element stride
handed to the kernel becomes w rather than the picture's stride.

Verified on a gfx1030: test_hip_adm_parity 3/3 (was a GPU coredump), HIP parity
suite 16 pass/1 fail -> 17 pass/1 fail, and `vmaf --backend hip --feature
adm_hip` returns integer_adm2 = 0.962084 instead of killing the process. The one
remaining HIP failure is the separately-tracked, ADR-0564-deferred ssim float
kernel.

Closes T-HIP-INTEGER-ADM-GPU-PAGE-FAULT-2026-09-05 and the second half of
T-GAP-HIP-INTEGER-ADM-PICTURE-STAGING-DEFERRED-2026-09-02.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…(ADR-1206)

Extends the large-fixture variants to HIP, now that ADR-1211 lets the HIP ADM
extractor run at all. Verified on a gfx1030: 16 pass, 0 fail, 1 skip.

Two tests are handled explicitly rather than silently. `float_ssim_hip` is a
documented v1 scale=1-only extractor, so its large variant records that
contract as a skip and still fails loudly if the twin ever stops refusing.
`test_hip_ssim_parity` is excluded from the list: its divergence is the
ADR-0564-deferred 11-tap float Gaussian
(T-GAP-HIP-INTEGER-SSIM-FLOAT-KERNEL-DEFERRED-2026-09-02), so a second fixture
would only re-report a deferred gap at another resolution.

Metal is now the only family without large-fixture variants — no Apple hardware
on this workstation to verify against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the fix/hip-integer-adm-picture-staging branch from 07ef118 to 0938742 Compare September 7, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant