From e8b4d29f91704905f1793664db5dd7957b7b8499 Mon Sep 17 00:00:00 2001 From: chrg6 Date: Wed, 11 Nov 2026 17:03:41 -0500 Subject: [PATCH] Give mesh output components outside the program's output map Maxwell's default of (0, 0, 0, 1). A mesh program's header lists the components of each output vector it has; the fragment stage may read the others. The native mesh entry function never wrote them, so they read as whatever the output held, and the fallback's vertex stage wrote 0 for all of them, w included. Maxwell gives an unwritten component (0, 0, 0, 1), as the pipeline code already pads a missing vertex output. Both paths now write that default: MeshSpirv.cs after copying each vertex's lines, mesh_fb.c meshfb_vs with w as the bits of 1.0f whatever the type. Checked: all 520 task and mesh programs of an installed shader cache translate and pass spirv-val (vulkan1.3); 500 mesh modules gained about 730 bytes each on average, so many of the game's mesh programs have partly listed vectors. --probe-meshfb passes (fallback pictures equal the mesh pipeline's), and its module part converts all 520 new translations with 0 failures, all 1,020 modules pass spirv-val and their compute pipelines build. Co-Authored-By: Claude Opus 5.5 --- docs/maxwell.md | 6 +++++- runtime/mesh_fb.c | 4 +++- tools/xlate/MeshSpirv.cs | 13 +++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/maxwell.md b/docs/maxwell.md index 4a0abaeb..eff48f7e 100644 --- a/docs/maxwell.md +++ b/docs/maxwell.md @@ -121,7 +121,11 @@ Grep-level look on 2026-10-22, statuses updated 2026-10-26; "saw" is what the gr not just their base location: an FS `vec4[16]` requires all 16 locations even when it only accesses some elements. The same reflected mask feeds recorded-pipeline prewarm, independent stage-library unions and direct pipeline builds. Our translator never links stages, so its `InitializeVertexOutputs` would initialise no user output; - translator patch 0006 initialises the unlinked outputs. **Implemented; array-span runtime validation pending.** + translator patch 0006 initialises the unlinked outputs. Mesh programs: a component of a position or generic vector + that the program's output map leaves out is written as (0, 0, 0, 1) by the mesh entry function + (`tools/xlate/MeshSpirv.cs`) and by the fallback's vertex stage (`runtime/mesh_fb.c` `meshfb_vs`); a whole location + the fragment stage reads and the mesh program lacks is still not padded with mesh shaders (`have = ~0u` for mesh in + `vk_pipeline.c`). **Implemented; array-span runtime validation pending.** 3. **Masked clears.** `vk_exec.c` skips colour clears with a partial channel mask (`W_CLEAR_MASK`); `clear_ds` skips stencil clears with a partial mask (`W_STENCIL_MASK`). NX2navi issues such clears. Check the log for `colour clear with channel mask` and `stencil clear with mask`. The hardware recipe (1.3) shows what the replay must do: colour clear = scissor 0 + channel mask, stencil clear = `value & mask` merged under the front write mask; so a draw with `colorWriteMask` / `stencilWriteMask` set to the clear mask is the exact equivalent. **Missing.** diff --git a/runtime/mesh_fb.c b/runtime/mesh_fb.c index 3d65be66..6c540748 100644 --- a/runtime/mesh_fb.c +++ b/runtime/mesh_fb.c @@ -583,9 +583,11 @@ uint32_t *meshfb_vs(const MeshFbInfo *m, uint32_t out_mask, const uint8_t out_ty for (int g = 0; g < 32; g++) { if (!loc_var[g]) continue; int t = out_type[g] < 3 ? out_type[g] : 0; + // A component outside the program's output map reads as Maxwell gives an unwritten one: (0, 0, 0, 1), the w + // as the bits of 1.0f whatever the type, as vk_pipeline.c spirv_add_outputs pads a missing output. uint32_t comp[4]; for (int k = 0; k < 4; k++) { - uint32_t word_k = gen[g][k] ? gen[g][k] : k0; + uint32_t word_k = gen[g][k] ? gen[g][k] : k == 3 ? K(&c, 0x3f800000) : k0; comp[k] = t == 2 ? word_k : E(&c, OpBitcast, t_scalar[t], word_k); } DO(&c, OpStore, loc_var[g], E(&c, OpCompositeConstruct, t_v4[t], comp[0], comp[1], comp[2], comp[3])); diff --git a/tools/xlate/MeshSpirv.cs b/tools/xlate/MeshSpirv.cs index a04b360a..d9dad17b 100644 --- a/tools/xlate/MeshSpirv.cs +++ b/tools/xlate/MeshSpirv.cs @@ -306,6 +306,9 @@ static class MeshSpirv // outputs uint tV4 = Ty(OpTypeVector, tFloat, 4); uint pOutFloat = Ptr(ScOutput, tFloat); + uint fZero = Id(), fOne = Id(); + globals.Add(new Insn(OpConstant, new[] { tFloat, fZero, 0u })); + globals.Add(new Insn(OpConstant, new[] { tFloat, fOne, 0x3f800000u })); uint posVar = 0, sizeVar = 0; var generic = new Dictionary(); foreach (int a in m.Lines) @@ -343,6 +346,16 @@ static class MeshSpirv uint ptr = comp == uint.MaxValue ? Emit(OpAccessChain, pOutFloat, var, v) : Emit(OpAccessChain, pOutFloat, var, v, C(comp)); Do(OpStore, ptr, value); } + // A component of an output vector that the program's output map leaves out reads as Maxwell gives an + // unwritten one, (0, 0, 0, 1), instead of whatever the output held. + void Defaults(uint var, int first) + { + for (int k = 0; k < 4; k++) + if (!m.Lines.Contains(first + 4 * k)) + Do(OpStore, Emit(OpAccessChain, pOutFloat, var, v, C((uint)k)), k == 3 ? fOne : fZero); + } + if (posVar != 0) Defaults(posVar, 0x70); + foreach (var (g, var) in generic) Defaults(var, 0x80 + 16 * g); }); } for (int k = 0; k * threads < maxP; k++)