#include "nw4r/g3d.h" // IWYU pragma: export // TODO: Naming enum TMemCachePlan { TMEM_CACHE_NONE, TMEM_CACHE_PLAN_0, TMEM_CACHE_PLAN_1, TMEM_CACHE_PLAN_2, TMEM_CACHE_MAX }; enum TexRegionID { TEX_REGION_DEFAULT, TEX_REGION_DEFAULT_MIPMAP, TEX_REGION_CI, TEX_REGION_CI_MIPMAP, TEX_REGION_RGBA8, TEX_REGION_RGBA8_MIPMAP, TEX_REGION_MAX }; struct TexRegionAddr { u32 addrDefaultEven[GX_MAX_TEXMAP]; // at 0x0 u32 addrDefaultMipMapEven[GX_MAX_TEXMAP]; // at 0x20 u32 addrDefaultMipMapOdd[GX_MAX_TEXMAP]; // at 0x40 u32 addrCiEven[GX_MAX_TEXMAP]; // at 0x60 u32 addrCiMipMapEven[GX_MAX_TEXMAP]; // at 0x80 u32 addrCiMipMapOdd[GX_MAX_TEXMAP]; // at 0xA0 u32 addrRgba8Even[GX_MAX_TEXMAP]; // at 0xC0 u32 addrRgba8Odd[GX_MAX_TEXMAP]; // at 0xE0 u32 addrRgba8MipMapEven[GX_MAX_TEXMAP]; // at 0x100 u32 addrRgba8MipMapOdd[GX_MAX_TEXMAP]; // at 0x120 }; struct TexRegionSize { u32 sizeDefaultEven[GX_MAX_TEXMAP]; // at 0x0 u32 sizeDefaultMipMapEven[GX_MAX_TEXMAP]; // at 0x20 u32 sizeDefaultMipMapOdd[GX_MAX_TEXMAP]; // at 0x40 u32 sizeCiEven[GX_MAX_TEXMAP]; // at 0x60 u32 sizeCiMipMapEven[GX_MAX_TEXMAP]; // at 0x80 u32 sizeCiMipMapOdd[GX_MAX_TEXMAP]; // at 0xA0 u32 sizeRgba8Even[GX_MAX_TEXMAP]; // at 0xC0 u32 sizeRgba8Odd[GX_MAX_TEXMAP]; // at 0xE0 u32 sizeRgba8MipMapEven[GX_MAX_TEXMAP]; // at 0x100 u32 sizeRgba8MipMapOdd[GX_MAX_TEXMAP]; // at 0x120 }; static GXTexRegion saaTexRegion[TEX_REGION_MAX][GX_MAX_TEXMAP]; static GXTlutRegion saaTlutRegion[GX_BIGTLUT3 + 1]; static TMemCachePlan sTMemCachePlan = TMEM_CACHE_NONE; static u32 sTlutRegionNum = 0; static GXTexRegionCallback sfpDefaultTexRegionCallback = NULL; static GXTlutRegionCallback sfpDefaultTlutRegionCallback = NULL; // clang-format off static const TexRegionAddr scaaaTexRegionAddr[TMEM_CACHE_MAX - 1] = { // TMEM_CACHE_PLAN_0 { {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x30000, 0x20000, 0x10000}, // addrDefaultEven {0x00000, 0xB0000, 0x50000, 0x90000, 0x70000, 0xB0000, 0x20000, 0x90000}, // addrDefaultMipMapEven {0x80000, 0x40000, 0xA0000, 0x60000, 0x80000, 0x30000, 0xA0000, 0x10000}, // addrDefaultMipMapOdd {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x30000, 0x20000, 0x10000}, // addrCiEven {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x30000, 0x20000, 0x10000}, // addrCiMipMapEven {0x20000, 0x48000, 0x58000, 0x68000, 0x78000, 0x38000, 0x28000, 0x18000}, // addrCiMipMapOdd {0x00000, 0xB0000, 0x50000, 0x90000, 0x70000, 0xB0000, 0x20000, 0x90000}, // addrRgba8Even {0x80000, 0x40000, 0xA0000, 0x60000, 0x80000, 0x30000, 0xA0000, 0x10000}, // addrRgba8Odd {0x00000, 0xB0000, 0x50000, 0x90000, 0x70000, 0xB0000, 0x20000, 0x90000}, // addrRgba8MipMapEven {0x80000, 0x40000, 0xA0000, 0x60000, 0x80000, 0x30000, 0xA0000, 0x10000}, // addrRgba8MipMapOdd }, // TMEM_CACHE_PLAN_1 { {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x78000, 0x68000, 0x58000}, // addrDefaultEven {0x00000, 0xC0000, 0x50000, 0xE0000, 0x70000, 0xD8000, 0x68000, 0xB8000}, // addrDefaultMipMapEven {0x80000, 0x40000, 0xA0000, 0x60000, 0x80000, 0x30000, 0xA0000, 0x10000}, // addrDefaultMipMapOdd {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x78000, 0x68000, 0x58000}, // addrCiEven {0x00000, 0x40000, 0x50000, 0x60000, 0x70000, 0x70000, 0x60000, 0x50000}, // addrCiMipMapEven {0x20000, 0x48000, 0x58000, 0x68000, 0x78000, 0x78000, 0x68000, 0x58000}, // addrCiMipMapOdd {0x00000, 0xC0000, 0x50000, 0xE0000, 0x70000, 0xD8000, 0x68000, 0xB8000}, // addrRgba8Even {0x80000, 0x40000, 0xD0000, 0x60000, 0xE8000, 0x78000, 0xC8000, 0x58000}, // addrRgba8Odd {0x00000, 0xC0000, 0x50000, 0xE0000, 0x70000, 0xD0000, 0x60000, 0xB0000}, // addrRgba8MipMapEven {0x80000, 0x40000, 0xD0000, 0x60000, 0xE0000, 0x70000, 0xC0000, 0x50000}, // addrRgba8MipMapOdd }, // TMEM_CACHE_PLAN_2 { {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrDefaultEven {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrDefaultMipMapEven {0x80000, 0xC0000, 0xC8000, 0xD0000, 0xD0000, 0xC8000, 0xC0000, 0xB0000}, // addrDefaultMipMapOdd {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrCiEven {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrCiMipMapEven {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrCiMipMapOdd {0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000}, // addrRgba8Even {0x80000, 0xC0000, 0xC8000, 0xD0000, 0xD0000, 0xC8000, 0xC0000, 0xB0000}, // addrRgba8Odd {0x00000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x40000, 0x00000}, // addrRgba8MipMapEven {0x80000, 0xC0000, 0xD0000, 0xE0000, 0xE0000, 0xD0000, 0xC0000, 0xB0000}, // addrRgba8MipMapOdd }, }; // clang-format on // clang-format off static const TexRegionSize scaaaTexRegionSize[TMEM_CACHE_MAX - 1] = { // TMEM_CACHE_PLAN_0 { {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultMipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultMipMapOdd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiMipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiMipMapOdd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8Even {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8Odd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8MipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8MipMapOdd }, // TMEM_CACHE_PLAN_1 { {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultMipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeDefaultMipMapOdd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiMipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeCiMipMapOdd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8Even {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8Odd {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8MipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8MipMapOdd }, // TMEM_CACHE_PLAN_2 { {2, 2, 2, 2, 2, 2, 2, 2}, // sizeDefaultEven {2, 2, 2, 2, 2, 2, 2, 2}, // sizeDefaultMipMapEven {1, 1, 1, 1, 1, 1, 0, 0}, // sizeDefaultMipMapOdd {2, 2, 2, 2, 2, 2, 2, 2}, // sizeCiEven {2, 2, 2, 2, 2, 2, 2, 2}, // sizeCiMipMapEven {1, 1, 1, 1, 1, 1, 0, 0}, // sizeCiMipMapOdd {2, 2, 2, 2, 2, 2, 2, 2}, // sizeRgba8Even {1, 1, 1, 1, 1, 1, 0, 0}, // sizeRgba8Odd {1, 1, 1, 1, 1, 1, 1, 1}, // sizeRgba8MipMapEven {1, 0, 0, 0, 0, 0, 0, 0}, // sizeRgba8MipMapOdd }, }; // clang-format on // Forward declarations static GXTexRegion *TexRegionCallback(const GXTexObj *pObj, GXTexMapID map); static GXTlutRegion *TlutRegionCallback(u32 id); static void setTexRegion_(TMemCachePlan plan) __attribute__((never_inline)); namespace nw4r { namespace g3d { namespace tmem { void SetTMemLayout(TMemLayout layout) { if (sfpDefaultTexRegionCallback == NULL) { // clang-format off sfpDefaultTexRegionCallback = GXSetTexRegionCallback(TexRegionCallback); GXSetTexRegionCallback(sfpDefaultTexRegionCallback); sfpDefaultTlutRegionCallback = GXSetTlutRegionCallback(TlutRegionCallback); GXSetTlutRegionCallback(sfpDefaultTlutRegionCallback); // clang-format on } if (sfpDefaultTexRegionCallback == NULL) { return; } sTMemCachePlan = static_cast(layout); setTexRegion_(sTMemCachePlan); switch (layout) { case TMEM_LAYOUT_NONE: case TMEM_LAYOUT_1: { GXSetTlutRegionCallback(sfpDefaultTlutRegionCallback); break; } case TMEM_LAYOUT_2: { int i; u32 num = 0; u32 addr; GXTlutRegion *pRegion = saaTlutRegion; for (i = 0, addr = 0xF0000; i < GX_MAX_TEXMAP; i++, pRegion++, num++, addr += 0x2000) { GXInitTlutRegion(pRegion, addr, 16); } sTlutRegionNum = num; GXSetTlutRegionCallback(TlutRegionCallback); break; } // TODO: Seems to imply no TMEM_LAYOUT_3 exists. Then why the [plan - 1]? default: { break; } } } } // namespace tmem } // namespace g3d } // namespace nw4r static GXTexRegion *TexRegionCallback(const GXTexObj *pObj, GXTexMapID map) { GXTexFmt fmt = GXGetTexObjFmt(pObj); GXBool mipmap = GXGetTexObjMipMap(pObj); switch (fmt) { case GX_TF_RGBA8: { return mipmap ? &saaTexRegion[TEX_REGION_RGBA8_MIPMAP][map] : &saaTexRegion[TEX_REGION_RGBA8][map]; } case GX_TF_C4: case GX_TF_C8: case GX_TF_C14X2: { return mipmap ? &saaTexRegion[TEX_REGION_CI_MIPMAP][map] : &saaTexRegion[TEX_REGION_CI][map]; } default: { return mipmap ? &saaTexRegion[TEX_REGION_DEFAULT_MIPMAP][map] : &saaTexRegion[TEX_REGION_DEFAULT][map]; } } } static GXTlutRegion *TlutRegionCallback(u32 id) { GXTlutRegion *pRegion = NULL; if (id < sTlutRegionNum) { pRegion = &saaTlutRegion[id]; } return pRegion; } static void setTexRegion_(TMemCachePlan plan) { if (plan == TMEM_CACHE_NONE) { GXSetTexRegionCallback(sfpDefaultTexRegionCallback); return; } for (int i = 0; i < GX_MAX_TEXMAP; i++) { // clang-format off GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_DEFAULT][i], FALSE, scaaaTexRegionAddr[plan - 1].addrDefaultEven[i], scaaaTexRegionSize[plan - 1].sizeDefaultEven[i], NULL, 3); GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_DEFAULT_MIPMAP][i], FALSE, scaaaTexRegionAddr[plan - 1].addrDefaultMipMapEven[i], scaaaTexRegionSize[plan - 1].sizeDefaultMipMapEven[i], scaaaTexRegionAddr[plan - 1].addrDefaultMipMapOdd[i], scaaaTexRegionSize[plan - 1].sizeDefaultMipMapOdd[i]); GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_CI][i], FALSE, scaaaTexRegionAddr[plan - 1].addrCiEven[i], scaaaTexRegionSize[plan - 1].sizeCiEven[i], NULL, 3); GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_CI_MIPMAP][i], FALSE, scaaaTexRegionAddr[plan - 1].addrCiMipMapEven[i], scaaaTexRegionSize[plan - 1].sizeCiMipMapEven[i], scaaaTexRegionAddr[plan - 1].addrCiMipMapOdd[i], scaaaTexRegionSize[plan - 1].sizeCiMipMapOdd[i]); GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_RGBA8][i], FALSE, scaaaTexRegionAddr[plan - 1].addrRgba8Even[i], scaaaTexRegionSize[plan - 1].sizeRgba8Even[i], scaaaTexRegionAddr[plan - 1].addrRgba8Odd[i], scaaaTexRegionSize[plan - 1].sizeRgba8Odd[i]); GXInitTexCacheRegion( &saaTexRegion[TEX_REGION_RGBA8_MIPMAP][i], FALSE, scaaaTexRegionAddr[plan - 1].addrRgba8MipMapEven[i], scaaaTexRegionSize[plan - 1].sizeRgba8MipMapEven[i], scaaaTexRegionAddr[plan - 1].addrRgba8MipMapOdd[i], scaaaTexRegionSize[plan - 1].sizeRgba8MipMapOdd[i]); // clang-format on } GXSetTexRegionCallback(TexRegionCallback); }