initial seed: retrofit campaign lineage from local working trees

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>
This commit is contained in:
2026-05-23 05:25:37 +02:00
parent 430d0da278
commit a4e7d8ab90
124 changed files with 22551 additions and 1 deletions
@@ -0,0 +1,213 @@
/*
* Copyright © 2026 mfritsche / claude-noether
* SPDX-License-Identifier: MIT
*
* iter16: primitive-decomposition tables for transform_feedback capture
* on PanVk-Bifrost (PAN_ARCH < 9 only). When XFB is active and the bound
* topology is a strip/fan/adjacency variant, the Vulkan spec requires
* vertices to be captured AS IF the primitive sequence were decomposed
* into a list of independent primitives. iter13's pan_nir_lower_xfb
* captures one entry per VS invocation, which gives one output per input
* vertex — wrong for non-LIST topologies.
*
* This file holds the seven decomposition tables (one per affected
* topology). Caller (jm/panvk_vX_cmd_draw.c CmdDraw) walks the table to
* build a synthetic index buffer, overrides the bound topology to the
* equivalent LIST, and dispatches as an indexed draw — the existing
* pan_nir_lower_xfb formula then writes the right number of entries in
* the right order.
*
* See ~/src/panvk-bifrost/iter16/phase2_design.md for the design lock.
*/
#include "panvk_macros.h"
#if PAN_ARCH < 9
#include "panvk_cmd_draw.h"
#include <vulkan/vulkan_core.h>
/* TRIANGLE_STRIP: 3*(N-2) outputs.
* Even prim i: {i, i+1, i+2}
* Odd prim i: {i, i+2, i+1} ← winding reverses, hence "winding" tests
*/
static uint32_t
prim_count_tri_strip(uint32_t n)
{
return (n >= 2) ? (n - 2) : 0;
}
static void
expected_tri_strip(uint32_t i, uint32_t *out)
{
uint32_t iMod2 = i & 1u;
out[0] = i;
out[1] = i + 1 + iMod2;
out[2] = i + 2 - iMod2;
}
/* LINE_STRIP: 2*(N-1) outputs. Each prim i: {i, i+1} */
static uint32_t
prim_count_line_strip(uint32_t n)
{
return (n >= 1) ? (n - 1) : 0;
}
static void
expected_line_strip(uint32_t i, uint32_t *out)
{
out[0] = i;
out[1] = i + 1u;
}
/* TRIANGLE_FAN: 3*(N-2) outputs. Each prim i: {i+1, i+2, 0} */
static uint32_t
prim_count_tri_fan(uint32_t n)
{
return (n >= 2) ? (n - 2) : 0;
}
static void
expected_tri_fan(uint32_t i, uint32_t *out)
{
out[0] = i + 1u;
out[1] = i + 2u;
out[2] = 0u;
}
/* LINE_LIST_WITH_ADJACENCY: N/4 primitives, each emits {i+1, i+2} from
* the 4-vertex input window (i, i+1, i+2, i+3). N must be a multiple of 4. */
static uint32_t
prim_count_line_list_adj(uint32_t n)
{
return n / 4u;
}
static void
expected_line_list_adj(uint32_t i, uint32_t *out)
{
out[0] = 4 * i + 1u;
out[1] = 4 * i + 2u;
}
/* LINE_STRIP_WITH_ADJACENCY: 2*(N-3) outputs. Each prim i: {i+1, i+2} */
static uint32_t
prim_count_line_strip_adj(uint32_t n)
{
return (n >= 3) ? (n - 3) : 0;
}
static void
expected_line_strip_adj(uint32_t i, uint32_t *out)
{
out[0] = i + 1u;
out[1] = i + 2u;
}
/* TRIANGLE_LIST_WITH_ADJACENCY: N/2 inputs map to N/6 primitives, each emits
* {6*i, 6*i+2, 6*i+4} from the 6-vertex input window. */
static uint32_t
prim_count_tri_list_adj(uint32_t n)
{
return n / 6u;
}
static void
expected_tri_list_adj(uint32_t i, uint32_t *out)
{
out[0] = 6 * i + 0u;
out[1] = 6 * i + 2u;
out[2] = 6 * i + 4u;
}
/* TRIANGLE_STRIP_WITH_ADJACENCY: 3*(N/2-2) outputs with winding flip on odd.
* Even prim i: {2i, 2i+2, 2i+4}
* Odd prim i: {2i, 2i+4, 2i+2}
*/
static uint32_t
prim_count_tri_strip_adj(uint32_t n)
{
return (n >= 6) ? (3u * (n / 2u - 2u) / 3u) : 0;
/* That's just (n/2 - 2) primitives, each emitting 3. */
}
static void
expected_tri_strip_adj(uint32_t i, uint32_t *out)
{
bool even = ((i & 1u) == 0u);
out[0] = 2 * i + 0u;
if (even) {
out[1] = 2 * i + 2u;
out[2] = 2 * i + 4u;
} else {
out[1] = 2 * i + 4u;
out[2] = 2 * i + 2u;
}
}
/* The table itself — gated to topologies that need decomposition.
* LIST topologies (POINT_LIST, LINE_LIST, TRIANGLE_LIST) return NULL. */
const struct panvk_winding_table *
panvk_per_arch(get_winding_table)(VkPrimitiveTopology topo)
{
static const struct panvk_winding_table TABLES[] = {
[VK_PRIMITIVE_TOPOLOGY_LINE_STRIP] = {
.verts_per_prim = 2,
.prim_count = prim_count_line_strip,
.decompose = expected_line_strip,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
.name = "LINE_STRIP",
},
[VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP] = {
.verts_per_prim = 3,
.prim_count = prim_count_tri_strip,
.decompose = expected_tri_strip,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.name = "TRIANGLE_STRIP",
},
[VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN] = {
.verts_per_prim = 3,
.prim_count = prim_count_tri_fan,
.decompose = expected_tri_fan,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.name = "TRIANGLE_FAN",
},
[VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY] = {
.verts_per_prim = 2,
.prim_count = prim_count_line_list_adj,
.decompose = expected_line_list_adj,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
.name = "LINE_LIST_WITH_ADJ",
},
[VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY] = {
.verts_per_prim = 2,
.prim_count = prim_count_line_strip_adj,
.decompose = expected_line_strip_adj,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
.name = "LINE_STRIP_WITH_ADJ",
},
[VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY] = {
.verts_per_prim = 3,
.prim_count = prim_count_tri_list_adj,
.decompose = expected_tri_list_adj,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.name = "TRIANGLE_LIST_WITH_ADJ",
},
[VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY] = {
.verts_per_prim = 3,
.prim_count = prim_count_tri_strip_adj,
.decompose = expected_tri_strip_adj,
.list_equiv = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.name = "TRIANGLE_STRIP_WITH_ADJ",
},
};
if (topo >= ARRAY_SIZE(TABLES))
return NULL;
const struct panvk_winding_table *t = &TABLES[topo];
/* Slots not in our table list above have verts_per_prim==0 (zero-init) */
return t->verts_per_prim ? t : NULL;
}
#endif /* PAN_ARCH < 9 */