# Phase 0 — substrate for panvk-bifrost iter1 Opened **2026-05-19** by mfritsche. Campaign goal restated against substrate (see [README](README.md)): 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 `apiVersion` at **Vulkan 1.0.335** with `conformanceVersion = 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-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](README.md) 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`](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: ```meson 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: ```c 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 recording - `jm/panvk_vX_cmd_draw.c` — draw call emission (already in JM dir) - `jm/panvk_vX_cmd_dispatch.c` — compute dispatch - `panvk_vX_nir_lower_descriptors.c` — NIR descriptor lowering - `panvk_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: 1. **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_ids` etc. succeed during enum but may fail during full device creation). 2. **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. 3. **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. 4. **WSI / swapchain.** `VK_KHR_swapchain` is in the device extension list but `present support = false` for the only queue family in a no-surface query. A real swapchain on Wayland may or may not work. iter1 should bypass WSI by using `VK_EXT_headless_surface` or 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 with `VK_LAYER_KHRONOS_validation` if 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 1. **This document** — substrate review locking the iter1 question. 2. **[`phase0_evidence/ohm_vulkaninfo_full.txt`](phase0_evidence/ohm_vulkaninfo_full.txt)** — captured driver capabilities on the target hardware. 3. **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. 4. **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.so` from JeffyCN/mirrors / tsukumijima/libmali-rockchip). Confirmed to exist at `libmali-bifrost-g52-g13p0` variant; 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`](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 `default` in the current arch gate. - Mali Bifrost Vulkan blob: `libmali-bifrost-g52-g13p0-x11-wayland-gbm.so` at `JeffyCN/mirrors/-/tree/libmali` (mirror) and `tsukumijima/libmali-rockchip`. Not downloaded.