panvk-bifrost campaigns (r1..r4 Vulkan compositor + r5.video1 Vulkan
video decode) shipped before this repo existed; the deliverable
patches live in marfrit-packages, but the reasoning chain, phase docs,
and source-state evidence lived only in local working trees on the
development host.
This retrofit imports:
- mesa-panvk-bifrost/ — r1..r4 era phase docs (iter1..iter18)
(libmali stub blobs at iter18/blob/ excluded
— 109MB of RE artifacts replaced with a README
pointer)
- mesa-panvk-bifrost-video/ — sibling campaign phase docs + probe
- evidence/ — frozen .tgz source snapshots at each milestone
(basis for the 0005 patch diff generation)
Future iterations should branch off here from day one, so each iter is
a commit rather than a snapshot. See [[feedback-session-local-process-pins]]
for the process drift this retrofit closes.
Total: 1.9 MB across 124 files.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
4.5 KiB
Iteration 2 close — GREEN
Closed 2026-05-19 by mfritsche + claude-noether, same session as iter1 close.
Locked question
(From phase0_findings_iter2.md)
Get a minimal Vulkan image-side workload to execute end-to-end on PanVk-Bifrost: create a 4×4
VK_FORMAT_R8G8B8A8_UNORMimage, transition UNDEFINED → TRANSFER_DST,vkCmdClearColorImageto 0x11223344, transition TRANSFER_DST → TRANSFER_SRC,vkCmdCopyImageToBufferto host-visible staging, fence-wait, verify all 16 pixels read back as 0x44332211.
Result: GREEN
7/7 runs PASS (1 baseline + 1 with VK_LAYER_KHRONOS_validation + 5 stability). All 16 pixels match exactly. No GPU faults, no MMU faults, no kernel-side panfrost messages, no validation-layer warnings or errors.
Evidence: phase0_evidence/iter2_image_clear_run.txt.
What the close tells us
Four image-side hypotheses from phase0_findings_iter2.md were tested. All four work:
| Hypothesis | Status at iter2 |
|---|---|
| H1: image creation + memory binding | ✗ no — vkCreateImage + vkGetImageMemoryRequirements + bind work for 4×4 RGBA8 optimal-tiled (4096-byte aligned allocation) |
| H2: layout transitions | ✗ no — UNDEFINED→TRANSFER_DST and TRANSFER_DST→TRANSFER_SRC both clean |
H3: vkCmdClearColorImage lowering |
✗ no — clear lands in image correctly |
H4: vkCmdCopyImageToBuffer + Bifrost tile decode |
✗ no — all 16 pixels round-trip with no shuffling, no rounding error |
The image-side transfer path on PanVk-Bifrost is functional for this minimal case. Combined with iter1, we now know the following work end-to-end:
- Vulkan instance + physical device + logical device + queue
- Buffer create + alloc + bind + map (host-visible)
- Image create + alloc + bind (device-local)
- Image layout transitions via
vkCmdPipelineBarrier vkCmdClearColorImage(transfer-op level, not via shader)vkCmdCopyImageToBufferwith Bifrost tile-layout decode- Compute pipeline: shader module + pipeline layout + compute pipeline + dispatch
- Command buffer recording + submit + fence wait + memory barriers (memory + image + buffer)
What we still don't know works: graphics pipeline (vertex + fragment + rasterizer + render pass / dynamic rendering).
iter2 in-tree artifacts
iter2/probe_image_clear.c— ~340 LoC, pure Vulkan 1.0 coreiter2/Makefile—makebuilds,make run/make run-validation
Deferred to iter3+ (not in iter2 scope)
- Vertex + fragment shaders
- Render pass and/or dynamic rendering
- Graphics pipeline state (rasterizer, viewport, blend, depth)
- Larger images, mipmaps, layered images, MSAA
- Other formats (R32G32B32A32_SFLOAT, BC/ETC2/ASTC compressed, depth/stencil)
- WSI / swapchain (iter4+)
- TuxRacer / Zink-on-PanVk
Next iter — iter3 lock proposal
Smallest viable graphics workload that exercises the rasterizer + shaders:
Render a single full-screen triangle into a 64×64 R8G8B8A8_UNORM color attachment via dynamic rendering (
VK_KHR_dynamic_rendering), using a trivial vertex shader (no vertex buffer — emit positions fromgl_VertexIndex) and a trivial fragment shader (output constant colorgl_FragCoord-encoded so we can detect rasterizer correctness). Copy attachment to host-visible buffer. Verify: (a) some pixels are written (not all sentinel), (b) at least one pixel has the encodedgl_FragCoordvalue matching its position.
Justifications:
- 64×64 (not 4×4) so multiple tiles get exercised — Bifrost is a tile-based rasterizer, so single-tile workloads might side-step real tile binning.
- Dynamic rendering instead of render pass — simpler API surface, no framebuffer object, no subpass dependencies. Render pass / framebuffer can be iter3.5 if needed.
- Fullscreen triangle from
gl_VertexIndexso no vertex buffer needed — exercises pipeline-state but not vertex-input-state. - Trivial fragment shader (no textures, no UBO, no SSBO) — exercises rasterization + frag shader output but not descriptor lookups (proven in iter1 anyway).
gl_FragCoord-encoded color so a wrong-rasterization bug (e.g. swapped-Y framebuffer convention, off-by-pixel) is detectable from pixel data.
If iter3 turns up the first real failure, that's the campaign's first interesting bug. If iter3 also passes, iter4 adds vertex buffer + UBO + a texture sample, and we're well into "actually exercising PanVk-Bifrost" territory.
Pacing: same 8-phase cadence. iter3 phase 0 substrate lock when the operator opens.