mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
50fda393a1
* handle_draw optimization 1. cache vtxSize 2. remove heap allocation from draw call merging index buffer 3. move things that aren't on the "draw call merging hot path" out to other functions, to reduce stack frame size of handle_draw (it was previously using __chkstk) * Make ByteBuffer expand exponentially Fix half a second of startup time being just that. * Babysit the compiler's inlining decisions * Merged draw call idxBuf now a global static * GXFlush() doesn't write NOPs to FIFO I'm sure this made sense on actual hardware * Don't bind unused textures/samplers * Remove C++ RAII types from build_bind_groups Most of this function's code was fucking with WebGPU AddRef and ReleaseRef. Seriously. * More refs in common.hpp * Index buffer in handle_draw_unmerged now not dynamically allocated for small draws * Fix gx_test_stubs.cpp * Some cleanup & renaming --------- Co-authored-by: Luke Street <luke@street.dev>
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;
|
|
}
|
|
};
|