summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLagoLunatic <LagoLunatic@users.noreply.github.com>2024-09-07 17:31:29 -0400
committerLagoLunatic <LagoLunatic@users.noreply.github.com>2024-09-07 17:31:29 -0400
commit3e7ece6ff50f48dbce8b044cfcc0851ce4859789 (patch)
tree6ae26e70f5d6e3ad9c2497538ff54a6dbe82e77f
parent340d18c6bcc8d6e0640748273109c55ab058df7b (diff)
Copy dolphin/gx progress from TP
-rw-r--r--include/dolphin/gx/GX.h76
-rw-r--r--include/dolphin/gx/GXAttr.h2
-rw-r--r--include/dolphin/gx/GXEnum.h1232
-rw-r--r--include/dolphin/gx/GXFifo.h14
-rw-r--r--include/dolphin/gx/GXFrameBuf.h2
-rw-r--r--include/dolphin/gx/GXInit.h213
-rw-r--r--include/dolphin/gx/GXMisc.h6
-rw-r--r--include/dolphin/gx/GXPerf.h4
-rw-r--r--include/dolphin/gx/GXStruct.h17
-rw-r--r--include/dolphin/gx/GXTexture.h6
-rw-r--r--include/dolphin/gx/GXTransform.h6
-rw-r--r--include/dolphin/os/OSError.h2
-rw-r--r--include/dolphin/os/OSMessage.h2
-rw-r--r--include/dolphin/vi/vi.h127
-rw-r--r--src/JSystem/J3DGraphBase/J3DGD.cpp2
-rw-r--r--src/JSystem/J3DGraphBase/J3DSys.cpp2
-rw-r--r--src/JSystem/JParticle/JPADraw.cpp16
-rw-r--r--src/d/d_kankyo_data.cpp4
-rw-r--r--src/dolphin/gx/GXAttr.c751
-rw-r--r--src/dolphin/gx/GXBump.c194
-rw-r--r--src/dolphin/gx/GXDisplayList.c21
-rw-r--r--src/dolphin/gx/GXDraw.c71
-rw-r--r--src/dolphin/gx/GXFifo.c337
-rw-r--r--src/dolphin/gx/GXFrameBuf.c638
-rw-r--r--src/dolphin/gx/GXGeometry.c149
-rw-r--r--src/dolphin/gx/GXInit.c561
-rw-r--r--src/dolphin/gx/GXLight.c294
-rw-r--r--src/dolphin/gx/GXMisc.c266
-rw-r--r--src/dolphin/gx/GXPerf.c384
-rw-r--r--src/dolphin/gx/GXPixel.c235
-rw-r--r--src/dolphin/gx/GXTev.c366
-rw-r--r--src/dolphin/gx/GXTexture.c593
-rw-r--r--src/dolphin/gx/GXTransform.c316
-rw-r--r--src/m_Do/m_Do_graphic.cpp4
34 files changed, 6713 insertions, 200 deletions
diff --git a/include/dolphin/gx/GX.h b/include/dolphin/gx/GX.h
index f8441f3c..bbb29e65 100644
--- a/include/dolphin/gx/GX.h
+++ b/include/dolphin/gx/GX.h
@@ -22,27 +22,77 @@ extern "C" {
// Pack value into bitfield
#define GX_BITFIELD_SET(field, pos, size, value) (field) = __rlwimi((field), (value), 31 - (pos) - (size) + 1, (pos), (pos) + (size)-1)
+#define GX_BITFIELD_TRUNC(field, pos, size, value) (__rlwimi((field), (value), 0, (pos), (pos) + (size)-1))
+
+#define GX_BITGET(field, pos, size) ((field) >> (31 - (pos) - (size) + 1) & ((1 << (size)) - 1))
+#define GX_GET_REG(reg, st, end) GX_BITGET(reg, st, (end - st + 1))
+#define GX_SET_REG(reg, x, st, end) GX_BITFIELD_SET(reg, st, (end - st + 1), x)
+#define GX_SET_TRUNC(reg, x, st, end) GX_BITFIELD_TRUNC((reg), (st), ((end) - (st) + 1), (x))
+
+#define GXCOLOR_AS_U32(color) (*((u32*)&(color)))
#define INSERT_FIELD(reg, value, nbits, shift) \
(reg) = ((u32) (reg) & ~(((1 << (nbits)) - 1) << (shift))) | \
((u32) (value) << (shift));
+#define FAST_FLAG_SET(regOrg, newFlag, shift, size) \
+ do { \
+ (regOrg) = (u32)__rlwimi((int)(regOrg), (int)(newFlag), (shift), (32 - (shift) - (size)), (31 - (shift))); \
+ } while (0);
+
+#define GX_LOAD_BP_REG 0x61
#define GX_NOP 0
typedef union {
- u8 u8;
- u16 u16;
- u32 u32;
- u64 u64;
- s8 s8;
- s16 s16;
- s32 s32;
- s64 s64;
- f32 f32;
- f64 f64;
+ u8 u8;
+ u16 u16;
+ u32 u32;
+ u64 u64;
+ s8 s8;
+ s16 s16;
+ s32 s32;
+ s64 s64;
+ f32 f32;
+ f64 f64;
} PPCWGPipe;
-volatile PPCWGPipe GXFIFO AT_ADDRESS(0xCC008000);
+#define GXFIFO_ADDR 0xCC008000
+volatile PPCWGPipe GXFIFO AT_ADDRESS(GXFIFO_ADDR);
+
+#define GX_CP_LOAD_REG(addr, data) \
+ GXFIFO.s8 = GX_FIFO_CMD_LOAD_CP_REG; \
+ GXFIFO.s8 = (addr); \
+ GXFIFO.s32 = (data);
+
+/**
+ * Header for an XF register load
+ */
+#define GX_XF_LOAD_REG_HDR(addr) \
+ GXFIFO.s8 = GX_FIFO_CMD_LOAD_XF_REG; \
+ GXFIFO.s32 = (addr);
+
+/**
+ * Load immediate value into XF register
+ */
+#define GX_XF_LOAD_REG(addr, data) \
+ GX_XF_LOAD_REG_HDR(addr); \
+ GXFIFO.s32 = (data);
+
+/**
+ * Load immediate value into BP register
+ */
+#define GX_BP_LOAD_REG(data) \
+ GXFIFO.s8 = GX_FIFO_CMD_LOAD_BP_REG; \
+ GXFIFO.s32 = (data);
+
+/**
+ * Load immediate values into multiple XF registers
+ */
+#define GX_XF_LOAD_REGS(size, addr) \
+ { \
+ u32 cmd = (size) << 16 | addr; \
+ GX_XF_LOAD_REG_HDR(cmd); \
+ }
// Direct
inline void GXPosition2f32(f32 x, f32 z) {
@@ -118,8 +168,8 @@ inline void GXTexCoord2u16(u16 x, u16 y) {
}
inline void GXTexCoord2s16(const s16 u, const s16 v) {
- GXFIFO.s16 = u;
- GXFIFO.s16 = v;
+ GXFIFO.s16 = u;
+ GXFIFO.s16 = v;
}
// Indexed
diff --git a/include/dolphin/gx/GXAttr.h b/include/dolphin/gx/GXAttr.h
index 7cebd8d6..bada1e08 100644
--- a/include/dolphin/gx/GXAttr.h
+++ b/include/dolphin/gx/GXAttr.h
@@ -24,7 +24,7 @@ void GXSetVtxDescv(GXVtxDescList* list);
void __GXSetVCD(void);
void __GXCalculateVLim(void);
void GXClearVtxDesc(void);
-void GXSetVtxAttrFmt(GXVtxFmt fmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u32);
+void GXSetVtxAttrFmt(GXVtxFmt fmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac);
void GXSetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList* list);
void __GXSetVAT(void);
void GXSetArray(GXAttr attr, void* base, u8);
diff --git a/include/dolphin/gx/GXEnum.h b/include/dolphin/gx/GXEnum.h
index 0fa10cdb..1cb56b15 100644
--- a/include/dolphin/gx/GXEnum.h
+++ b/include/dolphin/gx/GXEnum.h
@@ -228,29 +228,38 @@ typedef enum _GXAttr {
} GXAttr;
typedef enum _GXCompCnt {
- /* 0x0 */ GX_POS_XY = 0,
- /* 0x1 */ GX_POS_XYZ = 1,
- /* 0x0 */ GX_NRM_XYZ = 0,
- /* 0x1 */ GX_NRM_NBT = 1,
- /* 0x2 */ GX_NRM_NBT3 = 2,
- /* 0x0 */ GX_CLR_RGB = 0,
- /* 0x1 */ GX_CLR_RGBA = 1,
- /* 0x0 */ GX_TEX_S = 0,
- /* 0x1 */ GX_TEX_ST = 1,
+ GX_POS_XY = 0, // Position X, Y (two components).
+ GX_POS_XYZ = 1, // Position X, Y, Z (three components).
+
+ GX_NRM_XYZ = 0, // Normal X, Y, Z (three components).
+ GX_NRM_NBT = 1, // Normal, binormal, tangent (three components).
+ GX_NRM_NBT3 = 2, // Normal, binormal, tangent (three components). Use when NBT
+ // normal is indexed independently.
+
+ GX_CLR_RGB = 0, // RGB (three components).
+ GX_CLR_RGBA = 1, // RGBA (four components).
+
+ GX_TEX_S = 0, // Texture coordinate S (one component).
+ GX_TEX_ST = 1, // Texture coordinates S, T (two components).
+
+ GX_COMPCNT_NULL = 0, // Null count.
} GXCompCnt;
typedef enum _GXCompType {
- /* 0x0 */ GX_U8,
- /* 0x1 */ GX_S8,
- /* 0x2 */ GX_U16,
- /* 0x3 */ GX_S16,
- /* 0x4 */ GX_F32,
- /* 0x0 */ GX_RGB565 = 0,
- /* 0x1 */ GX_RGB8,
- /* 0x2 */ GX_RGBX8,
- /* 0x3 */ GX_RGBA4,
- /* 0x4 */ GX_RGBA6,
- /* 0x5 */ GX_RGBA8,
+ GX_U8 = 0, // Unsigned 8-bit.
+ GX_S8 = 1, // Signed 8-bit.
+ GX_U16 = 2, // Unsigned 16-bit.
+ GX_S16 = 3, // Signed 16-bit.
+ GX_F32 = 4, // Floating-point 32-bit.
+
+ GX_RGB565 = 0, // RGB565 16-bit.
+ GX_RGB8 = 1, // RGB888 24-bit.
+ GX_RGBX8 = 2, // RGB888x 32-bit.
+ GX_RGBA4 = 3, // RGBA4444 16-bit.
+ GX_RGBA6 = 4, // RGBA6666 24-bit.
+ GX_RGBA8 = 5, // RGBA8888 32-bit.
+
+ GX_COMP_NULL = 0, // Null type.
} GXCompType;
typedef enum _GXAttrType {
@@ -335,28 +344,50 @@ typedef enum _GXTevAlphaArg {
/* 0x7 */ GX_CA_ZERO,
} GXTevAlphaArg;
+/**
+ * RGB, RGBA, Intensity, Intensity/Alpha, Compressed, and Z texture format
+ * types. See GXCITexFmt for information on color index formats. The CTF format
+ * is used only by the GXSetTexCopyDst function to specify how data is copied
+ * out of the EFB into a texture in main memory. In order to actually use that
+ * texture, you must specify a non-copy format of matching size. For example, if
+ * copying using GX_CTF_RG8, you would apply the resulting texture using
+ * GX_TF_IA8.
+ */
typedef enum _GXTexFmt {
- /* 0x0 */ GX_TF_I4,
- /* 0x1 */ GX_TF_I8,
- /* 0x2 */ GX_TF_IA4,
- /* 0x3 */ GX_TF_IA8,
- /* 0x4 */ GX_TF_RGB565,
- /* 0x5 */ GX_TF_TGB5A3,
- /* 0x6 */ GX_TF_RGBA8,
- /* 0x7 */ GX_TF_CI4,
- /* 0x8 */ GX_TF_CI8,
- /* 0x9 */ GX_TF_CI14,
- /* 0xE */ GX_TF_CMPR = 14,
- /* 0x10 */ _GX_TF_ZTF = 0x10,
- /* 0x11 */ GX_TF_Z8 = (0x1 | _GX_TF_ZTF),
- /* 0x13 */ GX_TF_Z16 = (0x3 | _GX_TF_ZTF),
- /* 0x16 */ GX_TF_Z24X8 = (0x6 | _GX_TF_ZTF),
- /* 0x20 */ _GX_TF_CTF = 0x20,
- /* 0x28 */ _GX_CTF_R8 = 0x28,
- /* 0x30 */ GX_CTF_Z4 = (0x0 | _GX_TF_ZTF | _GX_TF_CTF),
- /* 0x39 */ GX_CTF_Z8M = (0x9 | _GX_TF_ZTF | _GX_TF_CTF),
- /* 0x3A */ GX_CTF_Z8L = (0xA | _GX_TF_ZTF | _GX_TF_CTF),
- /* 0x3C */ GX_CTF_Z16L = (0xC | _GX_TF_ZTF | _GX_TF_CTF),
+ // Intensities (I) and RGB/RGBA.
+ GX_TF_I4 = 0x0, // 4-bit I
+ GX_TF_I8 = 0x1, // 8-bit I
+ GX_TF_IA4 = 0x2, // 8-bit I + alpha (4+4).
+ GX_TF_IA8 = 0x3, // 16-bit I + alpha (8+8).
+ GX_TF_RGB565 = 0x4, // 16-bit RGB.
+ GX_TF_RGB5A3 = 0x5, // MSB=1, RGB555 (opaque). MSB=0, RGBA4443 (transparent).
+ GX_TF_RGBA8 = 0x6, // 32-bit RGB.
+ GX_TF_CI14 = 0x9,
+ GX_TF_CMPR = 0xE, // Compressed 4-bit texel.
+
+ // Z-texture format.
+ GX_TF_Z8 = 0x11, // Unsigned 8-bit Z. For texture copies, specify the upper 8 bits of Z.
+ GX_TF_Z16 = 0x13, // Unsigned 16-bit Z. For texture copies, specify the upper 16 bits of Z.
+ GX_TF_Z24X8 = 0x16, // Unsigned 24-bit (32-bit texture) Z. For texture copies, copy the 24-bit
+ // Z and 0xff.
+
+ // Copy-texture format.
+ GX_CTF_R4 = 0x20, // 4-bit red. For copying 4 bits from red.
+ GX_CTF_RA4 = 0x22, // 4-bit red + 4-bit alpha. For copying 4 bits from red, 4 bits from alpha.
+ GX_CTF_RA8 = 0x23, // 8-bit red + 8-bit alpha. For copying 8 bits from red, 8 bits from alpha.
+ GX_CTF_YUVA8 = 0x26, // 8-bit YUV + alpha. For copying 8 bits from YUV, 8 bits from alpha.
+ GX_CTF_A8 = 0x26, // 8-bit alpha. For copying 8 bits from alpha.
+ GX_CTF_R8 = 0x27, // 8-bit red. For copying 8 bits from red.
+ GX_CTF_G8 = 0x28, // 8-bit green. For copying 8 bits from green.
+ GX_CTF_B8 = 0x29, // 8-bit blue. For copying 8 bits from blue.
+ GX_CTF_RG8 = 0x2A, // 8-bit red +8-bit green. For copying 8 bits from red, 8 bits from green.
+ GX_CTF_GB8 = 0x2B, // 8-bit green +8-bit blue. For copying 8 bits from green, 8 bits from blue.
+
+ // Copy-Z-texture format.
+ GX_CTF_Z4 = 0x30, // 4-bit Z. For copying the 4 upper bits from Z.
+ GX_CTF_Z8M = 0x39, // 8-bit Z (median byte). For copying the middle 8 bits of Z.
+ GX_CTF_Z8L = 0x3A, // 8-bit Z (lower byte). For copying the lower 8 bits of Z.
+ GX_CTF_Z16L = 0x3C, // 16-bit Z (lower portion). For copying the lower 16 bits of Z.
} GXTexFmt;
typedef enum _GXGamma {
@@ -388,10 +419,14 @@ typedef enum _GXTlut {
/* 0x0D */ GX_TLUT13,
/* 0x0E */ GX_TLUT14,
/* 0x0F */ GX_TLUT15,
- /* 0x10 */ GX_BIGTLUT0,
+ /* 0x10 */ GX_MAX_TLUT,
+ /* 0x10 */ GX_BIGTLUT0 = 0x10,
/* 0x11 */ GX_BIGTLUT1,
/* 0x12 */ GX_BIGTLUT2,
/* 0x13 */ GX_BIGTLUT3,
+ /* 0x13 */ GX_MAX_BIGTLUT = 4,
+
+ GX_MAX_TLUT_ALL = GX_MAX_TLUT + GX_MAX_BIGTLUT,
} GXTlut;
typedef enum _GXTexWrapMode {
@@ -733,6 +768,7 @@ typedef enum _GXFBClamp {
/* 0x0 */ GX_CLAMP_NONE,
/* 0x1 */ GX_CLAMP_TOP,
/* 0x2 */ GX_CLAMP_BOTTOM,
+ GX_CLAMP_BOTH = GX_CLAMP_TOP | GX_CLAMP_BOTTOM,
} GXFBClamp;
typedef enum _GXPixelFmt {
@@ -744,6 +780,7 @@ typedef enum _GXPixelFmt {
/* 0x5 */ GX_PF_U8,
/* 0x6 */ GX_PF_V8,
/* 0x7 */ GX_PF_YUV420,
+ /* 0x8 */ GX_PF_MAX,
} GXPixelFmt;
typedef enum _GXZFmt16 {
@@ -795,4 +832,1115 @@ typedef enum _GXTlutSize {
/* 0x400 */ GX_TLUT_16K = 1024,
} GXTlutSize;
+typedef enum _GXDirtyFlag {
+ GX_DIRTY_SU_TEX = (1 << 0),
+ GX_DIRTY_BP_MASK = (1 << 1),
+ GX_DIRTY_GEN_MODE = (1 << 2),
+ GX_DIRTY_VCD = (1 << 3),
+ GX_DIRTY_VAT = (1 << 4),
+ GX_DIRTY_AMB_COLOR0 = (1 << 8),
+ GX_DIRTY_AMB_COLOR1 = (1 << 9),
+ GX_DIRTY_MAT_COLOR0 = (1 << 10),
+ GX_DIRTY_MAT_COLOR1 = (1 << 11),
+ GX_DIRTY_MTX_IDX = (1 << 26),
+ GX_DIRTY_PROJECTION = (1 << 27),
+ GX_DIRTY_VIEWPORT = (1 << 28),
+
+ GX_DIRTY_VLIM = GX_DIRTY_VCD | GX_DIRTY_VAT,
+
+ GX_AMB_MAT_MASK =
+ GX_DIRTY_AMB_COLOR0 | GX_DIRTY_AMB_COLOR1 | GX_DIRTY_MAT_COLOR0 | GX_DIRTY_MAT_COLOR1,
+ GX_LIGHT_CHAN_MASK = 0x100F000,
+ GX_TEX_GEN_MASK = 0x2FF0000,
+} GXDirtyFlag;
+
+// CP locator for vertex descriptor (lo).
+typedef enum _GXCPVCDLo {
+ // Position matrix idx [31]
+ GX_CP_VCD_LO_POSMTXIDX_ST = 31,
+ GX_CP_VCD_LO_POSMTXIDX_END = 31,
+
+ // Tex 0 matrix idx [30]
+ GX_CP_VCD_LO_TEX0MTXIDX_ST = 30,
+ GX_CP_VCD_LO_TEX0MTXIDX_END = 30,
+
+ // Tex 1 matrix idx [29]
+ GX_CP_VCD_LO_TEX1MTXIDX_ST = 29,
+ GX_CP_VCD_LO_TEX1MTXIDX_END = 29,
+
+ // Tex 2 matrix idx [28]
+ GX_CP_VCD_LO_TEX2MTXIDX_ST = 28,
+ GX_CP_VCD_LO_TEX2MTXIDX_END = 28,
+
+ // Tex 3 matrix idx [27]
+ GX_CP_VCD_LO_TEX3MTXIDX_ST = 27,
+ GX_CP_VCD_LO_TEX3MTXIDX_END = 27,
+
+ // Tex 4 matrix idx [26]
+ GX_CP_VCD_LO_TEX4MTXIDX_ST = 26,
+ GX_CP_VCD_LO_TEX4MTXIDX_END = 26,
+
+ // Tex 5 matrix idx [25]
+ GX_CP_VCD_LO_TEX5MTXIDX_ST = 25,
+ GX_CP_VCD_LO_TEX5MTXIDX_END = 25,
+
+ // Tex 6 matrix idx [24]
+ GX_CP_VCD_LO_TEX6MTXIDX_ST = 24,
+ GX_CP_VCD_LO_TEX6MTXIDX_END = 24,
+
+ // Tex 7 matrix idx [23]
+ GX_CP_VCD_LO_TEX7MTXIDX_ST = 23,
+ GX_CP_VCD_LO_TEX7MTXIDX_END = 23,
+
+ // Position [21-22]
+ GX_CP_VCD_LO_POS_ST = 21,
+ GX_CP_VCD_LO_POS_END = 22,
+
+ // Normal [19-20]
+ GX_CP_VCD_LO_NRM_ST = 19,
+ GX_CP_VCD_LO_NRM_END = 20,
+
+ // Color diffused [17-18]
+ GX_CP_VCD_LO_CLRDIF_ST = 17,
+ GX_CP_VCD_LO_CLRDIF_END = 18,
+
+ // Color specular [15-16]
+ GX_CP_VCD_LO_CLRSPEC_ST = 15,
+ GX_CP_VCD_LO_CLRSPEC_END = 16,
+} GXCPVCDLo;
+
+// CP locators for vertex descriptor (hi).
+typedef enum _GXCPVCDHi {
+ // Tex0 coordinates [30-31]
+ GX_CP_VCD_HI_TEX0COORD_ST = 30,
+ GX_CP_VCD_HI_TEX0COORD_END = 31,
+
+ // Tex1 coordinates [28-29]
+ GX_CP_VCD_HI_TEX1COORD_ST = 28,
+ GX_CP_VCD_HI_TEX1COORD_END = 29,
+
+ // Tex2 coordinates [26-27]
+ GX_CP_VCD_HI_TEX2COORD_ST = 26,
+ GX_CP_VCD_HI_TEX2COORD_END = 27,
+
+ // Tex3 coordinates [24-25]
+ GX_CP_VCD_HI_TEX3COORD_ST = 24,
+ GX_CP_VCD_HI_TEX3COORD_END = 25,
+
+ // Tex4 coordinates [22-23]
+ GX_CP_VCD_HI_TEX4COORD_ST = 22,
+ GX_CP_VCD_HI_TEX4COORD_END = 23,
+
+ // Tex5 coordinates [20-21]
+ GX_CP_VCD_HI_TEX5COORD_ST = 20,
+ GX_CP_VCD_HI_TEX5COORD_END = 21,
+
+ // Tex6 coordinates [18-19]
+ GX_CP_VCD_HI_TEX6COORD_ST = 18,
+ GX_CP_VCD_HI_TEX6COORD_END = 19,
+
+ // Tex7 coordinates [16-17]
+ GX_CP_VCD_HI_TEX7COORD_ST = 16,
+ GX_CP_VCD_HI_TEX7COORD_END = 17,
+} GXCPVCDHi;
+
+// Command processor registers.
+typedef enum _GXCPRegs {
+ GX_CP_REG_MTXIDXA = 0x30, // Matrix index A
+ GX_CP_REG_MTXIDXB = 0x40, // Matrix index B
+ GX_CP_REG_VCD_LO = 0x50, // Vertex descriptor (lo)
+ GX_CP_REG_VCD_HI = 0x60, // Vertex descriptor (hi)
+ GX_CP_REG_VAT_GRP0 = 0x70, // Vertex attribute table (group 0)
+ GX_CP_REG_VAT_GRP1 = 0x80, // Vertex attribute table (group 1)
+ GX_CP_REG_VAT_GRP2 = 0x90, // Vertex attribute table (group 2)
+ GX_CP_REG_ARRAYBASE = 0xA0, // Vertex array start/base
+ GX_CP_REG_ARRAYSTRIDE = 0xB0, // Vertex array stride
+} GXCPRegs;
+
+// Transform unit registers.
+typedef enum _GXXFRegs {
+ GX_XF_REG_ERROR = 0x1000,
+ GX_XF_REG_DIAGNOSTICS = 0x1001,
+ GX_XF_REG_STATE0 = 0x1002,
+ GX_XF_REG_STATE1 = 0x1003,
+ GX_XF_REG_CLOCK = 0x1004,
+ GX_XF_REG_CLIPDISABLE = 0x1005,
+ GX_XF_REG_PERF0 = 0x1006,
+ GX_XF_REG_PERF1 = 0x1007,
+ GX_XF_REG_INVERTEXSPEC = 0x1008,
+ GX_XF_REG_NUMCOLORS = 0x1009,
+ GX_XF_REG_AMBIENT0 = 0x100A,
+ GX_XF_REG_AMBIENT1 = 0x100B,
+ GX_XF_REG_MATERIAL0 = 0x100C,
+ GX_XF_REG_MATERIAL1 = 0x100D,
+ GX_XF_REG_COLOR0CNTRL = 0x100E,
+ GX_XF_REG_COLOR1CNTRL = 0x100F,
+ GX_XF_REG_ALPHA0CNTRL = 0x1010,
+ GX_XF_REG_ALPHA1CNTRL = 0x1011,
+ GX_XF_REG_DUALTEXTRAN = 0x1012,
+ GX_XF_REG_MATRIXINDEX0 = 0x1018,
+ GX_XF_REG_MATRIXINDEX1 = 0x1019,
+ GX_XF_REG_SCALEX = 0x101A,
+ GX_XF_REG_SCALEY = 0x101B,
+ GX_XF_REG_SCALEZ = 0x101C,
+ GX_XF_REG_OFFSETX = 0x101D,
+ GX_XF_REG_OFFSETY = 0x101E,
+ GX_XF_REG_OFFSETZ = 0x101F,
+ GX_XF_REG_PROJECTIONA = 0x1020,
+ GX_XF_REG_PROJECTIONB = 0x1021,
+ GX_XF_REG_PROJECTIONC = 0x1022,
+ GX_XF_REG_PROJECTIOND = 0x1023,
+ GX_XF_REG_PROJECTIONE = 0x1024,
+ GX_XF_REG_PROJECTIONF = 0x1025,
+ GX_XF_REG_PROJECTORTHO = 0x1026,
+ GX_XF_REG_NUMTEX = 0x103F,
+ GX_XF_REG_TEX0 = 0x1040,
+ GX_XF_REG_TEX1 = 0x1041,
+ GX_XF_REG_TEX2 = 0x1042,
+ GX_XF_REG_TEX3 = 0x1043,
+ GX_XF_REG_TEX4 = 0x1044,
+ GX_XF_REG_TEX5 = 0x1045,
+ GX_XF_REG_TEX6 = 0x1046,
+ GX_XF_REG_TEX7 = 0x1047,
+ GX_XF_REG_DUALTEX0 = 0x1050,
+ GX_XF_REG_DUALTEX1 = 0x1051,
+ GX_XF_REG_DUALTEX2 = 0x1052,
+ GX_XF_REG_DUALTEX3 = 0x1053,
+ GX_XF_REG_DUALTEX4 = 0x1054,
+ GX_XF_REG_DUALTEX5 = 0x1055,
+ GX_XF_REG_DUALTEX6 = 0x1056,
+ GX_XF_REG_DUALTEX7 = 0x1057,
+} GXXFRegs;
+
+// Commands for interacting with the GXFifo pipe.
+typedef enum _GXFifoCmd {
+ GX_FIFO_CMD_NOOP = 0x00, // no operation
+
+ GX_FIFO_CMD_LOAD_BP_REG = 0x61, // load blitting processor reg
+ GX_FIFO_CMD_LOAD_CP_REG = 0x08, // load command processor reg
+ GX_FIFO_CMD_LOAD_XF_REG = 0x10, // load transform unit reg
+
+ GX_FIFO_CMD_LOAD_INDX_A = 0x20, // load index A
+ GX_FIFO_CMD_LOAD_INDX_B = 0x28, // load index B
+ GX_FIFO_CMD_LOAD_INDX_C = 0x30, // load index C
+ GX_FIFO_CMD_LOAD_INDX_D = 0x38, // load index D
+
+ GX_FIFO_CMD_CALL_DL = 0x40, // call displaylist
+ GX_FIFO_CMD_INVAL_VTX = 0x48, // invalid vertex
+
+} GXFifoCmd;
+
+// CP locator for vertex attribute table (group 0).
+typedef enum _GXCPVATGrp0 {
+ // Position count [31-31]
+ GX_CP_VAT_GRP0_POS_CNT_ST = 31,
+ GX_CP_VAT_GRP0_POS_CNT_END = 31,
+
+ // Position type [28-30]
+ GX_CP_VAT_GRP0_POS_TYPE_ST = 28,
+ GX_CP_VAT_GRP0_POS_TYPE_END = 30,
+
+ // Position shift [23-27]
+ GX_CP_VAT_GRP0_POS_SHIFT_ST = 23,
+ GX_CP_VAT_GRP0_POS_SHIFT_END = 27,
+
+ // Normal count [22-22]
+ GX_CP_VAT_GRP0_NRM_CNT_ST = 22,
+ GX_CP_VAT_GRP0_NRM_CNT_END = 22,
+
+ // Normal type [19-21]
+ GX_CP_VAT_GRP0_NRM_TYPE_ST = 19,
+ GX_CP_VAT_GRP0_NRM_TYPE_END = 21,
+
+ // Color diffused count [18-18]
+ GX_CP_VAT_GRP0_CLRDIFF_CNT_ST = 18,
+ GX_CP_VAT_GRP0_CLRDIFF_CNT_END = 18,
+
+ // Color diffused type [15-17]
+ GX_CP_VAT_GRP0_CLRDIFF_TYPE_ST = 15,
+ GX_CP_VAT_GRP0_CLRDIFF_TYPE_END = 17,
+
+ // Color specular count [14-14]
+ GX_CP_VAT_GRP0_CLRSPEC_CNT_ST = 14,
+ GX_CP_VAT_GRP0_CLRSPEC_CNT_END = 14,
+
+ // Color specular type [11-13]
+ GX_CP_VAT_GRP0_CLRSPEC_TYPE_ST = 11,
+ GX_CP_VAT_GRP0_CLRSPEC_TYPE_END = 13,
+
+ // Tex0 coord count [10-10]
+ GX_CP_VAT_GRP0_TXC0_CNT_ST = 10,
+ GX_CP_VAT_GRP0_TXC0_CNT_END = 10,
+
+ // Tex0 coord type [7-9]
+ GX_CP_VAT_GRP0_TXC0_TYPE_ST = 7,
+ GX_CP_VAT_GRP0_TXC0_TYPE_END = 9,
+
+ // Tex0 coord shift [2-6]
+ GX_CP_VAT_GRP0_TXC0_SHIFT_ST = 2,
+ GX_CP_VAT_GRP0_TXC0_SHIFT_END = 6,
+
+ // Byte dequantised [1-1]
+ GX_CP_VAT_GRP0_BYTEDEQ_ST = 1,
+ GX_CP_VAT_GRP0_BYTEDEQ_END = 1,
+
+ // Normal index 3 [0-0] (Input will be treated as three staggered indices (one per triple biased
+ // by component size) into normal table))
+ GX_CP_VAT_GRP0_NRMIDX3_ST = 0,
+ GX_CP_VAT_GRP0_NRMIDX3_END = 0,
+} GXCPVATGrp0;
+
+// CP locators for vertex attribute table (group 1).
+typedef enum _GXCPVATGrp1 {
+ // Tex1 coord count [31-31]
+ GX_CP_VAT_GRP1_TXC1_CNT_ST = 31,
+ GX_CP_VAT_GRP1_TXC1_CNT_END = 31,
+
+ // Tex1 coord type [28-30]
+ GX_CP_VAT_GRP1_TXC1_TYPE_ST = 28,
+ GX_CP_VAT_GRP1_TXC1_TYPE_END = 30,
+
+ // Tex1 coord shift [23-27]
+ GX_CP_VAT_GRP1_TXC1_SHIFT_ST = 23,
+ GX_CP_VAT_GRP1_TXC1_SHIFT_END = 27,
+
+ // Tex2 coord count [22-22]
+ GX_CP_VAT_GRP1_TXC2_CNT_ST = 22,
+ GX_CP_VAT_GRP1_TXC2_CNT_END = 22,
+
+ // Tex2 coord type [19-21]
+ GX_CP_VAT_GRP1_TXC2_TYPE_ST = 19,
+ GX_CP_VAT_GRP1_TXC2_TYPE_END = 21,
+
+ // Tex2 coord shift [14-18]
+ GX_CP_VAT_GRP1_TXC2_SHIFT_ST = 14,
+ GX_CP_VAT_GRP1_TXC2_SHIFT_END = 18,
+
+ // Tex3 coord count [13-13]
+ GX_CP_VAT_GRP1_TXC3_CNT_ST = 13,
+ GX_CP_VAT_GRP1_TXC3_CNT_END = 13,
+
+ // Tex3 coord type [10-12]
+ GX_CP_VAT_GRP1_TXC3_TYPE_ST = 10,
+ GX_CP_VAT_GRP1_TXC3_TYPE_END = 12,
+
+ // Tex3 coord shift [5-9]
+ GX_CP_VAT_GRP1_TXC3_SHIFT_ST = 5,
+ GX_CP_VAT_GRP1_TXC3_SHIFT_END = 9,
+
+ // Tex4 coord count [4-4]
+ GX_CP_VAT_GRP1_TXC4_CNT_ST = 4,
+ GX_CP_VAT_GRP1_TXC4_CNT_END = 4,
+
+ // Tex4 coord type [1-3]
+ GX_CP_VAT_GRP1_TXC4_TYPE_ST = 1,
+ GX_CP_VAT_GRP1_TXC4_TYPE_END = 3,
+
+} GXCPVATGrp1;
+
+// CP locators for vertex attribute table (group 2).
+typedef enum _GXCPVATGrp2 {
+ // Tex4 coord shift [27-31]
+ GX_CP_VAT_GRP2_TXC4_SHIFT_ST = 27,
+ GX_CP_VAT_GRP2_TXC4_SHIFT_END = 31,
+
+ // Tex5 coord count [26-26]
+ GX_CP_VAT_GRP2_TXC5_CNT_ST = 26,
+ GX_CP_VAT_GRP2_TXC5_CNT_END = 26,
+
+ // Tex5 coord type [23-25]
+ GX_CP_VAT_GRP2_TXC5_TYPE_ST = 23,
+ GX_CP_VAT_GRP2_TXC5_TYPE_END = 25,
+
+ // Tex5 coord shift [18-22]
+ GX_CP_VAT_GRP2_TXC5_SHIFT_ST = 18,
+ GX_CP_VAT_GRP2_TXC5_SHIFT_END = 22,
+
+ // Tex6 coord count [17-17]
+ GX_CP_VAT_GRP2_TXC6_CNT_ST = 17,
+ GX_CP_VAT_GRP2_TXC6_CNT_END = 17,
+
+ // Tex6 coord type [14-16]
+ GX_CP_VAT_GRP2_TXC6_TYPE_ST = 14,
+ GX_CP_VAT_GRP2_TXC6_TYPE_END = 16,
+
+ // Tex6 coord shift [9-13]
+ GX_CP_VAT_GRP2_TXC6_SHIFT_ST = 9,
+ GX_CP_VAT_GRP2_TXC6_SHIFT_END = 13,
+
+ // Tex7 coord count [8-8]
+ GX_CP_VAT_GRP2_TXC7_CNT_ST = 8,
+ GX_CP_VAT_GRP2_TXC7_CNT_END = 8,
+
+ // Tex7 coord type [5-7]
+ GX_CP_VAT_GRP2_TXC7_TYPE_ST = 5,
+ GX_CP_VAT_GRP2_TXC7_TYPE_END = 7,
+
+ // Tex7 coord shift [0-4]
+ GX_CP_VAT_GRP2_TXC7_SHIFT_ST = 0,
+ GX_CP_VAT_GRP2_TXC7_SHIFT_END = 4,
+} GXCPVATGrp2;
+
+// BP GenMode locators.
+typedef enum _GXBPGenMode {
+ // Active texture counts [28-31]
+ GX_BP_GENMODE_NUMTEX_ST = 28,
+ GX_BP_GENMODE_NUMTEX_END = 31,
+
+ // Color/channel counts [25-27]
+ GX_BP_GENMODE_NUMCOLORS_ST = 25,
+ GX_BP_GENMODE_NUMCOLORS_END = 27,
+
+ // Multisample mode [22-22]
+ GX_BP_GENMODE_MULTISAMPLE_ST = 22,
+ GX_BP_GENMODE_MULTISAMPLE_END = 22,
+
+ // Cull mode [16-17]
+ GX_BP_GENMODE_CULLMODE_ST = 16,
+ GX_BP_GENMODE_CULLMODE_END = 17,
+
+ // Indirect stage counts [13-15]
+ GX_BP_GENMODE_NUMINDSTAGES_ST = 13,
+ GX_BP_GENMODE_NUMINDSTAGES_END = 15,
+
+ // Toggle co-planar/Z-freeze [12-12]
+ GX_BP_GENMODE_COPLANAR_ST = 12,
+ GX_BP_GENMODE_COPLANAR_END = 12,
+} GXBPGenMode;
+
+// Texture register fields for XF (transform) unit.
+typedef enum _GXXfTexReg {
+ GX_XF_TEX_PROJ_ST = 0, // (s,t) (2x4)
+ GX_XF_TEX_PROJ_STQ = 1, // (s,t,q) (3x4)
+
+ GX_XF_TEX_FORM_AB11 = 0, // (A, B, 1.0f, 1.0f), used for regular tex src
+ GX_XF_TEX_FORM_ABC1 = 1, // (A, B, C, 1.0f), used for geometry/normal src
+} GXXfTexReg;
+
+// XF locators for textures.
+typedef enum _GXXFTex {
+ // Projection type [30-30]
+ GX_XF_TEX_PROJTYPE_ST = 30,
+ GX_XF_TEX_PROJTYPE_END = 30,
+
+ // Input format [29-29]
+ GX_XF_TEX_INPUTFORM_ST = 29,
+ GX_XF_TEX_INPUTFORM_END = 29,
+
+ // Texture gen type [25-27]
+ GX_XF_TEX_TEXGENTYPE_ST = 25,
+ GX_XF_TEX_TEXGENTYPE_END = 27,
+
+ // Source row [20-24]
+ GX_XF_TEX_SRCROW_ST = 20,
+ GX_XF_TEX_SRCROW_END = 24,
+
+ // Bump source texture [17-19]
+ GX_XF_TEX_BUMPSRCTEX_ST = 17,
+ GX_XF_TEX_BUMPSRCTEX_END = 19,
+
+ // Bump source light [14-16]
+ GX_XF_TEX_BUMPSRCLIGHT_ST = 14,
+ GX_XF_TEX_BUMPSRCLIGHT_END = 16,
+} GXXFTex;
+
+// XF locators for dual textures.
+typedef enum _GXXFDualTex {
+ // Base row of the transform matrix [26-31]
+ GX_XF_DUALTEX_BASEROW_ST = 26,
+ GX_XF_DUALTEX_BASEROW_END = 31,
+
+ // Normalise texcoord before sending transform [23-23]
+ GX_XF_DUALTEX_NORMALISE_ST = 23,
+ GX_XF_DUALTEX_NORMALISE_END = 23,
+} GXXFDualTex;
+
+// General texture commands.
+typedef enum _GXXfTexGen {
+ GX_XF_TG_REGULAR = 0, // Regular; transform incoming data.
+ GX_XF_TG_BUMP = 1, // Texgen bump mapping.
+ GX_XF_TG_CLR0 = 2, // Color texgen for color 0 (s,t) = (r, g:b)
+ GX_XF_TG_CLR1 = 3, // Color texgen for color 1 (s,t) = (r, g:b)
+} GXXfTexGen;
+
+// XF locators for matrix index 0.
+typedef enum _GXXFMtxIdx0 {
+ // Geometry [26-31]
+ GX_XF_MTXIDX0_GEOM_ST = 26,
+ GX_XF_MTXIDX0_GEOM_END = 31,
+
+ // Tex 0 [20-25]
+ GX_XF_MTXIDX0_TEX0_ST = 20,
+ GX_XF_MTXIDX0_TEX0_END = 25,
+
+ // Tex 1 [14-19]
+ GX_XF_MTXIDX0_TEX1_ST = 14,
+ GX_XF_MTXIDX0_TEX1_END = 19,
+
+ // Tex 2 [8-13]
+ GX_XF_MTXIDX0_TEX2_ST = 8,
+ GX_XF_MTXIDX0_TEX2_END = 13,
+
+ // Tex 3 [2-7]
+ GX_XF_MTXIDX0_TEX3_ST = 2,
+ GX_XF_MTXIDX0_TEX3_END = 7,
+} GXXFMtxIdx0;
+
+// XF locators for matrix index 1.
+typedef enum _GXXFMtxIdx1 {
+ // Tex 4 [26-31]
+ GX_XF_MTXIDX1_TEX4_ST = 26,
+ GX_XF_MTXIDX1_TEX4_END = 31,
+
+ // Tex 5 [20-25]
+ GX_XF_MTXIDX1_TEX5_ST = 20,
+ GX_XF_MTXIDX1_TEX5_END = 25,
+
+ // Tex 6 [14-19]
+ GX_XF_MTXIDX1_TEX6_ST = 14,
+ GX_XF_MTXIDX1_TEX6_END = 19,
+
+ // Tex 7 [8-13]
+ GX_XF_MTXIDX1_TEX7_ST = 8,
+ GX_XF_MTXIDX1_TEX7_END = 13,
+} GXXFMtxIdx1;
+
+// Blitting processor registers.
+typedef enum _GXBPRegs {
+ // gen mode
+ GX_BP_REG_GENMODE = 0x0, // gen mode
+
+ // display copy filters
+ GX_BP_REG_DISPCOPYFILTER0 = 0x1, // display copy filter 0
+ GX_BP_REG_DISPCOPYFILTER1 = 0x2, // display copy filter 1
+ GX_BP_REG_DISPCOPYFILTER2 = 0x3, // display copy filter 2
+ GX_BP_REG_DISPCOPYFILTER3 = 0x4, // display copy filter 3
+
+ // indirect matrices
+ GX_BP_REG_INDMTX0A = 0x6, // indirect matrix 0A
+ GX_BP_REG_INDMTX0B = 0x7, // indirect matrix 0B
+ GX_BP_REG_INDMTX0C = 0x8, // indirect matrix 0C
+ GX_BP_REG_INDMTX1A = 0x9, // indirect matrix 1A
+ GX_BP_REG_INDMTX1B = 0xA, // indirect matrix 1B
+ GX_BP_REG_INDMTX1C = 0xB, // indirect matrix 1C
+ GX_BP_REG_INDMTX2A = 0xC, // indirect matrix 2A
+ GX_BP_REG_INDMTX2B = 0xD, // indirect matrix 2B
+ GX_BP_REG_INDMTX2C = 0xE, // indirect matrix 2C
+ GX_BP_REG_INDIMASK = 0xF, // indirect mask
+
+ // indirect TEV stages
+ GX_BP_REG_INDTEVSTAGE0 = 0x10, // indirect TEV stage 0
+ GX_BP_REG_INDTEVSTAGE1 = 0x11, // indirect TEV stage 1
+ GX_BP_REG_INDTEVSTAGE2 = 0x12, // indirect TEV stage 2
+ GX_BP_REG_INDTEVSTAGE3 = 0x13, // indirect TEV stage 3
+ GX_BP_REG_INDTEVSTAGE4 = 0x14, // indirect TEV stage 4
+ GX_BP_REG_INDTEVSTAGE5 = 0x15, // indirect TEV stage 5
+ GX_BP_REG_INDTEVSTAGE6 = 0x16, // indirect TEV stage 6
+ GX_BP_REG_INDTEVSTAGE7 = 0x17, // indirect TEV stage 7
+ GX_BP_REG_INDTEVSTAGE8 = 0x18, // indirect TEV stage 8
+ GX_BP_REG_INDTEVSTAGE9 = 0x19, // indirect TEV stage 9
+ GX_BP_REG_INDTEVSTAGE10 = 0x1A, // indirect TEV stage 10
+ GX_BP_REG_INDTEVSTAGE11 = 0x1B, // indirect TEV stage 11
+ GX_BP_REG_INDTEVSTAGE12 = 0x1C, // indirect TEV stage 12
+ GX_BP_REG_INDTEVSTAGE13 = 0x1D, // indirect TEV stage 13
+ GX_BP_REG_INDTEVSTAGE14 = 0x1E, // indirect TEV stage 14
+ GX_BP_REG_INDTEVSTAGE15 = 0x1F, // indirect TEV stage 15
+
+ // performance manips
+ GX_BP_REG_SCISSORTL = 0x20, // scissor top left
+ GX_BP_REG_SCISSORBR = 0x21, // scissor bottom right
+ GX_BP_REG_LINEPTWIDTH = 0x22, // line point width
+ GX_BP_REG_PERF0TRI = 0x23, // performance 0 (triangle)
+ GX_BP_REG_PERF0QUAD = 0x24, // performance 0 (quad)
+
+ // rasters
+ GX_BP_REG_RAS1_SS0 = 0x25,
+ GX_BP_REG_RAS1_SS1 = 0x26,
+ GX_BP_REG_RAS1_IREF = 0x27,
+ GX_BP_REG_RAS1_TREF0 = 0x28,
+ GX_BP_REG_RAS1_TREF1 = 0x29,
+ GX_BP_REG_RAS1_TREF2 = 0x2A,
+ GX_BP_REG_RAS1_TREF3 = 0x2B,
+ GX_BP_REG_RAS1_TREF4 = 0x2C,
+ GX_BP_REG_RAS1_TREF5 = 0x2D,
+ GX_BP_REG_RAS1_TREF6 = 0x2E,
+ GX_BP_REG_RAS1_TREF7 = 0x2F,
+
+ // setup sizes
+ GX_BP_REG_SU_SSIZE0 = 0x30,
+ GX_BP_REG_SU_TSIZE0 = 0x31,
+ GX_BP_REG_SU_SSIZE1 = 0x32,
+ GX_BP_REG_SU_TSIZE1 = 0x33,
+ GX_BP_REG_SU_SSIZE2 = 0x34,
+ GX_BP_REG_SU_TSIZE2 = 0x35,
+ GX_BP_REG_SU_SSIZE3 = 0x36,
+ GX_BP_REG_SU_TSIZE3 = 0x37,
+ GX_BP_REG_SU_SSIZE4 = 0x38,
+ GX_BP_REG_SU_TSIZE4 = 0x39,
+ GX_BP_REG_SU_SSIZE5 = 0x3A,
+ GX_BP_REG_SU_TSIZE5 = 0x3B,
+ GX_BP_REG_SU_SSIZE6 = 0x3C,
+ GX_BP_REG_SU_TSIZE6 = 0x3D,
+ GX_BP_REG_SU_SSIZE7 = 0x3E,
+ GX_BP_REG_SU_TSIZE7 = 0x3F,
+
+ // Z and blend controls
+ GX_BP_REG_ZMODE = 0x40,
+ GX_BP_REG_BLENDMODE = 0x41,
+ GX_BP_REG_DSTALPHA = 0x42,
+ GX_BP_REG_ZCONTROL = 0x43,
+ GX_BP_REG_FIELDMASK = 0x44,
+ GX_BP_REG_DRAWDONE = 0x45,
+ GX_BP_REG_PETOKEN = 0x47,
+ GX_BP_REG_PETOKENINT = 0x48,
+
+ // copying
+ GX_BP_REG_TEXCOPYSRCXY = 0x49,
+ GX_BP_REG_TEXCOPYSRCWH = 0x4A,
+ GX_BP_REG_TEXCOPYDST = 0x4B,
+ GX_BP_REG_DISPCOPYSTRIDE = 0x4D,
+ GX_BP_REG_DISPCOPYSCALEY = 0x4E,
+ GX_BP_REG_COPYCLEARAR = 0x4F,
+ GX_BP_REG_COPYCLEARGB = 0x50,
+ GX_BP_REG_COPYCLEARZ = 0x51,
+ GX_BP_REG_COPYFILTER0 = 0x53,
+ GX_BP_REG_COPYFILTER1 = 0x54,
+
+ //
+ GX_BP_REG_BOUNDINGBOX0 = 0x55,
+ GX_BP_REG_BOUNDINGBOX1 = 0x56,
+
+ GX_BP_REG_SCISSOROFFSET = 0x59,
+
+ // texture memory
+ GX_BP_REG_TMEMPRELOADADDR = 0x60,
+ GX_BP_REG_TMEMPRELOADEVEN = 0x61,
+ GX_BP_REG_TMEMPRELOADODD = 0x62,
+ GX_BP_REG_TMEMPRELOADMODE = 0x63,
+ GX_BP_REG_TMEMTLUTSRC = 0x64,
+ GX_BP_REG_TMEMTLUTDST = 0x65,
+ GX_BP_REG_TMEMTEXINVALIDATE = 0x66,
+
+ // performance 1
+ GX_BP_REG_PERF1 = 0x67,
+ GX_BP_REG_FIELDMODE = 0x68,
+
+ // set modes
+ GX_BP_REG_SETMODE0_TEX0 = 0x80,
+ GX_BP_REG_SETMODE0_TEX1 = 0x81,
+ GX_BP_REG_SETMODE0_TEX2 = 0x82,
+ GX_BP_REG_SETMODE0_TEX3 = 0x83,
+ GX_BP_REG_SETMODE1_TEX0 = 0x84,
+ GX_BP_REG_SETMODE1_TEX1 = 0x85,
+ GX_BP_REG_SETMODE1_TEX2 = 0x86,
+ GX_BP_REG_SETMODE1_TEX3 = 0x87,
+
+ // set images
+ GX_BP_REG_SETIMAGE0_TEX0 = 0x88,
+ GX_BP_REG_SETIMAGE0_TEX1 = 0x89,
+ GX_BP_REG_SETIMAGE0_TEX2 = 0x8A,
+ GX_BP_REG_SETIMAGE0_TEX3 = 0x8B,
+ GX_BP_REG_SETIMAGE1_TEX0 = 0x8C,
+ GX_BP_REG_SETIMAGE1_TEX1 = 0x8D,
+ GX_BP_REG_SETIMAGE1_TEX2 = 0x8E,
+ GX_BP_REG_SETIMAGE1_TEX3 = 0x8F,
+ GX_BP_REG_SETIMAGE2_TEX0 = 0x90,
+ GX_BP_REG_SETIMAGE2_TEX1 = 0x91,
+ GX_BP_REG_SETIMAGE2_TEX2 = 0x92,
+ GX_BP_REG_SETIMAGE2_TEX3 = 0x93,
+ GX_BP_REG_SETIMAGE3_TEX0 = 0x94,
+ GX_BP_REG_SETIMAGE3_TEX1 = 0x95,
+ GX_BP_REG_SETIMAGE3_TEX2 = 0x96,
+ GX_BP_REG_SETIMAGE3_TEX3 = 0x97,
+
+ // set texture lookups
+ GX_BP_REG_SETTLUT_TEX0 = 0x98,
+ GX_BP_REG_SETTLUT_TEX1 = 0x99,
+ GX_BP_REG_SETTLUT_TEX2 = 0x9A,
+ GX_BP_REG_SETTLUT_TEX3 = 0x9B,
+
+ // set modes continued
+ GX_BP_REG_SETMODE0_TEX4 = 0xA0,
+ GX_BP_REG_SETMODE0_TEX5 = 0xA1,
+ GX_BP_REG_SETMODE0_TEX6 = 0xA2,
+ GX_BP_REG_SETMODE0_TEX7 = 0xA3,
+ GX_BP_REG_SETMODE1_TEX4 = 0xA4,
+ GX_BP_REG_SETMODE1_TEX5 = 0xA5,
+ GX_BP_REG_SETMODE1_TEX6 = 0xA6,
+ GX_BP_REG_SETMODE1_TEX7 = 0xA7,
+
+ // set images continued
+ GX_BP_REG_SETIMAGE0_TEX4 = 0xA8,
+ GX_BP_REG_SETIMAGE0_TEX5 = 0xA9,
+ GX_BP_REG_SETIMAGE0_TEX6 = 0xAA,
+ GX_BP_REG_SETIMAGE0_TEX7 = 0xAB,
+ GX_BP_REG_SETIMAGE1_TEX4 = 0xAC,
+ GX_BP_REG_SETIMAGE1_TEX5 = 0xAD,
+ GX_BP_REG_SETIMAGE1_TEX6 = 0xAE,
+ GX_BP_REG_SETIMAGE1_TEX7 = 0xAF,
+ GX_BP_REG_SETIMAGE2_TEX4 = 0xB0,
+ GX_BP_REG_SETIMAGE2_TEX5 = 0xB1,
+ GX_BP_REG_SETIMAGE2_TEX6 = 0xB2,
+ GX_BP_REG_SETIMAGE2_TEX7 = 0xB3,
+ GX_BP_REG_SETIMAGE3_TEX4 = 0xB4,
+ GX_BP_REG_SETIMAGE3_TEX5 = 0xB5,
+ GX_BP_REG_SETIMAGE3_TEX6 = 0xB6,
+ GX_BP_REG_SETIMAGE3_TEX7 = 0xB7,
+
+ // set texture lookups continued
+ GX_BP_REG_SETTLUT_TEX4 = 0xB8,
+ GX_BP_REG_SETTLUT_TEX5 = 0xB9,
+ GX_BP_REG_SETTLUT_TEX6 = 0xBA,
+ GX_BP_REG_SETTLUT_TEX7 = 0xBB,
+
+ // TEV color manips
+ GX_BP_REG_TEVCOLORCOMBINER0 = 0xC0,
+ GX_BP_REG_TEVALPHACOMBINER0 = 0xC1,
+ GX_BP_REG_TEVCOLORCOMBINER1 = 0xC2,
+ GX_BP_REG_TEVALPHACOMBINER1 = 0xC3,
+ GX_BP_REG_TEVCOLORCOMBINER2 = 0xC4,
+ GX_BP_REG_TEVALPHACOMBINER2 = 0xC5,
+ GX_BP_REG_TEVCOLORCOMBINER3 = 0xC6,
+ GX_BP_REG_TEVALPHACOMBINER3 = 0xC7,
+ GX_BP_REG_TEVCOLORCOMBINER4 = 0xC8,
+ GX_BP_REG_TEVALPHACOMBINER4 = 0xC9,
+ GX_BP_REG_TEVCOLORCOMBINER5 = 0xCA,
+ GX_BP_REG_TEVALPHACOMBINER5 = 0xCB,
+ GX_BP_REG_TEVCOLORCOMBINER6 = 0xCC,
+ GX_BP_REG_TEVALPHACOMBINER6 = 0xCD,
+ GX_BP_REG_TEVCOLORCOMBINER7 = 0xCE,
+ GX_BP_REG_TEVALPHACOMBINER7 = 0xCF,
+ GX_BP_REG_TEVCOLORCOMBINER8 = 0xD0,
+ GX_BP_REG_TEVALPHACOMBINER8 = 0xD1,
+ GX_BP_REG_TEVCOLORCOMBINER9 = 0xD2,
+ GX_BP_REG_TEVALPHACOMBINER9 = 0xD3,
+ GX_BP_REG_TEVCOLORCOMBINER10 = 0xD4,
+ GX_BP_REG_TEVALPHACOMBINER10 = 0xD5,
+ GX_BP_REG_TEVCOLORCOMBINER11 = 0xD6,
+ GX_BP_REG_TEVALPHACOMBINER11 = 0xD7,
+ GX_BP_REG_TEVCOLORCOMBINER12 = 0xD8,
+ GX_BP_REG_TEVALPHACOMBINER12 = 0xD9,
+ GX_BP_REG_TEVCOLORCOMBINER13 = 0xDA,
+ GX_BP_REG_TEVALPHACOMBINER13 = 0xDB,
+ GX_BP_REG_TEVCOLORCOMBINER14 = 0xDC,
+ GX_BP_REG_TEVALPHACOMBINER14 = 0xDD,
+ GX_BP_REG_TEVCOLORCOMBINER15 = 0xDE,
+ GX_BP_REG_TEVALPHACOMBINER15 = 0xDF,
+
+ // TEV registers
+ GX_BP_REG_TEVREG0LO = 0xE0,
+ GX_BP_REG_TEVREG0HI = 0xE1,
+ GX_BP_REG_TEVREG1LO = 0xE2,
+ GX_BP_REG_TEVREG1HI = 0xE3,
+ GX_BP_REG_TEVREG2LO = 0xE4,
+ GX_BP_REG_TEVREG2HI = 0xE5,
+ GX_BP_REG_TEVREG3LO = 0xE6,
+ GX_BP_REG_TEVREG3HI = 0xE7,
+
+ // fog registers
+ GX_BP_REG_FOGRANGE = 0xE8,
+ GX_BP_REG_FOGRANGEK0 = 0xE9,
+ GX_BP_REG_FOGRANGEK1 = 0xEA,
+ GX_BP_REG_FOGRANGEK2 = 0xEB,
+ GX_BP_REG_FOGRANGEK3 = 0xEC,
+ GX_BP_REG_FOGRANGEK4 = 0xED,
+ GX_BP_REG_FOGPARAM0 = 0xEE,
+ GX_BP_REG_FOGPARAM1 = 0xEF,
+ GX_BP_REG_FOGPARAM2 = 0xF0,
+ GX_BP_REG_FOGPARAM3 = 0xF1,
+ GX_BP_REG_FOGCOLOR = 0xF2,
+
+ // performance manip registers
+ GX_BP_REG_ALPHACOMPARE = 0xF3,
+ GX_BP_REG_ZTEXTURE0 = 0xF4,
+ GX_BP_REG_ZTEXTURE1 = 0xF5,
+
+ // TEV K selectors
+ GX_BP_REG_TEVKSEL0 = 0xF6,
+ GX_BP_REG_TEVKSEL1 = 0xF7,
+ GX_BP_REG_TEVKSEL2 = 0xF8,
+ GX_BP_REG_TEVKSEL3 = 0xF9,
+ GX_BP_REG_TEVKSEL4 = 0xFA,
+ GX_BP_REG_TEVKSEL5 = 0xFB,
+ GX_BP_REG_TEVKSEL6 = 0xFC,
+ GX_BP_REG_TEVKSEL7 = 0xFD,
+
+ // SS mask
+ GX_BP_REG_SSMASK = 0xFE,
+} GXBPRegs;
+
+// BP locators for fog parameter 0.
+typedef enum _GXBPFogParam0 {
+ // A mantissa [21-31]
+ GX_BP_FOGPARAM0_A_MANT_ST = 21,
+ GX_BP_FOGPARAM0_A_MANT_END = 31,
+
+ // A exponent [13-20]
+ GX_BP_FOGPARAM0_A_EXP_ST = 13,
+ GX_BP_FOGPARAM0_A_EXP_END = 20,
+
+ // A sign [12-12]
+ GX_BP_FOGPARAM0_A_SIGN_ST = 12,
+ GX_BP_FOGPARAM0_A_SIGN_END = 12,
+} GXBPFogParam0;
+
+// BP locators for fog parameter 1.
+typedef enum _GXBPFogParam1 {
+ // B magnitude [8-31]
+ GX_BP_FOGPARAM1_B_MAG_ST = 8,
+ GX_BP_FOGPARAM1_B_MAG_END = 31,
+} GXBPFogParam1;
+
+// BP locators for fog parameter 2.
+typedef enum _GXBPFogParam2 {
+ // B shift [27-31]
+ GX_BP_FOGPARAM2_B_SHIFT_ST = 27,
+ GX_BP_FOGPARAM2_B_SHIFT_END = 31,
+} GXBPFogParam2;
+
+// BP locators for fog parameter 3.
+typedef enum _GXBPFogParam3 {
+ // C mantissa [21-31]
+ GX_BP_FOGPARAM3_C_MANT_ST = 21,
+ GX_BP_FOGPARAM3_C_MANT_END = 31,
+
+ // C exponent [13-20]
+ GX_BP_FOGPARAM3_C_EXP_ST = 13,
+ GX_BP_FOGPARAM3_C_EXP_END = 20,
+
+ // C sign [12-12]
+ GX_BP_FOGPARAM3_C_SIGN_ST = 12,
+ GX_BP_FOGPARAM3_C_SIGN_END = 12,
+
+ // Projection [11]
+ GX_BP_FOGPARAM3_PROJ_ST = 11,
+ GX_BP_FOGPARAM3_PROJ_END = 11,
+
+ // F select [8-10]
+ GX_BP_FOGPARAM3_FSEL_ST = 8,
+ GX_BP_FOGPARAM3_FSEL_END = 10,
+} GXBPFogParam3;
+
+// BP locators for fog color.
+typedef enum _GXBPFogColor {
+ // RGB components of color [8-31]
+ GX_BP_FOGCOLOR_RGB_ST = 8,
+ GX_BP_FOGCOLOR_RGB_END = 31,
+} GXBPFogColor;
+
+// BP locators for fog range.
+typedef enum _GXBPFogRange {
+ // Center [22-31]
+ GX_BP_FOGRANGE_CENTER_ST = 22,
+ GX_BP_FOGRANGE_CENTER_END = 31,
+
+ // Enabled [21-21]
+ GX_BP_FOGRANGE_ENABLED_ST = 21,
+ GX_BP_FOGRANGE_ENABLED_END = 21,
+} GXBPFogRange;
+
+// BP locators for fog range K.
+typedef enum _GXBPFogRangeK {
+ // Hi [20-31]
+ GX_BP_FOGRANGEK_HI_ST = 20,
+ GX_BP_FOGRANGEK_HI_END = 31,
+
+ // Lo [8-19]
+ GX_BP_FOGRANGEK_LO_ST = 8,
+ GX_BP_FOGRANGEK_LO_END = 19,
+} GXBPFogRangeK;
+
+// BP locators for blend mode.
+typedef enum _GXBPBlendMode {
+ // Blend enable [31-31]
+ GX_BP_BLENDMODE_ENABLE_ST = 31,
+ GX_BP_BLENDMODE_ENABLE_END = 31,
+
+ // Logic operation enable [30-30]
+ GX_BP_BLENDMODE_LOGIC_OP_ST = 30,
+ GX_BP_BLENDMODE_LOGIC_OP_END = 30,
+
+ // Dither [29-29]
+ GX_BP_BLENDMODE_DITHER_ST = 29,
+ GX_BP_BLENDMODE_DITHER_END = 29,
+
+ // Color update [28-28]
+ GX_BP_BLENDMODE_COLOR_UPDATE_ST = 28,
+ GX_BP_BLENDMODE_COLOR_UPDATE_END = 28,
+
+ // Alpha update [27-27]
+ GX_BP_BLENDMODE_ALPHA_UPDATE_ST = 27,
+ GX_BP_BLENDMODE_ALPHA_UPDATE_END = 27,
+
+ // Destination factor [24-26]
+ GX_BP_BLENDMODE_DSTFACTOR_ST = 24,
+ GX_BP_BLENDMODE_DSTFACTOR_END = 26,
+
+ // Source factor [21-23]
+ GX_BP_BLENDMODE_SRCFACTOR_ST = 21,
+ GX_BP_BLENDMODE_SRCFACTOR_END = 23,
+
+ // Subtract [20-20]
+ GX_BP_BLENDMODE_SUBTRACT_ST = 20,
+ GX_BP_BLENDMODE_SUBTRACT_END = 20,
+
+ // Logic mode [16-19]
+ GX_BP_BLENDMODE_LOGICMODE_ST = 16,
+ GX_BP_BLENDMODE_LOGICMODE_END = 19,
+} GXBPBlendMode;
+
+// BP locators for Z mode.
+typedef enum _GXBPZMode {
+ // Test enable [31-31]
+ GX_BP_ZMODE_TEST_ENABLE_ST = 31,
+ GX_BP_ZMODE_TEST_ENABLE_END = 31,
+
+ // Compare [28-30]
+ GX_BP_ZMODE_COMPARE_ST = 28,
+ GX_BP_ZMODE_COMPARE_END = 30,
+
+ // Update enable [27-27]
+ GX_BP_ZMODE_UPDATE_ENABLE_ST = 27,
+ GX_BP_ZMODE_UPDATE_ENABLE_END = 27,
+} GXBPZMode;
+
+// BP locators for Z control.
+typedef enum _GXBPZControl {
+ // Pixel format [29-31]
+ GX_BP_ZCONTROL_PIXEL_FMT_ST = 29,
+ GX_BP_ZCONTROL_PIXEL_FMT_END = 31,
+
+ // Z format [26-28]
+ GX_BP_ZCONTROL_Z_FMT_ST = 26,
+ GX_BP_ZCONTROL_Z_FMT_END = 28,
+
+ // Whether to do Z-buffering before or after texturing [25-25]
+ GX_BP_ZCONTROL_BEFORE_TEX_ST = 25,
+ GX_BP_ZCONTROL_BEFORE_TEX_END = 25,
+} GXBPZControl;
+
+// BP locators for destination alpha.
+typedef enum _GXBPDstAlpha {
+ // Alpha [24-31]
+ GX_BP_DSTALPHA_ALPHA_ST = 24,
+ GX_BP_DSTALPHA_ALPHA_END = 31,
+
+ // Enable [23-23]
+ GX_BP_DSTALPHA_ENABLE_ST = 23,
+ GX_BP_DSTALPHA_ENABLE_END = 23,
+
+ // YUV format [21-22]
+ GX_BP_DSTALPHA_YUV_FMT_ST = 21,
+ GX_BP_DSTALPHA_YUV_FMT_END = 22,
+} GXBPDstAlpha;
+
+// BP locators for field mask.
+typedef enum _GXBPFieldMask {
+ // Whether to write odd fields to the EFB [31-31]
+ GX_BP_FIELDMASK_ODD_ST = 31,
+ GX_BP_FIELDMASK_ODD_END = 31,
+
+ // Whether to write even fields to the EFB [30-30]
+ GX_BP_FIELDMASK_EVEN_ST = 30,
+ GX_BP_FIELDMASK_EVEN_END = 30,
+} GXBPFieldMask;
+
+// BP locators for line and point settings.
+typedef enum _GXBPLinePtWidth {
+ // Line size/width [24-31]
+ GX_BP_LINEPTWIDTH_LINESZ_ST = 24,
+ GX_BP_LINEPTWIDTH_LINESZ_END = 31,
+
+ // Point size [16-23]
+ GX_BP_LINEPTWIDTH_POINTSZ_ST = 16,
+ GX_BP_LINEPTWIDTH_POINTSZ_END = 23,
+
+ // Line offset [13-15]
+ GX_BP_LINEPTWIDTH_LINEOFS_ST = 13,
+ GX_BP_LINEPTWIDTH_LINEOFS_END = 15,
+
+ // Point offset [10-12]
+ GX_BP_LINEPTWIDTH_POINTOFS_ST = 10,
+ GX_BP_LINEPTWIDTH_POINTOFS_END = 12,
+
+ // Interlacing adjustment for aspect ratio [9-9]
+ GX_BP_LINEPTWIDTH_ADJUST_ST = 9,
+ GX_BP_LINEPTWIDTH_ADJUST_END = 9,
+} GXBPLinePtWidth;
+
+// Miscellaneous token types.
+typedef enum _GXMiscToken {
+ GX_MT_NULL = 0,
+ GX_MT_XF_FLUSH = 1,
+ GX_MT_DL_SAVE_CONTEXT = 2,
+ GX_MT_ABORT_WAIT_COPYOUT = 3,
+} GXMiscToken;
+
+// Transform memory types.
+typedef enum _GXXfMem {
+ GX_XF_MEM_POSMTX = 0x000, // position coord matrix
+ GX_XF_MEM_NRMMTX = 0x400, // normal coord matrix
+ GX_XF_MEM_DUALTEXMTX = 0x500, // dual texture matrix
+ GX_XF_MEM_LIGHTOBJ = 0x600, // light object
+} GXXfMem;
+
+// BP locators for top-left scissor.
+typedef enum _GXBPScissorTL {
+ // Top component [21-31]
+ GX_BP_SCISSORTL_TOP_ST = 21,
+ GX_BP_SCISSORTL_TOP_END = 31,
+
+ // Left component [9-19]
+ GX_BP_SCISSORTL_LEFT_ST = 9,
+ GX_BP_SCISSORTL_LEFT_END = 19,
+} GXBPScissorTL;
+
+// BP locators for bottom-right scissor.
+typedef enum _GXBPScissorBR {
+ // Bottom component [21-31]
+ GX_BP_SCISSORBR_BOT_ST = 21,
+ GX_BP_SCISSORBR_BOT_END = 31,
+
+ // Right component [9-19]
+ GX_BP_SCISSORBR_RIGHT_ST = 9,
+ GX_BP_SCISSORBR_RIGHT_END = 19,
+} GXBPScissorBR;
+
+// BP locators for scissor offset.
+typedef enum _GXBPScissorOffset {
+ // X offset [22-31]
+ GX_BP_SCISSOROFS_OX_ST = 22,
+ GX_BP_SCISSOROFS_OX_END = 31,
+
+ // Y offset [12-21]
+ GX_BP_SCISSOROFS_OY_ST = 12,
+ GX_BP_SCISSOROFS_OY_END = 21,
+} GXBPScissorOffset;
+
+// Perf-0 types.
+typedef enum _GXPerf0 {
+ GX_PERF0_VERTICES = 0,
+ GX_PERF0_CLIP_VTX = 1,
+ GX_PERF0_CLIP_CLKS = 2,
+ GX_PERF0_XF_WAIT_IN = 3,
+ GX_PERF0_XF_WAIT_OUT = 4,
+ GX_PERF0_XF_XFRM_CLKS = 5,
+ GX_PERF0_XF_LIT_CLKS = 6,
+ GX_PERF0_XF_BOT_CLKS = 7,
+ GX_PERF0_XF_REGLD_CLKS = 8,
+ GX_PERF0_XF_REGRD_CLKS = 9,
+ GX_PERF0_CLIP_RATIO = 10,
+
+ GX_PERF0_TRIANGLES = 11,
+ GX_PERF0_TRIANGLES_CULLED = 12,
+ GX_PERF0_TRIANGLES_PASSED = 13,
+ GX_PERF0_TRIANGLES_SCISSORED = 14,
+ GX_PERF0_TRIANGLES_0TEX = 15,
+ GX_PERF0_TRIANGLES_1TEX = 16,
+ GX_PERF0_TRIANGLES_2TEX = 17,
+ GX_PERF0_TRIANGLES_3TEX = 18,
+ GX_PERF0_TRIANGLES_4TEX = 19,
+ GX_PERF0_TRIANGLES_5TEX = 20,
+ GX_PERF0_TRIANGLES_6TEX = 21,
+ GX_PERF0_TRIANGLES_7TEX = 22,
+ GX_PERF0_TRIANGLES_8TEX = 23,
+ GX_PERF0_TRIANGLES_0CLR = 24,
+ GX_PERF0_TRIANGLES_1CLR = 25,
+ GX_PERF0_TRIANGLES_2CLR = 26,
+
+ GX_PERF0_QUAD_0CVG = 27,
+ GX_PERF0_QUAD_NON0CVG = 28,
+ GX_PERF0_QUAD_1CVG = 29,
+ GX_PERF0_QUAD_2CVG = 30,
+ GX_PERF0_QUAD_3CVG = 31,
+ GX_PERF0_QUAD_4CVG = 32,
+ GX_PERF0_AVG_QUAD_CNT = 33,
+
+ GX_PERF0_CLOCKS = 34,
+ GX_PERF0_NONE = 35,
+} GXPerf0;
+
+// Perf-1 types.
+typedef enum _GXPerf1 {
+ GX_PERF1_TEXELS = 0,
+ GX_PERF1_TX_IDLE = 1,
+ GX_PERF1_TX_REGS = 2,
+ GX_PERF1_TX_MEMSTALL = 3,
+ GX_PERF1_TC_CHECK1_2 = 4,
+ GX_PERF1_TC_CHECK3_4 = 5,
+ GX_PERF1_TC_CHECK5_6 = 6,
+ GX_PERF1_TC_CHECK7_8 = 7,
+ GX_PERF1_TC_MISS = 8,
+
+ GX_PERF1_VC_ELEMQ_FULL = 9,
+ GX_PERF1_VC_MISSQ_FULL = 10,
+ GX_PERF1_VC_MEMREQ_FULL = 11,
+ GX_PERF1_VC_STATUS7 = 12,
+ GX_PERF1_VC_MISSREP_FULL = 13,
+ GX_PERF1_VC_STREAMBUF_LOW = 14,
+ GX_PERF1_VC_ALL_STALLS = 15,
+ GX_PERF1_VERTICES = 16,
+
+ GX_PERF1_FIFO_REQ = 17,
+ GX_PERF1_CALL_REQ = 18,
+ GX_PERF1_VC_MISS_REQ = 19,
+ GX_PERF1_CP_ALL_REQ = 20,
+
+ GX_PERF1_CLOCKS = 21,
+ GX_PERF1_NONE = 22,
+} GXPerf1;
+
+// Vertex cache perf types.
+typedef enum _GXVCachePerf {
+ GX_VC_POS = 0,
+ GX_VC_NRM = 1,
+ GX_VC_CLR0 = 2,
+ GX_VC_CLR1 = 3,
+ GX_VC_TEX0 = 4,
+ GX_VC_TEX1 = 5,
+ GX_VC_TEX2 = 6,
+ GX_VC_TEX3 = 7,
+ GX_VC_TEX4 = 8,
+ GX_VC_TEX5 = 9,
+ GX_VC_TEX6 = 10,
+ GX_VC_TEX7 = 11,
+
+ GX_VC_ALL = 15
+} GXVCachePerf;
+
+// XF locators for Color 0 control.
+typedef enum _GXXFClr0Ctrl {
+ // Matrix source [31-31]
+ GX_XF_CLR0CTRL_MTXSRC_ST = 31,
+ GX_XF_CLR0CTRL_MTXSRC_END = 31,
+
+ // Light [30-30]
+ GX_XF_CLR0CTRL_LIGHT_ST = 30,
+ GX_XF_CLR0CTRL_LIGHT_END = 30,
+
+ // Light mask (hi) [26-29]
+ GX_XF_CLR0CTRL_LMASKHI_ST = 26,
+ GX_XF_CLR0CTRL_LMASKHI_END = 29,
+
+ // Ambient source [25-25]
+ GX_XF_CLR0CTRL_AMBSRC_ST = 25,
+ GX_XF_CLR0CTRL_AMBSRC_END = 25,
+
+ // Diffuse attenuation [23-24]
+ GX_XF_CLR0CTRL_DIFATTN_ST = 23,
+ GX_XF_CLR0CTRL_DIFATTN_END = 24,
+
+ // Enable attentuation [22-22]
+ GX_XF_CLR0CTRL_ATTNENABLE_ST = 22,
+ GX_XF_CLR0CTRL_ATTNENABLE_END = 22,
+
+ // Select attentuation [21-21]
+ GX_XF_CLR0CTRL_ATTNSEL_ST = 21,
+ GX_XF_CLR0CTRL_ATTNSEL_END = 21,
+
+ // Light mask (lo) [17-20]
+ GX_XF_CLR0CTRL_LMASKLO_ST = 17,
+ GX_XF_CLR0CTRL_LMASKLO_END = 20,
+} GXXFClr0Ctrl;
+
#endif /* GXENUM_H */
diff --git a/include/dolphin/gx/GXFifo.h b/include/dolphin/gx/GXFifo.h
index 7bdfceee..c234c51f 100644
--- a/include/dolphin/gx/GXFifo.h
+++ b/include/dolphin/gx/GXFifo.h
@@ -9,27 +9,29 @@
extern "C" {
#endif
+typedef void (*GXBreakPtCallback)(void);
+
void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size);
void GXInitFifoPtrs(GXFifoObj* fifo, void* read_ptr, void* write_ptr);
-void GXSetCPUFifo(void);
-void GXSetGPFifo(void);
+void GXSetCPUFifo(GXFifoObj* fifo);
+void GXSetGPFifo(GXFifoObj* fifo);
void GXSaveCPUFifo(GXFifoObj* fifo);
void __GXSaveCPUFifoAux(GXFifoObj* fifo);
void GXGetGPStatus(GXBool* overhi, GXBool* underlo, GXBool* read_idle, GXBool* cmd_idle, GXBool* breakpoint);
void* GXGetFifoBase(GXFifoObj* fifo);
u32 GXGetFifoSize(GXFifoObj* fifo);
-void GXSetBreakPtCallback(void);
+GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb);
void __GXFifoInit(void);
void __GXFifoReadEnable(void);
void __GXFifoReadDisable(void);
void __GXFifoLink(u8);
-void __GXWriteFifoIntEnable(u8, u8);
-void __GXWriteFifoIntReset(u8, u8);
+void __GXWriteFifoIntEnable(u32 p1, u32 p2);
+void __GXWriteFifoIntReset(u32 p1, u32 p2);
void __GXCleanGPFifo(void);
OSThread* GXSetCurrentGXThread(void);
OSThread* GXGetCurrentGXThread(void);
GXFifoObj* GXGetCPUFifo(void);
-u32 GXGetGPFifo(void);
+GXFifoObj* GXGetGPFifo(void);
#ifdef __cplusplus
};
diff --git a/include/dolphin/gx/GXFrameBuf.h b/include/dolphin/gx/GXFrameBuf.h
index ea4662b5..798cb8c2 100644
--- a/include/dolphin/gx/GXFrameBuf.h
+++ b/include/dolphin/gx/GXFrameBuf.h
@@ -17,7 +17,7 @@ extern GXRenderModeObj GXEurgb60Hz480IntDf;
void GXSetDispCopySrc(u16 left, u16 top, u16 width, u16 height);
void GXSetTexCopySrc(u16 left, u16 top, u16 width, u16 height);
void GXSetDispCopyDst(u16 arg0, u16 arg1);
-void GXSetTexCopyDst(u16 width, u16 height, s32 fmt, GXBool mipmap);
+void GXSetTexCopyDst(u16 width, u16 height, GXTexFmt format, GXBool useMIPmap);
void GXSetDispCopyFrame2Field(GXCopyMode mode);
void GXSetCopyClamp(GXFBClamp clamp);
u16 GXGetNumXfbLines(u16 efb_height, f32 y_scale);
diff --git a/include/dolphin/gx/GXInit.h b/include/dolphin/gx/GXInit.h
index 72eef5a6..87e9a754 100644
--- a/include/dolphin/gx/GXInit.h
+++ b/include/dolphin/gx/GXInit.h
@@ -5,112 +5,159 @@
#include "dolphin/gx/GXStruct.h"
#include "dolphin/mtx/mtx.h"
-typedef GXTexRegion (*GXTexRegionCallback)(GXTexObj* obj);
-typedef GXTlutRegion* (*GXTlutRegionCallback)(u32 name);
+typedef GXTexRegion* (*GXTexRegionCallback)(const GXTexObj* t_obj, GXTexMapID id);
+typedef GXTlutRegion* (*GXTlutRegionCallback)(u32 idx);
typedef struct _GXData {
- /* 0x000 */ u16 field_0x0;
- /* 0x002 */ u16 field_0x2;
- /* 0x004 */ u16 field_0x4;
- /* 0x006 */ u16 field_0x6;
- /* 0x008 */ u32 field_0x8;
- /* 0x00C */ u32 field_0xc;
- /* 0x010 */ u32 field_0x10;
- /* 0x014 */ u32 field_0x14;
- /* 0x018 */ GXAttrType field_0x18;
- /* 0x01C */ GXCompCnt field_0x1c[8];
- /* 0x03C */ GXCompCnt field_0x3c[8];
- /* 0x05C */ u32 field_0x5c[8];
- /* 0x07C */ u32 field_0x7c;
- /* 0x080 */ u32 field_0x80;
- /* 0x084 */ u32 field_0x84;
- /* 0x088 */ u8 field_0x88[0xA8 - 0x88];
- /* 0x0A8 */ GXColor ambColors[2];
- /* 0x0B0 */ GXColor matColors[2];
- /* 0x0B8 */ u32 field_0xb8[8]; // GX_MAX_TEXCOORD
- /* 0x0D8 */ u32 field_0xd8[8]; // GX_MAX_TEXCOORD
- /* 0x0F8 */ u32 field_0xf8;
- /* 0x0FC */ u32 field_0xfc;
- /* 0x100 */ u32 field_0x100[GX_MAX_TEVSTAGE / 2];
- /* 0x120 */ u32 field_0x120;
- /* 0x124 */ u32 field_0x124;
- /* 0x128 */ u32 field_0x128;
- /* 0x12C */ u32 field_0x12c;
- /* 0x130 */ u32 field_0x130[GX_MAX_TEVSTAGE];
- /* 0x170 */ u32 field_0x170[GX_MAX_TEVSTAGE];
- /* 0x1B0 */ u32 field_0x1b0[GX_MAX_TEVSTAGE / 2];
- /* 0x1D0 */ u32 field_0x1d0;
- /* 0x1D4 */ u32 field_0x1d4;
- /* 0x1D8 */ u32 field_0x1d8;
- /* 0x1DC */ u32 field_0x1dc;
- /* 0x1E0 */ u32 field_0x1e0;
- /* 0x1E4 */ u32 field_0x1e4;
- /* 0x1E8 */ u32 field_0x1e8;
- /* 0x1EC */ u32 field_0x1ec;
- /* 0x1F0 */ u32 field_0x1f0;
- /* 0x1F4 */ u32 field_0x1f4;
- /* 0x1F8 */ u32 field_0x1f8;
- /* 0x1FC */ u32 field_0x1fc;
- /* 0x200 */ u8 field_0x200;
- /* 0x204 */ u32 field_0x204;
- /* 0x208 */ GXTexRegion field_0x208[8];
- /* 0x288 */ GXTexRegion field_0x288[8];
- /* 0x308 */ GXTexRegion field_0x308[8];
- /* 0x388 */ GXTlutRegion field_0x388[16];
- /* 0x488 */ GXTlutRegion field_0x488[4];
- /* 0x4C8 */ GXTexRegionCallback field_0x4c8;
- /* 0x4CC */ GXTlutRegionCallback field_0x4cc;
- /* 0x4D0 */ GXAttrType field_0x4d0;
- /* 0x4D4 */ u8 field_0x4d4;
- /* 0x4D5 */ u8 field_0x4d5;
- /* 0x4D8 */ GXProjectionType field_0x4d8;
- /* 0x4DC */ Mtx field_0x4dc;
- /* 0x50C */ f32 field_0x50c;
- /* 0x510 */ f32 field_0x510;
- /* 0x514 */ u32 field_0x514[8];
- /* 0x534 */ u32 field_0x534[8];
- /* 0x554 */ u32 field_0x554;
- /* 0x558 */ u32 field_0x558[8];
- /* 0x578 */ u8 field_0x578[0x594 - 0x578];
- /* 0x594 */ u32 field_0x594;
- /* 0x598 */ u32 field_0x598;
- /* 0x59C */ u32 field_0x59c;
- /* 0x5A0 */ u8 field_0x5a0[4];
- /* 0x5A4 */ u32 field_0x5a4;
- /* 0x5A8 */ u8 field_0x5a8;
- /* 0x5A9 */ u8 field_0x5a9;
- /* 0x5AA */ u8 field_0x5aa;
- /* 0x5AB */ u8 field_0x5ab;
- /* 0x5AC */ u32 field_0x5ac;
+ // Bypass and vertex info
+ /* 0x000 */ u16 vNumNot;
+ /* 0x002 */ u16 bpSentNot;
+ /* 0x004 */ u16 vNum;
+ /* 0x006 */ u16 vLim;
+
+ // Command process (CP) regs
+ /* 0x008 */ u32 cpEnable;
+ /* 0x00C */ u32 cpStatus;
+ /* 0x010 */ u32 cpClr;
+ /* 0x014 */ u32 vcdLo;
+ /* 0x018 */ u32 vcdHi;
+ /* 0x01C */ u32 vatA[8];
+ /* 0x03C */ u32 vatB[8];
+ /* 0x05C */ u32 vatC[8];
+ /* 0x07C */ u32 lpSize;
+ /* 0x080 */ u32 matIdxA;
+ /* 0x084 */ u32 matIdxB;
+
+ // Index loading base/stride regs (pos, nrm, tex, light)
+ /* 0x088 */ u32 indexBase[4];
+ /* 0x098 */ u32 indexStride[4];
+
+ // Transform and lighting regs
+ /* 0x0A8 */ u32 ambColor[2];
+ /* 0x0B0 */ u32 matColor[2];
+
+ // Setup regs
+ /* 0x0B8 */ u32 suTs0[8];
+ /* 0x0D8 */ u32 suTs1[8];
+ /* 0x0F8 */ u32 suScis0;
+ /* 0x0FC */ u32 suScis1;
+
+ // Raster regs
+ /* 0x100 */ u32 tref[8];
+ /* 0x120 */ u32 iref;
+
+ // Bump/Indirect texture regs
+ /* 0x124 */ u32 bpMask;
+ /* 0x128 */ u32 IndTexScale0;
+ /* 0x12C */ u32 IndTexScale1;
+
+ // Tev regs
+ /* 0x130 */ u32 tevc[16];
+ /* 0x170 */ u32 teva[16];
+ /* 0x1B0 */ u32 tevKsel[8];
+
+ // Performance regs
+ /* 0x1D0 */ u32 cmode0;
+ /* 0x1D4 */ u32 cmode1;
+ /* 0x1D8 */ u32 zmode;
+ /* 0x1DC */ u32 peCtrl;
+
+ // Display copy regs
+ /* 0x1E0 */ u32 cpDispSrc;
+ /* 0x1E4 */ u32 cpDispSize;
+ /* 0x1E8 */ u32 cpDispStride;
+ /* 0x1EC */ u32 cpDisp;
+
+ // Texture copy regs
+ /* 0x1F0 */ u32 cpTexSrc;
+ /* 0x1F4 */ u32 cpTexSize;
+ /* 0x1F8 */ u32 cpTexStride;
+ /* 0x1FC */ u32 cpTex;
+ /* 0x200 */ GXBool cpTexZ;
+
+ // General raster mode
+ /* 0x204 */ u32 genMode;
+
+ // Texture regions
+ /* 0x208 */ GXTexRegion TexRegions0[GX_MAX_TEXMAP];
+ /* 0x288 */ GXTexRegion TexRegions1[GX_MAX_TEXMAP];
+ /* 0x308 */ GXTexRegion TexRegions2[GX_MAX_TEXMAP];
+
+ // Texture lookup table regions
+ /* 0x388 */ GXTlutRegion TlutRegions[GX_MAX_TLUT_ALL];
+ /* 0x4C8 */ GXTexRegionCallback texRegionCallback;
+ /* 0x4CC */ GXTlutRegionCallback tlutRegionCallback;
+
+ // Command processor vars
+ /* 0x4D0 */ GXAttrType nrmType;
+ /* 0x4D4 */ GXBool hasNrms;
+ /* 0x4D5 */ GXBool hasBiNrms;
+ /* 0x4D8 */ u32 projType;
+ /* 0x4DC */ f32 projMtx[6];
+
+ // Viewport parms
+ /* 0x4F4 */ f32 vpLeft;
+ /* 0x4F8 */ f32 vpTop;
+ /* 0x4FC */ f32 vpWd;
+ /* 0x500 */ f32 vpHt;
+ /* 0x504 */ f32 vpNearz;
+ /* 0x508 */ f32 vpFarz;
+ /* 0x50C */ f32 zOffset;
+ /* 0x510 */ f32 zScale;
+
+ // Texture regs
+ /* 0x514 */ u32 tImage0[8];
+ /* 0x534 */ u32 tMode0[8];
+ /* 0x554 */ u32 texmapId[16];
+ /* 0x594 */ u32 tcsManEnab;
+ /* 0x598 */ u32 tevTcEnab;
+
+ // Performance metrics
+ /* 0x59C */ GXPerf0 perf0;
+ /* 0x5A0 */ GXPerf1 perf1;
+ /* 0x5A4 */ u32 perfSel;
+
+ // Flags
+ /* 0x5A8 */ GXBool inDispList;
+ /* 0x5A9 */ GXBool dlSaveContext;
+ /* 0x5AA */ GXBool abtWaitPECopy;
+ /* 0x5AB */ u8 dirtyVAT;
+ /* 0x5AC */ u32 dirtyState;
} GXData; // Size: 0x5B0
STATIC_ASSERT(sizeof(GXData) == 0x5B0);
extern GXData* const __GXData;
+// Define register addresses.
+#define GX_CP_ADDR (0x0C000000)
+#define GX_PE_ADDR (0x0C001000)
+#define GX_PI_ADDR (0x0C003000)
+#define GX_MEM_ADDR (0x0C004000)
+
extern u32* __piReg;
extern u16* __cpReg;
-extern u8 __peReg[4];
-extern u8 __memReg[4];
+extern u16* __peReg;
+extern vu16* __memReg;
inline void GXSetWasteFlags() {
- GXData* data = __GXData;
- data->field_0x5ac |= 0x3;
- data->field_0x2 = 0;
+ GXData* data = __GXData;
+ data->dirtyState |= GX_DIRTY_SU_TEX | GX_DIRTY_BP_MASK;
+ data->bpSentNot = 0;
}
static inline void set_x2(u16 value)
{
- __GXData->field_0x2 = value;
+ __GXData->bpSentNot = value;
}
#ifdef __cplusplus
extern "C" {
#endif
-GXTexRegion* __GXDefaultTexRegionCallback(GXTexObj* obj, GXTexMapID mapID);
+GXTexRegion* __GXDefaultTexRegionCallback(const GXTexObj* obj, GXTexMapID id);
GXTlutRegion* __GXDefaultTlutRegionCallback(u32 tlut);
-void __GXShutdown(s32);
+BOOL __GXShutdown(BOOL final);
void __GXInitRevisionBits(void);
GXFifoObj* GXInit(void* base, u32 size);
void __GXInitGX(void);
diff --git a/include/dolphin/gx/GXMisc.h b/include/dolphin/gx/GXMisc.h
index 7c4524b6..86213dab 100644
--- a/include/dolphin/gx/GXMisc.h
+++ b/include/dolphin/gx/GXMisc.h
@@ -7,7 +7,7 @@
extern "C" {
#endif
-void GXSetMisc(u32 id, u32 value);
+void GXSetMisc(GXMiscToken token, u32 val);
void GXFlush(void);
void __GXAbort(void);
void GXAbortFrame(void);
@@ -21,7 +21,7 @@ void GXPokeBlendMode(GXBlendMode mode, GXBlendFactor src_factor, GXBlendFactor d
void GXPokeColorUpdate(GXBool enable_update);
void GXPokeDstAlpha(GXBool enable, u8 alpha);
void GXPokeDither(GXBool enable);
-void GXPokeZMode(GXBool enable_compare, GXCompare comp);
+void GXPokeZMode(GXBool enable_compare, GXCompare comp, GXBool update_enable);
void GXPeekARGB(u16 x, u16 y, u32* color);
void GXPeekZ(u16 x, u16 y, u32* z);
@@ -30,7 +30,7 @@ GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback callback);
void GXSetDrawSync(GXBool enable);
typedef void (*GXDrawDoneCallback)(void);
-void GXSetDrawDoneCallback(GXDrawDoneCallback callback);
+GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback callback);
void __GXPEInit(void);
#ifdef __cplusplus
diff --git a/include/dolphin/gx/GXPerf.h b/include/dolphin/gx/GXPerf.h
index 821c81b2..3edd9ea4 100644
--- a/include/dolphin/gx/GXPerf.h
+++ b/include/dolphin/gx/GXPerf.h
@@ -1,13 +1,13 @@
#ifndef GXPERF_H
#define GXPERF_H
-#include "dolphin/types.h"
+#include "dolphin/gx/GXEnum.h"
#ifdef __cplusplus
extern "C" {
#endif
-void GXSetGPMetric(u32 perf0, u32 perf1);
+void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1);
void GXClearGPMetric(void);
void GXReadXfRasMetric(u32*, u32*, u32*, u32*);
diff --git a/include/dolphin/gx/GXStruct.h b/include/dolphin/gx/GXStruct.h
index 57e02316..146fa09a 100644
--- a/include/dolphin/gx/GXStruct.h
+++ b/include/dolphin/gx/GXStruct.h
@@ -2,6 +2,8 @@
#define GXSTRUCT_H
#include "global.h"
+#include "dolphin/gx/GXEnum.h"
+#include "dolphin/vi/vi.h"
typedef struct _GXColor {
/* 0x0 */ u8 r;
@@ -72,18 +74,18 @@ typedef struct _GXLightObj {
} GXLightObj;
typedef struct _GXFogAdjTable {
- /* 0x0 */ u16 r[10];
+ /* 0x0 */ u16 fogVals[10];
} GXFogAdjTable;
typedef struct _GXFifoObj {
/* 0x00 */ void* base;
- /* 0x04 */ u32 end;
+ /* 0x04 */ void* end;
/* 0x08 */ u32 size;
/* 0x0C */ u32 high_wtrmark;
/* 0x10 */ u32 low_wtrmark;
/* 0x14 */ void* read_ptr;
/* 0x18 */ void* write_ptr;
- /* 0x1C */ void* rw_dst;
+ /* 0x1C */ s32 rw_dst;
/* 0x20 */ u8 fifo_wrap;
/* 0x21 */ u8 cpu_fifo_ready;
/* 0x22 */ u8 gp_fifo_ready;
@@ -91,11 +93,16 @@ typedef struct _GXFifoObj {
} GXFifoObj; // Size: 0x80
typedef struct _GXTexRegion {
- /* 0x00 */ u8 dummy[0x10];
+ u32 unk0; // _00
+ u32 unk4; // _04
+ u32 unk8; // _08
+ u8 unkC; // _0C
+ u8 unkD; // _0D
} GXTexRegion; // Size: 0x10
typedef struct _GXTlutRegion {
- /* 0x00 */ u8 dummy[0x10];
+ /* 0x00 */ u32 unk0;
+ /* 0x04 */ GXTlutObj tlutObj;
} GXTlutRegion; // Size: 0x10
#endif /* GXSTRUCT_H */
diff --git a/include/dolphin/gx/GXTexture.h b/include/dolphin/gx/GXTexture.h
index fc039dab..3c101306 100644
--- a/include/dolphin/gx/GXTexture.h
+++ b/include/dolphin/gx/GXTexture.h
@@ -8,7 +8,7 @@ extern "C" {
#endif
u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod);
-void __GetImageTileCount(u32 arg0, s16 arg1, s16 arg2, s32* arg3, s32* arg4, s32* arg5);
+void __GetImageTileCount(GXTexFmt format, u16 width, u16 height, u32* a, u32* b, u32* c);
void GXInitTexObj(GXTexObj* obj, void* image, u16 width, u16 height, GXTexFmt fmt,
GXTexWrapMode wrapS, GXTexWrapMode wrapT, GXBool mipmap);
void GXInitTexObjCI(GXTexObj* obj, void* image, u16 width, u16 height, GXCITexFmt format,
@@ -19,10 +19,10 @@ void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter min_filter, GXTexFilter max_filt
void* GXGetTexObjData(GXTexObj* obj);
u16 GXGetTexObjWidth(GXTexObj* obj);
u16 GXGetTexObjHeight(GXTexObj* obj);
-GXTexFmt GXGetTexObjFmt(GXTexObj* obj);
+GXTexFmt GXGetTexObjFmt(const GXTexObj* obj);
GXTexWrapMode GXGetTexObjWrapS(GXTexObj* obj);
GXTexWrapMode GXGetTexObjWrapT(GXTexObj* obj);
-GXBool GXGetTexObjMipMap(GXTexObj* obj);
+GXBool GXGetTexObjMipMap(const GXTexObj* obj);
u32 GXGetTexObjTlut(GXTexObj* obj);
void GXLoadTexObj(GXTexObj* obj, GXTexMapID id);
void GXInitTlutObj(GXTlutObj* obj, void* lut, GXTlutFmt fmt, u16 entry_num);
diff --git a/include/dolphin/gx/GXTransform.h b/include/dolphin/gx/GXTransform.h
index 98462c5d..af4b1ccd 100644
--- a/include/dolphin/gx/GXTransform.h
+++ b/include/dolphin/gx/GXTransform.h
@@ -9,18 +9,18 @@ extern "C" {
#endif
void GXProject(f32 model_x, f32 model_y, f32 model_z, Mtx model_mtx, f32* proj, f32* viewpoint, f32* screen_x, f32* screen_y, f32* screen_z);
-void GXSetProjection(Mtx44 mtx, GXProjectionType type);
+void GXSetProjection(const Mtx44 proj, GXProjectionType type);
void GXSetProjectionv(f32* p);
void GXGetProjectionv(f32* p);
void GXLoadPosMtxImm(Mtx mtx, u32 id);
void GXLoadNrmMtxImm(Mtx mtx, u32 id);
void GXSetCurrentMtx(u32 id);
-void GXLoadTexMtxImm(Mtx mtx, u32 id, GXTexMtxType type);
+void GXLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type);
void GXSetViewport(f32 x_orig, f32 y_orig, f32 width, f32 height, f32 near_z, f32 far_z);
void GXGetViewportv(f32* p);
void GXSetScissor(u32 left, u32 top, u32 width, u32 height);
void GXGetScissor(u32* left, u32* top, u32* width, u32* height);
-void GXSetScissorBoxOffset(u32 x_offset, u32 y_offset);
+void GXSetScissorBoxOffset(s32 x, s32 y);
void GXSetClipMode(GXClipMode mode);
#ifdef __cplusplus
diff --git a/include/dolphin/os/OSError.h b/include/dolphin/os/OSError.h
index 833ce346..159c32f2 100644
--- a/include/dolphin/os/OSError.h
+++ b/include/dolphin/os/OSError.h
@@ -41,7 +41,7 @@ typedef enum {
EXCEPTION_FLOATING_POINT,
EXCEPTION_DECREMENTER,
EXCEPTION_SYSTEM_CALL,
- EXCEPTION_TRACE ,
+ EXCEPTION_TRACE,
EXCEPTION_PERFORMANCE_MONITOR,
EXCEPTION_BREAKPOINT,
EXCEPTION_RESERVED,
diff --git a/include/dolphin/os/OSMessage.h b/include/dolphin/os/OSMessage.h
index 25f15361..1e0c09a4 100644
--- a/include/dolphin/os/OSMessage.h
+++ b/include/dolphin/os/OSMessage.h
@@ -23,7 +23,7 @@ typedef struct OSMessageQueue {
#define OS_MESSAGE_BLOCK 1
typedef enum {
- OS_MSG_PERSISTENT = (1 << 0),
+ OS_MSG_PERSISTENT = (1 << 0),
} OSMessageFlags;
void OSInitMessageQueue(OSMessageQueue* queue, OSMessage* msgArray, s32 msgCount);
diff --git a/include/dolphin/vi/vi.h b/include/dolphin/vi/vi.h
index 901879e5..a5bb9b9c 100644
--- a/include/dolphin/vi/vi.h
+++ b/include/dolphin/vi/vi.h
@@ -10,37 +10,120 @@ extern "C" {
typedef struct _GXRenderModeObj GXRenderModeObj;
-#define VI_TVMODE(format, interlace) (((format) << 2) + (interlace))
+#define VI_INTERLACE (0)
+#define VI_NON_INTERLACE (1)
+#define VI_PROGRESSIVE (2)
+#define VI_3D (3)
-#define VI_INTERLACE 0
-#define VI_NON_INTERLACE 1
-#define VI_PROGRESSIVE 2
+// Video output formats
+#define VI_NTSC (0)
+#define VI_PAL (1)
+#define VI_MPAL (2)
+#define VI_DEBUG (3)
+#define VI_DEBUG_PAL (4)
+#define VI_EURGB60 (5)
+#define VI_GCA (6)
-#define VI_NTSC 0
-#define VI_PAL 1
-#define VI_MPAL 2
-#define VI_DEBUG 3
-#define VI_DEBUG_PAL 4
-#define VI_EURGB60 5
+// Conversion to TVMode used in enums
+#define VI_TVMODE(FMT, INT) (((FMT) << 2) + (INT))
+// TV Modes
typedef enum {
- VI_TVMODE_NTSC_INT = VI_TVMODE(VI_NTSC, VI_INTERLACE),
- VI_TVMODE_NTSC_DS = VI_TVMODE(VI_NTSC, VI_NON_INTERLACE),
- VI_TVMODE_NTSC_PROG = VI_TVMODE(VI_NTSC, VI_PROGRESSIVE),
- VI_TVMODE_PAL_INT = VI_TVMODE(VI_PAL, VI_INTERLACE),
- VI_TVMODE_PAL_DS = VI_TVMODE(VI_PAL, VI_NON_INTERLACE),
- VI_TVMODE_EURGB60_INT = VI_TVMODE(VI_EURGB60, VI_INTERLACE),
- VI_TVMODE_EURGB60_DS = VI_TVMODE(VI_EURGB60, VI_NON_INTERLACE),
- VI_TVMODE_MPAL_INT = VI_TVMODE(VI_MPAL, VI_INTERLACE),
- VI_TVMODE_MPAL_DS = VI_TVMODE(VI_MPAL, VI_NON_INTERLACE),
- VI_TVMODE_DEBUG_INT = VI_TVMODE(VI_DEBUG, VI_INTERLACE),
- VI_TVMODE_DEBUG_PAL_INT = VI_TVMODE(VI_DEBUG_PAL, VI_INTERLACE),
- VI_TVMODE_DEBUG_PAL_DS = VI_TVMODE(VI_DEBUG_PAL, VI_NON_INTERLACE)
+ // NTSC
+ VI_TVMODE_NTSC_INT = VI_TVMODE(VI_NTSC, VI_INTERLACE), // 0
+ VI_TVMODE_NTSC_DS = VI_TVMODE(VI_NTSC, VI_NON_INTERLACE), // 1
+ VI_TVMODE_NTSC_PROG = VI_TVMODE(VI_NTSC, VI_PROGRESSIVE), // 2
+ VI_TVMODE_NTSC_3D = VI_TVMODE(VI_NTSC, VI_3D), // 3
+
+ // PAL
+ VI_TVMODE_PAL_INT = VI_TVMODE(VI_PAL, VI_INTERLACE), // 4
+ VI_TVMODE_PAL_DS = VI_TVMODE(VI_PAL, VI_NON_INTERLACE), // 5
+
+ // MPAL
+ VI_TVMODE_MPAL_INT = VI_TVMODE(VI_MPAL, VI_INTERLACE), // 8
+ VI_TVMODE_MPAL_DS = VI_TVMODE(VI_MPAL, VI_NON_INTERLACE), // 9
+
+ // Debug
+ VI_TVMODE_DEBUG_INT = VI_TVMODE(VI_DEBUG, VI_INTERLACE), // 12
+
+ // Debug PAL
+ VI_TVMODE_DEBUG_PAL_INT = VI_TVMODE(VI_DEBUG_PAL, VI_INTERLACE), // 16
+ VI_TVMODE_DEBUG_PAL_DS = VI_TVMODE(VI_DEBUG_PAL, VI_NON_INTERLACE), // 17
+
+ // EU RGB60
+ VI_TVMODE_EURGB60_INT = VI_TVMODE(VI_EURGB60, VI_INTERLACE), // 20
+ VI_TVMODE_EURGB60_DS = VI_TVMODE(VI_EURGB60, VI_NON_INTERLACE), // 21
+
+ // GCA
+ VI_TVMODE_GCA_INT = VI_TVMODE(VI_GCA, VI_INTERLACE), // 24
+ VI_TVMODE_GCA_DS = VI_TVMODE(VI_GCA, VI_NON_INTERLACE), // 25
+ VI_TVMODE_GCA_PROG = VI_TVMODE(VI_GCA, VI_PROGRESSIVE), // 26
} VITVMode;
typedef enum { VI_XFBMODE_SF = 0, VI_XFBMODE_DF } VIXFBMode;
typedef void (*VIRetraceCallback)(u32);
+typedef void (*VIPositionCallback)(s16 x, s16 y);
+
+typedef struct VITimingInfo {
+ u8 equ; // _00
+ u16 acv; // _02
+ u16 prbOdd; // _04
+ u16 prbEven; // _06
+ u16 psbOdd; // _08
+ u16 psbEven; // _0A
+ u8 bs1; // _0C
+ u8 bs2; // _0D
+ u8 bs3; // _0E
+ u8 bs4; // _0F
+ u16 be1; // _10
+ u16 be2; // _12
+ u16 be3; // _14
+ u16 be4; // _16
+ u16 numHalfLines; // _18
+ u16 hlw; // _1A
+ u8 hsy; // _1C
+ u8 hcs; // _1D
+ u8 hce; // _1E
+ u8 hbe640; // _1F
+ u16 hbs640; // _20
+ u8 hbeCCIR656; // _24
+ u16 hbsCCIR656; // _26
+} VITimingInfo;
+
+typedef struct VIPositionInfo {
+ u16 dispPosX; // _00
+ u16 dispPosY; // _02
+ u16 dispSizeX; // _04
+ u16 dispSizeY; // _06
+ u16 adjDispPosX; // _08
+ u16 adjDispPosY; // _0A
+ u16 adjDispSizeY; // _0C
+ u16 adjPanPosY; // _0E
+ u16 adjPanSizeY; // _10
+ u16 fbSizeX; // _12
+ u16 fbSizeY; // _14
+ u16 panPosX; // _16
+ u16 panPosY; // _18
+ u16 panSizeX; // _1A
+ u16 panSizeY; // _1C
+ VIXFBMode xfbMode; // _20
+ u32 nonInter; // _24
+ u32 tv; // _28
+ u8 wordPerLine; // _2C
+ u8 std; // _2D
+ u8 wpl; // _2E
+ u32 bufAddr; // _30
+ u32 tfbb; // _34
+ u32 bfbb; // _38
+ u8 xof; // _3C
+ BOOL isBlack; // _40
+ BOOL is3D; // _44
+ u32 rbufAddr; // _48
+ u32 rtfbb; // _4C
+ u32 rbfbb; // _50
+ VITimingInfo* timing; // _54
+} VIPositionInfo;
void VIWaitForRetrace(void);
void VISetNextFrameBuffer(void*);
diff --git a/src/JSystem/J3DGraphBase/J3DGD.cpp b/src/JSystem/J3DGraphBase/J3DGD.cpp
index 95d501a8..555558cf 100644
--- a/src/JSystem/J3DGraphBase/J3DGD.cpp
+++ b/src/JSystem/J3DGraphBase/J3DGD.cpp
@@ -502,7 +502,7 @@ void J3DGDSetFog(GXFogType type, f32 startZ, f32 endZ, f32 nearZ, f32 farZ, GXCo
void J3DGDSetFogRangeAdj(u8 enabled, u16 center, GXFogAdjTable* pFogAdjTable) {
if (enabled) {
for (s32 i = 0; i < 10; i += 2) {
- J3DGDWriteBPCmd((0xe9 + i / 2) << 24 | pFogAdjTable->r[i + 1] << 12 | pFogAdjTable->r[i] << 0);
+ J3DGDWriteBPCmd((0xe9 + i / 2) << 24 | pFogAdjTable->fogVals[i + 1] << 12 | pFogAdjTable->fogVals[i] << 0);
}
}
diff --git a/src/JSystem/J3DGraphBase/J3DSys.cpp b/src/JSystem/J3DGraphBase/J3DSys.cpp
index 3ef85963..8e910641 100644
--- a/src/JSystem/J3DGraphBase/J3DSys.cpp
+++ b/src/JSystem/J3DGraphBase/J3DSys.cpp
@@ -148,7 +148,7 @@ void J3DSys::setTexCacheRegion(GXTexCacheSize size) {
/* 802D8EE0-802D956C .text drawInit__6J3DSysFv */
void J3DSys::drawInit() {
- GXSetMisc(2, 0);
+ GXSetMisc(GX_MT_DL_SAVE_CONTEXT, 0);
GXInvalidateVtxCache();
GXSetCurrentMtx(GX_PNMTX0);
GXSetCullMode(GX_CULL_BACK);
diff --git a/src/JSystem/JParticle/JPADraw.cpp b/src/JSystem/JParticle/JPADraw.cpp
index 5aeea12d..ac9a624a 100644
--- a/src/JSystem/JParticle/JPADraw.cpp
+++ b/src/JSystem/JParticle/JPADraw.cpp
@@ -822,7 +822,7 @@ void JPADraw::drawParticle() {
GXSetCullMode(GX_CULL_NONE);
if (dc.pbsp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -845,7 +845,7 @@ void JPADraw::drawParticle() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026BC2C-8026BF88 .text drawChild__7JPADrawFv */
@@ -871,7 +871,7 @@ void JPADraw::drawChild() {
if (dc.pssp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -894,7 +894,7 @@ void JPADraw::drawChild() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026BF88-8026C024 .text zDraw__7JPADrawFv */
@@ -922,7 +922,7 @@ void JPADraw::zDrawParticle() {
GXSetCullMode(GX_CULL_NONE);
if (dc.pbsp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -945,7 +945,7 @@ void JPADraw::zDrawParticle() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026C24C-8026C4DC .text zDrawChild__7JPADrawFv */
@@ -971,7 +971,7 @@ void JPADraw::zDrawChild() {
if (dc.pssp->isClipOn()) {
GXSetClipMode(GX_CLIP_ENABLE);
- GXSetMisc(1, 8);
+ GXSetMisc(GX_MT_XF_FLUSH, 8);
} else {
GXSetClipMode(GX_CLIP_DISABLE);
}
@@ -994,7 +994,7 @@ void JPADraw::zDrawChild() {
}
}
- GXSetMisc(1, 0);
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
}
/* 8026C4DC-8026C640 .text loadYBBMtx__7JPADrawFPA4_f */
diff --git a/src/d/d_kankyo_data.cpp b/src/d/d_kankyo_data.cpp
index a173a6d8..6107f5fd 100644
--- a/src/d/d_kankyo_data.cpp
+++ b/src/d/d_kankyo_data.cpp
@@ -441,7 +441,7 @@ dKyd_Schedule* dKyd_schejule_menu_getp() {
/* 80086F34-80086F74 .text dKyd_xfog_table_set__FUc */
void dKyd_xfog_table_set(u8 i_idx) {
for (int i = 0; i < 10; i++) {
- u16 fogAdjTableEntry = S_xfog_table_data[i_idx].r[i];
- g_env_light.mFogAdjTable.r[i] = fogAdjTableEntry;
+ u16 fogAdjTableEntry = S_xfog_table_data[i_idx].fogVals[i];
+ g_env_light.mFogAdjTable.fogVals[i] = fogAdjTableEntry;
}
}
diff --git a/src/dolphin/gx/GXAttr.c b/src/dolphin/gx/GXAttr.c
new file mode 100644
index 00000000..724710e9
--- /dev/null
+++ b/src/dolphin/gx/GXAttr.c
@@ -0,0 +1,751 @@
+#include "dolphin/gx/GXAttr.h"
+#include "dolphin/gx/GX.h"
+
+static inline void SETVCDATTR(GXAttr name, GXAttrType type) {
+ switch (name) {
+ case GX_VA_PNMTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_POSMTXIDX_ST, GX_CP_VCD_LO_POSMTXIDX_END);
+ break;
+ case GX_VA_TEX0MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX0MTXIDX_ST,
+ GX_CP_VCD_LO_TEX0MTXIDX_END);
+ break;
+ case GX_VA_TEX1MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX1MTXIDX_ST,
+ GX_CP_VCD_LO_TEX1MTXIDX_END);
+ break;
+ case GX_VA_TEX2MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX2MTXIDX_ST,
+ GX_CP_VCD_LO_TEX2MTXIDX_END);
+ break;
+ case GX_VA_TEX3MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX3MTXIDX_ST,
+ GX_CP_VCD_LO_TEX3MTXIDX_END);
+ break;
+ case GX_VA_TEX4MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX4MTXIDX_ST,
+ GX_CP_VCD_LO_TEX4MTXIDX_END);
+ break;
+ case GX_VA_TEX5MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX5MTXIDX_ST,
+ GX_CP_VCD_LO_TEX5MTXIDX_END);
+ break;
+ case GX_VA_TEX6MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX6MTXIDX_ST,
+ GX_CP_VCD_LO_TEX6MTXIDX_END);
+ break;
+ case GX_VA_TEX7MTXIDX:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_TEX7MTXIDX_ST,
+ GX_CP_VCD_LO_TEX7MTXIDX_END);
+ break;
+ case GX_VA_POS:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_POS_ST, GX_CP_VCD_LO_POS_END);
+ break;
+ case GX_VA_NRM:
+ if (type != GX_NONE) {
+ __GXData->hasNrms = TRUE;
+ __GXData->hasBiNrms = FALSE;
+ __GXData->nrmType = type;
+ } else {
+ __GXData->hasNrms = FALSE;
+ }
+ break;
+ case GX_VA_NBT:
+ if (type != GX_NONE) {
+ __GXData->hasBiNrms = TRUE;
+ __GXData->hasNrms = FALSE;
+ __GXData->nrmType = type;
+ } else {
+ __GXData->hasBiNrms = FALSE;
+ }
+ break;
+ case GX_VA_CLR0:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_CLRDIF_ST, GX_CP_VCD_LO_CLRDIF_END);
+ break;
+ case GX_VA_CLR1:
+ GX_SET_REG(__GXData->vcdLo, type, GX_CP_VCD_LO_CLRSPEC_ST, GX_CP_VCD_LO_CLRSPEC_END);
+ break;
+ case GX_VA_TEX0:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX0COORD_ST, GX_CP_VCD_HI_TEX0COORD_END);
+ break;
+ case GX_VA_TEX1:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX1COORD_ST, GX_CP_VCD_HI_TEX1COORD_END);
+ break;
+ case GX_VA_TEX2:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX2COORD_ST, GX_CP_VCD_HI_TEX2COORD_END);
+ break;
+ case GX_VA_TEX3:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX3COORD_ST, GX_CP_VCD_HI_TEX3COORD_END);
+ break;
+ case GX_VA_TEX4:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX4COORD_ST, GX_CP_VCD_HI_TEX4COORD_END);
+ break;
+ case GX_VA_TEX5:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX5COORD_ST, GX_CP_VCD_HI_TEX5COORD_END);
+ break;
+ case GX_VA_TEX6:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX6COORD_ST, GX_CP_VCD_HI_TEX6COORD_END);
+ break;
+ case GX_VA_TEX7:
+ GX_SET_REG(__GXData->vcdHi, type, GX_CP_VCD_HI_TEX7COORD_ST, GX_CP_VCD_HI_TEX7COORD_END);
+ break;
+ }
+}
+
+void GXSetVtxDesc(GXAttr name, GXAttrType type) {
+ SETVCDATTR(name, type);
+
+ // Set normal data type if enabled
+ if (__GXData->hasNrms || __GXData->hasBiNrms) {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, __GXData->nrmType);
+ } else {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, 0);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+void GXSetVtxDescv(GXVtxDescList* list) {
+ for (; list->attr != GX_VA_NULL; list++) {
+ SETVCDATTR(list->attr, list->type);
+ }
+
+ // Set normal data type if enabled
+ if (__GXData->hasNrms || __GXData->hasBiNrms) {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, __GXData->nrmType);
+ } else {
+ GX_BITFIELD_SET(__GXData->vcdLo, 19, 2, 0);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+static void __GXXfVtxSpecs(void) {
+ u32 normCount, colorCount, texCount;
+
+ normCount = __GXData->hasBiNrms ? 2 : (__GXData->hasNrms ? 1 : 0);
+
+ // Both fields in one access
+ colorCount = 33 - __cntlzw((__GXData->vcdLo & (0xf << 0xd)) >> 0xd);
+ colorCount /= 2; // equivalent to /=2 and >>= 1
+
+ // All 16 assigned bits in VCD_Hi
+ texCount = 33 - __cntlzw((__GXData->vcdHi & (0xffff << 0)) >> 0);
+ texCount /= 2; // equivalent to /=2 and >>= 1
+
+ GX_XF_LOAD_REG(GX_XF_REG_INVERTEXSPEC, (colorCount) | (normCount << 2) | (texCount << 4));
+ __GXData->bpSentNot = GX_TRUE;
+
+ return;
+}
+
+void __GXSetVCD(void) {
+ GX_CP_LOAD_REG(GX_CP_REG_VCD_LO, __GXData->vcdLo);
+ GX_CP_LOAD_REG(GX_CP_REG_VCD_HI, __GXData->vcdHi);
+
+ __GXXfVtxSpecs();
+}
+
+void __GXCalculateVLim(void) {
+ static u8 tbl1[] = {0, 4, 1, 2};
+ static u8 tbl2[] = {0, 8, 1, 2};
+ static u8 tbl3[] = {0, 12, 1, 2};
+
+ u32 vlim;
+ u32 vcdLoReg;
+ u32 vcdHiReg;
+ s32 compCnt;
+
+ if (__GXData->vNum == 0) {
+ return;
+ }
+
+ vcdLoReg = __GXData->vcdLo;
+ vcdHiReg = __GXData->vcdHi;
+
+ // GXCompCnt bit of normal parameters
+ compCnt = __GXData->vatA[GX_VTXFMT0];
+ compCnt = (compCnt & 0x200) >> 9;
+
+ vlim = GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_POSMTXIDX_ST, GX_CP_VCD_LO_POSMTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX0MTXIDX_ST, GX_CP_VCD_LO_TEX0MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX1MTXIDX_ST, GX_CP_VCD_LO_TEX1MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX2MTXIDX_ST, GX_CP_VCD_LO_TEX2MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX3MTXIDX_ST, GX_CP_VCD_LO_TEX3MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX4MTXIDX_ST, GX_CP_VCD_LO_TEX4MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX5MTXIDX_ST, GX_CP_VCD_LO_TEX5MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX6MTXIDX_ST, GX_CP_VCD_LO_TEX6MTXIDX_END);
+ vlim += GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_TEX7MTXIDX_ST, GX_CP_VCD_LO_TEX7MTXIDX_END);
+
+ vlim += tbl3[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_POS_ST, GX_CP_VCD_LO_POS_END)];
+ vlim += tbl3[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_NRM_ST, GX_CP_VCD_LO_NRM_END)] *
+ (compCnt == GX_NRM_NBT ? 3 : 1);
+ vlim += tbl1[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_CLRDIF_ST, GX_CP_VCD_LO_CLRDIF_END)];
+ vlim += tbl1[GX_GET_REG(vcdLoReg, GX_CP_VCD_LO_CLRSPEC_ST, GX_CP_VCD_LO_CLRSPEC_END)];
+
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX0COORD_ST, GX_CP_VCD_HI_TEX0COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX1COORD_ST, GX_CP_VCD_HI_TEX1COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX2COORD_ST, GX_CP_VCD_HI_TEX2COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX3COORD_ST, GX_CP_VCD_HI_TEX3COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX4COORD_ST, GX_CP_VCD_HI_TEX4COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX5COORD_ST, GX_CP_VCD_HI_TEX5COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX6COORD_ST, GX_CP_VCD_HI_TEX6COORD_END)];
+ vlim += tbl2[GX_GET_REG(vcdHiReg, GX_CP_VCD_HI_TEX7COORD_ST, GX_CP_VCD_HI_TEX7COORD_END)];
+
+ __GXData->vLim = vlim;
+}
+
+void GXGetVtxDesc(int param_0, GXAttrType* param_1) {
+ int local_38;
+
+ switch (param_0) {
+ case 0:
+ local_38 = __GXData->vcdLo & 1;
+ break;
+ case 1:
+ local_38 = (__GXData->vcdLo & 2) >> 1;
+ break;
+ case 2:
+ local_38 = (__GXData->vcdLo & 4) >> 2;
+ break;
+ case 3:
+ local_38 = (__GXData->vcdLo & 8) >> 3;
+ break;
+ case 4:
+ local_38 = (__GXData->vcdLo & 0x10) >> 4;
+ break;
+ case 5:
+ local_38 = (__GXData->vcdLo & 0x20) >> 5;
+ break;
+ case 6:
+ local_38 = (__GXData->vcdLo & 0x40) >> 6;
+ break;
+ case 7:
+ local_38 = (__GXData->vcdLo & 0x80) >> 7;
+ break;
+ case 8:
+ local_38 = (__GXData->vcdLo & 0x100) >> 8;
+ break;
+ case 9:
+ local_38 = (__GXData->vcdLo & 0x600) >> 9;
+ break;
+ case 10:
+ if (__GXData->hasNrms != 0) {
+ local_38 = (__GXData->vcdLo & 0x1800) >> 11;
+ } else {
+ local_38 = 0;
+ }
+ break;
+ case 0x19:
+ if (__GXData->hasBiNrms != 0) {
+ local_38 = (__GXData->vcdLo & 0x1800) >> 11;
+ } else {
+ local_38 = 0;
+ }
+ break;
+ case 11:
+ local_38 = (__GXData->vcdLo & 0x6000) >> 13;
+ break;
+ case 12:
+ local_38 = (__GXData->vcdLo & 0x18000) >> 15;
+ break;
+ case 13:
+ local_38 = (__GXData->vcdHi & 3);
+ break;
+ case 14:
+ local_38 = (__GXData->vcdHi & 0xC) >> 2;
+ break;
+ case 15:
+ local_38 = (__GXData->vcdHi & 0x30) >> 4;
+ break;
+ case 16:
+ local_38 = (__GXData->vcdHi & 0xC0) >> 6;
+ break;
+ case 17:
+ local_38 = (__GXData->vcdHi & 0x300) >> 8;
+ break;
+ case 18:
+ local_38 = (__GXData->vcdHi & 0xC00) >> 10;
+ break;
+ case 19:
+ local_38 = (__GXData->vcdHi & 0x3000) >> 12;
+ break;
+ case 20:
+ local_38 = (__GXData->vcdHi & 0xC000) >> 14;
+ break;
+ default:
+ local_38 = 0;
+ break;
+ }
+
+ *param_1 = local_38;
+}
+
+void GXGetVtxDescv(GXVtxDescList* attrPtr) {
+ int i;
+
+ for (i = 0; i <= 0x14; i++) {
+ attrPtr[i].attr = (GXAttr)i;
+ GXGetVtxDesc(i, &attrPtr[i].type);
+ }
+
+ attrPtr[i].attr = (GXAttr)0x19;
+ GXGetVtxDesc(0x19, &attrPtr[i].type);
+
+ i++;
+ attrPtr[i].attr = (GXAttr)0xFF;
+}
+
+void GXClearVtxDesc(void) {
+ __GXData->vcdLo = 0;
+ GX_BITFIELD_SET(__GXData->vcdLo, 0x15, 2, GX_DIRECT);
+ __GXData->vcdHi = 0;
+ __GXData->hasNrms = FALSE;
+ __GXData->hasBiNrms = FALSE;
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+}
+
+/* ############################################################################################## */
+
+static inline void SETVAT(u32* vatA, u32* vatB, u32* vatC, GXAttr attr, GXCompCnt compCnt,
+ GXCompType compType, u8 shift) {
+ switch (attr) {
+ case GX_VA_POS:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_POS_CNT_ST, GX_CP_VAT_GRP0_POS_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_POS_TYPE_ST, GX_CP_VAT_GRP0_POS_TYPE_END);
+ GX_SET_REG(*vatA, shift, GX_CP_VAT_GRP0_POS_SHIFT_ST, GX_CP_VAT_GRP0_POS_SHIFT_END);
+ break;
+ case GX_VA_NRM:
+ case GX_VA_NBT:
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_NRM_TYPE_ST, GX_CP_VAT_GRP0_NRM_TYPE_END);
+ if (compCnt == GX_NRM_NBT3) {
+ // Probably because the compCnt can only be one bit?
+ GX_SET_REG(*vatA, GX_NRM_NBT, GX_CP_VAT_GRP0_NRM_CNT_ST, GX_CP_VAT_GRP0_NRM_CNT_END);
+ GX_SET_REG(*vatA, TRUE, GX_CP_VAT_GRP0_NRMIDX3_ST, GX_CP_VAT_GRP0_NRMIDX3_END);
+ } else {
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_NRM_CNT_ST, GX_CP_VAT_GRP0_NRM_CNT_END);
+ GX_SET_REG(*vatA, FALSE, GX_CP_VAT_GRP0_NRMIDX3_ST, GX_CP_VAT_GRP0_NRMIDX3_END);
+ }
+ break;
+ case GX_VA_CLR0:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_CLRDIFF_CNT_ST, GX_CP_VAT_GRP0_CLRDIFF_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_CLRDIFF_TYPE_ST,
+ GX_CP_VAT_GRP0_CLRDIFF_TYPE_END);
+ break;
+ case GX_VA_CLR1:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_CLRSPEC_CNT_ST, GX_CP_VAT_GRP0_CLRSPEC_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_CLRSPEC_TYPE_ST,
+ GX_CP_VAT_GRP0_CLRSPEC_TYPE_END);
+ break;
+ case GX_VA_TEX0:
+ GX_SET_REG(*vatA, compCnt, GX_CP_VAT_GRP0_TXC0_CNT_ST, GX_CP_VAT_GRP0_TXC0_CNT_END);
+ GX_SET_REG(*vatA, compType, GX_CP_VAT_GRP0_TXC0_TYPE_ST, GX_CP_VAT_GRP0_TXC0_TYPE_END);
+ GX_SET_REG(*vatA, shift, GX_CP_VAT_GRP0_TXC0_SHIFT_ST, GX_CP_VAT_GRP0_TXC0_SHIFT_END);
+ break;
+ case GX_VA_TEX1:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC1_CNT_ST, GX_CP_VAT_GRP1_TXC1_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC1_TYPE_ST, GX_CP_VAT_GRP1_TXC1_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC1_SHIFT_ST, GX_CP_VAT_GRP1_TXC1_SHIFT_END);
+ break;
+ case GX_VA_TEX2:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC2_CNT_ST, GX_CP_VAT_GRP1_TXC2_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC2_TYPE_ST, GX_CP_VAT_GRP1_TXC2_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC2_SHIFT_ST, GX_CP_VAT_GRP1_TXC2_SHIFT_END);
+ break;
+ case GX_VA_TEX3:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC3_CNT_ST, GX_CP_VAT_GRP1_TXC3_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC3_TYPE_ST, GX_CP_VAT_GRP1_TXC3_TYPE_END);
+ GX_SET_REG(*vatB, shift, GX_CP_VAT_GRP1_TXC3_SHIFT_ST, GX_CP_VAT_GRP1_TXC3_SHIFT_END);
+ break;
+ case GX_VA_TEX4:
+ GX_SET_REG(*vatB, compCnt, GX_CP_VAT_GRP1_TXC4_CNT_ST, GX_CP_VAT_GRP1_TXC4_CNT_END);
+ GX_SET_REG(*vatB, compType, GX_CP_VAT_GRP1_TXC4_TYPE_ST, GX_CP_VAT_GRP1_TXC4_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC4_SHIFT_ST, GX_CP_VAT_GRP2_TXC4_SHIFT_END);
+ break;
+ case GX_VA_TEX5:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC5_CNT_ST, GX_CP_VAT_GRP2_TXC5_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC5_TYPE_ST, GX_CP_VAT_GRP2_TXC5_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC5_SHIFT_ST, GX_CP_VAT_GRP2_TXC5_SHIFT_END);
+ break;
+ case GX_VA_TEX6:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC6_CNT_ST, GX_CP_VAT_GRP2_TXC6_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC6_TYPE_ST, GX_CP_VAT_GRP2_TXC6_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC6_SHIFT_ST, GX_CP_VAT_GRP2_TXC6_SHIFT_END);
+ break;
+ case GX_VA_TEX7:
+ GX_SET_REG(*vatC, compCnt, GX_CP_VAT_GRP2_TXC7_CNT_ST, GX_CP_VAT_GRP2_TXC7_CNT_END);
+ GX_SET_REG(*vatC, compType, GX_CP_VAT_GRP2_TXC7_TYPE_ST, GX_CP_VAT_GRP2_TXC7_TYPE_END);
+ GX_SET_REG(*vatC, shift, GX_CP_VAT_GRP2_TXC7_SHIFT_ST, GX_CP_VAT_GRP2_TXC7_SHIFT_END);
+ break;
+ }
+}
+
+void GXSetVtxAttrFmt(GXVtxFmt format, GXAttr attr, GXCompCnt count, GXCompType type, u8 frac) {
+ u32* vA = (u32*)&__GXData->vatA[format];
+ u32* vB = (u32*)&__GXData->vatB[format];
+ u32* vC = &__GXData->vatC[format];
+
+ SETVAT(vA, vB, vC, attr, count, type, frac);
+
+ __GXData->dirtyState |= GX_DIRTY_VAT;
+ __GXData->dirtyVAT |= (u8)(1 << (u8)format);
+}
+
+void GXSetVtxAttrFmtv(GXVtxFmt format, GXVtxAttrFmtList* list) {
+ u32* vatA;
+ u32* vatB;
+ u32* vatC;
+
+ vatA = (u32*)&__GXData->vatA[format];
+ vatB = (u32*)&__GXData->vatB[format];
+ vatC = &__GXData->vatC[format];
+
+ for (; list->mAttrib != GX_VA_NULL; list++) {
+ SETVAT(vatA, vatB, vatC, list->mAttrib, list->mCompCnt, list->mCompType, list->mCompShift);
+ }
+
+ __GXData->dirtyState |= GX_DIRTY_VAT;
+ __GXData->dirtyVAT |= (u8)(1 << (u8)format);
+}
+
+void __GXSetVAT(void) {
+ u32 i = 0;
+ u32 dirtyVAT = __GXData->dirtyVAT;
+ do {
+ if (dirtyVAT & (1)) {
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP0 | i, __GXData->vatA[i]);
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP1 | i, __GXData->vatB[i]);
+ GX_CP_LOAD_REG(GX_CP_REG_VAT_GRP2 | i, __GXData->vatC[i]);
+ }
+ dirtyVAT >>= 1;
+ i++;
+ } while (dirtyVAT != 0);
+
+ __GXData->dirtyVAT = 0;
+}
+
+static u8 GetFracForNrm(int param_0) {
+ int var_r31;
+
+ switch (param_0) {
+ case 1:
+ var_r31 = 6;
+ break;
+ case 3:
+ var_r31 = 14;
+ break;
+ default:
+ case 2:
+ var_r31 = 0;
+ break;
+ }
+
+ return var_r31;
+}
+
+void GXGetVtxAttrFmtv(GXVtxFmt param_0, GXVtxAttrFmtList* param_1) {
+ s32 tmp;
+ s32 tmp2;
+ s32 tmp3;
+ int i;
+
+#ifdef DEBUG
+ // not fully matching
+ /* tmp = 1;
+ if (data_8074d3c8 != 0) {
+ OSPanic("GXAttr.c", 941, "\'GXGetVtxAttrFmtv\' is not allowed between GXBegin/GXEnd");
+ tmp = 0;
+ }
+
+ tmp2 = 1;
+ if (param_1 == NULL) {
+ OSPanic("GXAttr.c", 942, "GXSetVtxAttrFmt: list pointer is NULL");
+ tmp2 = 0;
+ }
+
+ tmp3 = 1;
+ if (param_0 >= 8) {
+ OSPanic("GXAttr.c", 943, "GXSetVtxAttrFmt: Format Index is out of range");
+ tmp3 = 0;
+ } */
+#endif
+
+ for (i = 9; i <= 0x14; i++) {
+ param_1->mAttrib = i;
+ GXGetVtxAttrFmt(param_0, i, &param_1->mCompCnt, &param_1->mCompType, &param_1->mCompShift);
+ param_1++;
+ }
+
+ param_1->mAttrib = 0xFF;
+}
+
+void GXGetVtxAttrFmt(GXVtxFmt param_0, int param_1, GXCompCnt* param_2, GXCompType* param_3,
+ u8* param_4) {
+ s32 tmp;
+ s32 tmp2;
+ GXCompCnt* tmp_1;
+ GXCompCnt* tmp_2;
+ u32* tmp_3;
+
+#ifdef DEBUG
+ // not fully matching
+ /* tmp = 1;
+ if (data_8074d3c8) {
+ OSPanic("GXAttr.c", 844, "\'GXGetVtxAttrFmt\' is not allowed between GXBegin/GXEnd");
+ tmp = 0;
+ }
+
+ tmp2 = 1;
+ if (param_0 >= 8) {
+ OSPanic("GXAttr.c", 845, "GXSetVtxAttrFmt: Format Index is out of range");
+ tmp2 = 0;
+ } */
+#endif
+
+ tmp_1 = (GXCompCnt*)&__GXData->vatA[param_0];
+ tmp_2 = (GXCompCnt*)&__GXData->vatB[param_0];
+ tmp_3 = &__GXData->vatC[param_0];
+
+ switch (param_1) {
+ case 9:
+ *param_2 = *tmp_1 & 1;
+ *param_3 = (*tmp_1 & 0xE) >> 1;
+ *param_4 = (*tmp_1 & 0x1F0) >> 4;
+ break;
+ case 10:
+ case 0x19:
+ *param_2 = (*tmp_1 & 0x200) >> 9;
+ if (*param_2 == 1 && ((*tmp_1 & 0x80000000) >> 31) != 0) {
+ *param_2 = 2;
+ }
+
+ *param_3 = (*tmp_1 & 0x1C00) >> 10;
+ *param_4 = GetFracForNrm(*param_3);
+ break;
+ case 11:
+ *param_2 = (*tmp_1 & 0x2000) >> 0xd;
+ *param_3 = (*tmp_1 & 0x1C000) >> 0xe;
+ *param_4 = 0;
+ break;
+ case 12:
+ *param_2 = (*tmp_1 & 0x20000) >> 0x11;
+ *param_3 = (*tmp_1 & 0x1C0000) >> 0x12;
+ *param_4 = 0;
+ break;
+ case 13:
+ *param_2 = (*tmp_1 & 0x200000) >> 0x15;
+ *param_3 = (*tmp_1 & 0x1C00000) >> 0x16;
+ *param_4 = ((*tmp_1 & 0x3e000000)) >> 25;
+ break;
+ case 14:
+ *param_2 = *tmp_2 & 1;
+ *param_3 = (*tmp_2 & 0xE) >> 1;
+ *param_4 = (*tmp_2 & 0x1F0) >> 4;
+ break;
+ case 15:
+ *param_2 = (*tmp_2 & 0x200) >> 9;
+ *param_3 = (*tmp_2 & 0x1C00) >> 10;
+ *param_4 = (*tmp_2 & 0x3E000) >> 13;
+ break;
+ case 16:
+ *param_2 = (*tmp_2 & 0x40000) >> 0x12;
+ *param_3 = (*tmp_2 & 0x380000) >> 0x13;
+ *param_4 = (*tmp_2 & 0x7C00000) >> 0x16;
+ break;
+ case 17:
+ *param_2 = (*tmp_2 & 0x8000000) >> 0x1B;
+ *param_3 = (*tmp_2 & 0x70000000) >> 0x1C;
+ *param_4 = (*tmp_3 & 0x1F);
+ break;
+ case 18:
+ *param_2 = (*tmp_3 & 0x20) >> 5;
+ *param_3 = (*tmp_3 & 0x1C0) >> 6;
+ *param_4 = (*tmp_3 & 0x3E00) >> 9;
+ break;
+ case 19:
+ *param_2 = (*tmp_3 & 0x4000) >> 0xe;
+ *param_3 = (*tmp_3 & 0x38000) >> 0xf;
+ *param_4 = (*tmp_3 & 0x7c0000) >> 0x12;
+ break;
+ case 20:
+ *param_2 = (*tmp_3 & 0x800000) >> 0x17;
+ *param_3 = (*tmp_3 & 0x7000000) >> 0x18;
+ *param_4 = (*tmp_3 & 0xF8000000) >> 0x1b;
+ break;
+ default:
+ *param_2 = 1;
+ *param_3 = 0;
+ *param_4 = 0;
+ }
+}
+
+void GXSetArray(GXAttr attr, void* basePtr, u8 stride) {
+ s32 newAttr;
+ s32 attrReg;
+
+ newAttr = attr;
+ if (newAttr == GX_VA_NBT) {
+ newAttr = GX_VA_NRM;
+ }
+
+ attrReg = newAttr - GX_VA_POS;
+
+ GX_CP_LOAD_REG(GX_BP_REG_SETMODE0_TEX4 | attrReg,
+ // Address -> offset?
+ (u32)basePtr & ~0xC0000000);
+
+ GX_CP_LOAD_REG(GX_BP_REG_SETIMAGE2_TEX4 | attrReg, stride);
+}
+
+void GXInvalidateVtxCache(void) {
+ GXFIFO.u8 = GX_FIFO_CMD_INVAL_VTX;
+}
+
+void GXSetTexCoordGen2(GXTexCoordID id, GXTexGenType type, GXTexGenSrc src, u32 texMtxIdx,
+ GXBool normalize, u32 dualTexMtxIdx) {
+ u32 reg;
+ u32 inputRow;
+ GXXfTexReg inputForm;
+
+ reg = 0;
+ inputForm = GX_XF_TEX_FORM_AB11;
+ inputRow = 5;
+
+ switch (src) {
+ case GX_TG_POS:
+ inputRow = 0;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_NRM:
+ inputRow = 1;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_BINRM:
+ inputRow = 3;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_TANGENT:
+ inputRow = 4;
+ inputForm = GX_XF_TEX_FORM_ABC1;
+ break;
+ case GX_TG_COLOR0:
+ inputRow = 2;
+ break;
+ case GX_TG_COLOR1:
+ inputRow = 2;
+ break;
+ case GX_TG_TEX0:
+ inputRow = 5;
+ break;
+ case GX_TG_TEX1:
+ inputRow = 6;
+ break;
+ case GX_TG_TEX2:
+ inputRow = 7;
+ break;
+ case GX_TG_TEX3:
+ inputRow = 8;
+ break;
+ case GX_TG_TEX4:
+ inputRow = 9;
+ break;
+ case GX_TG_TEX5:
+ inputRow = 10;
+ break;
+ case GX_TG_TEX6:
+ inputRow = 11;
+ break;
+ case GX_TG_TEX7:
+ inputRow = 12;
+ break;
+ }
+
+ switch (type) {
+ case GX_TG_NRM:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_POS, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ case GX_TG_POS:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_STQ, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 3x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_POS, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ case GX_TG_BUMP0:
+ case GX_TG_BUMP1:
+ case GX_TG_BUMP2:
+ case GX_TG_BUMP3:
+ case GX_TG_BUMP4:
+ case GX_TG_BUMP5:
+ case GX_TG_BUMP6:
+ case GX_TG_BUMP7:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+ GX_SET_REG(reg, GX_TG_NRM, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ GX_SET_REG(reg, inputRow, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ GX_SET_REG(reg, src - GX_TG_TEXCOORD0, GX_XF_TEX_BUMPSRCTEX_ST, GX_XF_TEX_BUMPSRCTEX_END);
+ GX_SET_REG(reg, type - GX_TG_BUMP0, GX_XF_TEX_BUMPSRCLIGHT_ST, GX_XF_TEX_BUMPSRCLIGHT_END);
+ break;
+ case GX_TG_SRTG:
+ GX_SET_REG(reg, GX_XF_TEX_PROJ_ST, GX_XF_TEX_PROJTYPE_ST,
+ GX_XF_TEX_PROJTYPE_END); // 2x4 projection
+ GX_SET_REG(reg, inputForm, GX_XF_TEX_INPUTFORM_ST, GX_XF_TEX_INPUTFORM_END);
+
+ if (src == GX_TG_COLOR0) {
+ GX_SET_REG(reg, GX_XF_TG_CLR0, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ } else {
+ GX_SET_REG(reg, GX_XF_TG_CLR1, GX_XF_TEX_TEXGENTYPE_ST, GX_XF_TEX_TEXGENTYPE_END);
+ }
+ GX_SET_REG(reg, 2, GX_XF_TEX_SRCROW_ST, GX_XF_TEX_SRCROW_END);
+ break;
+ default:
+ break;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_TEX0 + id, reg);
+
+ reg = 0;
+ GX_SET_REG(reg, dualTexMtxIdx - 0x40, GX_XF_MTXIDX0_GEOM_ST, GX_XF_MTXIDX0_GEOM_END);
+ GX_SET_REG(reg, normalize, GX_XF_DUALTEX_NORMALISE_ST, GX_XF_DUALTEX_NORMALISE_END);
+
+ GX_XF_LOAD_REG(GX_XF_REG_DUALTEX0 + id, reg);
+
+ switch (id) {
+ case GX_TEXCOORD0:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX0_ST, GX_XF_MTXIDX0_TEX0_END);
+ break;
+ case GX_TEXCOORD1:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX1_ST, GX_XF_MTXIDX0_TEX1_END);
+ break;
+ case GX_TEXCOORD2:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX2_ST, GX_XF_MTXIDX0_TEX2_END);
+ break;
+ case GX_TEXCOORD3:
+ GX_SET_REG(__GXData->matIdxA, texMtxIdx, GX_XF_MTXIDX0_TEX3_ST, GX_XF_MTXIDX0_TEX3_END);
+ break;
+ case GX_TEXCOORD4:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX4_ST, GX_XF_MTXIDX1_TEX4_END);
+ break;
+ case GX_TEXCOORD5:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX5_ST, GX_XF_MTXIDX1_TEX5_END);
+ break;
+ case GX_TEXCOORD6:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX6_ST, GX_XF_MTXIDX1_TEX6_END);
+ break;
+ default:
+ GX_SET_REG(__GXData->matIdxB, texMtxIdx, GX_XF_MTXIDX1_TEX7_ST, GX_XF_MTXIDX1_TEX7_END);
+ break;
+ }
+ __GXSetMatrixIndex(id + 1);
+}
+
+void GXSetNumTexGens(u8 count) {
+ GX_SET_REG(__GXData->genMode, count, GX_BP_GENMODE_NUMTEX_ST, GX_BP_GENMODE_NUMTEX_END);
+ GX_XF_LOAD_REG(GX_XF_REG_NUMTEX, count);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+}
diff --git a/src/dolphin/gx/GXBump.c b/src/dolphin/gx/GXBump.c
new file mode 100644
index 00000000..8c1084df
--- /dev/null
+++ b/src/dolphin/gx/GXBump.c
@@ -0,0 +1,194 @@
+/**
+ * GXBump.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXBump.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetTevIndirect(GXTevStageID tevStage, GXIndTexStageID texStage, GXIndTexFormat texFmt,
+ GXIndTexBiasSel biasSel, GXIndTexMtxID mtxID, GXIndTexWrap wrapS,
+ GXIndTexWrap wrapT, u8 addPrev, u8 utcLod, GXIndTexAlphaSel alphaSel) {
+ u32 field = 0;
+ u32 stage = tevStage + 0x10;
+
+ GX_BITFIELD_SET(field, 30, 2, texStage);
+ GX_BITFIELD_SET(field, 28, 2, texFmt);
+ GX_BITFIELD_SET(field, 25, 3, biasSel);
+ GX_BITFIELD_SET(field, 23, 2, alphaSel);
+ GX_BITFIELD_SET(field, 19, 4, mtxID);
+ GX_BITFIELD_SET(field, 16, 3, wrapS);
+ GX_BITFIELD_SET(field, 13, 3, wrapT);
+ GX_BITFIELD_SET(field, 12, 1, utcLod);
+ GX_BITFIELD_SET(field, 11, 1, addPrev);
+ GX_BITFIELD_SET(field, 0, 8, stage);
+
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexMtx(GXIndTexMtxID mtxID, f32 offset[6], s8 scale_exp) {
+ u32 val;
+ u32 field;
+ f32 mtx2[6];
+
+ scale_exp += 17;
+
+ switch (mtxID) {
+ case GX_ITM_0:
+ case GX_ITM_1:
+ case GX_ITM_2:
+ val = mtxID - 1;
+ break;
+ case GX_ITM_S0:
+ case GX_ITM_S1:
+ case GX_ITM_S2:
+ val = mtxID - 5;
+ break;
+ case GX_ITM_T0:
+ case GX_ITM_T1:
+ case GX_ITM_T2:
+ val = mtxID - 9;
+ break;
+ case GX_ITM_3:
+ case GX_ITM_S3:
+ default:
+ val = 0;
+ }
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[0]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[3]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 0) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 6);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[1]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[4]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 2) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 7);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ field = 0;
+ GX_BITFIELD_SET(field, 21, 11, 1024.0f * offset[2]);
+ GX_BITFIELD_SET(field, 10, 11, 1024.0f * offset[5]);
+ GX_BITFIELD_SET(field, 8, 2, (scale_exp >> 4) & 3);
+ GX_BITFIELD_SET(field, 0, 8, val * 3 + 8);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = field;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexCoordScale(GXIndTexStageID texStage, GXIndTexScale scaleS, GXIndTexScale scaleT) {
+ GXData* data;
+
+ switch (texStage) {
+ case GX_INDTEXSTAGE0:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale0, 28, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale0, 24, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale0, 0, 8, 0x25);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale0;
+ break;
+ case GX_INDTEXSTAGE1:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale0, 20, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale0, 16, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale0, 0, 8, 0x25);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale0;
+ break;
+ case GX_INDTEXSTAGE2:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale1, 28, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale1, 24, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale1, 0, 8, 0x26);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale1;
+ break;
+ case GX_INDTEXSTAGE3:
+ data = __GXData;
+ GX_BITFIELD_SET(data->IndTexScale1, 20, 4, scaleS);
+ GX_BITFIELD_SET(data->IndTexScale1, 16, 4, scaleT);
+ GX_BITFIELD_SET(data->IndTexScale1, 0, 8, 0x26);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->IndTexScale1;
+ break;
+ }
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetIndTexOrder(GXIndTexStageID stage, GXTexCoordID coord, GXTexMapID map) {
+ GXData* data;
+
+ if (map == 0xFF) {
+ map = GX_TEXMAP0;
+ }
+
+ if (coord == 0xFF) {
+ coord = GX_TEXCOORD0;
+ }
+
+ switch (stage) {
+ case GX_INDTEXSTAGE0:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 29, 3, map);
+ GX_BITFIELD_SET(data->iref, 26, 3, coord);
+ break;
+ case GX_INDTEXSTAGE1:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 23, 3, map);
+ GX_BITFIELD_SET(data->iref, 20, 3, coord);
+ break;
+ case GX_INDTEXSTAGE2:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 17, 3, map);
+ GX_BITFIELD_SET(data->iref, 14, 3, coord);
+ break;
+ case GX_INDTEXSTAGE3:
+ data = __GXData;
+ GX_BITFIELD_SET(data->iref, 11, 3, map);
+ GX_BITFIELD_SET(data->iref, 8, 3, coord);
+ break;
+ }
+
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = __GXData->iref;
+ GXSetWasteFlags();
+}
+
+void GXSetNumIndStages(u8 num) {
+ GXData* data = __GXData;
+ GX_BITFIELD_SET(data->genMode, 13, 3, num);
+ data->dirtyState |= GX_DIRTY_BP_MASK | GX_DIRTY_GEN_MODE;
+}
+
+void GXSetTevDirect(GXTevStageID stage) {
+ GXSetTevIndirect(stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF,
+ GX_ITW_OFF, FALSE, FALSE, GX_ITBA_OFF);
+}
+
+void __GXUpdateBPMask(void) {}
+
+void __GXSetIndirectMask(u32 mask) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->bpMask, 24, 8, mask);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = data->bpMask;
+ data->bpSentNot = 0;
+}
+
+void __GXFlushTextureState(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.s32 = __GXData->bpMask;
+ __GXData->bpSentNot = 0;
+}
diff --git a/src/dolphin/gx/GXDisplayList.c b/src/dolphin/gx/GXDisplayList.c
new file mode 100644
index 00000000..eaebb628
--- /dev/null
+++ b/src/dolphin/gx/GXDisplayList.c
@@ -0,0 +1,21 @@
+/**
+ * GXDisplayList.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXDisplayList.h"
+#include "dolphin/gx/GX.h"
+
+void GXCallDisplayList(void* list, u32 nbytes) {
+ if (__GXData->dirtyState != 0) {
+ __GXSetDirtyState();
+ }
+
+ if (*(u32*)__GXData == 0) {
+ __GXSendFlushPrim();
+ }
+
+ GXFIFO.u8 = 0x40;
+ GXFIFO.u32 = (u32)list;
+ GXFIFO.u32 = nbytes;
+}
diff --git a/src/dolphin/gx/GXDraw.c b/src/dolphin/gx/GXDraw.c
new file mode 100644
index 00000000..22311b3b
--- /dev/null
+++ b/src/dolphin/gx/GXDraw.c
@@ -0,0 +1,71 @@
+#include "dolphin/gx/GXDraw.h"
+#include "dolphin/gx/GX.h"
+
+static GXVtxDescList vcd[27];
+static GXVtxAttrFmtList vat[27];
+
+void GetVertState(void) {
+ GXGetVtxDescv(vcd);
+ GXGetVtxAttrFmtv(GX_VTXFMT3, vat);
+ GXClearVtxDesc();
+ GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
+ GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
+ GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
+ GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
+}
+
+void RestoreVertState(void) {
+ GXSetVtxDescv(vcd);
+ GXSetVtxAttrFmtv(GX_VTXFMT3, vat);
+}
+
+// doesn't fully match debug
+void GXDrawCylinder(u8 numEdges) {
+ f32 temp_f29;
+ f32 temp_f30;
+ f32 temp_f31;
+
+ s32 i;
+
+ f32 sp1A0[100];
+ f32 sp10[100];
+
+ temp_f31 = 1.0f;
+ temp_f30 = -temp_f31;
+
+ GetVertState();
+ for (i = 0; i <= numEdges; i++) {
+ temp_f29 = (i * 2.0f * 3.141593f) / numEdges;
+ sp1A0[i] = cosf(temp_f29);
+ sp10[i] = sinf(temp_f29);
+ }
+
+ GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numEdges + 1) * 2);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f30);
+ GXNormal3f32(sp1A0[i], sp10[i], 0.0f);
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f31);
+ GXNormal3f32(sp1A0[i], sp10[i], 0.0f);
+ }
+ GXEnd();
+
+ GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2);
+ GXPosition3f32(0.0f, 0.0f, temp_f31);
+ GXNormal3f32(0.0f, 0.0f, 1.0f);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], -sp10[i], temp_f31);
+ GXNormal3f32(0.0f, 0.0f, 1.0f);
+ }
+ GXEnd();
+
+ GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2);
+ GXPosition3f32(0.0f, 0.0f, temp_f30);
+ GXNormal3f32(0.0f, 0.0f, -1.0f);
+ for (i = 0; i <= numEdges; i++) {
+ GXPosition3f32(sp1A0[i], sp10[i], temp_f30);
+ GXNormal3f32(0.0f, 0.0f, -1.0f);
+ }
+ GXEnd();
+
+ RestoreVertState();
+} \ No newline at end of file
diff --git a/src/dolphin/gx/GXFifo.c b/src/dolphin/gx/GXFifo.c
new file mode 100644
index 00000000..7ff20556
--- /dev/null
+++ b/src/dolphin/gx/GXFifo.c
@@ -0,0 +1,337 @@
+#include "dolphin/gx/GXFifo.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.h"
+
+static void GXInitFifoLimits(GXFifoObj* fifo, u32 hi_watermark, u32 lo_watermark);
+
+static GXFifoObj* CPUFifo;
+
+static GXFifoObj* GPFifo;
+
+static OSThread* __GXCurrentThread;
+
+static GXBool data_80451954;
+
+static u32 GXOverflowSuspendInProgress;
+
+static GXBreakPtCallback BreakPointCB;
+
+static u32 __GXOverflowCount;
+
+static void GXOverflowHandler() {
+ __GXOverflowCount += 1;
+ __GXWriteFifoIntEnable(0, 1);
+ __GXWriteFifoIntReset(1, 0);
+ GXOverflowSuspendInProgress = TRUE;
+ OSSuspendThread(__GXCurrentThread);
+}
+
+static void GXUnderflowHandler() {
+ OSResumeThread(__GXCurrentThread);
+ GXOverflowSuspendInProgress = FALSE;
+ __GXWriteFifoIntReset(1, 1);
+ __GXWriteFifoIntEnable(1, 0);
+}
+
+static void GXBreakPointHandler(OSContext* context) {
+ OSContext bpContext;
+
+ FAST_FLAG_SET(__GXData->cpEnable, 0, 5, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+
+ if (BreakPointCB) {
+ OSClearContext(&bpContext);
+ OSSetCurrentContext(&bpContext);
+ BreakPointCB();
+ OSClearContext(&bpContext);
+ OSSetCurrentContext(context);
+ }
+}
+
+static void GXCPInterruptHandler(s16 p1, OSContext* context) {
+ __GXData->cpStatus = GX_GET_CP_REG(0);
+
+ if ((__GXData->cpEnable >> 3 & 1) && (__GXData->cpStatus >> 1 & 1)) {
+ GXUnderflowHandler();
+ }
+
+ if ((__GXData->cpEnable >> 2 & 1) && (__GXData->cpStatus >> 0 & 1)) {
+ GXOverflowHandler();
+ }
+
+ if ((__GXData->cpEnable >> 5 & 1) && (__GXData->cpStatus >> 4 & 1)) {
+ GXBreakPointHandler(context);
+ }
+}
+
+void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size) {
+ fifo->base = base;
+ fifo->end = (void*)((u32)base + size - 4);
+ fifo->size = size;
+ fifo->rw_dst = 0;
+ GXInitFifoLimits(fifo, size - 0x4000, OSRoundDown32B(size / 2));
+ GXInitFifoPtrs(fifo, base, base);
+}
+
+void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr) {
+ int interrupts = OSDisableInterrupts();
+ fifo->read_ptr = readPtr;
+ fifo->write_ptr = writePtr;
+ fifo->rw_dst = (u32)writePtr - (u32)readPtr;
+ if (fifo->rw_dst < 0) {
+ fifo->rw_dst += fifo->size;
+ }
+ OSRestoreInterrupts(interrupts);
+}
+
+static void GXInitFifoLimits(GXFifoObj* fifo, u32 hi_watermark, u32 lo_watermark) {
+ fifo->high_wtrmark = hi_watermark;
+ fifo->low_wtrmark = lo_watermark;
+}
+
+void GXSetCPUFifo(GXFifoObj* fifo) {
+ BOOL interrupts;
+ interrupts = OSDisableInterrupts();
+
+ CPUFifo = fifo;
+
+ if (fifo == GPFifo) {
+ u32 reg;
+ GX_SET_PI_REG(3, (u32)fifo->base & 0x3FFFFFFF);
+ GX_SET_PI_REG(4, (u32)fifo->end & 0x3FFFFFFF);
+ reg = 0;
+ GX_BITFIELD_SET(reg, 6, 21, (u32)fifo->write_ptr >> 5);
+ GX_BITFIELD_SET(reg, 5, 1, 0);
+ GX_SET_PI_REG(5, reg);
+
+ data_80451954 = GX_TRUE;
+
+ __GXWriteFifoIntReset(1, 1);
+ __GXWriteFifoIntEnable(1, 0);
+ __GXFifoLink(1);
+ } else {
+ u32 reg;
+ if (data_80451954) {
+ __GXFifoLink(0);
+ data_80451954 = GX_FALSE;
+ }
+ __GXWriteFifoIntEnable(0, 0);
+
+ GX_SET_PI_REG(3, (u32)fifo->base & 0x3FFFFFFF);
+ GX_SET_PI_REG(4, (u32)fifo->end & 0x3FFFFFFF);
+ reg = 0;
+ GX_BITFIELD_SET(reg, 6, 21, (u32)fifo->write_ptr >> 5);
+ GX_BITFIELD_SET(reg, 5, 1, 0);
+ GX_SET_PI_REG(5, reg);
+ }
+
+ PPCSync();
+
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXSetGPFifo(GXFifoObj* fifo) {
+ int interrupts = OSDisableInterrupts();
+ u32 reg;
+ __GXFifoReadDisable();
+ __GXWriteFifoIntEnable(0, 0);
+ GPFifo = fifo;
+ GX_SET_CP_REG(16, (u16)fifo->base);
+ GX_SET_CP_REG(18, (u16)fifo->end);
+ GX_SET_CP_REG(24, (u16)fifo->rw_dst);
+ GX_SET_CP_REG(26, (u16)fifo->write_ptr);
+ GX_SET_CP_REG(28, (u16)fifo->read_ptr);
+ GX_SET_CP_REG(20, (u16)fifo->high_wtrmark);
+ GX_SET_CP_REG(22, (u16)fifo->low_wtrmark);
+
+ GX_SET_CP_REG(17, ((u32)fifo->base & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(19, ((u32)fifo->end & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(25, (fifo->rw_dst) >> 16);
+ GX_SET_CP_REG(27, ((u32)fifo->write_ptr & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(29, ((u32)fifo->read_ptr & 0x3FFFFFFF) >> 16);
+ GX_SET_CP_REG(21, (fifo->high_wtrmark) >> 16);
+ GX_SET_CP_REG(23, (fifo->low_wtrmark) >> 16);
+
+ PPCSync();
+
+ if (CPUFifo == GPFifo) {
+ data_80451954 = 1;
+ __GXWriteFifoIntEnable(1, 0);
+ __GXFifoLink(1);
+ } else {
+ data_80451954 = 0;
+ __GXWriteFifoIntEnable(0, 0);
+ __GXFifoLink(0);
+ }
+ reg = __GXData->cpEnable;
+ GX_BITFIELD_SET(reg, 0x1e, 1, 0);
+ GX_BITFIELD_SET(reg, 0x1a, 1, 0);
+ GX_SET_CP_REG(1, reg);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+ __GXWriteFifoIntReset(1, 1);
+ __GXFifoReadEnable();
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXSaveCPUFifo(GXFifoObj* fifo) {
+ GXFlush();
+ __GXSaveCPUFifoAux(fifo);
+}
+
+void __GXSaveCPUFifoAux(GXFifoObj* fifo) {
+ int interrupts = OSDisableInterrupts();
+ fifo->base = OSPhysicalToCached(GX_GET_PI_REG(3));
+ fifo->end = OSPhysicalToCached(GX_GET_PI_REG(4));
+ fifo->write_ptr = OSPhysicalToCached(GX_GET_PI_REG(5) & ~0x4000000);
+ if (data_80451954 != 0) {
+ u32 reg2 = GX_GET_CP_REG(28) | (GX_GET_CP_REG(29) << 16);
+ fifo->read_ptr = (void*)(reg2 + -0x80000000);
+ fifo->rw_dst = (((u32)GX_GET_CP_REG(24) | (GX_GET_CP_REG(25) << 16)));
+ } else {
+ fifo->rw_dst = (u32)fifo->write_ptr - (u32)fifo->read_ptr;
+ if (fifo->rw_dst < 0) {
+ fifo->rw_dst += fifo->size;
+ }
+ }
+ OSRestoreInterrupts(interrupts);
+}
+
+void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle,
+ GXBool* brkpt) {
+ __GXData->cpStatus = GX_GET_CP_REG(0);
+ *overhi = __GXData->cpStatus & 1;
+ *underlow = (__GXData->cpStatus >> 1) & 1;
+ *readIdle = (__GXData->cpStatus >> 2) & 1;
+ *cmdIdle = (__GXData->cpStatus >> 3) & 1;
+ *brkpt = (__GXData->cpStatus >> 4) & 1;
+}
+
+void* GXGetFifoBase(GXFifoObj* fifo) {
+ return fifo->base;
+}
+
+u32 GXGetFifoSize(GXFifoObj* fifo) {
+ return fifo->size;
+}
+
+GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb) {
+ GXBreakPtCallback oldCallback = BreakPointCB;
+ int interrupts = OSDisableInterrupts();
+ BreakPointCB = cb;
+ OSRestoreInterrupts(interrupts);
+ return oldCallback;
+}
+
+void __GXFifoInit(void) {
+ __OSSetInterruptHandler(0x11, GXCPInterruptHandler);
+ __OSUnmaskInterrupts(0x4000);
+ __GXCurrentThread = OSGetCurrentThread();
+ GXOverflowSuspendInProgress = 0;
+ CPUFifo = NULL;
+ GPFifo = NULL;
+}
+
+void __GXFifoReadEnable(void) {
+ FAST_FLAG_SET(__GXData->cpEnable, 1, 0, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXFifoReadDisable(void) {
+ FAST_FLAG_SET(__GXData->cpEnable, 0, 0, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXFifoLink(u8 link) {
+ u32 b;
+ if (link) {
+ b = 1;
+ } else {
+ b = 0;
+ }
+ FAST_FLAG_SET(__GXData->cpEnable, b, 4, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXWriteFifoIntEnable(u32 p1, u32 p2) {
+ FAST_FLAG_SET(__GXData->cpEnable, p1, 2, 1);
+ FAST_FLAG_SET(__GXData->cpEnable, (u8)p2, 3, 1);
+ GX_SET_CP_REG(1, __GXData->cpEnable);
+}
+
+void __GXWriteFifoIntReset(u32 p1, u32 p2) {
+ FAST_FLAG_SET(__GXData->cpClr, p1, 0, 1);
+ FAST_FLAG_SET(__GXData->cpClr, (u8)p2, 1, 1);
+ GX_SET_CP_REG(2, __GXData->cpClr);
+}
+
+void __GXCleanGPFifo(void) {
+ BOOL interrupts;
+ GXFifoObj tempObj; // 0x14
+ u32 i, j, k; // stack alloc
+ GXFifoObj* gpFifo; // r31
+ GXFifoObj* cpuFifo; // r30
+ void* tempPtr; // r29
+
+ gpFifo = GXGetGPFifo();
+ if (!gpFifo) {
+ return;
+ }
+
+ cpuFifo = GXGetCPUFifo();
+ tempPtr = gpFifo->base;
+
+ tempObj = *gpFifo;
+
+ interrupts = OSDisableInterrupts();
+
+ tempObj.read_ptr = tempPtr;
+ tempObj.write_ptr = tempPtr;
+ tempObj.rw_dst = 0;
+ if (tempObj.rw_dst < 0) {
+ tempObj.rw_dst += tempObj.size;
+ }
+
+ OSRestoreInterrupts(interrupts);
+
+ GXSetGPFifo(&tempObj);
+
+ if (cpuFifo == gpFifo) {
+ GXSetCPUFifo(&tempObj);
+ }
+
+ interrupts = OSDisableInterrupts();
+
+ gpFifo->read_ptr = tempPtr;
+ gpFifo->write_ptr = tempPtr;
+ gpFifo->rw_dst = 0;
+
+ if (gpFifo->rw_dst < 0) {
+ gpFifo->rw_dst += gpFifo->size;
+ }
+ OSRestoreInterrupts(interrupts);
+
+ GXSetGPFifo(gpFifo);
+ if (cpuFifo == gpFifo) {
+ GXSetCPUFifo(cpuFifo);
+ }
+}
+
+OSThread* GXSetCurrentGXThread(void) {
+ BOOL interrupts = OSDisableInterrupts();
+ OSThread* prevThread = __GXCurrentThread;
+ __GXCurrentThread = OSGetCurrentThread();
+ OSRestoreInterrupts(interrupts);
+ return prevThread;
+}
+
+OSThread* GXGetCurrentGXThread(void) {
+ return *(OSThread**)(&__GXCurrentThread);
+}
+
+GXFifoObj* GXGetCPUFifo(void) {
+ return *(GXFifoObj**)(&CPUFifo);
+}
+
+GXFifoObj* GXGetGPFifo(void) {
+ return GPFifo;
+}
diff --git a/src/dolphin/gx/GXFrameBuf.c b/src/dolphin/gx/GXFrameBuf.c
new file mode 100644
index 00000000..3cedf7e6
--- /dev/null
+++ b/src/dolphin/gx/GXFrameBuf.c
@@ -0,0 +1,638 @@
+#include "dolphin/gx/GXFrameBuf.h"
+#include "dolphin/gx/GX.h"
+
+GXRenderModeObj GXNtsc480IntDf = {
+ VI_TVMODE_NTSC_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXNtsc480Int = {
+ VI_TVMODE_NTSC_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 0,
+ 0,
+ 21,
+ 22,
+ 21,
+ 0,
+ 0,
+};
+
+GXRenderModeObj GXMpal480IntDf = {
+ VI_TVMODE_MPAL_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXPal528IntDf = {
+ VI_TVMODE_PAL_INT,
+ 640,
+ 528,
+ 528,
+ 40,
+ 23,
+ 640,
+ 528,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+GXRenderModeObj GXEurgb60Hz480IntDf = {
+ VI_TVMODE_EURGB60_INT,
+ 640,
+ 480,
+ 480,
+ 40,
+ 0,
+ 640,
+ 480,
+ VI_XFBMODE_DF,
+ GX_FALSE,
+ GX_FALSE,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 6,
+ 8,
+ 8,
+ 10,
+ 12,
+ 10,
+ 8,
+ 8,
+};
+
+void GXSetDispCopySrc(u16 left, u16 top, u16 width, u16 height) {
+ __GXData->cpDispSrc = 0;
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 22, 10, left);
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 12, 10, top);
+ GX_BITFIELD_SET(__GXData->cpDispSrc, 0, 8, 73);
+
+ __GXData->cpDispSize = 0;
+ GX_BITFIELD_SET(__GXData->cpDispSize, 22, 10, width - 1);
+ GX_BITFIELD_SET(__GXData->cpDispSize, 12, 10, height - 1);
+ GX_BITFIELD_SET(__GXData->cpDispSize, 0, 8, 74);
+}
+
+void GXSetTexCopySrc(u16 left, u16 top, u16 width, u16 height) {
+ __GXData->cpTexSrc = 0;
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 22, 10, left);
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 12, 10, top);
+ GX_BITFIELD_SET(__GXData->cpTexSrc, 0, 8, 0x49);
+ __GXData->cpTexSize = 0;
+ GX_BITFIELD_SET(__GXData->cpTexSize, 22, 10, width - 1);
+ GX_BITFIELD_SET(__GXData->cpTexSize, 12, 10, height - 1);
+ GX_BITFIELD_SET(__GXData->cpTexSize, 0, 8, 0x4A);
+}
+
+void GXSetDispCopyDst(u16 arg0, u16 arg1) {
+ s32 val = (s32)((arg0 << 1) & 0xFFFE) >> 5;
+ __GXData->cpDispStride = 0;
+ GX_BITFIELD_SET(__GXData->cpDispStride, 22, 10, val);
+ GX_BITFIELD_SET(__GXData->cpDispStride, 0, 8, 0x4D);
+}
+
+void GXSetTexCopyDst(u16 width, u16 height, GXTexFmt format, GXBool useMIPmap) {
+ u32 sp20, sp1C, sp18;
+ u32 value;
+ u8 depthRelated;
+
+ __GXData->cpTexZ = GX_NONE;
+
+ depthRelated = format & 0xf;
+ if (format == GX_TF_Z16) {
+ depthRelated = 0xb;
+ }
+
+ switch (format) {
+ case GX_TF_I4:
+ case GX_TF_I8:
+ case GX_TF_IA4:
+ case GX_TF_IA8:
+ case GX_CTF_A8:
+ GX_SET_REG(__GXData->cpTex, 3, 15, 16);
+ break;
+ default:
+ GX_SET_REG(__GXData->cpTex, 2, 15, 16);
+ break;
+ }
+
+ __GXData->cpTexZ = (format & 0x10) == 0x10;
+
+ value = depthRelated >> 3;
+
+ GX_SET_REG(__GXData->cpTex, value, 28, 28);
+
+ depthRelated &= 7;
+
+ __GetImageTileCount(format, width, height, &sp20, &sp1C, &sp18);
+
+ __GXData->cpTexStride = GX_NONE;
+ GX_SET_REG(__GXData->cpTexStride, sp20 * sp18, 22, 31);
+ GX_SET_REG(__GXData->cpTexStride, 0x4D, 0, 7);
+
+ GX_SET_REG(__GXData->cpTex, useMIPmap, 22, 22);
+ GX_SET_REG(__GXData->cpTex, depthRelated, 25, 27);
+}
+
+void GXSetDispCopyFrame2Field(GXCopyMode arg0) {
+ GX_BITFIELD_SET(__GXData->cpDisp, 18, 2, arg0);
+ GX_BITFIELD_SET(__GXData->cpTex, 18, 2, 0);
+}
+
+// clang-format off
+#define INSERT_FIELD(reg, value, nbits, shift) \
+ (reg) = ((u32) (reg) & ~(((1 << (nbits)) - 1) << (shift))) | \
+ ((u32) (value) << (shift));
+// clang-format on
+
+void GXSetCopyClamp(GXFBClamp clamp) {
+ u8 isTop = (clamp & GX_CLAMP_TOP) == GX_CLAMP_TOP;
+ u8 isBottom = (clamp & GX_CLAMP_BOTTOM) == GX_CLAMP_BOTTOM;
+ __GXData->cpDisp = __rlwimi(__GXData->cpDisp, isTop, 0, 31, 31);
+ __GXData->cpDisp = __rlwimi(__GXData->cpDisp, isBottom, 1, 30, 30);
+ __GXData->cpTex = __rlwimi(__GXData->cpTex, isTop, 0, 31, 31);
+ __GXData->cpTex = __rlwimi(__GXData->cpTex, isBottom, 1, 30, 30);
+}
+
+static u32 __GXGetNumXfbLines(u32 height, u32 scale) {
+ u32 numLines;
+ u32 actualHeight;
+ u32 newScale;
+
+ numLines = (height - 1) * 0x100;
+ actualHeight = (numLines / scale) + 1;
+
+ newScale = scale;
+
+ if (newScale > 0x80 && newScale < 0x100) {
+ while (newScale % 2 == 0) {
+ newScale /= 2;
+ }
+
+ if (height % newScale == 0) {
+ actualHeight++;
+ }
+ }
+
+ if (actualHeight > 0x400) {
+ actualHeight = 0x400;
+ }
+
+ return actualHeight;
+}
+
+u16 GXGetNumXfbLines(const u16 efbHeight, f32 yScale) {
+ u32 scale = (u32)(256.0f / yScale) & 0x1FF;
+
+ return __GXGetNumXfbLines(efbHeight, scale);
+}
+
+f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight) {
+ u32 scale;
+ u32 height1;
+ u32 height2;
+ f32 scale2;
+ f32 scale1;
+
+ height1 = xfbHeight;
+ scale1 = (f32)xfbHeight / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+
+ while (height2 > xfbHeight) {
+ height1--;
+ scale1 = (f32)height1 / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+ }
+
+ scale2 = scale1;
+ while (height2 < xfbHeight) {
+ scale2 = scale1;
+ height1++;
+ scale1 = (f32)height1 / (f32)efbHeight;
+ scale = (u32)(256.0f / scale1) & 0x1FF;
+ height2 = __GXGetNumXfbLines(efbHeight, scale);
+ }
+
+ return scale2;
+}
+
+u32 GXSetDispCopyYScale(f32 vertScale) {
+ u32 scale;
+ GXBool check;
+ u32 height;
+ u32 reg;
+
+ scale = (u32)(256.0f / vertScale) & 0x1FF;
+ check = (scale != 0x100);
+
+ reg = 0;
+ GX_SET_REG(reg, scale, 23, 31);
+ GX_SET_REG(reg, 0x4E, 0, 7);
+ GX_BP_LOAD_REG(reg);
+ __GXData->bpSentNot = GX_FALSE;
+
+ GX_SET_REG(__GXData->cpDisp, check, 21, 21);
+
+ height = (__GXData->cpDispSize >> 10 & 0x3FF) + 1;
+
+ return __GXGetNumXfbLines(height, scale);
+}
+
+void GXSetCopyClear(GXColor color, u32 clear_z) {
+ u32 r6 = 0;
+ GX_BITFIELD_SET(r6, 24, 8, color.r);
+ GX_BITFIELD_SET(r6, 16, 8, color.a);
+ GX_BITFIELD_SET(r6, 0, 8, 0x4f);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ r6 = 0;
+ GX_BITFIELD_SET(r6, 24, 8, color.b);
+ GX_BITFIELD_SET(r6, 16, 8, color.g);
+ GX_BITFIELD_SET(r6, 0, 8, 0x50);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ r6 = 0;
+ GX_BITFIELD_SET(r6, 8, 24, clear_z);
+ GX_BITFIELD_SET(r6, 0, 8, 0x51);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = r6;
+
+ __GXData->bpSentNot = 0;
+}
+
+void GXSetCopyFilter(GXBool useAA, u8 samplePattern[12][2], GXBool doVertFilt, u8 vFilt[7]) {
+ u32 vals[4];
+ u32 unk1;
+ u32 unk2;
+
+ if (useAA) {
+ vals[0] = 0;
+ GX_SET_REG(vals[0], samplePattern[0][0], 28, 31);
+ GX_SET_REG(vals[0], samplePattern[0][1], 24, 27);
+ GX_SET_REG(vals[0], samplePattern[1][0], 20, 23);
+ GX_SET_REG(vals[0], samplePattern[1][1], 16, 19);
+ GX_SET_REG(vals[0], samplePattern[2][0], 12, 15);
+ GX_SET_REG(vals[0], samplePattern[2][1], 8, 11);
+ GX_SET_REG(vals[0], 1, 0, 7);
+
+ vals[1] = 0;
+ GX_SET_REG(vals[1], samplePattern[3][0], 28, 31);
+ GX_SET_REG(vals[1], samplePattern[3][1], 24, 27);
+ GX_SET_REG(vals[1], samplePattern[4][0], 20, 23);
+ GX_SET_REG(vals[1], samplePattern[4][1], 16, 19);
+ GX_SET_REG(vals[1], samplePattern[5][0], 12, 15);
+ GX_SET_REG(vals[1], samplePattern[5][1], 8, 11);
+ GX_SET_REG(vals[1], 2, 0, 7);
+
+ vals[2] = 0;
+ GX_SET_REG(vals[2], samplePattern[6][0], 28, 31);
+ GX_SET_REG(vals[2], samplePattern[6][1], 24, 27);
+ GX_SET_REG(vals[2], samplePattern[7][0], 20, 23);
+ GX_SET_REG(vals[2], samplePattern[7][1], 16, 19);
+ GX_SET_REG(vals[2], samplePattern[8][0], 12, 15);
+ GX_SET_REG(vals[2], samplePattern[8][1], 8, 11);
+ GX_SET_REG(vals[2], 3, 0, 7);
+
+ vals[3] = 0;
+ GX_SET_REG(vals[3], samplePattern[9][0], 28, 31);
+ GX_SET_REG(vals[3], samplePattern[9][1], 24, 27);
+ GX_SET_REG(vals[3], samplePattern[10][0], 20, 23);
+ GX_SET_REG(vals[3], samplePattern[10][1], 16, 19);
+ GX_SET_REG(vals[3], samplePattern[11][0], 12, 15);
+ GX_SET_REG(vals[3], samplePattern[11][1], 8, 11);
+ GX_SET_REG(vals[3], 4, 0, 7);
+ } else {
+ vals[0] = 0x01666666;
+ vals[1] = 0x02666666;
+ vals[2] = 0x03666666;
+ vals[3] = 0x04666666;
+ }
+
+ GX_BP_LOAD_REG(vals[0]);
+ GX_BP_LOAD_REG(vals[1]);
+ GX_BP_LOAD_REG(vals[2]);
+ GX_BP_LOAD_REG(vals[3]);
+
+ unk1 = 0;
+ GX_SET_REG(unk1, 0x53, 0, 7);
+ unk2 = 0;
+ GX_SET_REG(unk2, 0x54, 0, 7);
+
+ if (doVertFilt) {
+ GX_SET_REG(unk1, vFilt[0], 26, 31);
+ GX_SET_REG(unk1, vFilt[1], 20, 25);
+ GX_SET_REG(unk1, vFilt[2], 14, 19);
+ GX_SET_REG(unk1, vFilt[3], 8, 13);
+ GX_SET_REG(unk2, vFilt[4], 26, 31);
+ GX_SET_REG(unk2, vFilt[5], 20, 25);
+ GX_SET_REG(unk2, vFilt[6], 14, 19);
+
+ } else {
+ GX_SET_REG(unk1, 0, 26, 31);
+ GX_SET_REG(unk1, 0, 20, 25);
+ GX_SET_REG(unk1, 21, 14, 19);
+ GX_SET_REG(unk1, 22, 8, 13);
+ GX_SET_REG(unk2, 21, 26, 31);
+ GX_SET_REG(unk2, 0, 20, 25);
+ GX_SET_REG(unk2, 0, 14, 19);
+ }
+
+ GX_BP_LOAD_REG(unk1);
+ GX_BP_LOAD_REG(unk2);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetDispCopyGamma(GXGamma gamma) {
+ GX_BITFIELD_SET(__GXData->cpDisp, 23, 2, gamma);
+}
+
+void GXCopyDisp(void* dest, GXBool doClear) {
+ u32 reg;
+ u32 newDest;
+ GXBool check;
+
+ if (doClear) {
+ reg = __GXData->zmode;
+ GX_SET_REG(reg, 1, 31, 31);
+ GX_SET_REG(reg, 7, 28, 30);
+ GX_BP_LOAD_REG(reg);
+
+ reg = __GXData->cmode0;
+ GX_SET_REG(reg, 0, 31, 31);
+ GX_SET_REG(reg, 0, 30, 30);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ check = GX_FALSE;
+ if ((doClear || (__GXData->peCtrl & 0x7) == 3) && (__GXData->peCtrl >> 6 & 0x1) == 1) {
+ check = GX_TRUE;
+ reg = __GXData->peCtrl;
+ GX_SET_REG(reg, 0, 25, 25);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ GX_BP_LOAD_REG(__GXData->cpDispSrc);
+ GX_BP_LOAD_REG(__GXData->cpDispSize);
+ GX_BP_LOAD_REG(__GXData->cpDispStride);
+
+ newDest = (u32)dest & 0x3FFFFFFF;
+ reg = 0;
+ GX_SET_REG(reg, newDest >> 5, 11, 31);
+ GX_SET_REG(reg, 0x4B, 0, 7);
+ GX_BP_LOAD_REG(reg);
+
+ GX_SET_REG(__GXData->cpDisp, doClear, 20, 20);
+ GX_SET_REG(__GXData->cpDisp, 1, 17, 17);
+ GX_SET_REG(__GXData->cpDisp, 0x52, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cpDisp);
+
+ if (doClear) {
+ GX_BP_LOAD_REG(__GXData->zmode);
+ GX_BP_LOAD_REG(__GXData->cmode0);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXCopyTex(void* dest, GXBool doClear) {
+ u32 reg;
+ u32 reg2;
+ u32 newDest;
+ GXBool check;
+
+ if (doClear) {
+ reg = __GXData->zmode;
+ GX_SET_REG(reg, 1, 31, 31);
+ GX_SET_REG(reg, 7, 28, 30);
+ GX_BP_LOAD_REG(reg);
+
+ reg = __GXData->cmode0;
+ GX_SET_REG(reg, 0, 31, 31);
+ GX_SET_REG(reg, 0, 30, 30);
+ GX_BP_LOAD_REG(reg);
+ }
+
+ check = GX_FALSE;
+ reg2 = __GXData->peCtrl;
+ if (__GXData->cpTexZ && (reg2 & 0x7) != 3) {
+ check = GX_TRUE;
+ GX_SET_REG(reg2, 3, 29, 31);
+ }
+
+ if ((doClear || (reg2 & 0x7) == 3) && (reg2 >> 6 & 0x1) == 1) {
+ check = GX_TRUE;
+ GX_SET_REG(reg2, 0, 25, 25);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(reg2);
+ }
+
+ GX_BP_LOAD_REG(__GXData->cpTexSrc);
+ GX_BP_LOAD_REG(__GXData->cpTexSize);
+ GX_BP_LOAD_REG(__GXData->cpTexStride);
+
+ newDest = (u32)dest & 0x3FFFFFFF;
+ reg = 0;
+ GX_SET_REG(reg, newDest >> 5, 11, 31);
+ GX_SET_REG(reg, 0x4B, 0, 7);
+ GX_BP_LOAD_REG(reg);
+
+ GX_SET_REG(__GXData->cpTex, doClear, 20, 20);
+ GX_SET_REG(__GXData->cpTex, 0, 17, 17);
+ GX_SET_REG(__GXData->cpTex, 0x52, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cpTex);
+
+ if (doClear) {
+ GX_BP_LOAD_REG(__GXData->zmode);
+ GX_BP_LOAD_REG(__GXData->cmode0);
+ }
+
+ if (check) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXClearBoundingBox(void) {
+ GXFIFO.u8 = GX_LOAD_BP_REG;
+ GXFIFO.u32 = 0x550003FF;
+ GXFIFO.u8 = GX_LOAD_BP_REG;
+ GXFIFO.u32 = 0x560003FF;
+ set_x2(GX_FALSE);
+}
diff --git a/src/dolphin/gx/GXGeometry.c b/src/dolphin/gx/GXGeometry.c
new file mode 100644
index 00000000..a6de9560
--- /dev/null
+++ b/src/dolphin/gx/GXGeometry.c
@@ -0,0 +1,149 @@
+/**
+ * GXGeometry.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXGeometry.h"
+#include "dolphin/gx/GX.h"
+
+void __GXSetDirtyState(void) {
+ u32 dirtyFlags = __GXData->dirtyState;
+
+ if (dirtyFlags & GX_DIRTY_SU_TEX) {
+ __GXSetSUTexRegs();
+ }
+
+ if (dirtyFlags & GX_DIRTY_BP_MASK) {
+ __GXUpdateBPMask();
+ }
+
+ if (dirtyFlags & GX_DIRTY_GEN_MODE) {
+ __GXSetGenMode();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VCD) {
+ __GXSetVCD();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VAT) {
+ __GXSetVAT();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VLIM) {
+ __GXCalculateVLim();
+ }
+
+ __GXData->dirtyState = 0;
+}
+
+void GXBegin(GXPrimitive type, GXVtxFmt fmt, u16 vert_num) {
+ GXData* data = __GXData;
+ u32 dirtyFlags = data->dirtyState;
+
+ if (data->dirtyState != 0) {
+ if (dirtyFlags & GX_DIRTY_SU_TEX) {
+ __GXSetSUTexRegs();
+ }
+
+ if (dirtyFlags & GX_DIRTY_BP_MASK) {
+ __GXUpdateBPMask();
+ }
+
+ if (dirtyFlags & GX_DIRTY_GEN_MODE) {
+ __GXSetGenMode();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VCD) {
+ __GXSetVCD();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VAT) {
+ __GXSetVAT();
+ }
+
+ if (dirtyFlags & GX_DIRTY_VLIM) {
+ __GXCalculateVLim();
+ }
+
+ __GXData->dirtyState = 0;
+ }
+
+ if (*(u32*)__GXData == 0) {
+ __GXSendFlushPrim();
+ }
+
+ GXFIFO.u8 = fmt | type;
+ GXFIFO.u16 = vert_num;
+}
+
+void __GXSendFlushPrim(void) {
+ u32 i;
+ u32 sz = __GXData->vNum * __GXData->vLim;
+
+ GXFIFO.u8 = 0x98;
+ GXFIFO.u16 = __GXData->vNum;
+
+ for (i = 0; i < sz; i += 4) {
+ GXFIFO.s32 = 0;
+ }
+
+ __GXData->bpSentNot = 1;
+}
+
+void GXSetLineWidth(u8 width, GXTexOffset offsets) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->lpSize, 24, 8, width);
+ GX_BITFIELD_SET(data->lpSize, 13, 3, offsets);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->lpSize;
+ data->bpSentNot = 0;
+}
+
+void GXSetPointSize(u8 size, GXTexOffset offsets) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->lpSize, 16, 8, size);
+ GX_BITFIELD_SET(data->lpSize, 10, 3, offsets);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->lpSize;
+ data->bpSentNot = 0;
+}
+
+void GXEnableTexOffsets(GXTexCoordID coord, GXBool line, GXBool point) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->suTs0[coord], 13, 1, line);
+ GX_BITFIELD_SET(data->suTs0[coord], 12, 1, point);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->suTs0[coord];
+ data->bpSentNot = 0;
+}
+
+void GXSetCullMode(GXCullMode mode) {
+ GXData* data;
+ GXCullMode mode2;
+ data = __GXData;
+
+ mode2 = (mode >> 1) & 1;
+ GX_BITFIELD_SET(mode2, 30, 1, mode);
+
+ GX_BITFIELD_SET(data->genMode, 16, 2, mode2);
+ data->dirtyState |= GX_DIRTY_GEN_MODE;
+}
+
+void GXSetCoPlanar(GXBool enable) {
+ GXData* data = __GXData;
+
+ GX_BITFIELD_SET(data->genMode, 12, 1, enable);
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0xFE080000;
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = data->genMode;
+}
+
+void __GXSetGenMode(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = __GXData->genMode;
+ __GXData->bpSentNot = 0;
+}
diff --git a/src/dolphin/gx/GXInit.c b/src/dolphin/gx/GXInit.c
new file mode 100644
index 00000000..f8e47061
--- /dev/null
+++ b/src/dolphin/gx/GXInit.c
@@ -0,0 +1,561 @@
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.h"
+#include "dolphin/vi/vi.h"
+
+char* __GXVersion = "<< Dolphin SDK - GX release build: Nov 10 2004 06:27:12 (0x2301) >>";
+
+static GXFifoObj FifoObj;
+
+static GXData gxData;
+
+GXData* const __GXData = &gxData;
+
+GXTexRegion* __GXDefaultTexRegionCallback(const GXTexObj* obj, GXTexMapID id) {
+ GXTexFmt format; // r31
+ GXBool isMipMap; // r3
+
+ format = GXGetTexObjFmt(obj);
+ isMipMap = GXGetTexObjMipMap(obj);
+ id = (GXTexMapID)(id % GX_MAX_TEXMAP);
+
+ switch (format) {
+ case GX_TF_RGBA8:
+ if (isMipMap) {
+ return &__GXData->TexRegions2[id];
+ }
+ return &__GXData->TexRegions1[id];
+
+ case GX_TF_C4:
+ case GX_TF_C8:
+ case GX_TF_C14X2:
+ return &__GXData->TexRegions0[id];
+
+ default:
+ if (isMipMap) {
+ return &__GXData->TexRegions1[id];
+ }
+ return &__GXData->TexRegions0[id];
+ }
+}
+
+GXTlutRegion* __GXDefaultTlutRegionCallback(u32 tlut) {
+ if (tlut >= 0x14) {
+ return NULL;
+ } else {
+ return &__GXData->TlutRegions[tlut];
+ }
+}
+
+u32 resetFuncRegistered;
+
+u32 calledOnce;
+
+OSTime time;
+
+u32 peCount;
+
+vu16* __memReg;
+
+u16* __peReg;
+
+u16* __cpReg;
+
+/* ############################################################################################## */
+u32* __piReg;
+
+BOOL __GXShutdown(BOOL final) {
+ u32 val;
+ u32 newPeCount;
+ OSTime newTime;
+
+ if (!final) {
+ if (!calledOnce) {
+ peCount = GXReadMEMReg(0x28, 0x27);
+ time = OSGetTime();
+ calledOnce = 1;
+ return FALSE;
+ }
+
+ newTime = OSGetTime();
+ newPeCount = GXReadMEMReg(0x28, 0x27);
+
+ if (newTime - time < 10) {
+ return FALSE;
+ }
+
+ if (newPeCount != peCount) {
+ peCount = newPeCount;
+ time = newTime;
+ return FALSE;
+ }
+
+ } else {
+ GXSetBreakPtCallback(NULL);
+ GXSetDrawSyncCallback(NULL);
+ GXSetDrawDoneCallback(NULL);
+
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+ GX_WRITE_U32(0);
+
+ PPCSync();
+
+ GX_SET_CP_REG(1, 0);
+ GX_SET_CP_REG(2, 3);
+
+ __GXData->abtWaitPECopy = GX_TRUE;
+
+ __GXAbort();
+ }
+
+ return TRUE;
+}
+
+void __GXInitRevisionBits(void) {
+ u32 i;
+ for (i = 0; i < 8; i++) {
+ FAST_FLAG_SET(__GXData->vatA[i], 1, 30, 33);
+ FAST_FLAG_SET(__GXData->vatB[i], 1, 31, 33);
+
+ GX_WRITE_U8(0x8);
+ GX_WRITE_U8(i | 0x80);
+ GX_WRITE_U32(__GXData->vatB[i]);
+ }
+
+ {
+ u32 reg1 = 0;
+ u32 reg2 = 0;
+
+ FAST_FLAG_SET(reg1, 1, 0, 1);
+ FAST_FLAG_SET(reg1, 1, 1, 1);
+ FAST_FLAG_SET(reg1, 1, 2, 1);
+ FAST_FLAG_SET(reg1, 1, 3, 1);
+ FAST_FLAG_SET(reg1, 1, 4, 1);
+ FAST_FLAG_SET(reg1, 1, 5, 1);
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1000);
+ GX_WRITE_U32(reg1);
+
+ FAST_FLAG_SET(reg2, 1, 0, 1);
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1012);
+ GX_WRITE_U32(reg2);
+ }
+
+ {
+ u32 reg = 0;
+ FAST_FLAG_SET(reg, 1, 0, 1);
+ FAST_FLAG_SET(reg, 1, 1, 1);
+ FAST_FLAG_SET(reg, 1, 2, 1);
+ FAST_FLAG_SET(reg, 1, 3, 1);
+ FAST_FLAG_SET(reg, 0x58, 24, 8);
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(reg);
+ }
+}
+
+static u16 DefaultTexData[] ALIGN_DECL(32) = {
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+};
+
+static GXVtxAttrFmtList GXDefaultVATList[] = {
+ {GX_VA_POS, GX_POS_XYZ, GX_F32, 0},
+ {GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0},
+ {GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0},
+ {GX_VA_CLR1, GX_CLR_RGBA, GX_RGBA8, 0},
+ {GX_VA_TEX0, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX1, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX2, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX3, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX4, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX5, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX6, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_TEX7, GX_TEX_ST, GX_F32, 0},
+ {GX_VA_NULL, GX_COMPCNT_NULL, GX_COMP_NULL, 0},
+};
+
+static f32 GXDefaultProjData[] = {1.0f, 0.0f, 1.0f, 0.0f, -1.0f, -2.0f, 0.0f};
+
+static u32 GXTexRegionAddrTable[] = {
+ 0x00000, 0x10000, 0x20000, 0x30000, 0x40000, 0x50000, 0x60000, 0x70000, 0x08000, 0x18000,
+ 0x28000, 0x38000, 0x48000, 0x58000, 0x68000, 0x78000, 0x00000, 0x90000, 0x20000, 0xB0000,
+ 0x40000, 0x98000, 0x60000, 0xB8000, 0x80000, 0x10000, 0xA0000, 0x30000, 0x88000, 0x50000,
+ 0xA8000, 0x70000, 0x00000, 0x90000, 0x20000, 0xB0000, 0x40000, 0x90000, 0x60000, 0xB0000,
+ 0x80000, 0x10000, 0xA0000, 0x30000, 0x80000, 0x50000, 0xA0000, 0x70000,
+};
+
+static OSResetFunctionInfo GXResetFuncInfo = {__GXShutdown, OS_RESET_PRIO_GX};
+
+static void EnableWriteGatherPipe() {
+ u32 hid2; // r31
+ hid2 = PPCMfhid2();
+ PPCMtwpar(OSUncachedToPhysical((void*)GXFIFO_ADDR));
+ hid2 |= 0x40000000;
+ PPCMthid2(hid2);
+}
+
+GXFifoObj* GXInit(void* base, u32 size) {
+ u32 i;
+ u32 pad2; // for stack matching
+
+ OSRegisterVersion(__GXVersion);
+ __GXData->inDispList = GX_FALSE;
+ __GXData->dlSaveContext = GX_TRUE;
+ __GXData->abtWaitPECopy = GX_TRUE;
+
+ __GXData->tcsManEnab = 0;
+ __GXData->tevTcEnab = 0;
+
+ GXSetMisc(GX_MT_XF_FLUSH, 0);
+
+ __piReg = (void*)OSPhysicalToUncached(GX_PI_ADDR);
+ __cpReg = (void*)OSPhysicalToUncached(GX_CP_ADDR);
+ __peReg = (void*)OSPhysicalToUncached(GX_PE_ADDR);
+ __memReg = (void*)OSPhysicalToUncached(GX_MEM_ADDR);
+
+ __GXFifoInit();
+
+ GXInitFifoBase(&FifoObj, base, size);
+ GXSetCPUFifo(&FifoObj);
+ GXSetGPFifo(&FifoObj);
+
+ if (!resetFuncRegistered) {
+ OSRegisterResetFunction(&GXResetFuncInfo);
+ resetFuncRegistered = 1;
+ }
+
+ __GXPEInit();
+ EnableWriteGatherPipe();
+
+ __GXData->genMode = 0;
+ FAST_FLAG_SET(__GXData->genMode, 0, 24, 8);
+
+ __GXData->bpMask = 255;
+ FAST_FLAG_SET(__GXData->bpMask, 0xF, 24, 8);
+
+ __GXData->lpSize = 0;
+ FAST_FLAG_SET(__GXData->lpSize, 34, 24, 8);
+
+ for (i = 0; i < GX_MAX_TEVSTAGE; i++) {
+ __GXData->tevc[i] = 0;
+ __GXData->teva[i] = 0;
+ __GXData->tref[i / 2] = 0;
+ __GXData->texmapId[i] = GX_TEXMAP_NULL;
+
+ FAST_FLAG_SET(__GXData->tevc[i], 0xC0 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->teva[i], 0xC1 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->tevKsel[i / 2], 0xF6 + i / 2, 24, 8);
+ FAST_FLAG_SET(__GXData->tref[i / 2], 0x28 + i / 2, 24, 8);
+ }
+
+ __GXData->iref = 0;
+ FAST_FLAG_SET(__GXData->iref, 0x27, 24, 8);
+
+ for (i = 0; i < GX_MAXCOORD; i++) {
+ __GXData->suTs0[i] = 0;
+ __GXData->suTs1[i] = 0;
+
+ FAST_FLAG_SET(__GXData->suTs0[i], 0x30 + i * 2, 24, 8);
+ FAST_FLAG_SET(__GXData->suTs1[i], 0x31 + i * 2, 24, 8);
+ }
+
+ FAST_FLAG_SET(__GXData->suScis0, 0x20, 24, 8);
+ FAST_FLAG_SET(__GXData->suScis1, 0x21, 24, 8);
+
+ FAST_FLAG_SET(__GXData->cmode0, 0x41, 24, 8);
+ FAST_FLAG_SET(__GXData->cmode1, 0x42, 24, 8);
+
+ FAST_FLAG_SET(__GXData->zmode, 0x40, 24, 8);
+ FAST_FLAG_SET(__GXData->peCtrl, 0x43, 24, 8);
+
+ FAST_FLAG_SET(__GXData->cpTex, 0, 7, 2);
+
+ __GXData->zScale = 1.6777216E7f;
+ __GXData->zOffset = 0.0f;
+
+ __GXData->dirtyState = 0;
+ __GXData->dirtyVAT = 0;
+
+ {
+ u32 val1;
+ u32 val2;
+
+ val2 = OS_BUS_CLOCK / 500;
+
+ __GXFlushTextureState();
+
+ val1 = (val2 / 2048) | 0x69000400;
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(val1);
+
+ __GXFlushTextureState();
+
+ val1 = (val2 / 4224) | 0x46000200;
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(val1);
+ }
+
+ __GXInitRevisionBits();
+
+ for (i = 0; i < GX_MAX_TEXMAP; i++) {
+ GXInitTexCacheRegion(&__GXData->TexRegions0[i], GX_FALSE, GXTexRegionAddrTable[i],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 8], GX_TEXCACHE_32K);
+ GXInitTexCacheRegion(&__GXData->TexRegions1[i], GX_FALSE, GXTexRegionAddrTable[i + 16],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 24], GX_TEXCACHE_32K);
+ GXInitTexCacheRegion(&__GXData->TexRegions2[i], GX_TRUE, GXTexRegionAddrTable[i + 32],
+ GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 40], GX_TEXCACHE_32K);
+ }
+
+ for (i = 0; i < GX_MAX_TLUT; i++) {
+ GXInitTlutRegion(&__GXData->TlutRegions[i], 0xC0000 + 0x2000 * i, GX_TLUT_256);
+ }
+
+ for (i = 0; i < GX_MAX_BIGTLUT; i++) {
+ GXInitTlutRegion(&__GXData->TlutRegions[i + 16], 0xE0000 + 0x8000 * i, GX_TLUT_1K);
+ }
+
+ GX_SET_CP_REG(3, 0);
+
+ FAST_FLAG_SET(__GXData->perfSel, 0, 4, 4);
+
+ GX_WRITE_U8(0x8);
+ GX_WRITE_U8(0x20);
+ GX_WRITE_U32(__GXData->perfSel);
+
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x24000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000000);
+
+ __GXSetIndirectMask(0);
+ __GXSetTmemConfig(2);
+ __GXInitGX();
+
+ return &FifoObj;
+}
+
+void __GXInitGX(void) {
+ GXRenderModeObj* renderObj;
+ GXTexObj texObj;
+ Mtx ident;
+ GXColor clearColor = {64, 64, 64, 255};
+ GXColor ambColor = {0, 0, 0, 0};
+ GXColor matColor = {255, 255, 255, 255};
+ u32 i;
+
+ switch (VIGetTvFormat()) {
+ case VI_NTSC:
+ renderObj = &GXNtsc480IntDf;
+ break;
+
+ case VI_PAL:
+ renderObj = &GXPal528IntDf;
+ break;
+
+ case VI_EURGB60:
+ renderObj = &GXEurgb60Hz480IntDf;
+ break;
+
+ case VI_MPAL:
+ renderObj = &GXMpal480IntDf;
+ break;
+
+ default:
+ renderObj = &GXNtsc480IntDf;
+ break;
+ }
+
+ GXSetCopyClear(clearColor, 0xFFFFFF);
+
+ GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+ GXSetTexCoordGen2(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
+
+ GXSetNumTexGens(1);
+ GXClearVtxDesc();
+ GXInvalidateVtxCache();
+
+ for (i = GX_VA_POS; i <= GX_LIGHT_ARRAY; i++) {
+ GXSetArray((GXAttr)i, __GXData, 0);
+ }
+
+ for (i = 0; i < GX_MAX_VTXFMT; i++) {
+ GXSetVtxAttrFmtv((GXVtxFmt)i, GXDefaultVATList);
+ }
+
+ GXSetLineWidth(6, GX_TO_ZERO);
+ GXSetPointSize(6, GX_TO_ZERO);
+ GXEnableTexOffsets(GX_TEXCOORD0, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD1, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD2, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD3, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD4, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD5, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD6, GX_FALSE, GX_FALSE);
+ GXEnableTexOffsets(GX_TEXCOORD7, GX_FALSE, GX_FALSE);
+
+ ident[0][0] = 1.0f;
+ ident[0][1] = 0.0f;
+ ident[0][2] = 0.0f;
+ ident[0][3] = 0.0f;
+
+ ident[1][0] = 0.0f;
+ ident[1][1] = 1.0f;
+ ident[1][2] = 0.0f;
+ ident[1][3] = 0.0f;
+
+ ident[2][0] = 0.0f;
+ ident[2][1] = 0.0f;
+ ident[2][2] = 1.0f;
+ ident[2][3] = 0.0f;
+
+ GXLoadPosMtxImm(ident, GX_PNMTX0);
+ GXLoadNrmMtxImm(ident, GX_PNMTX0);
+ GXSetCurrentMtx(GX_PNMTX0);
+
+ GXLoadTexMtxImm(ident, GX_IDENTITY, GX_MTX3x4);
+ GXLoadTexMtxImm(ident, GX_PTIDENTITY, GX_MTX3x4);
+
+ GXSetViewport(0.0f, 0.0f, renderObj->fb_width, renderObj->xfb_height, 0.0f, 1.0f);
+
+ GXSetProjectionv(GXDefaultProjData);
+
+ GXSetCoPlanar(GX_FALSE);
+ GXSetCullMode(GX_CULL_BACK);
+ GXSetClipMode(GX_CLIP_ENABLE);
+
+ GXSetScissor(0, 0, renderObj->fb_width, renderObj->efb_height);
+ GXSetScissorBoxOffset(0, 0);
+
+ GXSetNumChans(0);
+ GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
+ GXSetChanAmbColor(GX_COLOR0A0, ambColor);
+ GXSetChanMatColor(GX_COLOR0A0, matColor);
+
+ GXSetChanCtrl(GX_COLOR1A1, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
+ GXSetChanAmbColor(GX_COLOR1A1, ambColor);
+ GXSetChanMatColor(GX_COLOR1A1, matColor);
+
+ GXInvalidateTexAll();
+ GXSetTexRegionCallback(__GXDefaultTexRegionCallback);
+ GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback);
+
+ GXInitTexObj(&texObj, DefaultTexData, 4, 4, GX_TF_IA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
+ GXLoadTexObj(&texObj, GX_TEXMAP0);
+ GXLoadTexObj(&texObj, GX_TEXMAP1);
+ GXLoadTexObj(&texObj, GX_TEXMAP2);
+ GXLoadTexObj(&texObj, GX_TEXMAP3);
+ GXLoadTexObj(&texObj, GX_TEXMAP4);
+ GXLoadTexObj(&texObj, GX_TEXMAP5);
+ GXLoadTexObj(&texObj, GX_TEXMAP6);
+ GXLoadTexObj(&texObj, GX_TEXMAP7);
+
+ 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 = 0; i < GX_MAX_TEVSTAGE; i++) {
+ GXSetTevKColorSel((GXTevStageID)i, GX_TEV_KCSEL_1_4);
+ GXSetTevKAlphaSel((GXTevStageID)i, GX_TEV_KASEL_1);
+ GXSetTevSwapMode((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 = 0; i < GX_MAX_TEVSTAGE; i++) {
+ GXSetTevDirect((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, ambColor);
+ GXSetFogRangeAdj(GX_FALSE, 0, NULL);
+
+ GXSetBlendMode(GX_BM_NONE, GX_BL_SRC_ALPHA, GX_BL_INV_SRC_ALPHA, GX_LO_CLEAR);
+
+ GXSetColorUpdate(GX_TRUE);
+ GXSetAlphaUpdate(GX_TRUE);
+
+ GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
+ GXSetZCompLoc(GX_TRUE);
+
+ GXSetDither(GX_TRUE);
+
+ GXSetDstAlpha(GX_FALSE, 0);
+ GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
+
+ GXSetFieldMask(GX_TRUE, GX_TRUE);
+ GXSetFieldMode(
+ (GXBool)renderObj->field_rendering,
+ (GXBool)((renderObj->vi_height == 2 * renderObj->xfb_height) ? GX_TRUE : GX_FALSE));
+
+ GXSetDispCopySrc(0, 0, renderObj->fb_width, renderObj->efb_height);
+ GXSetDispCopyDst(renderObj->fb_width, renderObj->efb_height);
+ GXSetDispCopyYScale((f32)renderObj->xfb_height / (f32)renderObj->efb_height);
+ GXSetCopyClamp(GX_CLAMP_BOTH);
+
+ GXSetCopyFilter(renderObj->antialiasing, renderObj->sample_pattern, GX_TRUE,
+ renderObj->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_FALSE, 0);
+ GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE);
+ GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE);
+ GXClearGPMetric();
+} \ No newline at end of file
diff --git a/src/dolphin/gx/GXLight.c b/src/dolphin/gx/GXLight.c
new file mode 100644
index 00000000..a90c2a21
--- /dev/null
+++ b/src/dolphin/gx/GXLight.c
@@ -0,0 +1,294 @@
+/**
+ * GXLight.c
+ * Description:
+ */
+
+#include "dolphin/gx/GXLight.h"
+#include "dolphin/gx/GX.h"
+#include "math.h"
+
+void GXInitLightAttn(GXLightObj* obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) {
+ obj->a0 = a0;
+ obj->a1 = a1;
+ obj->a2 = a2;
+ obj->k0 = k0;
+ obj->k1 = k1;
+ obj->k2 = k2;
+}
+
+void GXInitLightSpot(GXLightObj* obj, f32 cutoff, GXSpotFn spot_fn) {
+ f32 rad;
+ f32 a, b, c, d;
+
+ if (cutoff <= 0.0f || cutoff > 90.0f) {
+ spot_fn = GX_SP_OFF;
+ }
+
+ rad = cosf((3.1415927f * cutoff) / 180.0f);
+
+ switch (spot_fn) {
+ case GX_SP_FLAT:
+ a = -1000.0f * rad;
+ b = 1000.0f;
+ c = 0.0f;
+ break;
+ case GX_SP_COS:
+ b = 1.0f / (1.0f - rad);
+ a = -rad * b;
+ c = 0.0f;
+ break;
+ case GX_SP_COS2:
+ c = 1.0f / (1.0f - rad);
+ a = 0.0f;
+ b = -rad * c;
+ break;
+ case GX_SP_SHARP:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ a = (rad * (rad - 2.0f)) * d;
+ b = 2.0f * d;
+ c = -d;
+ break;
+ case GX_SP_RING1:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ c = -4.0f * d;
+ a = c * rad;
+ b = 4.0f * (1.0f + rad) * d;
+ break;
+ case GX_SP_RING2:
+ d = 1.0f / ((1.0f - rad) * (1.0f - rad));
+ a = 1.0f - 2.0f * rad * rad * d;
+ b = 4.0f * rad * d;
+ c = -2.0f * d;
+ break;
+ case GX_SP_OFF:
+ default:
+ a = 1.0f;
+ b = 0.0f;
+ c = 0.0f;
+ break;
+ }
+
+ obj->a0 = a;
+ obj->a1 = b;
+ obj->a2 = c;
+}
+
+void GXInitLightDistAttn(GXLightObj* obj, f32 dist, f32 brightness, GXDistAttnFn dist_fn) {
+ f32 a, b, c;
+
+ if (dist < 0.0f) {
+ dist_fn = GX_DA_OFF;
+ }
+
+ if (brightness <= 0.0f || brightness >= 1.0f) {
+ dist_fn = GX_DA_OFF;
+ }
+
+ switch (dist_fn) {
+ case GX_DA_GENTLE:
+ a = 1.0f;
+ b = (1.0f - brightness) / (brightness * dist);
+ c = 0.0f;
+ break;
+ case GX_DA_MEDIUM:
+ a = 1.0f;
+ b = (0.5f * (1.0f - brightness)) / (brightness * dist);
+ c = (0.5f * (1.0f - brightness)) / (dist * (brightness * dist));
+ break;
+ case GX_DA_STEEP:
+ a = 1.0f;
+ b = 0.0f;
+ c = (1.0f - brightness) / (dist * (brightness * dist));
+ break;
+ case GX_DA_OFF:
+ default:
+ a = 1.0f;
+ b = 0.0f;
+ c = 0.0f;
+ break;
+ }
+
+ obj->k0 = a;
+ obj->k1 = b;
+ obj->k2 = c;
+}
+
+void GXInitLightPos(GXLightObj* obj, f32 x, f32 y, f32 z) {
+ obj->posX = x;
+ obj->posY = y;
+ obj->posZ = z;
+}
+
+void GXInitLightDir(GXLightObj* obj, f32 x, f32 y, f32 z) {
+ obj->dirX = -x;
+ obj->dirY = -y;
+ obj->dirZ = -z;
+}
+
+void GXInitLightColor(GXLightObj* obj, GXColor color) {
+ *(u32*)&obj->color = *(u32*)&color;
+}
+
+static inline void PushLight(const register GXLightObj* lt_obj, register void* dest) {
+ register u32 zero, color;
+ register f32 a0_a1, a2_k0, k1_k2;
+ register f32 px_py, pz_dx, dy_dz;
+#ifdef __MWERKS__ // clang-format off
+ asm {
+ lwz color, 12(lt_obj)
+ xor zero, zero, zero
+ psq_l a0_a1, 16(lt_obj), 0, 0
+ psq_l a2_k0, 24(lt_obj), 0, 0
+ psq_l k1_k2, 32(lt_obj), 0, 0
+ psq_l px_py, 40(lt_obj), 0, 0
+ psq_l pz_dx, 48(lt_obj), 0, 0
+ psq_l dy_dz, 56(lt_obj), 0, 0
+
+ stw zero, 0(dest)
+ stw zero, 0(dest)
+ stw zero, 0(dest)
+ stw color, 0(dest)
+ psq_st a0_a1, 0(dest), 0, 0
+ psq_st a2_k0, 0(dest), 0, 0
+ psq_st k1_k2, 0(dest), 0, 0
+ psq_st px_py, 0(dest), 0, 0
+ psq_st pz_dx, 0(dest), 0, 0
+ psq_st dy_dz, 0(dest), 0, 0
+ }
+#endif // clang-format on
+}
+
+void GXLoadLightObjImm(GXLightObj* obj, GXLightID light) {
+ u32 addr;
+ u32 idx;
+ GXLightObj* pObj = (GXLightObj*)obj;
+
+ idx = 31 - __cntlzw(light);
+ idx &= 7;
+
+ addr = 0x600 + idx * 0x10;
+
+ GX_XF_LOAD_REG_HDR(addr | (0x10 - 1) << 16);
+
+ PushLight(pObj, (void*)GXFIFO_ADDR);
+ __GXData->bpSentNot = 1;
+}
+
+void GXSetChanAmbColor(GXChannelID channel, GXColor color) {
+ u32 reg;
+ u32 colorID;
+ u8 alpha;
+
+ switch (channel) {
+ case GX_COLOR0:
+ reg = __GXData->ambColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1:
+ reg = __GXData->ambColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR1;
+ break;
+ case GX_ALPHA0:
+ reg = __GXData->ambColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR0;
+ break;
+ case GX_ALPHA1:
+ reg = __GXData->ambColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR1;
+ break;
+ case GX_COLOR0A0:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1A1:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR1;
+ break;
+ default:
+ return;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_AMBIENT0 + colorID, reg);
+ __GXData->bpSentNot = GX_TRUE;
+ __GXData->ambColor[colorID] = reg;
+}
+
+void GXSetChanMatColor(GXChannelID channel, GXColor color) {
+ u32 reg = 0;
+ GXChannelID colorID;
+
+ switch (channel) {
+ case GX_COLOR0:
+ reg = __GXData->matColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1:
+ reg = __GXData->matColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
+ colorID = GX_COLOR1;
+ break;
+ case GX_ALPHA0:
+ reg = __GXData->matColor[GX_COLOR0];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR0;
+ break;
+ case GX_ALPHA1:
+ reg = __GXData->matColor[GX_COLOR1];
+ reg = GX_SET_TRUNC(reg, color.a, 24, 31);
+ colorID = GX_COLOR1;
+ break;
+ case GX_COLOR0A0:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR0;
+ break;
+ case GX_COLOR1A1:
+ reg = GXCOLOR_AS_U32(color);
+ colorID = GX_COLOR1;
+ break;
+ default:
+ return;
+ }
+
+ GX_XF_LOAD_REG(GX_XF_REG_MATERIAL0 + colorID, reg);
+ __GXData->bpSentNot = GX_TRUE;
+ __GXData->matColor[colorID] = reg;
+}
+
+void GXSetNumChans(u8 count) {
+ GX_SET_REG(__GXData->genMode, count, 25, 27);
+ GX_XF_LOAD_REG(GX_XF_REG_NUMCOLORS, count);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+}
+
+void GXSetChanCtrl(GXChannelID channel, GXBool doEnable, GXColorSrc ambSrc, GXColorSrc matSrc,
+ u32 mask, GXDiffuseFn diffFunc, GXAttnFn attnFunc) {
+ const u32 colorID = (u32)channel & 0x3;
+ u32 reg = 0;
+
+ GX_SET_REG(reg, doEnable, GX_XF_CLR0CTRL_LIGHT_ST, GX_XF_CLR0CTRL_LIGHT_END);
+ GX_SET_REG(reg, matSrc, GX_XF_CLR0CTRL_MTXSRC_ST, GX_XF_CLR0CTRL_MTXSRC_END);
+ GX_SET_REG(reg, ambSrc, GX_XF_CLR0CTRL_AMBSRC_ST, GX_XF_CLR0CTRL_AMBSRC_END);
+ GX_SET_REG(reg, (attnFunc == GX_AF_SPEC ? GX_DF_NONE : diffFunc), GX_XF_CLR0CTRL_DIFATTN_ST,
+ GX_XF_CLR0CTRL_DIFATTN_END);
+ GX_SET_REG(reg, (attnFunc != GX_AF_NONE), GX_XF_CLR0CTRL_ATTNENABLE_ST,
+ GX_XF_CLR0CTRL_ATTNENABLE_END);
+ GX_SET_REG(reg, (attnFunc != GX_AF_SPEC), GX_XF_CLR0CTRL_ATTNSEL_ST,
+ GX_XF_CLR0CTRL_ATTNSEL_END);
+ GX_BITFIELD_SET(reg, 26, 4, (u32)mask);
+ reg = __rlwimi(reg, (u32)mask, 7, 0x11, 0x14);
+
+ GX_XF_LOAD_REG(GX_XF_REG_COLOR0CNTRL + colorID, reg);
+
+ if (channel == GX_COLOR0A0) {
+ GX_XF_LOAD_REG(GX_XF_REG_ALPHA0CNTRL, reg);
+ } else if (channel == GX_COLOR1A1) {
+ GX_XF_LOAD_REG(GX_XF_REG_ALPHA1CNTRL, reg);
+ }
+
+ __GXData->bpSentNot = GX_TRUE;
+}
diff --git a/src/dolphin/gx/GXMisc.c b/src/dolphin/gx/GXMisc.c
new file mode 100644
index 00000000..468192ea
--- /dev/null
+++ b/src/dolphin/gx/GXMisc.c
@@ -0,0 +1,266 @@
+#include "dolphin/gx/GXMisc.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OSInterrupt.h"
+#include "dolphin/os/OSReset.h"
+#include "dolphin/os/OSTime.h"
+
+static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext* context);
+static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext* pContext);
+
+void GXSetMisc(GXMiscToken token, u32 val) {
+ switch (token) {
+ case GX_MT_NULL:
+ break;
+
+ case GX_MT_XF_FLUSH:
+ __GXData->vNum = val;
+ __GXData->vNumNot = !__GXData->vNum;
+ __GXData->bpSentNot = GX_TRUE;
+
+ if (__GXData->vNum) {
+ __GXData->dirtyState |= GX_DIRTY_VCD;
+ }
+ break;
+
+ case GX_MT_DL_SAVE_CONTEXT:
+ __GXData->dlSaveContext = (val != 0);
+ break;
+
+ case GX_MT_ABORT_WAIT_COPYOUT:
+ __GXData->abtWaitPECopy = (val != 0);
+ break;
+ }
+}
+
+void GXFlush(void) {
+ if (__GXData->dirtyState) {
+ __GXSetDirtyState();
+ }
+
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+ GXFIFO.u32 = 0;
+
+ PPCSync();
+}
+
+static void __GXAbortWait(u32 clocks) {
+ OSTime time0, time1;
+ time0 = OSGetTime();
+
+ do {
+ time1 = OSGetTime();
+ } while (time1 - time0 <= clocks / 4);
+}
+
+static void __GXAbortWaitPECopyDone(void) {
+ u32 peCnt0, peCnt1;
+
+ peCnt0 = GXReadMEMReg(0x28, 0x27);
+ do {
+ peCnt1 = peCnt0;
+ __GXAbortWait(32);
+
+ peCnt0 = GXReadMEMReg(0x28, 0x27);
+ } while (peCnt0 != peCnt1);
+}
+
+void __GXAbort(void) {
+ if (__GXData->abtWaitPECopy && GXGetGPFifo()) {
+ __GXAbortWaitPECopyDone();
+ }
+
+ __PIRegs[0x18 / 4] = 1;
+ __GXAbortWait(200);
+ __PIRegs[0x18 / 4] = 0;
+ __GXAbortWait(20);
+}
+
+void GXAbortFrame(void) {
+ __GXAbort();
+ if (GXGetGPFifo()) {
+ __GXCleanGPFifo();
+ __GXInitRevisionBits();
+ __GXData->dirtyState = 0;
+ GXFlush();
+ }
+}
+
+/* ############################################################################################## */
+static GXDrawSyncCallback TokenCB;
+
+static GXDrawDoneCallback DrawDoneCB;
+
+static GXBool DrawDone;
+
+void GXSetDrawDone(void) {
+ u8 padding[8];
+ BOOL restore = OSDisableInterrupts();
+ GFWriteBPCmd(0x45000002);
+ GXFlush();
+ DrawDone = 0;
+ OSRestoreInterrupts(restore);
+}
+
+/* ############################################################################################## */
+static OSThreadQueue FinishQueue;
+
+static void GXWaitDrawDone(void) {
+ BOOL restore = OSDisableInterrupts();
+ while (DrawDone == 0) {
+ OSSleepThread(&FinishQueue);
+ }
+ OSRestoreInterrupts(restore);
+}
+
+void GXDrawDone(void) {
+ u8 padding[8];
+ GXSetDrawDone();
+ GXWaitDrawDone();
+}
+
+void GXPixModeSync(void) {
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = __GXData->peCtrl;
+ __GXData->bpSentNot = 0;
+}
+
+void GXPokeAlphaMode(GXCompare comp, u8 threshold) {
+ __peReg[3] = (comp << 8) | threshold;
+}
+
+void GXPokeAlphaRead(GXAlphaReadMode mode) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x1e, 2, mode);
+ GX_BITFIELD_SET(val, 0x1d, 1, 1);
+ __peReg[4] = val;
+}
+
+void GXPokeAlphaUpdate(GXBool enable_update) {
+ GX_BITFIELD_SET(__peReg[1], 0x1b, 1, enable_update);
+}
+
+void GXPokeBlendMode(GXBlendMode mode, GXBlendFactor srcFactor, GXBlendFactor destFactor,
+ GXLogicOp op) {
+ u32 reg;
+
+ reg = GX_GET_PE_REG(1);
+ GX_SET_REG(reg, (mode == GX_BM_BLEND) || (mode == GX_BM_SUBTRACT), 31, 31);
+ GX_SET_REG(reg, (mode == GX_BM_SUBTRACT), 20, 20);
+ GX_SET_REG(reg, (mode == GX_BM_LOGIC), 30, 30);
+ GX_SET_REG(reg, op, 16, 19);
+ GX_SET_REG(reg, srcFactor, 21, 23);
+ GX_SET_REG(reg, destFactor, 24, 26);
+ GX_SET_REG(reg, 0x41, 0, 7);
+ GX_SET_PE_REG(1, reg);
+}
+
+void GXPokeColorUpdate(GXBool enable_update) {
+ GX_BITFIELD_SET(__peReg[1], 0x1c, 1, enable_update);
+}
+
+void GXPokeDstAlpha(GXBool enable, u8 alpha) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x18, 8, alpha);
+ GX_BITFIELD_SET(val, 0x17, 1, enable);
+ __peReg[2] = val;
+}
+
+void GXPokeDither(GXBool enable) {
+ GX_BITFIELD_SET(__peReg[1], 0x1d, 1, enable);
+}
+
+void GXPokeZMode(GXBool enable_compare, GXCompare comp, GXBool update_enable) {
+ u32 val = 0;
+ GX_BITFIELD_SET(val, 0x1f, 1, enable_compare);
+ GX_BITFIELD_SET(val, 0x1c, 3, comp);
+ GX_BITFIELD_SET(val, 0x1b, 1, update_enable);
+ __peReg[0] = val;
+}
+
+void GXPeekZ(u16 x, u16 y, u32* z) {
+ u32 addr = 0xc8000000;
+ GX_BITFIELD_SET(addr, 0x14, 10, x);
+ GX_BITFIELD_SET(addr, 0xa, 10, y);
+ GX_BITFIELD_SET(addr, 8, 2, 1);
+ *z = *(u32*)addr;
+}
+
+GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback callback) {
+ BOOL restore;
+ GXDrawSyncCallback prevCb = TokenCB;
+ restore = OSDisableInterrupts();
+ TokenCB = callback;
+ OSRestoreInterrupts(restore);
+ return prevCb;
+}
+
+static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
+ u16 token;
+ OSContext exceptContext;
+ u32 reg;
+
+ token = GX_GET_PE_REG(7);
+
+ if (TokenCB) {
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(&exceptContext);
+ TokenCB(token);
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(context);
+ }
+
+ reg = GX_GET_PE_REG(5);
+ GX_SET_REG(reg, 1, 29, 29);
+ GX_SET_PE_REG(5, reg);
+}
+
+GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback callback) {
+ BOOL restore;
+ GXDrawDoneCallback prevCb = DrawDoneCB;
+ restore = OSDisableInterrupts();
+ DrawDoneCB = callback;
+ OSRestoreInterrupts(restore);
+ return prevCb;
+}
+
+static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext* context) {
+ OSContext exceptContext;
+ u32 reg;
+
+ reg = GX_GET_PE_REG(5);
+ GX_SET_REG(reg, 1, 28, 28);
+ GX_SET_PE_REG(5, reg);
+
+ DrawDone = GX_TRUE;
+
+ if (DrawDoneCB) {
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(&exceptContext);
+ DrawDoneCB();
+ OSClearContext(&exceptContext);
+ OSSetCurrentContext(context);
+ }
+
+ OSWakeupThread(&FinishQueue);
+}
+
+void __GXPEInit(void) {
+ u32 val;
+ __OSSetInterruptHandler(OS_INTR_PI_PE_TOKEN, GXTokenInterruptHandler);
+ __OSSetInterruptHandler(OS_INTR_PI_PE_FINISH, GXFinishInterruptHandler);
+ OSInitThreadQueue(&FinishQueue);
+ __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_PE_TOKEN);
+ __OSUnmaskInterrupts(OS_INTERRUPTMASK_PI_PE_FINISH);
+ val = __peReg[5];
+ GX_BITFIELD_SET(val, 0x1d, 1, 1);
+ GX_BITFIELD_SET(val, 0x1c, 1, 1);
+ GX_BITFIELD_SET(val, 0x1f, 1, 1);
+ GX_BITFIELD_SET(val, 0x1e, 1, 1);
+ __peReg[5] = val;
+}
diff --git a/src/dolphin/gx/GXPerf.c b/src/dolphin/gx/GXPerf.c
new file mode 100644
index 00000000..60591b0b
--- /dev/null
+++ b/src/dolphin/gx/GXPerf.c
@@ -0,0 +1,384 @@
+#include "dolphin/gx/GXPerf.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1) {
+ switch (__GXData->perf0) {
+ case GX_PERF0_VERTICES:
+ case GX_PERF0_CLIP_VTX:
+ case GX_PERF0_CLIP_CLKS:
+ case GX_PERF0_XF_WAIT_IN:
+ case GX_PERF0_XF_WAIT_OUT:
+ case GX_PERF0_XF_XFRM_CLKS:
+ case GX_PERF0_XF_LIT_CLKS:
+ case GX_PERF0_XF_BOT_CLKS:
+ case GX_PERF0_XF_REGLD_CLKS:
+ case GX_PERF0_XF_REGRD_CLKS:
+ case GX_PERF0_CLIP_RATIO:
+ case GX_PERF0_CLOCKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0);
+ break;
+
+ case GX_PERF0_TRIANGLES:
+ case GX_PERF0_TRIANGLES_CULLED:
+ case GX_PERF0_TRIANGLES_PASSED:
+ case GX_PERF0_TRIANGLES_SCISSORED:
+ case GX_PERF0_TRIANGLES_0TEX:
+ case GX_PERF0_TRIANGLES_1TEX:
+ case GX_PERF0_TRIANGLES_2TEX:
+ case GX_PERF0_TRIANGLES_3TEX:
+ case GX_PERF0_TRIANGLES_4TEX:
+ case GX_PERF0_TRIANGLES_5TEX:
+ case GX_PERF0_TRIANGLES_6TEX:
+ case GX_PERF0_TRIANGLES_7TEX:
+ case GX_PERF0_TRIANGLES_8TEX:
+ case GX_PERF0_TRIANGLES_0CLR:
+ case GX_PERF0_TRIANGLES_1CLR:
+ case GX_PERF0_TRIANGLES_2CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23000000);
+ break;
+
+ case GX_PERF0_QUAD_0CVG:
+ case GX_PERF0_QUAD_NON0CVG:
+ case GX_PERF0_QUAD_1CVG:
+ case GX_PERF0_QUAD_2CVG:
+ case GX_PERF0_QUAD_3CVG:
+ case GX_PERF0_QUAD_4CVG:
+ case GX_PERF0_AVG_QUAD_CNT:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x24000000);
+ break;
+
+ case GX_PERF0_NONE:
+ break;
+ }
+
+ switch (__GXData->perf1) {
+ case GX_PERF1_TEXELS:
+ case GX_PERF1_TX_IDLE:
+ case GX_PERF1_TX_REGS:
+ case GX_PERF1_TX_MEMSTALL:
+ case GX_PERF1_TC_CHECK1_2:
+ case GX_PERF1_TC_CHECK3_4:
+ case GX_PERF1_TC_CHECK5_6:
+ case GX_PERF1_TC_CHECK7_8:
+ case GX_PERF1_TC_MISS:
+ case GX_PERF1_CLOCKS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000000);
+ break;
+
+ case GX_PERF1_VC_ELEMQ_FULL:
+ case GX_PERF1_VC_MISSQ_FULL:
+ case GX_PERF1_VC_MEMREQ_FULL:
+ case GX_PERF1_VC_STATUS7:
+ case GX_PERF1_VC_MISSREP_FULL:
+ case GX_PERF1_VC_STREAMBUF_LOW:
+ case GX_PERF1_VC_ALL_STALLS:
+ case GX_PERF1_VERTICES:
+ FAST_FLAG_SET(__GXData->perfSel, 0, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+
+ case GX_PERF1_FIFO_REQ:
+ case GX_PERF1_CALL_REQ:
+ case GX_PERF1_VC_MISS_REQ:
+ case GX_PERF1_CP_ALL_REQ:
+ GX_SET_CP_REG(3, 0);
+ break;
+
+ case GX_PERF1_NONE:
+ break;
+ }
+
+ __GXData->perf0 = perf0;
+
+ switch (__GXData->perf0) {
+ case GX_PERF0_VERTICES:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x273);
+ break;
+ case GX_PERF0_CLIP_VTX:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x14A);
+ break;
+ case GX_PERF0_CLIP_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x16B);
+ break;
+ case GX_PERF0_XF_WAIT_IN:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x84);
+ break;
+ case GX_PERF0_XF_WAIT_OUT:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0xC6);
+ break;
+ case GX_PERF0_XF_XFRM_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x210);
+ break;
+ case GX_PERF0_XF_LIT_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x252);
+ break;
+ case GX_PERF0_XF_BOT_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x231);
+ break;
+ case GX_PERF0_XF_REGLD_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x1AD);
+ break;
+ case GX_PERF0_XF_REGRD_CLKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x1CE);
+ break;
+ case GX_PERF0_CLOCKS:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x21);
+ break;
+ case GX_PERF0_CLIP_RATIO:
+ GX_WRITE_U8(0x10);
+ GX_WRITE_U32(0x1006);
+ GX_WRITE_U32(0x153);
+ break;
+
+ case GX_PERF0_TRIANGLES:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AE7F);
+ break;
+ case GX_PERF0_TRIANGLES_CULLED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23008E7F);
+ break;
+ case GX_PERF0_TRIANGLES_PASSED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23009E7F);
+ break;
+ case GX_PERF0_TRIANGLES_SCISSORED:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x23001E7F);
+ break;
+ case GX_PERF0_TRIANGLES_0TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AC3F);
+ break;
+ case GX_PERF0_TRIANGLES_1TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AC7F);
+ break;
+ case GX_PERF0_TRIANGLES_2TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ACBF);
+ break;
+ case GX_PERF0_TRIANGLES_3TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ACFF);
+ break;
+ case GX_PERF0_TRIANGLES_4TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AD3F);
+ break;
+ case GX_PERF0_TRIANGLES_5TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AD7F);
+ break;
+ case GX_PERF0_TRIANGLES_6TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ADBF);
+ break;
+ case GX_PERF0_TRIANGLES_7TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300ADFF);
+ break;
+ case GX_PERF0_TRIANGLES_8TEX:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AE3F);
+ break;
+ case GX_PERF0_TRIANGLES_0CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300A27F);
+ break;
+ case GX_PERF0_TRIANGLES_1CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300A67F);
+ break;
+ case GX_PERF0_TRIANGLES_2CLR:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2300AA7F);
+ break;
+
+ case GX_PERF0_QUAD_0CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C0C6);
+ break;
+ case GX_PERF0_QUAD_NON0CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C16B);
+ break;
+ case GX_PERF0_QUAD_1CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C0E7);
+ break;
+ case GX_PERF0_QUAD_2CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C108);
+ break;
+ case GX_PERF0_QUAD_3CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C129);
+ break;
+ case GX_PERF0_QUAD_4CVG:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C14A);
+ break;
+ case GX_PERF0_AVG_QUAD_CNT:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x2402C1AD);
+ break;
+
+ case GX_PERF0_NONE:
+ break;
+ }
+
+ __GXData->perf1 = perf1;
+
+ switch (__GXData->perf1) {
+ case GX_PERF1_TEXELS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000042);
+ break;
+ case GX_PERF1_TX_IDLE:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000084);
+ break;
+ case GX_PERF1_TX_REGS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000063);
+ break;
+ case GX_PERF1_TX_MEMSTALL:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000129);
+ break;
+ case GX_PERF1_TC_MISS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000252);
+ break;
+ case GX_PERF1_CLOCKS:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000021);
+ break;
+ case GX_PERF1_TC_CHECK1_2:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x6700014B);
+ break;
+ case GX_PERF1_TC_CHECK3_4:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x6700018D);
+ break;
+ case GX_PERF1_TC_CHECK5_6:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x670001CF);
+ break;
+ case GX_PERF1_TC_CHECK7_8:
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(0x67000211);
+ break;
+
+ case GX_PERF1_VC_ELEMQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 2, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MISSQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 3, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MEMREQ_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 4, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_STATUS7:
+ FAST_FLAG_SET(__GXData->perfSel, 5, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_MISSREP_FULL:
+ FAST_FLAG_SET(__GXData->perfSel, 6, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_STREAMBUF_LOW:
+ FAST_FLAG_SET(__GXData->perfSel, 7, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VC_ALL_STALLS:
+ FAST_FLAG_SET(__GXData->perfSel, 9, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+ case GX_PERF1_VERTICES:
+ FAST_FLAG_SET(__GXData->perfSel, 8, 4, 4);
+ GX_WRITE_U8(8);
+ GX_WRITE_U8(32);
+ GX_WRITE_U32(__GXData->perfSel);
+ break;
+
+ case GX_PERF1_FIFO_REQ:
+ GX_SET_CP_REG(3, 2);
+ break;
+ case GX_PERF1_CALL_REQ:
+ GX_SET_CP_REG(3, 3);
+ break;
+ case GX_PERF1_VC_MISS_REQ:
+ GX_SET_CP_REG(3, 4);
+ break;
+ case GX_PERF1_CP_ALL_REQ:
+ GX_SET_CP_REG(3, 5);
+ break;
+
+ case GX_PERF1_NONE:
+ break;
+ }
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXClearGPMetric(void) {
+ GX_SET_CP_REG(2, 4);
+}
+
+#pragma scheduling off
+void GXReadXfRasMetric(u32* xfWaitIn, u32* xfWaitOut, u32* rasBusy, u32* clocks) {
+ *rasBusy = GXReadCPReg(32, 33);
+ *clocks = GXReadCPReg(34, 35);
+ *xfWaitIn = GXReadCPReg(36, 37);
+ *xfWaitOut = GXReadCPReg(38, 39);
+}
+#pragma scheduling reset
diff --git a/src/dolphin/gx/GXPixel.c b/src/dolphin/gx/GXPixel.c
new file mode 100644
index 00000000..f3448bc3
--- /dev/null
+++ b/src/dolphin/gx/GXPixel.c
@@ -0,0 +1,235 @@
+#include "dolphin/gx/GXPixel.h"
+#include "dolphin/gx/GX.h"
+
+void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color) {
+ f32 a, c;
+ u32 a_bits, c_bits;
+
+ u32 fogColorReg = 0;
+ u32 fogParamReg0 = 0;
+ u32 fogParamReg1 = 0;
+ u32 fogParamReg2 = 0;
+ u32 fogParamReg3 = 0;
+
+ u32 fsel = type & 7;
+ BOOL isOrtho = (type >> 3) & 1;
+ u32 col;
+
+ if (isOrtho) {
+ if (farz == nearz || endz == startz) {
+ a = 0.0f;
+ c = 0.0f;
+ } else {
+ a = (1.0f / (endz - startz)) * (farz - nearz);
+ c = (1.0f / (endz - startz)) * (startz - nearz);
+ }
+ } else {
+ f32 tmpA, tmpB, tmpC;
+ u32 expB, magB, shiftB;
+
+ if (farz == nearz || endz == startz) {
+ tmpA = 0.0f;
+ tmpB = 0.5f;
+ tmpC = 0.0f;
+ } else {
+ tmpA = (farz * nearz) / ((farz - nearz) * (endz - startz));
+ tmpB = farz / (farz - nearz);
+ tmpC = startz / (endz - startz);
+ }
+
+ expB = 0;
+ while (tmpB > 1.0) {
+ tmpB /= 2.0f;
+ expB++;
+ }
+ while (tmpB > 0.0f && tmpB < 0.5) {
+ tmpB *= 2.0f;
+ expB--;
+ }
+
+ a = tmpA / (1 << expB + 1);
+ magB = 8388638.0f * tmpB;
+ shiftB = expB + 1;
+ c = tmpC;
+
+ GX_SET_REG(fogParamReg1, magB, GX_BP_FOGPARAM1_B_MAG_ST, GX_BP_FOGPARAM1_B_MAG_END);
+ GX_SET_REG(fogParamReg2, shiftB, GX_BP_FOGPARAM2_B_SHIFT_ST, GX_BP_FOGPARAM2_B_SHIFT_END);
+
+ GX_SET_REG(fogParamReg1, GX_BP_REG_FOGPARAM1, 0, 7);
+ GX_SET_REG(fogParamReg2, GX_BP_REG_FOGPARAM2, 0, 7);
+ }
+
+ a_bits = *(u32*)&a;
+ c_bits = *(u32*)&c;
+
+ GX_SET_REG(fogParamReg0, a_bits >> 12, GX_BP_FOGPARAM0_A_MANT_ST, GX_BP_FOGPARAM0_A_MANT_END);
+ GX_SET_REG(fogParamReg0, a_bits >> 23, GX_BP_FOGPARAM0_A_EXP_ST, GX_BP_FOGPARAM0_A_EXP_END);
+ GX_SET_REG(fogParamReg0, a_bits >> 31, GX_BP_FOGPARAM0_A_SIGN_ST, GX_BP_FOGPARAM0_A_SIGN_END);
+ GX_SET_REG(fogParamReg0, GX_BP_REG_FOGPARAM0, 0, 7);
+
+ GX_SET_REG(fogParamReg3, c_bits >> 12, GX_BP_FOGPARAM3_C_MANT_ST, GX_BP_FOGPARAM3_C_MANT_END);
+ GX_SET_REG(fogParamReg3, c_bits >> 23, GX_BP_FOGPARAM3_C_EXP_ST, GX_BP_FOGPARAM3_C_EXP_END);
+ GX_SET_REG(fogParamReg3, c_bits >> 31, GX_BP_FOGPARAM3_C_SIGN_ST, GX_BP_FOGPARAM3_C_SIGN_END);
+ GX_SET_REG(fogParamReg3, isOrtho, GX_BP_FOGPARAM3_PROJ_ST, GX_BP_FOGPARAM3_PROJ_END);
+ GX_SET_REG(fogParamReg3, fsel, GX_BP_FOGPARAM3_FSEL_ST, GX_BP_FOGPARAM3_FSEL_END);
+ GX_SET_REG(fogParamReg3, GX_BP_REG_FOGPARAM3, 0, 7);
+
+ col = *(u32*)&color;
+ GX_SET_REG(fogColorReg, col >> 8, GX_BP_FOGCOLOR_RGB_ST, GX_BP_FOGCOLOR_RGB_END);
+ GX_SET_REG(fogColorReg, GX_BP_REG_FOGCOLOR, 0, 7);
+
+ GX_BP_LOAD_REG(fogParamReg0);
+ GX_BP_LOAD_REG(fogParamReg1);
+ GX_BP_LOAD_REG(fogParamReg2);
+ GX_BP_LOAD_REG(fogParamReg3);
+ GX_BP_LOAD_REG(fogColorReg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable* table) {
+ u32 fogRangeReg;
+ u32 fogRangeRegK;
+ u32 i;
+
+ if (enable) {
+ for (i = 0; i < 10; i += 2) {
+ fogRangeRegK = 0;
+ GX_SET_REG(fogRangeRegK, table->fogVals[i], GX_BP_FOGRANGEK_HI_ST,
+ GX_BP_FOGRANGEK_HI_END);
+ GX_SET_REG(fogRangeRegK, table->fogVals[i + 1], GX_BP_FOGRANGEK_LO_ST,
+ GX_BP_FOGRANGEK_LO_END);
+ GX_SET_REG(fogRangeRegK, GX_BP_REG_FOGRANGEK0 + (i / 2), 0, 7);
+ GX_BP_LOAD_REG(fogRangeRegK);
+ }
+ }
+
+ fogRangeReg = 0;
+ GX_SET_REG(fogRangeReg, center + 342, GX_BP_FOGRANGE_CENTER_ST, GX_BP_FOGRANGE_CENTER_END);
+ GX_SET_REG(fogRangeReg, enable, GX_BP_FOGRANGE_ENABLED_ST, GX_BP_FOGRANGE_ENABLED_END);
+ GX_SET_REG(fogRangeReg, GX_BP_REG_FOGRANGE, 0, 7);
+ GX_BP_LOAD_REG(fogRangeReg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor,
+ GXLogicOp op) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, type == GX_BM_SUBTRACT, GX_BP_BLENDMODE_SUBTRACT_ST,
+ GX_BP_BLENDMODE_SUBTRACT_END);
+ GX_SET_REG(blendModeReg, type, GX_BP_BLENDMODE_ENABLE_ST, GX_BP_BLENDMODE_ENABLE_END);
+ GX_SET_REG(blendModeReg, type == GX_BM_LOGIC, GX_BP_BLENDMODE_LOGIC_OP_ST,
+ GX_BP_BLENDMODE_LOGIC_OP_END);
+ GX_SET_REG(blendModeReg, op, GX_BP_BLENDMODE_LOGICMODE_ST, GX_BP_BLENDMODE_LOGICMODE_END);
+ GX_SET_REG(blendModeReg, src_factor, GX_BP_BLENDMODE_SRCFACTOR_ST,
+ GX_BP_BLENDMODE_SRCFACTOR_END);
+ GX_SET_REG(blendModeReg, dst_factor, GX_BP_BLENDMODE_DSTFACTOR_ST,
+ GX_BP_BLENDMODE_DSTFACTOR_END);
+
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+
+ __GXData->bpSentNot = FALSE;
+}
+
+void GXSetColorUpdate(GXBool updateEnable) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, updateEnable, GX_BP_BLENDMODE_COLOR_UPDATE_ST,
+ GX_BP_BLENDMODE_COLOR_UPDATE_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetAlphaUpdate(GXBool updateEnable) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, updateEnable, GX_BP_BLENDMODE_ALPHA_UPDATE_ST,
+ GX_BP_BLENDMODE_ALPHA_UPDATE_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZMode(GXBool compareEnable, GXCompare func, GXBool updateEnable) {
+ u32 zModeReg = __GXData->zmode;
+ GX_SET_REG(zModeReg, compareEnable, GX_BP_ZMODE_TEST_ENABLE_ST, GX_BP_ZMODE_TEST_ENABLE_END);
+ GX_SET_REG(zModeReg, func, GX_BP_ZMODE_COMPARE_ST, GX_BP_ZMODE_COMPARE_END);
+ GX_SET_REG(zModeReg, updateEnable, GX_BP_ZMODE_UPDATE_ENABLE_ST, GX_BP_ZMODE_UPDATE_ENABLE_END);
+ GX_BP_LOAD_REG(zModeReg);
+ __GXData->zmode = zModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZCompLoc(GXBool beforeTex) {
+ GX_SET_REG(__GXData->peCtrl, beforeTex, GX_BP_ZCONTROL_BEFORE_TEX_ST,
+ GX_BP_ZCONTROL_BEFORE_TEX_END);
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetPixelFmt(GXPixelFmt pixelFmt, GXZFmt16 zFmt) {
+ GXBool isZ16;
+ static u32 p2f[GX_PF_MAX] = {GX_PF_RGB8_Z24, GX_PF_RGBA6_Z24, GX_PF_RGB565_Z16, GX_PF_Z24,
+ GX_PF_Y8, GX_PF_Y8, GX_PF_Y8, GX_PF_U8};
+
+ const u32 zControlRegOld = __GXData->peCtrl;
+
+ GX_SET_REG(__GXData->peCtrl, p2f[pixelFmt], GX_BP_ZCONTROL_PIXEL_FMT_ST,
+ GX_BP_ZCONTROL_PIXEL_FMT_END);
+ GX_SET_REG(__GXData->peCtrl, zFmt, GX_BP_ZCONTROL_Z_FMT_ST, GX_BP_ZCONTROL_Z_FMT_END);
+
+ if (zControlRegOld != __GXData->peCtrl) {
+ GX_BP_LOAD_REG(__GXData->peCtrl);
+ isZ16 = (pixelFmt == GX_PF_RGB565_Z16) ? GX_TRUE : GX_FALSE;
+ GX_SET_REG(__GXData->genMode, isZ16, GX_BP_GENMODE_MULTISAMPLE_ST,
+ GX_BP_GENMODE_MULTISAMPLE_END);
+ __GXData->dirtyState |= GX_DIRTY_GEN_MODE;
+ }
+
+ if (p2f[pixelFmt] == GX_PF_Y8) {
+ GX_SET_REG(__GXData->cmode1, pixelFmt - GX_PF_Y8, GX_BP_DSTALPHA_YUV_FMT_ST,
+ GX_BP_DSTALPHA_YUV_FMT_END);
+ GX_SET_REG(__GXData->cmode1, GX_BP_REG_DSTALPHA, 0, 7);
+ GX_BP_LOAD_REG(__GXData->cmode1);
+ }
+
+ __GXData->bpSentNot = FALSE;
+}
+
+void GXSetDither(GXBool dither) {
+ u32 blendModeReg = __GXData->cmode0;
+ GX_SET_REG(blendModeReg, dither, GX_BP_BLENDMODE_DITHER_ST, GX_BP_BLENDMODE_DITHER_END);
+ GX_BP_LOAD_REG(blendModeReg);
+ __GXData->cmode0 = blendModeReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetDstAlpha(GXBool enable, u8 alpha) {
+ u32 dstAlpha = __GXData->cmode1;
+ GX_SET_REG(dstAlpha, alpha, GX_BP_DSTALPHA_ALPHA_ST, GX_BP_DSTALPHA_ALPHA_END);
+ GX_SET_REG(dstAlpha, enable, GX_BP_DSTALPHA_ENABLE_ST, GX_BP_DSTALPHA_ENABLE_END);
+ GX_BP_LOAD_REG(dstAlpha);
+ __GXData->cmode1 = dstAlpha;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFieldMask(GXBool enableEven, GXBool enableOdd) {
+ u32 fieldMaskReg = 0;
+ GX_SET_REG(fieldMaskReg, enableOdd, GX_BP_FIELDMASK_ODD_ST, GX_BP_FIELDMASK_ODD_END);
+ GX_SET_REG(fieldMaskReg, enableEven, GX_BP_FIELDMASK_EVEN_ST, GX_BP_FIELDMASK_EVEN_END);
+ GX_SET_REG(fieldMaskReg, GX_BP_REG_FIELDMASK, 0, 7);
+
+ GX_BP_LOAD_REG(fieldMaskReg);
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetFieldMode(GXBool texLOD, GXBool adjustAR) {
+ GX_SET_REG(__GXData->lpSize, adjustAR, GX_BP_LINEPTWIDTH_ADJUST_ST,
+ GX_BP_LINEPTWIDTH_ADJUST_END);
+ GX_BP_LOAD_REG(__GXData->lpSize);
+
+ __GXFlushTextureState();
+ GX_BP_LOAD_REG(GX_BP_REG_FIELDMODE << 24 | texLOD);
+ __GXFlushTextureState();
+}
diff --git a/src/dolphin/gx/GXTev.c b/src/dolphin/gx/GXTev.c
new file mode 100644
index 00000000..af060678
--- /dev/null
+++ b/src/dolphin/gx/GXTev.c
@@ -0,0 +1,366 @@
+#include "dolphin/gx/GXTev.h"
+#include "dolphin/gx/GX.h"
+
+/* ############################################################################################## */
+static u32 TEVCOpTableST0[] = {
+ 0xC008F8AF, // modulate
+ 0xC008A89F, // decal
+ 0xC008AC8F, // blend
+ 0xC008FFF8, // replace
+ 0xC008FFFA, // passclr
+};
+
+static u32 TEVCOpTableST1[] = {
+ 0xC008F80F, // modulate
+ 0xC008089F, // decal
+ 0xC0080C8F, // blend
+ 0xC008FFF8, // replace
+ 0xC008FFF0, // passclr
+};
+
+static u32 TEVAOpTableST0[] = {
+ 0xC108F2F0, // modulate
+ 0xC108FFD0, // decal
+ 0xC108F2F0, // blend
+ 0xC108FFC0, // replace
+ 0xC108FFD0, // passclr
+};
+
+static u32 TEVAOpTableST1[] = {
+ 0xC108F070, // modulate
+ 0xC108FF80, // decal
+ 0xC108F070, // blend
+ 0xC108FFC0, // replace
+ 0xC108FF80, // passclr
+};
+
+void GXSetTevOp(GXTevStageID stage, GXTevMode mode) {
+ u32* color;
+ u32* alpha;
+ u32 tevReg;
+
+ if (stage == GX_TEVSTAGE0) {
+ color = &TEVCOpTableST0[mode];
+ alpha = &TEVAOpTableST0[mode];
+ } else {
+ color = &TEVCOpTableST1[mode];
+ alpha = &TEVAOpTableST1[mode];
+ }
+
+ tevReg = __GXData->tevc[stage];
+ tevReg = (*color & ~0xFF000000) | (tevReg & 0xFF000000);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->tevc[stage] = tevReg;
+
+ tevReg = __GXData->teva[stage];
+ tevReg = (*alpha & ~0xFF00000F) | (tevReg & 0xFF00000F);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->teva[stage] = tevReg;
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c,
+ GXTevColorArg d) {
+ u32 tevReg;
+
+ tevReg = __GXData->tevc[stage];
+
+ FAST_FLAG_SET(tevReg, a, 12, 4);
+ FAST_FLAG_SET(tevReg, b, 8, 4);
+ FAST_FLAG_SET(tevReg, c, 4, 4);
+ FAST_FLAG_SET(tevReg, d, 0, 4);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->tevc[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c,
+ GXTevAlphaArg d) {
+ u32 tevReg;
+
+ tevReg = __GXData->teva[stage];
+
+ FAST_FLAG_SET(tevReg, a, 13, 3);
+ FAST_FLAG_SET(tevReg, b, 10, 3);
+ FAST_FLAG_SET(tevReg, c, 7, 3);
+ FAST_FLAG_SET(tevReg, d, 4, 3);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+
+ __GXData->teva[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale,
+ GXBool doClamp, GXTevRegID outReg) {
+ u32 tevReg;
+
+ tevReg = __GXData->tevc[stage];
+ FAST_FLAG_SET(tevReg, op & 1, 18, 1);
+
+ if (op <= 1) {
+ FAST_FLAG_SET(tevReg, scale, 20, 2);
+ FAST_FLAG_SET(tevReg, bias, 16, 2);
+ } else {
+ FAST_FLAG_SET(tevReg, (op >> 1) & 3, 20, 2);
+ FAST_FLAG_SET(tevReg, 3, 16, 2);
+ }
+
+ FAST_FLAG_SET(tevReg, doClamp, 19, 1);
+ FAST_FLAG_SET(tevReg, outReg, 22, 2);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+ __GXData->tevc[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale,
+ GXBool doClamp, GXTevRegID outReg) {
+ u32 tevReg;
+
+ tevReg = __GXData->teva[stage];
+ FAST_FLAG_SET(tevReg, op & 1, 18, 1);
+
+ if (op <= 1) {
+ FAST_FLAG_SET(tevReg, scale, 20, 2);
+ FAST_FLAG_SET(tevReg, bias, 16, 2);
+ } else {
+ FAST_FLAG_SET(tevReg, (op >> 1) & 3, 20, 2);
+ FAST_FLAG_SET(tevReg, 3, 16, 2);
+ }
+
+ FAST_FLAG_SET(tevReg, doClamp, 19, 1);
+ FAST_FLAG_SET(tevReg, outReg, 22, 2);
+
+ GX_WRITE_U8(0x61);
+ GX_WRITE_U32(tevReg);
+ __GXData->teva[stage] = tevReg;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColor(GXTevRegID reg, GXColor color) {
+ u32 col = *(u32*)&color;
+ u32 ra = (0xE0 + reg * 2) << 24;
+ u32 bg = (0xE1 + reg * 2) << 24;
+
+ GX_SET_REG(ra, col >> 24, 24, 31);
+ GX_SET_REG(bg, col >> 8, 24, 31);
+ GX_SET_REG(bg, col >> 16, 12, 19);
+ GX_SET_REG(ra, col & 0xFF, 12, 19);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevColorS10(GXTevRegID reg, GXColorS10 color) {
+ u32 col = *(u32*)&color;
+ u32 col1 = ((u32*)&color)[1];
+ u32 ra = (0xE0 + reg * 2) << 24;
+ u32 bg = (0xE1 + reg * 2) << 24;
+
+ GX_SET_REG(ra, col >> 16, 21, 31);
+ GX_SET_REG(bg, col1 >> 16, 21, 31);
+ GX_SET_REG(bg, col & 0x7FF, 9, 19);
+ GX_SET_REG(ra, col1 & 0x7FF, 9, 19);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKColor(GXTevKColorID id, GXColor color) {
+ u32 col = *(u32*)&color;
+ u32 ra;
+ u32 bg;
+
+ ra = (0xE0 + id * 2) << 24;
+ GX_SET_REG(ra, col >> 24, 24, 31);
+ GX_SET_REG(ra, col & 0xFF, 12, 19);
+ GX_SET_REG(ra, 8, 8, 11);
+
+ bg = (0xE1 + id * 2) << 24;
+ GX_SET_REG(bg, col >> 8, 24, 31);
+ GX_SET_REG(bg, col >> 16, 12, 19);
+ GX_SET_REG(bg, 8, 8, 11);
+
+ GX_BP_LOAD_REG(ra);
+ GX_BP_LOAD_REG(bg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[stage >> 1];
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, sel, 13, 17);
+ } else {
+ GX_SET_REG(*reg, sel, 23, 27);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[stage >> 1];
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, sel, 8, 12);
+ } else {
+ GX_SET_REG(*reg, sel, 18, 22);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel rasSel, GXTevSwapSel texSel) {
+ u32* reg = &__GXData->teva[stage];
+ GX_SET_REG(*reg, rasSel, 30, 31);
+ GX_SET_REG(*reg, texSel, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, GXTevColorChan green,
+ GXTevColorChan blue, GXTevColorChan alpha) {
+ u32* reg;
+
+ reg = &__GXData->tevKsel[table << 1];
+ GX_SET_REG(*reg, red, 30, 31);
+ GX_SET_REG(*reg, green, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ reg = &__GXData->tevKsel[(table << 1) + 1];
+ GX_SET_REG(*reg, blue, 30, 31);
+ GX_SET_REG(*reg, alpha, 28, 29);
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) {
+ u32 reg = 0xF3000000;
+
+ GX_SET_REG(reg, ref0, 24, 31);
+ GX_SET_REG(reg, ref1, 16, 23);
+ GX_SET_REG(reg, comp0, 13, 15);
+ GX_SET_REG(reg, comp1, 10, 12);
+ GX_SET_REG(reg, op, 8, 9);
+
+ GX_BP_LOAD_REG(reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetZTexture(GXZTexOp op, GXTexFmt format, u32 bias) {
+ u32 val1;
+ u32 val2;
+ u32 val3;
+
+ val1 = 0;
+ GX_SET_REG(val1, bias, 8, 31);
+ GX_SET_REG(val1, 0xF4, 0, 7);
+
+ val2 = 0;
+ switch (format) {
+ case GX_TF_Z8:
+ val3 = 0;
+ break;
+ case GX_TF_Z16:
+ val3 = 1;
+ break;
+ case GX_TF_Z24X8:
+ val3 = 2;
+ break;
+ default:
+ val3 = 2;
+ break;
+ }
+
+ GX_SET_REG(val2, val3, 30, 31);
+ GX_SET_REG(val2, op, 28, 29);
+ GX_SET_REG(val2, 0xF5, 0, 7);
+
+ GX_BP_LOAD_REG(val1);
+
+ GX_BP_LOAD_REG(val2);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetTevOrder(GXTevStageID stage, GXTexCoordID coord, GXTexMapID map, GXChannelID color) {
+ static int c2r[] = {0, 1, 0, 1, 0, 1, 7, 5, 6};
+
+ u32* reg;
+ u32 tempMap;
+ u32 tempCoord;
+
+ reg = &__GXData->tref[stage / 2];
+ __GXData->texmapId[stage] = map;
+
+ tempMap = map & ~0x100;
+ tempMap = (tempMap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tempMap;
+
+ if (coord >= GX_MAXCOORD) {
+ tempCoord = GX_TEXCOORD0;
+ __GXData->tevTcEnab = __GXData->tevTcEnab & ~(1 << stage);
+ } else {
+ tempCoord = coord;
+ __GXData->tevTcEnab = __GXData->tevTcEnab | (1 << stage);
+ }
+
+ if (stage & 1) {
+ GX_SET_REG(*reg, tempMap, 17, 19);
+ GX_SET_REG(*reg, tempCoord, 14, 16);
+ GX_SET_REG(*reg, (color == GX_COLOR_NULL ? 7 : c2r[color]), 10, 12);
+ GX_SET_REG(*reg, ((map != GX_TEXMAP_NULL) && !(map & 0x100)), 13, 13);
+
+ } else {
+ GX_SET_REG(*reg, tempMap, 29, 31);
+ GX_SET_REG(*reg, tempCoord, 26, 28);
+ GX_SET_REG(*reg, (color == GX_COLOR_NULL ? 7 : c2r[color]), 22, 24);
+ GX_SET_REG(*reg, ((map != GX_TEXMAP_NULL) && !(map & 0x100)), 25, 25);
+ }
+
+ GX_BP_LOAD_REG(*reg);
+
+ __GXData->bpSentNot = GX_FALSE;
+ __GXData->dirtyState |= 1;
+}
+
+void GXSetNumTevStages(u8 count) {
+ GX_SET_REG(__GXData->genMode, count - 1, 18, 21);
+
+ __GXData->dirtyState |= 0x4;
+}
diff --git a/src/dolphin/gx/GXTexture.c b/src/dolphin/gx/GXTexture.c
new file mode 100644
index 00000000..e4b8485d
--- /dev/null
+++ b/src/dolphin/gx/GXTexture.c
@@ -0,0 +1,593 @@
+#include "dolphin/gx/GXTexture.h"
+#include "dolphin/gx/GX.h"
+
+#define GET_TILE_COUNT(a, b) (((a) + (1 << (b)) - 1) >> (b))
+
+inline void __GXGetTexTileShift(GXTexFmt format, u32* widthTiles, u32* heightTiles) {
+ switch (format) {
+ case GX_TF_I4:
+ case GX_TF_C4:
+ case GX_TF_CMPR:
+ case GX_CTF_R4:
+ case GX_CTF_Z4:
+ *widthTiles = 3;
+ *heightTiles = 3;
+ break;
+
+ case GX_TF_I8:
+ case GX_TF_IA4:
+ case GX_TF_C8:
+ case GX_TF_Z8:
+ case GX_CTF_RA4:
+ case GX_CTF_R8:
+ case GX_CTF_G8:
+ case GX_CTF_B8:
+ case GX_CTF_RG8:
+ case GX_CTF_Z8M:
+ case GX_CTF_Z8L:
+ *widthTiles = 3;
+ *heightTiles = 2;
+ break;
+
+ case GX_TF_IA8:
+ case GX_TF_RGB565:
+ case GX_TF_RGB5A3:
+ case GX_TF_RGBA8:
+ case GX_TF_C14X2:
+ case GX_TF_Z16:
+ case GX_TF_Z24X8:
+ case GX_CTF_RA8:
+ case GX_CTF_GB8:
+ case 44:
+ case GX_CTF_Z16L:
+ *widthTiles = 2;
+ *heightTiles = 2;
+ break;
+
+ default:
+ *heightTiles = 0;
+ *widthTiles = 0;
+ break;
+ }
+}
+
+u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod) {
+ u32 widthTiles, heightTiles, tileSize, bufferSize, numX, numY, i;
+
+ __GXGetTexTileShift(format, &widthTiles, &heightTiles);
+
+ if (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) {
+ tileSize = 0x40;
+ } else {
+ tileSize = 0x20;
+ }
+
+ if (mipmap == GX_TRUE) {
+ bufferSize = 0;
+
+ for (i = 0; i < max_lod; i++) {
+ numX = GET_TILE_COUNT(width, widthTiles);
+ numY = GET_TILE_COUNT(height, heightTiles);
+
+ bufferSize += numX * numY * tileSize;
+ if (width == 1 && height == 1) {
+ break;
+ }
+
+ width = (width > 1) ? (width >> 1) : 1;
+ height = (height > 1) ? (height >> 1) : 1;
+ }
+
+ } else {
+ numX = GET_TILE_COUNT(width, widthTiles);
+ numY = GET_TILE_COUNT(height, heightTiles);
+ bufferSize = numX * numY * tileSize;
+ }
+
+ return bufferSize;
+}
+
+void __GetImageTileCount(GXTexFmt format, u16 width, u16 height, u32* a, u32* b, u32* c) {
+ u32 widthTiles, heightTiles;
+
+ __GXGetTexTileShift(format, &widthTiles, &heightTiles);
+
+ if (width <= 0) {
+ width = 1;
+ }
+
+ if (height <= 0) {
+ height = 1;
+ }
+
+ *a = GET_TILE_COUNT(width, widthTiles);
+ *b = GET_TILE_COUNT(height, heightTiles);
+ *c = (format == GX_TF_RGBA8 || format == GX_TF_Z24X8) ? 2 : 1;
+}
+
+void GXInitTexObj(GXTexObj* obj, void* imagePtr, u16 width, u16 height, GXTexFmt format,
+ GXTexWrapMode sWrap, GXTexWrapMode tWrap, GXBool useMIPmap) {
+ u32 imageBase;
+ u16 a, b;
+ u32 c, d;
+
+ GXTexObj* internal = (GXTexObj*)obj;
+ memset(internal, 0, sizeof(*internal));
+
+ GX_SET_REG(internal->texture_filter, sWrap, 30, 31);
+ GX_SET_REG(internal->texture_filter, tWrap, 28, 29);
+ GX_SET_REG(internal->texture_filter, GX_TRUE, 27, 27);
+
+ if (useMIPmap) {
+ u32 maxDimSize;
+ internal->texture_flags |= 1;
+ if (format == 8 || format == 9 || format == 10) {
+ GX_SET_REG(internal->texture_filter, 5, 24, 26);
+ } else {
+ GX_SET_REG(internal->texture_filter, 6, 24, 26);
+ }
+
+ maxDimSize = width > height ? 31 - __cntlzw(width) : 31 - __cntlzw(height);
+
+ GX_SET_REG(internal->texture_lod, (maxDimSize) * 16.f, 16, 23);
+ } else {
+ GX_SET_REG(internal->texture_filter, 4, 24, 26);
+ }
+
+ internal->texture_format = format;
+ GX_SET_REG(internal->texture_size, width - 1, 22, 31);
+ GX_SET_REG(internal->texture_size, height - 1, 12, 21);
+
+ GX_SET_REG(internal->texture_size, format & 0xf, 8, 11);
+ imageBase = (u32)imagePtr >> 5;
+ GX_SET_REG(internal->texture_address, imageBase, 11, 31);
+
+ switch (format & 0xf) {
+ case 0:
+ case 8:
+ internal->texture_tile_type = 1;
+ a = 3;
+ b = 3;
+ break;
+ case 1:
+ case 2:
+ case 9:
+ internal->texture_tile_type = 2;
+ a = 3;
+ b = 2;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 10:
+ internal->texture_tile_type = 2;
+ a = 2;
+ b = 2;
+ break;
+ case 6:
+ internal->texture_tile_type = 3;
+ a = 2;
+ b = 2;
+ break;
+ case 0xe:
+ internal->texture_tile_type = 0;
+ a = 3;
+ b = 3;
+ break;
+ default:
+ internal->texture_tile_type = 2;
+ a = 2;
+ b = 2;
+ break;
+ }
+
+ internal->texture_time_count = (GET_TILE_COUNT(width, a) * GET_TILE_COUNT(height, b)) & 0x7fff;
+
+ internal->texture_flags |= 2;
+}
+
+void GXInitTexObjCI(GXTexObj* obj, void* imagePtr, u16 width, u16 height, GXCITexFmt format,
+ GXTexWrapMode sWrap, GXTexWrapMode tWrap, GXBool useMIPmap, u32 tlut_name) {
+ GXTexObj* internal = (GXTexObj*)obj;
+
+ GXInitTexObj(obj, imagePtr, width, height, format, sWrap, tWrap, useMIPmap);
+
+ internal->texture_flags &= ~2;
+ internal->tlut_name = tlut_name;
+}
+
+u8 GXTexMode0Ids[8] = {0x80, 0x81, 0x82, 0x83, 0xA0, 0xA1, 0xA2, 0xA3};
+
+u8 GXTexMode1Ids[8] = {0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7};
+
+u8 GXTexImage0Ids[8] = {0x88, 0x89, 0x8a, 0x8b, 0xA8, 0xA9, 0xAa, 0xAb};
+
+u8 GXTexImage1Ids[8] = {0x8c, 0x8d, 0x8e, 0x8f, 0xAc, 0xAd, 0xAe, 0xAf};
+
+u8 GXTexImage2Ids[8] = {0x90, 0x91, 0x92, 0x93, 0xB0, 0xB1, 0xB2, 0xB3};
+
+u8 GXTexImage3Ids[8] = {0x94, 0x95, 0x96, 0x97, 0xB4, 0xB5, 0xB6, 0xB7};
+
+u8 GXTexTlutIds[8] = {0x98, 0x99, 0x9a, 0x9b, 0xB8, 0xB9, 0xBa, 0xBb};
+
+u8 GX2HWFiltConv[6] = {0x00, 0x04, 0x01, 0x05, 0x02, 0x06};
+
+void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilter, GXTexFilter maxFilter, f32 minLOD,
+ f32 maxLOD, f32 lodBias, GXBool doBiasClamp, GXBool doEdgeLOD,
+ GXAnisotropy maxAniso) {
+ GXTexObj* internal = (GXTexObj*)obj;
+ u8 reg1, reg2;
+ if (lodBias < -4.0f) {
+ lodBias = -4.0f;
+ } else if (lodBias >= 4.0f) {
+ lodBias = 3.99f;
+ }
+
+ GX_SET_REG(internal->texture_filter, lodBias * 32.0f, 15, 22);
+ GX_SET_REG(internal->texture_filter, maxFilter == 1 ? 1 : 0, 27, 27);
+ GX_SET_REG(internal->texture_filter, GX2HWFiltConv[minFilter], 24, 26);
+ GX_SET_REG(internal->texture_filter, doEdgeLOD ? 0 : 1, 23, 23);
+ GX_SET_REG(internal->texture_filter, 0, 14, 14);
+ GX_SET_REG(internal->texture_filter, 0, 13, 13);
+ GX_SET_REG(internal->texture_filter, maxAniso, 11, 12);
+ GX_SET_REG(internal->texture_filter, doBiasClamp, 10, 10);
+
+ if (minLOD < 0.0f) {
+ minLOD = 0.0f;
+ } else if (minLOD > 10.0f) {
+ minLOD = 10.0f;
+ }
+ reg1 = minLOD * 16.0f;
+
+ if (maxLOD < 0.0f) {
+ maxLOD = 0.0f;
+ } else if (maxLOD > 10.0f) {
+ maxLOD = 10.0f;
+ }
+ reg2 = maxLOD * 16.0f;
+
+ GX_SET_REG(internal->texture_lod, reg1, 24, 31);
+ GX_SET_REG(internal->texture_lod, reg2, 16, 23);
+}
+
+u16 GXGetTexObjWidth(GXTexObj* obj) {
+ return (obj->texture_size & 0x3ff) + 1;
+}
+
+u16 GXGetTexObjHeight(GXTexObj* obj) {
+ return ((obj->texture_size >> 10) & 0x3ff) + 1;
+}
+
+GXTexFmt GXGetTexObjFmt(const GXTexObj* obj) {
+ return obj->texture_format;
+}
+
+GXTexWrapMode GXGetTexObjWrapS(GXTexObj* obj) {
+ return obj->texture_filter & 0x3;
+}
+
+GXTexWrapMode GXGetTexObjWrapT(GXTexObj* obj) {
+ return (obj->texture_filter & 0xc) >> 2;
+}
+
+GXBool GXGetTexObjMipMap(const GXTexObj* obj) {
+ return (obj->texture_flags & 1) == 1;
+}
+
+u32 GXGetTexObjTlut(GXTexObj* obj) {
+ return obj->tlut_name;
+}
+
+void GXLoadTexObjPreLoaded(GXTexObj* obj, GXTexRegion* region, GXTexMapID map) {
+ u8 stackManipulation[0x18];
+
+ GXTexObj* internalObj = (GXTexObj*)obj;
+ GXTexRegion* internalRegion = (GXTexRegion*)region;
+
+ GX_SET_REG(internalObj->texture_filter, GXTexMode0Ids[map], 0, 7);
+ GX_SET_REG(internalObj->texture_lod, GXTexMode1Ids[map], 0, 7);
+ GX_SET_REG(internalObj->texture_size, GXTexImage0Ids[map], 0, 7);
+
+ GX_SET_REG(internalRegion->unk0, GXTexImage1Ids[map], 0, 7);
+ GX_SET_REG(internalRegion->unk4, GXTexImage2Ids[map], 0, 7);
+
+ GX_SET_REG(internalObj->texture_address, GXTexImage3Ids[map], 0, 7);
+
+ GX_BP_LOAD_REG(internalObj->texture_filter);
+ GX_BP_LOAD_REG(internalObj->texture_lod);
+ GX_BP_LOAD_REG(internalObj->texture_size);
+ GX_BP_LOAD_REG(internalRegion->unk0);
+ GX_BP_LOAD_REG(internalRegion->unk4);
+ GX_BP_LOAD_REG(internalObj->texture_address);
+
+ if ((internalObj->texture_flags & 2) == 0) {
+ GXTlutObj* tlut = (GXTlutObj*)__GXData->tlutRegionCallback(internalObj->tlut_name);
+ GX_SET_REG(tlut->address, GXTexTlutIds[map], 0, 7);
+
+ GX_BP_LOAD_REG(tlut->address);
+ }
+
+ __GXData->tImage0[map] = internalObj->texture_size;
+ __GXData->tMode0[map] = internalObj->texture_filter;
+
+ __GXData->dirtyState |= GX_DIRTY_SU_TEX;
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXLoadTexObj(GXTexObj* obj, GXTexMapID map) {
+ GXTexRegion* ret = (GXTexRegion*)__GXData->texRegionCallback(obj, map);
+
+ GXLoadTexObjPreLoaded(obj, ret, map);
+}
+
+void GXInitTlutObj(GXTlutObj* obj, void* table, GXTlutFmt format, u16 numEntries) {
+ GXTlutObj* internal = (GXTlutObj*)obj;
+
+ internal->format = 0;
+
+ GX_SET_REG(internal->format, format, 20, 21);
+ GX_SET_REG(internal->address, (u32)table >> 5, 11, 31);
+ GX_SET_REG(internal->address, 100, 0, 7);
+
+ internal->numEntries = numEntries;
+}
+
+void GXLoadTlut(GXTlutObj* obj, u32 tlut_name) {
+ GXTlutObj* internal = (GXTlutObj*)obj;
+ GXTlutRegion* ret = (GXTlutRegion*)__GXData->tlutRegionCallback(tlut_name);
+ u32 reg;
+
+ __GXFlushTextureState();
+
+ GX_BP_LOAD_REG(internal->address);
+ GX_BP_LOAD_REG(ret->unk0);
+
+ __GXFlushTextureState();
+
+ reg = ret->unk0;
+ GX_SET_REG(internal->format, reg, 22, 31);
+
+ ret->tlutObj = *internal;
+}
+
+void GXInitTexCacheRegion(GXTexRegion* region, GXBool is32bMIPmap, u32 memEven,
+ GXTexCacheSize sizeEven, u32 memOdd, GXTexCacheSize sizeOdd) {
+ GXTexRegion* internal = (GXTexRegion*)region;
+
+ u32 reg;
+ switch (sizeEven) {
+ case 0:
+ reg = 3;
+ break;
+ case 1:
+ reg = 4;
+ break;
+ case 2:
+ reg = 5;
+ break;
+ }
+
+ internal->unk0 = 0;
+
+ GX_SET_REG(internal->unk0, memEven >> 5, 17, 31);
+ GX_SET_REG(internal->unk0, reg, 14, 16);
+ GX_SET_REG(internal->unk0, reg, 11, 13);
+ GX_SET_REG(internal->unk0, 0, 10, 10);
+
+ switch (sizeOdd) {
+ case 0:
+ reg = 3;
+ break;
+ case 1:
+ reg = 4;
+ break;
+ case 2:
+ reg = 5;
+ break;
+ case 3:
+ reg = 0;
+ break;
+ }
+
+ internal->unk4 = 0;
+ GX_SET_REG(internal->unk4, memOdd >> 5, 17, 31);
+ GX_SET_REG(internal->unk4, reg, 14, 16);
+ GX_SET_REG(internal->unk4, reg, 11, 13);
+
+ internal->unkC = is32bMIPmap;
+ internal->unkD = 1;
+}
+
+void GXInitTlutRegion(GXTlutRegion* region, u32 memAddr, GXTlutSize tlutSize) {
+ GXTlutRegion* internal = (GXTlutRegion*)region;
+
+ internal->unk0 = 0;
+ GX_SET_REG(internal->unk0, (memAddr - 0x80000) >> 9, 22, 31);
+ GX_SET_REG(internal->unk0, tlutSize, 11, 21);
+ GX_SET_REG(internal->unk0, 0x65, 0, 7);
+}
+
+void GXInvalidateTexAll(void) {
+ __GXFlushTextureState();
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0x66001000;
+ GXFIFO.u8 = 0x61;
+ GXFIFO.u32 = 0x66001100;
+ __GXFlushTextureState();
+}
+
+GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback callback) {
+ GXTexRegionCallback prev = __GXData->texRegionCallback;
+ __GXData->texRegionCallback = callback;
+ return prev;
+}
+
+GXTlutRegionCallback GXSetTlutRegionCallback(GXTlutRegionCallback callback) {
+ GXTlutRegionCallback prev = __GXData->tlutRegionCallback;
+ __GXData->tlutRegionCallback = callback;
+ return prev;
+}
+
+void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 s_scale, u16 t_scale) {
+ /* Nonmatching */
+}
+
+void __SetSURegs(u32 texImgIndex, u32 setUpRegIndex) {
+ u16 a1, a2;
+ GXBool b, c;
+
+ a1 = GX_GET_REG(__GXData->tImage0[texImgIndex], 22, 31);
+ a2 = (__GXData->tImage0[texImgIndex] & (0x3ff << 10)) >> 10;
+
+ GX_SET_REG(__GXData->suTs0[setUpRegIndex], a1, 16, 31);
+ GX_SET_REG(__GXData->suTs1[setUpRegIndex], a2, 16, 31);
+
+ b = GX_GET_REG(__GXData->tMode0[texImgIndex], 30, 31) == 1;
+ c = GX_GET_REG(__GXData->tMode0[texImgIndex], 28, 29) == 1;
+
+ GX_SET_REG(__GXData->suTs0[setUpRegIndex], b, 15, 15);
+ GX_SET_REG(__GXData->suTs1[setUpRegIndex], c, 15, 15);
+
+ GX_BP_LOAD_REG(__GXData->suTs0[setUpRegIndex]);
+ GX_BP_LOAD_REG(__GXData->suTs1[setUpRegIndex]);
+
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+#pragma dont_inline on
+void __GXSetSUTexRegs(void) {
+ u32 i;
+ u32 b;
+ u32 a;
+ u32 c;
+ u32 d;
+ u32 stackFiller;
+ if (__GXData->tcsManEnab != 0xff) {
+ a = GX_GET_REG(__GXData->genMode, 18, 21) + 1;
+ b = GX_GET_REG(__GXData->genMode, 13, 15);
+ for (i = 0; i < b; i++) {
+ switch (i) {
+ case 0:
+ c = GX_GET_REG(__GXData->iref, 29, 31);
+ d = GX_GET_REG(__GXData->iref, 26, 28);
+ break;
+ case 1:
+ c = GX_GET_REG(__GXData->iref, 23, 25);
+ d = GX_GET_REG(__GXData->iref, 20, 22);
+ break;
+ case 2:
+ c = GX_GET_REG(__GXData->iref, 17, 19);
+ d = GX_GET_REG(__GXData->iref, 14, 16);
+ break;
+ case 3:
+ c = GX_GET_REG(__GXData->iref, 11, 13);
+ d = GX_GET_REG(__GXData->iref, 8, 10);
+ break;
+ }
+
+ if (!(__GXData->tcsManEnab & (1 << d))) {
+ __SetSURegs(c, d);
+ }
+ }
+
+ for (i = 0; i < a; i++) {
+ u32* g = &__GXData->tref[i / 2];
+
+ c = __GXData->texmapId[i] & ~0x100;
+
+ if (i & 1) {
+ d = GX_GET_REG(*g, 14, 16);
+ } else {
+ d = GX_GET_REG(*g, 26, 28);
+ }
+
+ if (c != 0xff && !(__GXData->tcsManEnab & (1 << d)) && __GXData->tevTcEnab & (1 << i)) {
+ __SetSURegs(c, d);
+ }
+ }
+ }
+}
+#pragma dont_inline reset
+
+void __GXSetTmemConfig(u32 config) {
+ switch (config) {
+ case 2:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8800);
+ GX_BP_LOAD_REG(0x910dc800);
+
+ GX_BP_LOAD_REG(0x8e0d9000);
+ GX_BP_LOAD_REG(0x920dd000);
+
+ GX_BP_LOAD_REG(0x8f0d9800);
+ GX_BP_LOAD_REG(0x930dd800);
+
+ GX_BP_LOAD_REG(0xac0da000);
+ GX_BP_LOAD_REG(0xb00dc400);
+
+ GX_BP_LOAD_REG(0xad0da800);
+ GX_BP_LOAD_REG(0xb10dcc00);
+
+ GX_BP_LOAD_REG(0xae0db000);
+ GX_BP_LOAD_REG(0xb20dd400);
+
+ GX_BP_LOAD_REG(0xaf0db800);
+ GX_BP_LOAD_REG(0xb30ddc00);
+ break;
+ case 1:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8800);
+ GX_BP_LOAD_REG(0x910dc800);
+
+ GX_BP_LOAD_REG(0x8e0d9000);
+ GX_BP_LOAD_REG(0x920dd000);
+
+ GX_BP_LOAD_REG(0x8f0d9800);
+ GX_BP_LOAD_REG(0x930dd800);
+
+ GX_BP_LOAD_REG(0xac0da000);
+ GX_BP_LOAD_REG(0xb00de000);
+
+ GX_BP_LOAD_REG(0xad0da800);
+ GX_BP_LOAD_REG(0xb10de800);
+
+ GX_BP_LOAD_REG(0xae0db000);
+ GX_BP_LOAD_REG(0xb20df000);
+
+ GX_BP_LOAD_REG(0xaf0db800);
+ GX_BP_LOAD_REG(0xb30df800);
+
+ break;
+ case 0:
+ default:
+ GX_BP_LOAD_REG(0x8c0d8000);
+ GX_BP_LOAD_REG(0x900dc000);
+
+ GX_BP_LOAD_REG(0x8d0d8400);
+ GX_BP_LOAD_REG(0x910dc400);
+
+ GX_BP_LOAD_REG(0x8e0d8800);
+ GX_BP_LOAD_REG(0x920dc800);
+
+ GX_BP_LOAD_REG(0x8f0d8c00);
+ GX_BP_LOAD_REG(0x930dcc00);
+
+ GX_BP_LOAD_REG(0xac0d9000);
+ GX_BP_LOAD_REG(0xb00dd000);
+
+ GX_BP_LOAD_REG(0xad0d9400);
+ GX_BP_LOAD_REG(0xb10dd400);
+
+ GX_BP_LOAD_REG(0xae0d9800);
+ GX_BP_LOAD_REG(0xb20dd800);
+
+ GX_BP_LOAD_REG(0xaf0d9c00);
+ GX_BP_LOAD_REG(0xb30ddc00);
+
+ break;
+ }
+}
diff --git a/src/dolphin/gx/GXTransform.c b/src/dolphin/gx/GXTransform.c
new file mode 100644
index 00000000..1bf66bbb
--- /dev/null
+++ b/src/dolphin/gx/GXTransform.c
@@ -0,0 +1,316 @@
+#include "dolphin/gx/GXTransform.h"
+#include "dolphin/gx/GX.h"
+#include "dolphin/os/OS.h"
+
+void __GXSetMatrixIndex();
+
+static void Copy6Floats(register f32 src[6], register f32 dst[6]) {
+ register f32 ps_0, ps_1, ps_2;
+
+ // clang-format off
+ asm {
+ psq_l ps_0, 0(src), 0, 0
+ psq_l ps_1, 8(src), 0, 0
+ psq_l ps_2, 16(src), 0, 0
+ psq_st ps_0, 0(dst), 0, 0
+ psq_st ps_1, 8(dst), 0, 0
+ psq_st ps_2, 16(dst), 0, 0
+ }
+ // clang-format on
+}
+
+static void WriteProjPS(const register f32 src[6], register volatile void* dst) {
+ register f32 ps_0, ps_1, ps_2;
+
+ // clang-format off
+ asm {
+ psq_l ps_0, 0(src), 0, 0
+ psq_l ps_1, 8(src), 0, 0
+ psq_l ps_2, 16(src), 0, 0
+ psq_st ps_0, 0(dst), 0, 0
+ psq_st ps_1, 0(dst), 0, 0
+ psq_st ps_2, 0(dst), 0, 0
+ }
+ // clang-format on
+}
+
+void GXProject(f32 model_x, f32 model_y, f32 model_z, Mtx model_mtx, f32* proj_mtx, f32* viewpoint,
+ f32* screen_x, f32* screen_y, f32* screen_z) {
+ f32 sp10[3];
+ f32 var_f30;
+ f32 var_f29;
+ f32 var_f28;
+ f32 var_f31;
+
+ ASSERTMSG(proj_mtx != NULL && viewpoint != NULL && screen_x != NULL && screen_y != NULL && screen_z != NULL, "GXGet*: invalid null pointer");
+
+ sp10[0] = (model_mtx[0][0] * model_x) + (model_mtx[0][1] * model_y) +
+ (model_mtx[0][2] * model_z) + model_mtx[0][3];
+ sp10[1] = (model_mtx[1][0] * model_x) + (model_mtx[1][1] * model_y) +
+ (model_mtx[1][2] * model_z) + model_mtx[1][3];
+ sp10[2] = (model_mtx[2][0] * model_x) + (model_mtx[2][1] * model_y) +
+ (model_mtx[2][2] * model_z) + model_mtx[2][3];
+
+ if (proj_mtx[0] == 0.0f) {
+ var_f30 = (sp10[0] * proj_mtx[1]) + (sp10[2] * proj_mtx[2]);
+ var_f29 = (sp10[1] * proj_mtx[3]) + (sp10[2] * proj_mtx[4]);
+ var_f28 = proj_mtx[6] + (sp10[2] * proj_mtx[5]);
+ var_f31 = 1.0f / -sp10[2];
+ } else {
+ var_f30 = proj_mtx[2] + (sp10[0] * proj_mtx[1]);
+ var_f29 = proj_mtx[4] + (sp10[1] * proj_mtx[3]);
+ var_f28 = proj_mtx[6] + (sp10[2] * proj_mtx[5]);
+ var_f31 = 1.0f;
+ }
+
+ *screen_x = (viewpoint[2] / 2) + (viewpoint[0] + (var_f31 * (var_f30 * viewpoint[2] / 2)));
+ *screen_y = (viewpoint[3] / 2) + (viewpoint[1] + (var_f31 * (-var_f29 * viewpoint[3] / 2)));
+ *screen_z = viewpoint[5] + (var_f31 * (var_f28 * (viewpoint[5] - viewpoint[4])));
+}
+
+void __GXSetProjection(void) {
+ GX_XF_LOAD_REGS(6, GX_XF_REG_PROJECTIONA);
+ WriteProjPS(__GXData->projMtx, (volatile void*)GXFIFO_ADDR);
+ GX_WRITE_U32(__GXData->projType);
+}
+
+void GXSetProjection(const Mtx44 proj, GXProjectionType type) {
+ volatile void* fifo;
+ __GXData->projType = type;
+
+ __GXData->projMtx[0] = proj[0][0];
+ __GXData->projMtx[2] = proj[1][1];
+ __GXData->projMtx[4] = proj[2][2];
+ __GXData->projMtx[5] = proj[2][3];
+
+ if (type == GX_ORTHOGRAPHIC) {
+ __GXData->projMtx[1] = proj[0][3];
+ __GXData->projMtx[3] = proj[1][3];
+ } else {
+ __GXData->projMtx[1] = proj[0][2];
+ __GXData->projMtx[3] = proj[1][2];
+ }
+
+ __GXSetProjection();
+
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+void GXSetProjectionv(f32* proj) {
+ __GXData->projType = proj[0] == 0.0f ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC;
+ Copy6Floats(&proj[1], __GXData->projMtx);
+
+ __GXSetProjection();
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+void GXGetProjectionv(f32* proj) {
+ *proj = (u32)__GXData->projType != GX_PERSPECTIVE ? 1.0f : 0.0f;
+ Copy6Floats(__GXData->projMtx, &proj[1]);
+}
+
+static void WriteMTXPS4x3(register volatile void* dst, register const Mtx src) {
+ register f32 ps_0, ps_1, ps_2, ps_3, ps_4, ps_5;
+
+ // clang-format off
+ asm {
+ psq_l ps_0, 0(src), 0, 0
+ psq_l ps_1, 8(src), 0, 0
+ psq_l ps_2, 16(src), 0, 0
+ psq_l ps_3, 24(src), 0, 0
+ psq_l ps_4, 32(src), 0, 0
+ psq_l ps_5, 40(src), 0, 0
+
+ psq_st ps_0, 0(dst), 0, 0
+ psq_st ps_1, 0(dst), 0, 0
+ psq_st ps_2, 0(dst), 0, 0
+ psq_st ps_3, 0(dst), 0, 0
+ psq_st ps_4, 0(dst), 0, 0
+ psq_st ps_5, 0(dst), 0, 0
+ }
+ // clang-format on
+}
+
+void GXLoadPosMtxImm(Mtx mtx, u32 id) {
+ GX_XF_LOAD_REGS(4 * 3 - 1, id * 4 + GX_XF_MEM_POSMTX);
+ WriteMTXPS4x3(&GXFIFO, mtx);
+}
+
+static void WriteMTXPS3x3(register volatile void* dst, register const Mtx src) {
+ register f32 ps_0, ps_1, ps_2, ps_3, ps_4, ps_5;
+
+ // clang-format off
+ asm {
+ psq_l ps_0, 0(src), 0, 0
+ lfs ps_1, 8(src)
+ psq_l ps_2, 16(src), 0, 0
+ lfs ps_3, 24(src)
+ psq_l ps_4, 32(src), 0, 0
+ lfs ps_5, 40(src)
+
+ psq_st ps_0, 0(dst), 0, 0
+ stfs ps_1, 0(dst)
+ psq_st ps_2, 0(dst), 0, 0
+ stfs ps_3, 0(dst)
+ psq_st ps_4, 0(dst), 0, 0
+ stfs ps_5, 0(dst)
+ }
+ // clang-format on
+}
+
+void GXLoadNrmMtxImm(Mtx mtx, u32 id) {
+ GX_XF_LOAD_REGS(3 * 3 - 1, id * 3 + GX_XF_MEM_NRMMTX);
+ WriteMTXPS3x3(&GXFIFO, mtx);
+}
+
+void GXSetCurrentMtx(u32 id) {
+ GX_SET_REG(__GXData->matIdxA, id, GX_XF_MTXIDX0_GEOM_ST, GX_XF_MTXIDX0_GEOM_END);
+ __GXSetMatrixIndex(GX_VA_PNMTXIDX);
+}
+
+static void WriteMTXPS4x2(register volatile void* dst, register const Mtx src) {
+ register f32 ps_0, ps_1, ps_2, ps_3;
+
+ // clang-format off
+ asm {
+ psq_l ps_0, 0(src), 0, 0
+ psq_l ps_1, 8(src), 0, 0
+ psq_l ps_2, 16(src), 0, 0
+ psq_l ps_3, 24(src), 0, 0
+
+ psq_st ps_0, 0(dst), 0, 0
+ psq_st ps_1, 0(dst), 0, 0
+ psq_st ps_2, 0(dst), 0, 0
+ psq_st ps_3, 0(dst), 0, 0
+ }
+ // clang-format on
+}
+
+void GXLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type) {
+ u32 addr;
+ u32 num;
+ u32 reg;
+
+ // Matrix address in XF memory
+ addr = id >= GX_PTTEXMTX0 ? (id - GX_PTTEXMTX0) * 4 + GX_XF_MEM_DUALTEXMTX :
+ id * 4 + (u64)GX_XF_MEM_POSMTX;
+
+ // Number of elements in matrix
+ num = type == GX_MTX2x4 ? (u64)(2 * 4) : 3 * 4;
+
+ reg = addr | (num - 1) << 16;
+
+ GX_XF_LOAD_REG_HDR(reg);
+
+ if (type == GX_MTX3x4) {
+ WriteMTXPS4x3(&GXFIFO, mtx);
+ } else {
+ WriteMTXPS4x2(&GXFIFO, mtx);
+ }
+}
+
+void __GXSetViewport(void) {
+ f32 a, b, c, d, e, f;
+ f32 near, far;
+
+ a = __GXData->vpWd / 2;
+ b = -__GXData->vpHt / 2;
+ d = __GXData->vpLeft + (__GXData->vpWd / 2) + 342.0f;
+ e = __GXData->vpTop + (__GXData->vpHt / 2) + 342.0f;
+
+ near = __GXData->vpNearz * __GXData->zScale;
+ far = __GXData->vpFarz * __GXData->zScale;
+
+ c = far - near;
+ f = far + __GXData->zOffset;
+
+ GX_XF_LOAD_REGS(5, GX_XF_REG_SCALEX);
+ GX_WRITE_F32(a);
+ GX_WRITE_F32(b);
+ GX_WRITE_F32(c);
+ GX_WRITE_F32(d);
+ GX_WRITE_F32(e);
+ GX_WRITE_F32(f);
+}
+
+void GXSetViewport(f32 left, f32 top, f32 width, f32 height, f32 nearZ, f32 farZ) {
+ __GXData->vpLeft = left;
+ __GXData->vpTop = top;
+ __GXData->vpWd = width;
+ __GXData->vpHt = height;
+ __GXData->vpNearz = nearZ;
+ __GXData->vpFarz = farZ;
+ __GXSetViewport();
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+void GXGetViewportv(f32* p) {
+ Copy6Floats(&__GXData->vpLeft, p);
+}
+
+void GXSetScissor(u32 left, u32 top, u32 width, u32 height) {
+ u32 y1, x1, y2, x2;
+ u32 reg;
+
+ y1 = top + 342;
+ x1 = left + 342;
+
+ GX_SET_REG(__GXData->suScis0, y1, GX_BP_SCISSORTL_TOP_ST, GX_BP_SCISSORTL_TOP_END);
+ GX_SET_REG(__GXData->suScis0, x1, GX_BP_SCISSORTL_LEFT_ST, GX_BP_SCISSORTL_LEFT_END);
+
+ y2 = y1 + height - 1;
+ x2 = (x1 + width) - 1;
+
+ GX_SET_REG(__GXData->suScis1, y2, GX_BP_SCISSORBR_BOT_ST, GX_BP_SCISSORBR_BOT_END);
+ GX_SET_REG(__GXData->suScis1, x2, GX_BP_SCISSORBR_RIGHT_ST, GX_BP_SCISSORBR_RIGHT_END);
+
+ GX_BP_LOAD_REG(__GXData->suScis0);
+ GX_BP_LOAD_REG(__GXData->suScis1);
+ __GXData->bpSentNot = FALSE;
+}
+
+void GXGetScissor(u32* left, u32* top, u32* width, u32* height) {
+ u32 y1 = (__GXData->suScis0 & 0x0007FF) >> 0;
+ u32 x1 = (__GXData->suScis0 & 0x7FF000) >> 12;
+ u32 y2 = (__GXData->suScis1 & 0x0007FF) >> 0;
+ u32 x2 = (__GXData->suScis1 & 0x7FF000) >> 12;
+
+ *left = x1 - 0x156;
+ *top = y1 - 0x156;
+ *width = (x2 - x1) + 1;
+ *height = (y2 - y1) + 1;
+}
+
+void GXSetScissorBoxOffset(s32 x, s32 y) {
+ u32 cmd = 0;
+ u32 x1;
+ u32 y1;
+
+ x1 = (u32)(x + 342) / 2;
+ y1 = (u32)(y + 342) / 2;
+ GX_SET_REG(cmd, x1, GX_BP_SCISSOROFS_OX_ST, GX_BP_SCISSOROFS_OX_END);
+ GX_SET_REG(cmd, y1, GX_BP_SCISSOROFS_OY_ST, GX_BP_SCISSOROFS_OY_END);
+
+ GX_SET_REG(cmd, GX_BP_REG_SCISSOROFFSET, 0, 7);
+
+ GX_BP_LOAD_REG(cmd);
+ __GXData->bpSentNot = GX_FALSE;
+}
+
+void GXSetClipMode(GXClipMode mode) {
+ GX_XF_LOAD_REG(GX_XF_REG_CLIPDISABLE, mode);
+ __GXData->bpSentNot = GX_TRUE;
+}
+
+void __GXSetMatrixIndex(GXAttr index) {
+ // Tex4 and after is stored in XF MatrixIndex1
+ if (index < GX_VA_TEX4MTXIDX) {
+ GX_CP_LOAD_REG(GX_CP_REG_MTXIDXA, __GXData->matIdxA);
+ GX_XF_LOAD_REG(GX_XF_REG_MATRIXINDEX0, __GXData->matIdxA);
+ } else {
+ GX_CP_LOAD_REG(GX_CP_REG_MTXIDXB, __GXData->matIdxB);
+ GX_XF_LOAD_REG(GX_XF_REG_MATRIXINDEX1, __GXData->matIdxB);
+ }
+
+ __GXData->bpSentNot = GX_TRUE;
+}
diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp
index 10618b76..9c84bb00 100644
--- a/src/m_Do/m_Do_graphic.cpp
+++ b/src/m_Do/m_Do_graphic.cpp
@@ -522,7 +522,7 @@ void drawDepth(view_class* view, view_port_class* viewport, int depth) {
GXCopyTex(zbuf, GX_FALSE);
GXSetTexCopySrc(x, y, w, h);
- GXSetTexCopyDst(hw, hh, mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE);
+ GXSetTexCopyDst(hw, hh, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE);
GXCopyTex(fbbuf, GX_FALSE);
GXInitTexObj(mDoGph_gInf_c::getZbufferTexObj(), zbuf, w, h, GX_TF_IA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
@@ -933,7 +933,7 @@ bool mDoGph_screenCapture() {
setUpRectangle();
GXSetTexCopySrc(centerX - sizeW, centerY - sizeH, sizeW2, sizeH2);
- GXSetTexCopyDst(sizeW, sizeH, mCaptureCaptureFormat, GX_TRUE);
+ GXSetTexCopyDst(sizeW, sizeH, (_GXTexFmt)mCaptureCaptureFormat, GX_TRUE);
DCInvalidateRange(mCaptureCaptureBuffer, mCaptureCaptureSize);
GXCopyTex(mCaptureCaptureBuffer, GX_FALSE);
GXPixModeSync();