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.
This commit is contained in:
James Dansereau committed 2026-08-28 13:26:23 -04:00
1 parent 419a50a677
commit c18c8b8366
2 files changed
+27

No files matched your search

+22
View File
@@ -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;
}
+5
View File
@@ -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;