From c18c8b8366a4c8ca57281144144b669fe9ed9f65 Mon Sep 17 00:00:00 2001 From: James Dansereau <106631954+jkdansereau@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:25:38 -0400 Subject: [PATCH] D85: give the stage texture pool (ptr_texture_alloc_start) real storage The decomp declares ptr_texture_alloc_start as `struct texpool *` but no code ever dereferences it as a pointer -- every use takes its address and treats the storage itself as a `struct texpool` (texInitPool writes all four members through &ptr_texture_alloc_start; texLoad / texFindInPool read them back). On N64 the four members are 4 bytes each (16 total) and overlap the following split-out symbols (ptr_texture_alloc_end etc.); the layout happens to work. On x86-64 `struct texpool` is 32 bytes (four widened pointers), so texInitPool smashes 24 bytes past the 8-byte pointer global and, worse, reads of ->leftpos / ->rightpos (offsets 16 and 24) come back as unrelated BSS -- the stage texture pool then looks permanently exhausted (texFreeBytesInBuffer() < 0) the very first time texLoad() runs on the -level_09 path. Every room texLoad bails at its out-of-memory guard without adding to the pool, texFindInPool() returns NULL for every room texnum, and gfx_pc aborts with 'Bad size for RGBA texture in tile 0: 00'. Fix: under PORT, define ptr_texture_alloc_start as a real `struct texpool` (not a pointer). All call sites already do `&ptr_texture_alloc_start`, so they now get a correctly-typed `struct texpool *` and the N64 build is untouched. Verified: -level_09 stage texture pool now fills normally (no premature OOM), ~630 room textures resolve, and the 'Bad size for RGBA texture' FATAL is gone. Rendering now advances to a separate issue -- gfx_sp_matrix dereferencing an unrelocated N64 segment address (0x90000000) from a room GDL gsSPMatrix, the next D85 layer. Also renamed the D85 texLoad pool-full probe (GE_D85TEX) from 'OOM' since with this fix it now only fires on a genuinely full pool. --- src/game/image.c | 22 ++++++++++++++++++++++ src/game/image.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/src/game/image.c b/src/game/image.c index 1ff9c247..3dbe8736 100644 --- a/src/game/image.c +++ b/src/game/image.c @@ -12,7 +12,22 @@ // bss //8008C720 +#ifdef PORT +/* D85: the decomp declares this as `struct texpool *` (a 4-byte pointer on + * N64), but every use takes its address and treats the storage AS a + * `struct texpool` -- texInitPool(&ptr_texture_alloc_start, ...) writes all + * four members through it, and texLoad/texFindInPool read them back. On N64 + * `struct texpool` is 16 bytes and this "pointer" global only reserves 4, + * so it already relies on the linker leaving the next 12 bytes unused; on + * x86-64 the struct is 32 bytes (four widened pointers) and the write + * smashes 24 bytes of whatever BSS follows -- and reads of ->leftpos / + * ->rightpos (offsets 16, 24) come back as garbage, which is why the stage + * texture pool looks permanently exhausted (free < 0) on the -level_09 + * path. Give it real storage. */ +struct texpool ptr_texture_alloc_start; +#else struct texpool *ptr_texture_alloc_start; +#endif //8008C724 s32 ptr_texture_alloc_end; //8008C728 @@ -2448,6 +2463,13 @@ void texLoad(s32 *updateword, struct texpool *pool) // only other option is a crash. GBI commands contain texture IDs // instead of pointers, and they must be replaced with pointers. if ((!iszlib && (texFreeBytesInBuffer(pool) < 0x10CC)) || (iszlib && texFreeBytesInBuffer(pool) < 0xA28)) { +#if defined(PORT) + /* D85: env-gated -- a room rendering with placeholder textures + * usually means the stage pool filled up here. */ + if (getenv("GE_D85TEX")) + osSyncPrintf("D85TEX texLoad pool-full texnum=%d iszlib=%d free=%d\n", + (int)g_TexNumToLoad, (int)iszlib, (int)texFreeBytesInBuffer(pool)); +#endif *updateword = osVirtualToPhysical(pool->start); return; } diff --git a/src/game/image.h b/src/game/image.h index dbc8972b..5c7657c6 100644 --- a/src/game/image.h +++ b/src/game/image.h @@ -95,7 +95,12 @@ struct texcacheitem { }; extern struct texcacheitem g_TexCacheItems[]; +#ifdef PORT +/* D85: real storage, not a pointer -- see the definition in image.c. */ +extern struct texpool ptr_texture_alloc_start; +#else extern struct texpool *ptr_texture_alloc_start; +#endif extern struct image_entry g_Textures[]; extern s32 g_TexCacheCount; extern u32 bytes;