Adds iter19 campaign-close doc (mesa-panvk-bifrost r7 ship, XFB packed-varying channel-extract fix). Also lands the r5 full dEQP-VK sweep scoreboard (2.26M tests, 97.65% runnable pass rate) that surfaced the holes_vert crash in the first place. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
5.1 KiB
iter19 — XFB store channel-extract fix for packed varyings (campaign close)
Shipped: 2026-05-25
PR: marfrit/marfrit-packages#96
Merge commit: 902de73a02d9
Package: mesa-panvk-bifrost-26.0.6.r7-1-aarch64
What shipped
Single 21+/3- line patch to src/panfrost/vulkan/panvk_vX_xfb_lower.c
(0007-panvk-bifrost-xfb-component-base-fix.patch). Eliminates a
reproducible SIGSEGV in vkCreateGraphicsPipeline for any shader with
XFB-bound varyings declared at non-zero layout (component=N).
How surfaced
The r5 full dEQP-VK sweep (2,258,378 tests, 97.65% runnable pass rate)
on 2026-05-24/25 included 27 fails in transform_feedback plus a
SIGKILL on the chunk when transform_feedback.simple.holes_vert hit
FATAL ERROR: Test program crashed. Isolated repro produced a userspace
SIGSEGV with no kernel GPU fault (dmesg clean), pointing at a pure
libvulkan_panfrost bug.
Root cause
lower_xfb_output_iter17 (and identically upstream
pan_nir_lower_xfb.c::lower_xfb_output, which carries a // TODO)
computed the source-channel mask as mask << channel_idx. channel_idx
is the varying-location component (0..3) but src only contains
channels starting at nir_intrinsic_component(intr). For a scalar
declared layout (component=2) flat out float vegeta, NIR emits
store_output src=<vec1>, component=2, and the lowering computed
mask << 2 against a 1-component src — out-of-range; the malformed
nir_def then segfaulted during downstream NIR constant-folding in
nir_constant_expressions.c::evaluate_*.
The assert(nir_intrinsic_component(intr) == 0) precondition was
inherited from upstream Mesa as a documented // TODO; release builds
(-DNDEBUG) elided it, turning the precondition violation directly
into a SIGSEGV.
Fix
- Compute
src_channel = channel_idx - nir_intrinsic_component(intr)and usemask << src_channelinstead. - Convert both elided asserts to explicit release-mode early-return guards (closes the same elision class as the original bug).
- Add a dispatcher-side comment explaining why
i*2+jis the varying-location component index.
Verification
| Family | Result |
|---|---|
transform_feedback.simple.holes_vert |
Crash → Fail (color) |
transform_feedback.simple.holes_extra_draw_vert |
Crash → Fail (color) |
transform_feedback.simple.basic_* |
36/36 Pass |
transform_feedback.simple.depth_clip_* |
1 Pass + 4 NotSupp |
transform_feedback.simple.lines_or_triangles* |
16 NotSupp |
transform_feedback.simple.holes_geom* |
NotSupp (no GS on G52) |
Zero new regressions on previously passing tests.
Process
Full 8-step bugfix process followed:
- Phase 0 — characterize:
iter19/phase0_holes_vert_close.md - Phase 1 — source map:
iter19/phase1_holes_vert_situation.md - Phase 2 — root-cause + ranked options:
iter19/phase2_holes_vert_situation.md - Phase 3 — implement + inner-test:
iter19/phase3_holes_vert_close.md - Phase 4 — wider verify (focused subset)
- Phase 5 — 2nd-model review: APPROVE WITH CHANGES (non-blocking) → defensive-guards added
- Phase 7 — final retest: clean
- Phase 8 — ship: r7 PR → CI green → marfrit repo published → ohm
pacman -Supgraded → smoke test confirms Crash→Fail
Three-point ship-check verdict
- ✓ PR #96 merged at
902de73a02d9 - ✓ CI runs #1380 (
mesa-panvk-bifrost-aarch64) and #1381 (mesa-panvk-bifrost-video-aarch64) bothsuccess - ✓
pacman -Q mesa-panvk-bifroston ohm reports26.0.6.r7-1; installed lib BuildID9f8dacfc...; holes_vert no longer SIGSEGVs
Open follow-ups (not blocking r7 ship)
- iter20: holes_vert color-check residual — when
panvk_per_arch(nir_lower_xfb)removes the original store_output post-XFB-lowering, varyings that are both XFB-bound and read by the fragment shader lose their rasterizer-side path. holes_vert's fragment shader seesgoku/vegetaas undef → outputs black instead of expected blue. Naive "keep store_output" probe fixed color but blew up compile-time onmax_output_components_128— needs a more nuanced fix. - iter20+: pre-existing latent crashes unmasked by r7 —
dEQP-VK.transform_feedback.simple.max_output_components_{64,128,256}coredump on shipped r6 baseline too (confirmed independently); they were never reached during the r5 sweep because the watchdog killed transform_feedback after holes_vert.
Lineage
| rev | What | Date |
|---|---|---|
| r1 | KHR_robustness2 + nullDescriptor + nullDescriptor on Bifrost | iter8 |
| r2 | has_vk1_1/has_vk1_2 = true on Bifrost | iter9 |
| r3 | VK_EXT_transform_feedback (iter13) | iter13 |
| r4 | XFB primitive decomposition (iter17) | iter17 |
| r5 | fragmentStoresAndAtomics = true | 2026-05-23 |
| r6 | VK_EXT_legacy_dithering | 2026-05-25 |
| r7 | XFB packed-varying channel-extract fix | 2026-05-25 |