D95: double the -mgfx master-DL buffer on PC (16-byte Gfx vs N64 8-byte)

g_GfxSizesByPlayerCount / -mgfx is a BYTE budget sized for N64 8-byte Gfx
slots. On x86-64 a Gfx is 16 bytes, so the master display list needs 2x
the bytes for the same command count. Every render fn appends with a bare
'gdl++' and no bounds check, so once BUNKER1 emits real room geometry the
list overruns g_GfxBuffers[1]/[2], runs off the stage mempool, and faults
writing a GBI command at the end of the 8 MB emulated DRAM (0x70800000) --
non-deterministically, and corrupting room GDL blobs on the way (the
'unknown GBI opcode' / seg-9 0x90000000 faults were downstream of this).

Scale the gfx allocation by sizeof(Gfx)/8 under #ifdef PORT. Vtx/Mtx are
16/64 bytes on both targets so g_VtxBuffers is unchanged.

Verified: -level_09 runs 90 s+ (5000+ VI posts) with no crash where it
previously faulted within seconds. (Separate open issue: the kernel
heartbeat reports frames=0 -- render-loop completion needs a look.)
This commit is contained in:
James Dansereau committed 2026-08-28 16:04:37 -04:00
1 parent 83b7287f07
commit 6229d20a6d
1 file changed
+17
+17
View File
@@ -53,9 +53,26 @@ void dynInitMemory(void) {
g_VtxSizesByPlayerCount[getPlayerCount() - 1] = strtol(tokenFind(1, "-mvtx"), NULL, 0) * 1024;
}
#ifdef PORT
/* D95: the -mgfx budget (from boss.c's per-level memallocstringtable) is a
* byte count sized for N64 8-byte `Gfx` slots. On x86-64 a `Gfx` is 16
* bytes, so the same master display list needs 2x the bytes -- otherwise
* `gdl` (bumped with a bare `gdl++` by every render fn, no bounds check)
* marches past g_GfxBuffers[1]/[2], off the stage mempool, and eventually
* faults at the end of the 8 MB emulated DRAM (0x70800000) while writing a
* GBI command. Scale by sizeof(Gfx)/8. Vtx/Mtx are 16/64 bytes on both
* targets, so g_VtxBuffers is left alone. */
{
s32 gfxHalf = g_GfxSizesByPlayerCount[getPlayerCount() - 1] * ((s32)sizeof(Gfx) / 8);
g_GfxBuffers[0] = mempAllocBytesInBank(gfxHalf * 2, MEMPOOL_STAGE);
g_GfxBuffers[1] = (g_GfxBuffers[0] + gfxHalf);
g_GfxBuffers[2] = (g_GfxBuffers[1] + gfxHalf);
}
#else
g_GfxBuffers[0] = mempAllocBytesInBank(g_GfxSizesByPlayerCount[getPlayerCount() - 1] * 2, MEMPOOL_STAGE);
g_GfxBuffers[1] = (g_GfxBuffers[0] + g_GfxSizesByPlayerCount[getPlayerCount() - 1]);
g_GfxBuffers[2] = (g_GfxBuffers[1] + g_GfxSizesByPlayerCount[getPlayerCount() - 1]);
#endif
g_VtxBuffers[0] = mempAllocBytesInBank(g_VtxSizesByPlayerCount[getPlayerCount() - 1] * 2, MEMPOOL_STAGE);
g_VtxBuffers[1] = (g_VtxBuffers[0] + g_VtxSizesByPlayerCount[getPlayerCount() - 1]);