mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Give NVN2 compute programs the local memory their control section asks for, and put spills after it.
An NVN2 compute program's control section gives its local memory in bytes a thread at +0x68, beside the shared memory size at +0x64 that the job already carried. Without it the translator declared its default of 0x1000 bytes: one of the game's compute programs needs 4,752 bytes a thread, and its translation declared a 1,024-word local array that it indexed up to word 1,187, outside the array. The job now carries "local_mem" from +0x68, and the lowering starts a compute program's spill area after its own local memory (at least 0x1000 bytes) instead of always at 0x1000, where a larger program's own memory would have overlapped it. Checked: that program's translation now declares 1,188 words (indices up to 1,187) and passes spirv-val; two programs of 3,456 bytes a thread translate as before. All 266 compute programs whose stored input id starts with 0 in an installed shader cache translate and pass spirv-val (vulkan1.3), and tools/xlate_smoke.py passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1527,6 +1527,11 @@ static size_t build_request(char *o0, const char *hex, const char *stage, const
|
||||
memcpy(&magic0, control, 4);
|
||||
if (!shared && magic0 == 0x98761234u && !strcmp(stage, "cs")) memcpy(&shared, control + 0x64, 4);
|
||||
o += sprintf(o, "},\"shared\":%u", shared);
|
||||
// Their local memory, bytes a thread, follows at +0x68. Without it the translator declares its 0x1000-byte
|
||||
// default: one compute program of the game needs 4,752 bytes a thread and indexed past the end of its array.
|
||||
uint32_t local = 0;
|
||||
if (magic0 == 0x98761234u && !strcmp(stage, "cs")) memcpy(&local, control + 0x68, 4);
|
||||
if (local && local <= (1u << 20)) o += sprintf(o, ",\"local_mem\":%u", local);
|
||||
}
|
||||
if (!strcmp(stage, "cs")) {
|
||||
uint32_t l[3] = {1, 1, 1};
|
||||
|
||||
@@ -2536,7 +2536,10 @@ static class AmpereLowering
|
||||
// localBytes: the local memory size the lowered program needs when that changed (spill mode), else 0. Graphics
|
||||
// programs carry it in their header already; compute and task/mesh programs need it from the translator's host
|
||||
// (job "local_mem").
|
||||
public static byte[] Lower(byte[] code, int size, bool graphics, out int localBytes, int[] table = null, MeshInfo mesh = null)
|
||||
// computeLocal: a compute program's own local memory in bytes, where its spill area starts (0: the translator's
|
||||
// compute default of 0x1000).
|
||||
public static byte[] Lower(byte[] code, int size, bool graphics, out int localBytes, int[] table = null, MeshInfo mesh = null,
|
||||
int computeLocal = 0)
|
||||
{
|
||||
localBytes = 0;
|
||||
int header = graphics || mesh != null ? 0x80 : 0;
|
||||
@@ -2555,9 +2558,9 @@ static class AmpereLowering
|
||||
try { lowered = new Lowerer(insns, sph, !graphics, table, mesh) { C1 = C1Bytes }.Run(out branches, out first); }
|
||||
catch (RegisterPressureException)
|
||||
{
|
||||
// Local memory after the program's own: the header's sizes (translator: low + high + CRS / 32), or the
|
||||
// translator's compute default (0x1000) for compute programs.
|
||||
spillAt = 0x1000;
|
||||
// Local memory after the program's own: the header's sizes (translator: low + high + CRS / 32), or for a
|
||||
// compute program its own size (computeLocal), the translator's compute default (0x1000) when not given.
|
||||
spillAt = computeLocal > 0 ? computeLocal : 0x1000;
|
||||
if (header != 0)
|
||||
spillAt = ((int)(BitConverter.ToUInt32(code, 4) & 0xffffff) + (int)(BitConverter.ToUInt32(code, 8) & 0xffffff)
|
||||
+ (int)(BitConverter.ToUInt32(code, 12) & 0xffffff) / 32 + 15) & ~15;
|
||||
|
||||
@@ -199,8 +199,13 @@ static class SwshXlate
|
||||
}
|
||||
else
|
||||
{
|
||||
code = AmpereLowering.Lower(code, size, (string)job["stage"] != "cs", out int local, table);
|
||||
// A compute program's own local memory: "local_mem" from its control section, at least the
|
||||
// translator's default of 0x1000 bytes; the lowering's spill area goes after it.
|
||||
bool cs = (string)job["stage"] == "cs";
|
||||
int own = cs ? (Math.Max(job["local_mem"] is JsonNode lm ? (int)lm : 0, 0x1000) + 15) & ~15 : 0;
|
||||
code = AmpereLowering.Lower(code, size, !cs, out int local, table, null, own);
|
||||
if (local != 0) job["local_mem"] = local;
|
||||
else if (cs) job["local_mem"] = own;
|
||||
}
|
||||
if (job["lowered_out"] is JsonNode lo) File.WriteAllBytes((string)lo, code);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user