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>
13 KiB
Phase 0 — substrate for panvk-bifrost iter1
Opened 2026-05-19 by mfritsche. Campaign goal restated against substrate (see README): complete Mesa's PanVk Vulkan driver for Bifrost-gen Mali GPUs, target hardware Mali-G52 r1 MC1 on PineTab2 v2.0 (RK3566). Concrete operator-level milestone: smoother TuxRacer on PineTab2 via Zink-on-PanVk.
This Phase 0 substrate doc reframes the campaign against what's actually in Mesa today — which is substantially further along than the original charter assumed.
Headline finding
PanVk-Bifrost is not a blank slate. Mesa 26.0.6 (current Arch Linux ARM package on ohm/PineTab2) ships a working libvulkan_panfrost.so that already:
- Loads via the Vulkan ICD loader (
/usr/share/vulkan/icd.d/panfrost_icd.json). - Enumerates the Mali-G52 r1 MC1 device end-to-end (passes
create_kmod_dev,pan_get_model,pan_format_table,pan_query_core_count,get_core_masks,get_device_heaps,get_device_sync_types). - Reports 118 device extensions including dynamic rendering, GPL (Graphics Pipeline Library), buffer device address, custom border colors, multisampled-render-to-single-sampled, host image copy, sampler YCbCr, inline uniform block, scalar block layout, vulkan memory model, timeline semaphore, sync2, push descriptor, BC/ETC2/ASTC texture compression, shader subgroup ops.
- Caps
apiVersionat Vulkan 1.0.335 withconformanceVersion = 0.0.0.0. - Is explicitly gated as broken by Mesa upstream behind
PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1(see arch gate).
The campaign is therefore not "RE the Bifrost Vulkan command stream from scratch using Arm's blob as oracle" as the README's Scope sketch implies. The campaign is "characterize what already works, find the first thing that fails on a real workload, fix it, repeat." The blob trace-and-diff methodology becomes a Phase 2 fallback when source-level diffing against the Valhall-JM (v9) reference path runs out of signal — not the iter1 starting move.
Locked baseline: ohm (PineTab2 v2.0 / RK3566 / Mali-G52 r1 MC1)
Hardware
DT compatible: pine64,pinetab2-v2.0 / pine64,pinetab2 / rockchip,rk3566
GPU: Mali-G52 r1 MC1 (1 shader core)
GPU ID: 0x7402 (major 0x1, minor 0x0)
Mesa PAN_ARCH: 7 (Mali-G52 r1 silicon — G52 r0 would be v6)
Memory model: UMA, 6.04 GiB device-local
Render node: /dev/dri/renderD128
DRM driver: panfrost 1.6.0 (NOT panthor)
Software stack
OS: Arch Linux ARM (danctnix kernel 7.0.0-danctnix1-5-pinetab2)
Mesa: 1:26.0.6-1
vulkan-panfrost: 1:26.0.6-1 (14.9 MiB libvulkan_panfrost.so)
vulkan-icd-loader: 1.4.350.0-1
ICD JSON: api_version 1.4.335, library_path libvulkan_panfrost.so
Note on README.md: the README's "Mali-G52 MP2" is empirically wrong — RK3566 silicon has Mali-G52 MC1 (1 core). RK3568 has MC2. The Goal section should be Mali-G52 MC1 (or Mali-G52 MP1, same thing).
Driver state on ohm (captured 2026-05-19)
Full vulkaninfo output at phase0_evidence/ohm_vulkaninfo_full.txt. Headlines:
Supported features (selected): robustBufferAccess, fullDrawIndexUint32, imageCubeArray, independentBlend, sampleRateShading, dualSrcBlend, depthClamp/depthBiasClamp, wideLines, samplerAnisotropy, all 3 dynamic-indexing flavors, shaderInt64+Int16, BC/ETC2/ASTC, occlusionQueryPrecise, dynamic rendering + local read, GPL, host image copy, sampler YCbCr, sync2, timeline semaphore.
NOT supported (hardware-fundamental): geometryShader, tessellationShader, multiViewport, fillModeNonSolid (no wireframe), shaderFloat64, shaderClipDistance/CullDistance, sparseBinding (Bifrost can't), multisample 2x/8x (only 1x and 4x).
NOT supported (potential driver gaps, not hardware): shaderFloat16 (despite 16bit_storage = true — inconsistent), multiDrawIndirect, fragmentStoresAndAtomics, vertexPipelineStoresAndAtomics, pipelineStatisticsQuery, depthBounds, inheritedQueries.
Known broken: timestamp queries (timestampComputeAndGraphics = false, timestampPeriod = 0, timestampValidBits = 0).
Missing extensions worth noting: VK_EXT_descriptor_indexing (no bindless), VK_EXT_transform_feedback (no XFB), VK_EXT_conditional_rendering, all VK_KHR_ray_tracing_*, VK_EXT_mesh_shader, VK_EXT_fragment_shader_interlock, VK_EXT_fragment_density_map.
Mesa source tree (~/src/mesa-ref/mesa @ depth 1, 2026-05-19)
src/panfrost/vulkan/ layout
panvk_vX_*.c — 19 arch-templated files compiled per PAN_ARCH (v6/v7/v9/v10/v12/v13/v14)
panvk_*.c (no _vX_) — arch-agnostic (instance, device_memory, image, mempool, buffer, etc.)
bifrost/ — 1 file: panvk_vX_meta_desc_copy.c (484 lines) — Bifrost descriptor-table copy NIR
jm/ — 9 files: ~4242 LOC — JM (Job Manager) submit/cmdbuf — SHARED v6/v7/v9
csf/ — CSF (Command Stream Frontend) submit — v10+ only
valhall/ — empty placeholder
fifthgen/ — empty placeholder (would hold fifth-gen Valhall-after-v11 code)
meson.build arch wiring:
bifrost_archs = [6, 7] # G31, G52, G72 (v6), G76 (v7)
valhall_archs = [9, 10] # Valhall JM (v9) + CSF (v10)
fifthgen_archs = [12, 13, 14] # post-Valhall (G6xx/G7xx)
jm_archs = [6, 7] # JM submit only used for Bifrost in current tree
Important: the jm_archs = [6, 7] line means the JM submit code only compiles for Bifrost — Valhall-JM (v9, G57/G77) is implicitly not sharing the same JM code in the current layout. That contradicts MR !27217's stated direction ("share Bifrost / Valhall(JM)"). Worth following up — either MR !27217 is unmerged and v9-JM uses a different path entirely, or the meson.build has shifted since the MR description was written. Open question for Phase 1.
The arch gate
src/panfrost/vulkan/panvk_physical_device.c lines 413–432:
switch (arch) {
case 6:
case 7:
case 14:
if (!os_get_option("PAN_I_WANT_A_BROKEN_VULKAN_DRIVER")) {
result = panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"WARNING: panvk is not well-tested on v%d, "
"pass PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1 "
"if you know what you're doing.", arch);
goto fail;
}
break;
case 10:
case 12:
case 13:
break;
default:
result = panvk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"%s not supported", device->model->name);
goto fail;
}
Reading: v9 (Valhall-JM) is NEITHER in the "broken" list NOR the "ok" list — falls through to default and the device is rejected outright (%s not supported). So Valhall-JM is currently more broken than Bifrost. Bifrost (v6/v7) and the experimental v14 fifthgen are the "broken but loadable with env var" tier; v10/v12/v13 are the production tier.
This further refines the strategy: Valhall-JM cannot be our reference template right now — the v9 path is not maintained. The closest reference becomes the v10 CSF code minus the CSF-isms, plus whatever JM-style code lives in jm/.
Bifrost-conditional code outside jm/
grep -l PANVK_BIFROST_DESC finds Bifrost-specific divergence in:
panvk_vX_cmd_desc_state.c— descriptor state recordingjm/panvk_vX_cmd_draw.c— draw call emission (already in JM dir)jm/panvk_vX_cmd_dispatch.c— compute dispatchpanvk_vX_nir_lower_descriptors.c— NIR descriptor loweringpanvk_vX_shader.c— shader compilation entry
So Bifrost's descriptor model genuinely differs from Valhall's — that's where the bifrost/panvk_vX_meta_desc_copy.c shader gen file lives, and it's also why descriptor-related code paths are scattered across the per-arch sources.
Hypothesis space — where iter1 will likely fail first
Three layers can produce a real-workload failure on PanVk-Bifrost today:
-
Device init → logical device creation gap. vulkaninfo succeeds because it only does instance+physical-device. The first failure is likely
vkCreateDevice— queue creation, sync object init, or the post-arch-gate code path (get_drm_device_idsetc. succeed during enum but may fail during full device creation). -
Command buffer recording. The JM cmd_buffer/cmd_draw/cmd_dispatch code is shared with the long-dead v9-JM path. Any code that assumes Valhall-JM register/descriptor layouts could miscompile for v6/v7. Specifically: the Bifrost descriptor table model (
PANVK_BIFROST_DESC_TABLE_COUNT) is referenced from cmd_draw/cmd_dispatch but the JM code may not consistently handle the Bifrost variant. -
Shader compilation / NIR lowering. Bifrost ISA support exists in Mesa (Panfrost GLES uses it), but the PanVk-side NIR lowering (
panvk_vX_nir_lower_descriptors.c,panvk_vX_shader.c) may be Valhall-shaped and produce shaders that fail to compile/link or run incorrectly on Bifrost. -
WSI / swapchain.
VK_KHR_swapchainis in the device extension list butpresent support = falsefor the only queue family in a no-surface query. A real swapchain on Wayland may or may not work. iter1 should bypass WSI by usingVK_EXT_headless_surfaceor off-screen rendering to a host-visible buffer.
Locked research question — iter1
Get a minimal Vulkan compute workload to execute end-to-end on PanVk-Bifrost on ohm (PineTab2, Mali-G52 r1 MC1) with
PAN_I_WANT_A_BROKEN_VULKAN_DRIVER=1: write a known value to a host-visible storage buffer from a single-invocation compute shader, fence-wait, read back, verify. No GPU faults in dmesg, no validation errors withVK_LAYER_KHRONOS_validationif installable, no submit timeout.If this works: lock iter2 against a minimal graphics workload (single triangle to a host-visible image, headless surface, readback).
If this fails: characterize the first failure point and fix it.
Rationale for compute-first over graphics-first:
- Fewer moving parts (no swapchain, no framebuffer, no render pass, no rasterizer state).
- Compute exercises the submit path + memory model + shader compilation + sync in isolation, which is the fundamental loop.
- TuxRacer end-goal is graphics-heavy, but iter1 needs to find the first failure cheaply.
Phase 0 deliverables
- This document — substrate review locking the iter1 question.
phase0_evidence/ohm_vulkaninfo_full.txt— captured driver capabilities on the target hardware.- Local Mesa clone at
~/src/mesa-ref/mesa(depth=1, freedesktop.org/mesa/mesa main) for source reads. Not checked into this campaign repo — too large. - README.md correction — Mali-G52 MP2 → MP1 (RK3566 silicon). Deferred to operator's call.
In-scope (LOCKED 2026-05-19 for iter1)
- Hardware: ohm only (PineTab2 v2.0, RK3566, Mali-G52 r1 MC1).
- Software: Mesa 26.0.6 as packaged in Arch Linux ARM. No local Mesa build yet — out-of-tree builds enter scope only if iter1 needs a one-line fix to characterize.
- Vulkan workload: minimal compute (single SPIR-V shader, single dispatch, single buffer write, single readback).
- Tooling: stock vulkan-tools, vulkan-validation-layers (if installable on archarm). No deqp-vk yet.
Out-of-scope (LOCKED 2026-05-19 for iter1)
- Graphics pipeline (deferred to iter2+).
- WSI / swapchain / display (deferred — use headless throughout iter1).
- Mali Bifrost blob (
libGLES_mali.sofrom JeffyCN/mirrors / tsukumijima/libmali-rockchip). Confirmed to exist atlibmali-bifrost-g52-g13p0variant; download deferred until source-level diffing against Mesa runs out of signal. - Mesa out-of-tree build / local PanVk modifications. iter1 measures stock 26.0.6; modifications enter scope in iter2+.
- TuxRacer / Zink-on-PanVk / any real end-user workload. Way too far out.
- v6 silicon (G52 r0, G31, G72). ohm is v7. Other Bifrost variants enter scope when the campaign produces a portable fix worth verifying elsewhere.
- Valhall-JM (v9). Currently unsupported by panvk_physical_device.c arch gate — not a reference template.
- CTS / deqp-vk conformance. Years away.
- Upstreaming. Per feedback-no-upstream (libva-multiplanar feedback memory; same applies here).
Reference history
README.md— campaign charter (2026-05-05, refreshed 2026-05-19 with desktop-game line).~/src/mesa-ref/mesa/src/panfrost/vulkan/— current Mesa PanVk source.~/src/libva-multiplanar/phase0_findings_iter*.md— 8-phase loop format reference.- Collabora blog history (2020–2026): "From Bifrost to Panfrost" (2020), original PanVk announcement (Mar 2021), "Mesa 25.0 PanVk moves towards production quality" (2026), "PanVK V10 support" (2026). All focus shifted to Valhall after 2022; Bifrost left as the "well-tested" → "not well-tested" gate that ships today.
- Mesa MR !27217 (Draft: panvk cleanup, shares code between Bifrost and Valhall(JM)/Valhall(CSF)) — directionally relevant but its claim about Valhall(JM) being a sibling to Bifrost may be out of date given v9 falls through
defaultin the current arch gate. - Mali Bifrost Vulkan blob:
libmali-bifrost-g52-g13p0-x11-wayland-gbm.soatJeffyCN/mirrors/-/tree/libmali(mirror) andtsukumijima/libmali-rockchip. Not downloaded.