mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
b1bf531884
* FIFOify texture binding * Use __cntlzw helper * Some cleanup * Fix texture eviction & cleanup
503 lines
17 KiB
C++
503 lines
17 KiB
C++
#include "gx.hpp"
|
|
#include "__gx.h"
|
|
|
|
#include "../../gx/fifo.hpp"
|
|
|
|
#include <cstring>
|
|
|
|
// Global shadow register instance
|
|
static __GXData_struct sGXData;
|
|
__GXData_struct* __gx = &sGXData;
|
|
static GXFifoObj sFifoObj;
|
|
|
|
extern "C" {
|
|
static GXDrawDoneCallback DrawDoneCB = nullptr;
|
|
|
|
GXFifoObj* GXInit(void* base, u32 size) {
|
|
GXRenderModeObj* rmode;
|
|
f32 identity_mtx[3][4];
|
|
GXColor clear = {64, 64, 64, 255};
|
|
GXColor black = {0, 0, 0, 0};
|
|
GXColor white = {255, 255, 255, 255};
|
|
u32 i;
|
|
|
|
std::memset(&sGXData, 0, sizeof(sGXData));
|
|
__gx = &sGXData;
|
|
__gx->inDispList = 0;
|
|
__gx->dlSaveContext = 1;
|
|
__gx->tcsManEnab = 0;
|
|
__gx->vNum = 0;
|
|
|
|
// Initialize FIFO subsystem
|
|
aurora::gx::fifo::init();
|
|
GXInitFifoBase(&sFifoObj, base, size);
|
|
GXSetCPUFifo(&sFifoObj);
|
|
GXSetGPFifo(&sFifoObj);
|
|
|
|
// Initialize shadow registers: genMode, bpMask, lpSize
|
|
__gx->genMode = 0;
|
|
SET_REG_FIELD(0, __gx->genMode, 8, 24, 0x00);
|
|
__gx->bpMask = 0xFF;
|
|
SET_REG_FIELD(0, __gx->bpMask, 8, 24, 0x0F);
|
|
__gx->lpSize = 0;
|
|
SET_REG_FIELD(0, __gx->lpSize, 8, 24, 0x22);
|
|
|
|
// TEV / tref / ksel shadow registers
|
|
for (i = 0; i < 16; i++) {
|
|
__gx->tevc[i] = 0;
|
|
__gx->teva[i] = 0;
|
|
__gx->tref[i / 2] = 0;
|
|
__gx->texmapId[i] = GX_TEXMAP_NULL;
|
|
SET_REG_FIELD(0, __gx->tevc[i], 8, 24, 0xC0 + i * 2);
|
|
SET_REG_FIELD(0, __gx->teva[i], 8, 24, 0xC1 + i * 2);
|
|
SET_REG_FIELD(0, __gx->tevKsel[i / 2], 8, 24, 0xF6 + i / 2);
|
|
SET_REG_FIELD(0, __gx->tref[i / 2], 8, 24, 0x28 + i / 2);
|
|
}
|
|
|
|
// iref and SU texture scale registers
|
|
__gx->iref = 0;
|
|
SET_REG_FIELD(0, __gx->iref, 8, 24, 0x27);
|
|
for (i = 0; i < 8; i++) {
|
|
__gx->suTs0[i] = 0;
|
|
__gx->suTs1[i] = 0;
|
|
SET_REG_FIELD(0, __gx->suTs0[i], 8, 24, 0x30 + i * 2);
|
|
SET_REG_FIELD(0, __gx->suTs1[i], 8, 24, 0x31 + i * 2);
|
|
}
|
|
|
|
// Other BP command byte init
|
|
SET_REG_FIELD(0, __gx->suScis0, 8, 24, 0x20);
|
|
SET_REG_FIELD(0, __gx->suScis1, 8, 24, 0x21);
|
|
SET_REG_FIELD(0, __gx->cmode0, 8, 24, 0x41);
|
|
SET_REG_FIELD(0, __gx->cmode1, 8, 24, 0x42);
|
|
SET_REG_FIELD(0, __gx->zmode, 8, 24, 0x40);
|
|
SET_REG_FIELD(0, __gx->peCtrl, 8, 24, 0x43);
|
|
SET_REG_FIELD(0, __gx->IndTexScale0, 8, 24, 0x25);
|
|
SET_REG_FIELD(0, __gx->IndTexScale1, 8, 24, 0x26);
|
|
|
|
__gx->dirtyState = 0;
|
|
__gx->dirtyVAT = 0;
|
|
|
|
// VAT initialization: set default bits and write vatB to CP
|
|
for (i = 0; i < GX_MAX_VTXFMT; i++) {
|
|
SET_REG_FIELD(0, __gx->vatA[i], 1, 30, 1);
|
|
SET_REG_FIELD(0, __gx->vatB[i], 1, 31, 1);
|
|
GX_WRITE_U8(8);
|
|
GX_WRITE_U8(i | 0x80);
|
|
GX_WRITE_U32(__gx->vatB[i]);
|
|
}
|
|
|
|
// XF register init: error/mode control + dual-tex transform
|
|
{
|
|
u32 reg1 = 0;
|
|
u32 reg2 = 0;
|
|
SET_REG_FIELD(0, reg1, 1, 0, 1);
|
|
SET_REG_FIELD(0, reg1, 1, 1, 1);
|
|
SET_REG_FIELD(0, reg1, 1, 2, 1);
|
|
SET_REG_FIELD(0, reg1, 1, 3, 1);
|
|
SET_REG_FIELD(0, reg1, 1, 4, 1);
|
|
SET_REG_FIELD(0, reg1, 1, 5, 1);
|
|
GX_WRITE_XF_REG(0, reg1);
|
|
SET_REG_FIELD(0, reg2, 1, 0, 1);
|
|
GX_WRITE_XF_REG(0x12, reg2);
|
|
}
|
|
|
|
// BP 0x58 register init
|
|
{
|
|
u32 reg = 0;
|
|
SET_REG_FIELD(0, reg, 1, 0, 1);
|
|
SET_REG_FIELD(0, reg, 1, 1, 1);
|
|
SET_REG_FIELD(0, reg, 1, 2, 1);
|
|
SET_REG_FIELD(0, reg, 1, 3, 1);
|
|
SET_REG_FIELD(0, reg, 8, 24, 0x58);
|
|
GX_WRITE_RAS_REG(reg);
|
|
}
|
|
|
|
// Default render mode (NTSC)
|
|
rmode = &GXNtsc480IntDf;
|
|
|
|
// Default state initialization via API calls
|
|
GXSetCopyClear(clear, 0xFFFFFF);
|
|
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, 0x3C);
|
|
GXSetTexCoordGen(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, 0x3C);
|
|
GXSetNumTexGens(1);
|
|
GXClearVtxDesc();
|
|
GXInvalidateVtxCache();
|
|
GXSetLineWidth(6, GX_TO_ZERO);
|
|
GXSetPointSize(6, GX_TO_ZERO);
|
|
GXEnableTexOffsets(GX_TEXCOORD0, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD1, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD2, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD3, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD4, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD5, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD6, GX_DISABLE, GX_DISABLE);
|
|
GXEnableTexOffsets(GX_TEXCOORD7, GX_DISABLE, GX_DISABLE);
|
|
|
|
// Identity matrix
|
|
identity_mtx[0][0] = 1.0f;
|
|
identity_mtx[0][1] = 0.0f;
|
|
identity_mtx[0][2] = 0.0f;
|
|
identity_mtx[0][3] = 0.0f;
|
|
identity_mtx[1][0] = 0.0f;
|
|
identity_mtx[1][1] = 1.0f;
|
|
identity_mtx[1][2] = 0.0f;
|
|
identity_mtx[1][3] = 0.0f;
|
|
identity_mtx[2][0] = 0.0f;
|
|
identity_mtx[2][1] = 0.0f;
|
|
identity_mtx[2][2] = 1.0f;
|
|
identity_mtx[2][3] = 0.0f;
|
|
GXLoadPosMtxImm(identity_mtx, GX_PNMTX0);
|
|
GXLoadNrmMtxImm(identity_mtx, GX_PNMTX0);
|
|
GXSetCurrentMtx(GX_PNMTX0);
|
|
GXLoadTexMtxImm(identity_mtx, GX_IDENTITY, GX_MTX3x4);
|
|
GXLoadTexMtxImm(identity_mtx, GX_PTIDENTITY, GX_MTX3x4);
|
|
|
|
GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f);
|
|
GXSetCoPlanar(GX_DISABLE);
|
|
GXSetCullMode(GX_CULL_BACK);
|
|
GXSetClipMode(GX_CLIP_ENABLE);
|
|
GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
// GXSetScissorBoxOffset(0, 0);
|
|
|
|
GXSetNumChans(0);
|
|
GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
|
|
GXSetChanAmbColor(GX_COLOR0A0, black);
|
|
GXSetChanMatColor(GX_COLOR0A0, white);
|
|
GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
|
|
GXSetChanAmbColor(GX_COLOR1A1, black);
|
|
GXSetChanMatColor(GX_COLOR1A1, white);
|
|
|
|
GXInvalidateTexAll();
|
|
// __gx->nextTexRgn = 0;
|
|
// for (i = 0; i < 8; i++)
|
|
// GXInitTexCacheRegion(&__gx->TexRegions[i], 0, i * 0x8000, 0, 0x80000 + i * 0x8000, 0);
|
|
// __gx->nextTexRgnCI = 0;
|
|
// for (i = 0; i < 4; i++)
|
|
// GXInitTexCacheRegion(&__gx->TexRegionsCI[i], 0, (i * 2 + 8) * 0x8000, 0, (i * 2 + 9) * 0x8000, 0);
|
|
// for (i = 0; i < 16; i++)
|
|
// GXInitTlutRegion(&__gx->TlutRegions[i], 0xC0000 + i * 0x2000, 16);
|
|
// for (i = 0; i < 4; i++)
|
|
// GXInitTlutRegion(&__gx->TlutRegions[i + 16], 0xE0000 + i * 0x8000, 64);
|
|
// GXSetTexRegionCallback(__GXDefaultTexRegionCallback);
|
|
// GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback);
|
|
|
|
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD2, GX_TEXMAP2, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD3, GX_TEXMAP3, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD4, GX_TEXMAP4, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD5, GX_TEXMAP5, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD6, GX_TEXMAP6, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD7, GX_TEXMAP7, GX_COLOR0A0);
|
|
GXSetTevOrder(GX_TEVSTAGE8, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE9, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE10, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE11, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE12, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE13, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE14, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
GXSetTevOrder(GX_TEVSTAGE15, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
|
|
GXSetNumTevStages(1);
|
|
GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
|
|
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
|
GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0);
|
|
|
|
for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++) {
|
|
GXSetTevKColorSel(static_cast<GXTevStageID>(i), GX_TEV_KCSEL_1_4);
|
|
GXSetTevKAlphaSel(static_cast<GXTevStageID>(i), GX_TEV_KASEL_1);
|
|
GXSetTevSwapMode(static_cast<GXTevStageID>(i), GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
}
|
|
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
|
|
GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA);
|
|
GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA);
|
|
GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA);
|
|
|
|
for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++)
|
|
GXSetTevDirect(static_cast<GXTevStageID>(i));
|
|
GXSetNumIndStages(0);
|
|
GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1);
|
|
GXSetIndTexCoordScale(GX_INDTEXSTAGE1, GX_ITS_1, GX_ITS_1);
|
|
GXSetIndTexCoordScale(GX_INDTEXSTAGE2, GX_ITS_1, GX_ITS_1);
|
|
GXSetIndTexCoordScale(GX_INDTEXSTAGE3, GX_ITS_1, GX_ITS_1);
|
|
|
|
GXSetFog(GX_FOG_NONE, 0.0f, 1.0f, 0.1f, 1.0f, black);
|
|
GXSetFogRangeAdj(GX_DISABLE, 0, nullptr);
|
|
GXSetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
GXSetColorUpdate(GX_ENABLE);
|
|
GXSetAlphaUpdate(GX_ENABLE);
|
|
GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
|
|
GXSetZCompLoc(GX_TRUE);
|
|
GXSetDither(GX_ENABLE);
|
|
GXSetDstAlpha(GX_DISABLE, 0);
|
|
GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
GXSetFieldMask(GX_ENABLE, GX_ENABLE);
|
|
GXSetFieldMode(rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
|
|
|
|
GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GXSetDispCopyDst(rmode->fbWidth, rmode->efbHeight);
|
|
GXSetDispCopyYScale(static_cast<f32>(rmode->xfbHeight) / static_cast<f32>(rmode->efbHeight));
|
|
// GXSetCopyClamp(static_cast<GXFBClamp>(GX_CLAMP_TOP | GX_CLAMP_BOTTOM));
|
|
GXSetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
GXSetDispCopyGamma(GX_GM_1_0);
|
|
// GXSetDispCopyFrame2Field(GX_COPY_PROGRESSIVE);
|
|
// GXClearBoundingBox();
|
|
|
|
// GXPokeColorUpdate(GX_TRUE);
|
|
// GXPokeAlphaUpdate(GX_TRUE);
|
|
// GXPokeDither(GX_FALSE);
|
|
// GXPokeBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ONE, GX_LO_SET);
|
|
// GXPokeAlphaMode(GX_ALWAYS, 0);
|
|
// GXPokeAlphaRead(GX_READ_FF);
|
|
// GXPokeDstAlpha(GX_DISABLE, 0);
|
|
// GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE);
|
|
|
|
return &sFifoObj;
|
|
}
|
|
|
|
void GXDrawDone() {
|
|
if (DrawDoneCB != nullptr)
|
|
DrawDoneCB();
|
|
}
|
|
|
|
void GXSetDrawDone() {
|
|
if (DrawDoneCB != nullptr)
|
|
DrawDoneCB();
|
|
}
|
|
|
|
GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb) {
|
|
GXDrawDoneCallback old = DrawDoneCB;
|
|
DrawDoneCB = cb;
|
|
return old;
|
|
}
|
|
|
|
void GXFlush() {
|
|
if (__gx->dirtyState) {
|
|
__GXSetDirtyState();
|
|
}
|
|
}
|
|
|
|
void GXPixModeSync() {
|
|
GX_WRITE_RAS_REG(__gx->peCtrl);
|
|
__gx->bpSent = 1;
|
|
}
|
|
|
|
void GXTexModeSync() {
|
|
GX_WRITE_RAS_REG(0x63000000);
|
|
__gx->bpSent = 1;
|
|
}
|
|
|
|
// Dirty state flush functions
|
|
|
|
void __GXSetDirtyState() {
|
|
if (__gx->dirtyState & 1) {
|
|
__GXSetSUTexRegs();
|
|
}
|
|
if (__gx->dirtyState & 2) {
|
|
__GXUpdateBPMask();
|
|
}
|
|
if (__gx->dirtyState & 4) {
|
|
__GXSetGenMode();
|
|
}
|
|
if (__gx->dirtyState & 8) {
|
|
__GXSetVCD();
|
|
}
|
|
if (__gx->dirtyState & 0x10) {
|
|
__GXSetVAT();
|
|
}
|
|
__gx->dirtyState = 0;
|
|
}
|
|
|
|
void __GXSetGenMode() {
|
|
GX_WRITE_RAS_REG(__gx->genMode);
|
|
__gx->bpSent = 1;
|
|
}
|
|
|
|
void __GXSendFlushPrim() {
|
|
// Originally, this writes a dummy triangle strip draw to force the GP
|
|
// to process the FIFO up to this point, flushing pending BP register changes.
|
|
// We can skip the FIFO writes and just clear the bpSent flag.
|
|
|
|
// GX_WRITE_U8(0x98);
|
|
// GX_WRITE_U16(__gx->vNum);
|
|
// for (u32 i = 0; i < __gx->vNum * __gx->vLim; i += 4) {
|
|
// GX_WRITE_U32(0);
|
|
// }
|
|
|
|
__gx->bpSent = 0;
|
|
}
|
|
|
|
void __GXSetVCD() {
|
|
// Write VCD lo and hi to CP registers
|
|
GX_WRITE_SOME_REG4(8, 0x50, __gx->vcdLo, -12);
|
|
GX_WRITE_SOME_REG4(8, 0x60, __gx->vcdHi, -12);
|
|
|
|
// Write XF vertex specs
|
|
u32 nCols = 0;
|
|
nCols = GET_REG_FIELD(__gx->vcdLo, 2, 13) ? 1 : 0;
|
|
nCols += GET_REG_FIELD(__gx->vcdLo, 2, 15) ? 1 : 0;
|
|
u32 nNrm = __gx->hasBiNrms ? 2 : __gx->hasNrms ? 1 : 0;
|
|
u32 nTex = 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 0) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 2) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 4) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 6) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 8) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 10) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 12) ? 1 : 0;
|
|
nTex += GET_REG_FIELD(__gx->vcdHi, 2, 14) ? 1 : 0;
|
|
u32 reg = (nCols) | (nNrm << 2) | (nTex << 4);
|
|
GX_WRITE_XF_REG(8, reg);
|
|
__gx->bpSent = 0;
|
|
|
|
// Calculate vertex data limit for flush prim
|
|
if (__gx->vNum != 0) {
|
|
static u8 tbl1[] = {0, 4, 1, 2};
|
|
static u8 tbl2[] = {0, 8, 1, 2};
|
|
static u8 tbl3[] = {0, 12, 1, 2};
|
|
|
|
u32 vl = __gx->vcdLo;
|
|
u32 vh = __gx->vcdHi;
|
|
u32 vlm = 0;
|
|
vlm = GET_REG_FIELD(vl, 1, 0);
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 1));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 2));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 3));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 4));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 5));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 6));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 7));
|
|
vlm += static_cast<u8>(GET_REG_FIELD(vl, 1, 8));
|
|
vlm += tbl3[static_cast<u8>(GET_REG_FIELD(vl, 2, 9))];
|
|
u32 b = (__gx->hasBiNrms << 1) + 1;
|
|
vlm += tbl3[static_cast<u8>(GET_REG_FIELD(vl, 2, 11))] * b;
|
|
vlm += tbl1[static_cast<u8>(GET_REG_FIELD(vl, 2, 13))];
|
|
vlm += tbl1[static_cast<u8>(GET_REG_FIELD(vl, 2, 15))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 0))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 2))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 4))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 6))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 8))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 10))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 12))];
|
|
vlm += tbl2[static_cast<u8>(GET_REG_FIELD(vh, 2, 14))];
|
|
__gx->vLim = vlm;
|
|
}
|
|
}
|
|
|
|
void __GXSetVAT() {
|
|
for (u8 i = 0; i < 8; i++) {
|
|
if (__gx->dirtyVAT & (1 << i)) {
|
|
GX_WRITE_SOME_REG4(8, i | 0x70, __gx->vatA[i], i - 12);
|
|
GX_WRITE_SOME_REG4(8, i | 0x80, __gx->vatB[i], i - 12);
|
|
GX_WRITE_SOME_REG4(8, i | 0x90, __gx->vatC[i], i - 12);
|
|
}
|
|
}
|
|
__gx->dirtyVAT = 0;
|
|
}
|
|
|
|
static void __SetSURegs(u32 tmap, u32 tcoord) {
|
|
// Copy texture dimensions from tImage0 to SU registers
|
|
u32 w = GET_REG_FIELD(__gx->tImage0[tmap], 10, 0);
|
|
u32 h = GET_REG_FIELD(__gx->tImage0[tmap], 10, 10);
|
|
SET_REG_FIELD(0, __gx->suTs0[tcoord], 16, 0, w);
|
|
SET_REG_FIELD(0, __gx->suTs1[tcoord], 16, 0, h);
|
|
// Bias from wrap mode
|
|
u8 s_bias = GET_REG_FIELD(__gx->tMode0[tmap], 2, 0) == 1;
|
|
u8 t_bias = GET_REG_FIELD(__gx->tMode0[tmap], 2, 2) == 1;
|
|
SET_REG_FIELD(0, __gx->suTs0[tcoord], 1, 16, s_bias);
|
|
SET_REG_FIELD(0, __gx->suTs1[tcoord], 1, 16, t_bias);
|
|
GX_WRITE_RAS_REG(__gx->suTs0[tcoord]);
|
|
GX_WRITE_RAS_REG(__gx->suTs1[tcoord]);
|
|
__gx->bpSent = 1;
|
|
}
|
|
|
|
void __GXSetSUTexRegs() {
|
|
// Write SU texture size/bias registers for each active TEV stage and indirect stage.
|
|
// Skip coords that have manual scale enabled (tcsManEnab bit set).
|
|
// If all coords are manual (0xFF), skip entirely.
|
|
if (__gx->tcsManEnab == 0xFF) {
|
|
return;
|
|
}
|
|
|
|
u32 nStages = GET_REG_FIELD(__gx->genMode, 4, 10) + 1;
|
|
u32 nIndStages = GET_REG_FIELD(__gx->genMode, 3, 16);
|
|
|
|
// Indirect texture stages
|
|
for (u32 i = 0; i < nIndStages; i++) {
|
|
u32 tmap, coord;
|
|
switch (i) {
|
|
case 0:
|
|
tmap = GET_REG_FIELD(__gx->iref, 3, 0);
|
|
coord = GET_REG_FIELD(__gx->iref, 3, 3);
|
|
break;
|
|
case 1:
|
|
tmap = GET_REG_FIELD(__gx->iref, 3, 6);
|
|
coord = GET_REG_FIELD(__gx->iref, 3, 9);
|
|
break;
|
|
case 2:
|
|
tmap = GET_REG_FIELD(__gx->iref, 3, 12);
|
|
coord = GET_REG_FIELD(__gx->iref, 3, 15);
|
|
break;
|
|
default:
|
|
tmap = GET_REG_FIELD(__gx->iref, 3, 18);
|
|
coord = GET_REG_FIELD(__gx->iref, 3, 21);
|
|
break;
|
|
}
|
|
if (!(__gx->tcsManEnab & (1 << coord))) {
|
|
__SetSURegs(tmap, coord);
|
|
}
|
|
}
|
|
|
|
// Direct TEV stages
|
|
for (u32 i = 0; i < nStages; i++) {
|
|
u32* ptref = &__gx->tref[i / 2];
|
|
u32 map = __gx->texmapId[i];
|
|
u32 tmap = map & ~0x100u;
|
|
u32 coord;
|
|
if (i & 1) {
|
|
coord = GET_REG_FIELD(*ptref, 3, 15);
|
|
} else {
|
|
coord = GET_REG_FIELD(*ptref, 3, 3);
|
|
}
|
|
if (tmap != 0xFF && !(__gx->tcsManEnab & (1 << coord))) {
|
|
__SetSURegs(tmap, coord);
|
|
}
|
|
}
|
|
}
|
|
|
|
void __GXUpdateBPMask() {
|
|
// Mark texture maps used by indirect texture stages in the BP mask
|
|
u32 nIndStages = GET_REG_FIELD(__gx->genMode, 3, 16);
|
|
u32 newImask = 0;
|
|
|
|
for (u32 i = 0; i < nIndStages; i++) {
|
|
u32 tmap = GET_REG_FIELD(__gx->iref, 3, i * 6);
|
|
newImask |= 1u << tmap;
|
|
}
|
|
|
|
if (static_cast<u8>(__gx->bpMask) != static_cast<u8>(newImask)) {
|
|
SET_REG_FIELD(0, __gx->bpMask, 8, 0, newImask);
|
|
GX_WRITE_RAS_REG(__gx->bpMask);
|
|
__gx->bpSent = 1;
|
|
}
|
|
}
|
|
|
|
void __GXSetMatrixIndex(GXAttr matIdxAttr) {
|
|
if (matIdxAttr < GX_VA_TEX4MTXIDX) {
|
|
GX_WRITE_SOME_REG4(8, 0x30, __gx->matIdxA, -12);
|
|
GX_WRITE_XF_REG(24, __gx->matIdxA);
|
|
} else {
|
|
GX_WRITE_SOME_REG4(8, 0x40, __gx->matIdxB, -12);
|
|
GX_WRITE_XF_REG(25, __gx->matIdxB);
|
|
}
|
|
__gx->bpSent = 0;
|
|
}
|
|
};
|