Files

246 lines
8.5 KiB
C++
Raw Permalink Normal View History

2022-07-27 11:25:25 -04:00
#include "gx.hpp"
2026-02-17 17:35:13 -07:00
#include "__gx.h"
2022-07-27 11:25:25 -04:00
extern "C" {
2022-07-27 11:25:25 -04:00
void GXSetTevOp(GXTevStageID id, GXTevMode mode) {
GXTevColorArg inputColor = GX_CC_RASC;
GXTevAlphaArg inputAlpha = GX_CA_RASA;
if (id != GX_TEVSTAGE0) {
inputColor = GX_CC_CPREV;
inputAlpha = GX_CA_APREV;
}
switch (mode) {
case GX_MODULATE:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_TEXC, inputColor, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, inputAlpha, GX_CA_ZERO);
break;
case GX_DECAL:
GXSetTevColorIn(id, inputColor, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, inputAlpha);
break;
case GX_BLEND:
GXSetTevColorIn(id, inputColor, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, inputAlpha, GX_CA_ZERO);
break;
case GX_REPLACE:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
break;
case GX_PASSCLR:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, inputColor);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, inputAlpha);
break;
}
GXSetTevColorOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
void GXSetTevColorIn(GXTevStageID stageId, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) {
2026-02-17 17:35:13 -07:00
u32* reg = &__gx->tevc[stageId];
SET_REG_FIELD(0, *reg, 4, 12, a);
SET_REG_FIELD(0, *reg, 4, 8, b);
SET_REG_FIELD(0, *reg, 4, 4, c);
SET_REG_FIELD(0, *reg, 4, 0, d);
GX_WRITE_RAS_REG(*reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevAlphaIn(GXTevStageID stageId, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d) {
2026-02-17 17:35:13 -07:00
u32* reg = &__gx->teva[stageId];
SET_REG_FIELD(0, *reg, 3, 13, a);
SET_REG_FIELD(0, *reg, 3, 10, b);
SET_REG_FIELD(0, *reg, 3, 7, c);
SET_REG_FIELD(0, *reg, 3, 4, d);
GX_WRITE_RAS_REG(*reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevColorOp(GXTevStageID stageId, GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp,
GXTevRegID outReg) {
2026-02-17 17:35:13 -07:00
u32* reg = &__gx->tevc[stageId];
SET_REG_FIELD(0, *reg, 1, 18, op & 1);
if (op <= 1) {
SET_REG_FIELD(0, *reg, 2, 20, scale);
SET_REG_FIELD(0, *reg, 2, 16, bias);
} else {
SET_REG_FIELD(0, *reg, 2, 20, (op >> 1) & 3);
SET_REG_FIELD(0, *reg, 2, 16, 3);
}
SET_REG_FIELD(0, *reg, 1, 19, clamp);
SET_REG_FIELD(0, *reg, 2, 22, outReg);
GX_WRITE_RAS_REG(*reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevAlphaOp(GXTevStageID stageId, GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp,
GXTevRegID outReg) {
2026-02-17 17:35:13 -07:00
u32* reg = &__gx->teva[stageId];
SET_REG_FIELD(0, *reg, 1, 18, op & 1);
if (op <= 1) {
SET_REG_FIELD(0, *reg, 2, 20, scale);
SET_REG_FIELD(0, *reg, 2, 16, bias);
} else {
SET_REG_FIELD(0, *reg, 2, 20, (op >> 1) & 3);
SET_REG_FIELD(0, *reg, 2, 16, 3);
}
SET_REG_FIELD(0, *reg, 1, 19, clamp);
SET_REG_FIELD(0, *reg, 2, 22, outReg);
GX_WRITE_RAS_REG(*reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevColor(GXTevRegID id, GXColor color) {
2022-08-09 02:05:33 -04:00
CHECK(id >= GX_TEVPREV && id < GX_MAX_TEVREG, "bad tevreg {}", static_cast<int>(id));
2026-02-17 17:35:13 -07:00
// Write BP registers (RA + BG pairs) - needed for display list capture
u32 regRA = 0;
SET_REG_FIELD(0, regRA, 11, 0, color.r);
SET_REG_FIELD(0, regRA, 11, 12, color.a);
SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2);
u32 regBG = 0;
SET_REG_FIELD(0, regBG, 11, 0, color.b);
SET_REG_FIELD(0, regBG, 11, 12, color.g);
SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
2026-02-17 20:44:09 -07:00
// NOTE: The SDK writes regBG three additional times here for hardware timing.
// We omit the redundant writes since they don't change the register value and
// our software command processor doesn't need the sync delay.
2026-02-17 17:35:13 -07:00
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevColorS10(GXTevRegID id, GXColorS10 color) {
2026-02-17 17:35:13 -07:00
// Write BP registers (RA + BG pairs) - needed for display list capture
u32 regRA = 0;
SET_REG_FIELD(0, regRA, 11, 0, color.r & 0x7FF);
SET_REG_FIELD(0, regRA, 11, 12, color.a & 0x7FF);
SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2);
u32 regBG = 0;
SET_REG_FIELD(0, regBG, 11, 0, color.b & 0x7FF);
SET_REG_FIELD(0, regBG, 11, 12, color.g & 0x7FF);
SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
2026-02-17 20:44:09 -07:00
// NOTE: The SDK writes regBG three additional times here for hardware timing.
// We omit the redundant writes since they don't change the register value and
// our software command processor doesn't need the sync delay.
2026-02-17 17:35:13 -07:00
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) {
2026-02-17 17:35:13 -07:00
// BP register 0xF3
u32 reg = 0;
SET_REG_FIELD(0, reg, 8, 0, ref0);
2026-02-17 20:44:09 -07:00
SET_REG_FIELD(0, reg, 8, 8, ref1);
SET_REG_FIELD(0, reg, 3, 16, comp0);
SET_REG_FIELD(0, reg, 3, 19, comp1);
SET_REG_FIELD(0, reg, 2, 22, op);
2026-02-17 17:35:13 -07:00
SET_REG_FIELD(0, reg, 8, 24, 0xF3);
GX_WRITE_RAS_REG(reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevOrder(GXTevStageID id, GXTexCoordID tcid, GXTexMapID tmid, GXChannelID cid) {
2026-02-17 17:35:13 -07:00
// Channel ID mapping to hardware register values
static const u8 c2r[] = {0, 1, 0, 1, 0, 1, 7, 5, 6};
u32* ptref = &__gx->tref[id / 2];
__gx->texmapId[id] = tmid;
u32 tmap = tmid & ~0x100u;
tmap = (tmap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tmap;
u32 tcoord = (tcid >= GX_MAX_TEXCOORD) ? GX_TEXCOORD0 : tcid;
2026-02-18 20:09:48 -07:00
u32 chanHw = (cid == GX_COLOR_NULL) ? 7 : c2r[cid];
2026-02-17 17:35:13 -07:00
if (id & 1) {
SET_REG_FIELD(0, *ptref, 3, 12, tmap);
SET_REG_FIELD(0, *ptref, 3, 15, tcoord);
2026-02-18 20:09:48 -07:00
SET_REG_FIELD(0, *ptref, 3, 19, chanHw);
2026-02-17 17:35:13 -07:00
SET_REG_FIELD(0, *ptref, 1, 18, (tmid != GX_TEXMAP_NULL && !(tmid & 0x100)));
} else {
SET_REG_FIELD(0, *ptref, 3, 0, tmap);
SET_REG_FIELD(0, *ptref, 3, 3, tcoord);
2026-02-18 20:09:48 -07:00
SET_REG_FIELD(0, *ptref, 3, 7, chanHw);
2026-02-17 17:35:13 -07:00
SET_REG_FIELD(0, *ptref, 1, 6, (tmid != GX_TEXMAP_NULL && !(tmid & 0x100)));
}
GX_WRITE_RAS_REG(*ptref);
__gx->bpSent = 1;
__gx->dirtyState |= 1; // SU tex regs dirty
2022-07-27 11:25:25 -04:00
}
2025-04-18 21:52:38 -06:00
void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) {
// TODO
}
2022-07-27 11:25:25 -04:00
2026-02-17 17:35:13 -07:00
void GXSetNumTevStages(u8 num) {
SET_REG_FIELD(0, __gx->genMode, 4, 10, num - 1);
__gx->dirtyState |= 4; // gen mode dirty
}
2022-07-27 11:25:25 -04:00
void GXSetTevKColor(GXTevKColorID id, GXColor color) {
2022-08-09 02:05:33 -04:00
CHECK(id >= GX_KCOLOR0 && id < GX_MAX_KCOLOR, "bad kcolor {}", static_cast<int>(id));
2026-02-17 17:35:13 -07:00
2026-02-17 23:41:06 -07:00
// Write BP registers (RA + BG pairs with bit 23 set for K color)
2026-02-17 17:35:13 -07:00
u32 regRA = 0;
SET_REG_FIELD(0, regRA, 8, 0, color.r);
SET_REG_FIELD(0, regRA, 8, 12, color.a);
SET_REG_FIELD(0, regRA, 4, 20, 8); // K color flag
SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2);
u32 regBG = 0;
SET_REG_FIELD(0, regBG, 8, 0, color.b);
SET_REG_FIELD(0, regBG, 8, 12, color.g);
SET_REG_FIELD(0, regBG, 4, 20, 8); // K color flag
SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
2026-02-17 17:35:13 -07:00
void GXSetTevKColorSel(GXTevStageID id, GXTevKColorSel sel) {
// tevKsel registers: 2 stages per register
u32 kselIdx = id / 2;
if (id & 1) {
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 14, sel);
} else {
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 4, sel);
}
GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]);
__gx->bpSent = 1;
}
2022-07-27 11:25:25 -04:00
2026-02-17 17:35:13 -07:00
void GXSetTevKAlphaSel(GXTevStageID id, GXTevKAlphaSel sel) {
u32 kselIdx = id / 2;
if (id & 1) {
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 19, sel);
} else {
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 9, sel);
}
GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]);
__gx->bpSent = 1;
}
2022-07-27 11:25:25 -04:00
void GXSetTevSwapMode(GXTevStageID stageId, GXTevSwapSel rasSel, GXTevSwapSel texSel) {
2026-02-17 17:35:13 -07:00
// Swap mode is stored in teva register
u32* reg = &__gx->teva[stageId];
SET_REG_FIELD(0, *reg, 2, 0, rasSel);
SET_REG_FIELD(0, *reg, 2, 2, texSel);
GX_WRITE_RAS_REG(*reg);
__gx->bpSent = 1;
2022-07-27 11:25:25 -04:00
}
void GXSetTevSwapModeTable(GXTevSwapSel id, GXTevColorChan red, GXTevColorChan green, GXTevColorChan blue,
GXTevColorChan alpha) {
2022-08-09 02:05:33 -04:00
CHECK(id >= GX_TEV_SWAP0 && id < GX_MAX_TEVSWAP, "bad tev swap sel {}", static_cast<int>(id));
2026-02-17 17:35:13 -07:00
// Swap table is stored in tevKsel registers
u32 kselIdx = id * 2;
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 2, 0, red);
SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 2, 2, green);
GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]);
SET_REG_FIELD(0, __gx->tevKsel[kselIdx + 1], 2, 0, blue);
SET_REG_FIELD(0, __gx->tevKsel[kselIdx + 1], 2, 2, alpha);
GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx + 1]);
__gx->bpSent = 1;
}
2022-07-27 11:25:25 -04:00
}