a4e7d8ab90
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>
214 lines
6.0 KiB
C
214 lines
6.0 KiB
C
/*
|
|
* 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 */
|