Merge branch 'mariopartyrd:main' into main

This commit is contained in:
CreateSource 2024-12-31 01:09:43 -05:00 committed by GitHub
commit b80953f068
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 13418 additions and 652 deletions

View file

@ -206,19 +206,19 @@ void fn_1_C164(unkStruct8* arg0) {
}
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_RGBA6, 0);
GXSetArray(GX_VA_POS, var_r31->unk40, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetArray(GX_VA_POS, var_r31->unk40, 12);
GXSetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_TEX_ST, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetArray(GX_VA_CLR0, var_r31->unk44, 4);
for (var_r26 = 0; var_r26 < var_r31->unk32; var_r26++) {
GXSetVtxDesc(var_r26 + GX_VA_TEX0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, var_r26 + GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, var_r26 + GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetArray(var_r26 + GX_VA_TEX0, var_r31->unk54[var_r26].unk4, 8);
}
GXSetVtxDesc(GX_VA_NRM, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_TEX_S, GX_RGBA6, 0);
GXSetArray(GX_VA_NRM, var_r31->unk48, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetArray(GX_VA_NRM, var_r31->unk48, 12);
GXCallDisplayList(var_r31->unk3C, var_r31->unk38);
}
}

View file

@ -1376,13 +1376,13 @@ void fn_1_602C(ModelData *arg0, f32 (*arg1)[4])
}
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_RGBA6, 0);
GXSetArray(GX_VA_POS, temp_r30->unk1C, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetArray(GX_VA_POS, temp_r30->unk1C, 12);
GXSetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_TEX_ST, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetArray(GX_VA_CLR0, temp_r30->unk24, 4);
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetArray(GX_VA_TEX0, temp_r30->unk20, 8);
fn_1_40A4(arg1, sp128);
PSMTXReorder(sp128, spF8);

View file

@ -230,20 +230,20 @@ void fn_1_88B8(unkSubStruct2* arg0) {
}
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_RGBA6, 0);
GXSetArray(GX_VA_POS, var_r31->unk40, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetArray(GX_VA_POS, var_r31->unk40, 12);
GXSetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_TEX_ST, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetArray(GX_VA_CLR0, var_r31->unk44, 4);
for (var_r27 = 0; var_r27 < var_r31->unk33; var_r27++) {
GXSetVtxDesc(var_r27 + GX_VA_TEX0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, var_r27 + GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, var_r27 + GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetArray(var_r27 + GX_VA_TEX0, var_r31->unk54[var_r27].unk4, 8);
}
GXSetVtxDesc(GX_VA_NRM, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_RGBA6, 0);
GXSetArray(GX_VA_NRM, var_r31->unk48, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetArray(GX_VA_NRM, var_r31->unk48, 12);
GXCallDisplayList(var_r31->unk3C, var_r31->unk38);
}
}
@ -1433,4 +1433,4 @@ void fn_1_C81C(s16 arg0, u8 arg1) {
var_r31 = &lbl_1_bss_36C.unk3C[arg0];
var_r31->unk4 = arg1;
}
}
}

5648
src/REL/m423Dll/main.c Executable file

File diff suppressed because it is too large Load diff

View file

@ -3170,7 +3170,7 @@ void fn_1_88B4(ModelData *arg0, Mtx arg1)
GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetArray(GX_VA_POS, lbl_1_data_27C, 12);
GXSetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);

View file

@ -1875,11 +1875,11 @@ void fn_1_806C(ModelData *arg0, Mtx arg1)
GXSetChanMatColor(GX_COLOR0A0, sp10);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_TEX_ST, GX_RGBA6, 0);
GXSetArray(GX_VA_POS, temp_r31->unkC, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetArray(GX_VA_POS, temp_r31->unkC, 12);
GXSetVtxDesc(GX_VA_NRM, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_TEX_S, GX_RGBA6, 0);
GXSetArray(GX_VA_NRM, temp_r31->unk14, 0xC);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetArray(GX_VA_NRM, temp_r31->unk14, 12);
lbl_1_bss_C = temp_r31->unk3C;
if (temp_r31->unk28->unk34 == 0) {
GXSetNumTevStages(1);
@ -1893,7 +1893,7 @@ void fn_1_806C(ModelData *arg0, Mtx arg1)
}
else {
GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetArray(GX_VA_TEX0, temp_r31->unk1C, 8);
temp_r29 = &temp_r31->unk2C[temp_r31->unk28->unk38[0]];
fn_1_7D60(temp_r29->unk80, temp_r29, 0);
@ -2600,7 +2600,7 @@ void fn_1_A390(ModelData *arg0, Mtx arg1)
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_TEX_ST, GX_RGBA8, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetNumTevStages(1);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO);

View file

@ -220,11 +220,11 @@ void fn_1_4FC(ModelData *model, Mtx matrix)
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
for (i = 0; i < 0; i++) {
s32 sp84[5] = { 0, 1, 1, 0, 1 };
float sp70[5] = { 1.0f, 2.0f, 2.5f, 0.0f, 0.0f };

View file

@ -775,13 +775,13 @@ void fn_1_2B68(ModelData *mdl, Mtx arg1)
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0U);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0U);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0U);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
GXSetCullMode(GX_CULL_NONE);
GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
GXSetNumTexGens(1);
GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3CU, 0U, 0x7DU);
GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY);
GXSetNumTevStages(1);
sp17.r = sp17.g = sp17.b = sp17.a = 255;

View file

@ -2,6 +2,7 @@
#include "dolphin/hw_regs.h"
#include "dolphin/os.h"
#include "dolphin/os/OSCache.h"
static ARCallback __AR_Callback;
static u32 __AR_Size;
@ -10,242 +11,333 @@ static u32 __AR_ExpansionSize;
static u32 __AR_StackPointer;
static u32 __AR_FreeBlocks;
static u32* __AR_BlockLength;
static u32 *__AR_BlockLength;
static volatile BOOL __AR_init_flag = FALSE;
static void __ARHandler(__OSInterrupt interrupt, OSContext* context);
static void __ARHandler(__OSInterrupt interrupt, OSContext *context);
static void __ARChecksize(void);
static void __ARClearArea(u32 start_addr, u32 length);
ARCallback ARRegisterDMACallback(ARCallback callback) {
ARCallback oldCb;
BOOL enabled;
oldCb = __AR_Callback;
enabled = OSDisableInterrupts();
__AR_Callback = callback;
OSRestoreInterrupts(enabled);
return oldCb;
}
// TODO import defines for magic numbers from other repos
u32 ARGetDMAStatus() {
BOOL enabled;
u32 val;
enabled = OSDisableInterrupts();
val = __DSPRegs[5] & 0x0200;
OSRestoreInterrupts(enabled);
return val;
}
void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length) {
BOOL enabled;
enabled = OSDisableInterrupts();
__DSPRegs[16] = (u16)(__DSPRegs[16] & ~0x3ff) | (u16)(mainmem_addr >> 16);
__DSPRegs[17] = (u16)(__DSPRegs[17] & ~0xffe0) | (u16)(mainmem_addr & 0xffff);
__DSPRegs[18] = (u16)(__DSPRegs[18] & ~0x3ff) | (u16)(aram_addr >> 16);
__DSPRegs[19] = (u16)(__DSPRegs[19] & ~0xffe0) | (u16)(aram_addr & 0xffff);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x8000) | (type << 15));
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x3ff) | (u16)(length >> 16);
__DSPRegs[21] = (u16)(__DSPRegs[21] & ~0xffe0) | (u16)(length & 0xffff);
OSRestoreInterrupts(enabled);
}
u32 ARAlloc(u32 length) {
u32 tmp;
BOOL enabled;
enabled = OSDisableInterrupts();
tmp = __AR_StackPointer;
__AR_StackPointer += length;
*__AR_BlockLength = length;
__AR_BlockLength++;
__AR_FreeBlocks--;
OSRestoreInterrupts(enabled);
return tmp;
}
#if NONMATCHING
u32 ARFree(u32* length) {
BOOL old;
old = OSDisableInterrupts();
__AR_BlockLength--;
if (length) {
*length = *__AR_BlockLength;
}
__AR_StackPointer -= *__AR_BlockLength;
__AR_FreeBlocks++;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
#else
/* clang-format off */
#pragma push
#pragma optimization_level 0
#pragma optimizewithasm off
asm u32 ARFree(u32* length) {
nofralloc
mflr r0
stw r0, 4(r1)
stwu r1, -0x18(r1)
stw r31, 0x14(r1)
mr r31, r3
bl OSDisableInterrupts
lwz r4, __AR_BlockLength
cmplwi r31, 0
addi r0, r4, -4
stw r0, __AR_BlockLength
beq lbl_8036DAB4
lwz r4, __AR_BlockLength
lwz r0, 0(r4)
stw r0, 0(r31)
lbl_8036DAB4:
lwz r5, __AR_BlockLength
lwz r4, __AR_FreeBlocks
lwz r6, 0(r5)
addi r0, r4, 1
lwz r5, __AR_StackPointer
stw r0, __AR_FreeBlocks
subf r0, r6, r5
stw r0, __AR_StackPointer
bl OSRestoreInterrupts
lwz r3, __AR_StackPointer
lwz r0, 0x1c(r1)
lwz r31, 0x14(r1)
addi r1, r1, 0x18
mtlr r0
blr
}
#pragma pop
/* clang-format on */
#endif
BOOL ARCheckInit() { return __AR_init_flag; }
u32 ARInit(u32* stack_index_addr, u32 num_entries) {
BOOL old;
u16 refresh;
if (__AR_init_flag == TRUE) {
return 0x4000;
}
old = OSDisableInterrupts();
__AR_Callback = NULL;
__OSSetInterruptHandler(__OS_INTERRUPT_DSP_ARAM, __ARHandler);
__OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_ARAM);
__AR_StackPointer = 0x4000;
__AR_FreeBlocks = num_entries;
__AR_BlockLength = stack_index_addr;
refresh = (u16)(__DSPRegs[13] & 0x000000ff);
__DSPRegs[13] = (u16)((__DSPRegs[13] & ~0x000000ff) | (refresh & 0x000000ff));
__ARChecksize();
__AR_init_flag = TRUE;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
u32 ARGetBaseAddress(void) { return 0x4000; }
void ARSetSize(void)
ARCallback ARRegisterDMACallback(ARCallback callback)
{
ARCallback oldCb;
BOOL enabled;
oldCb = __AR_Callback;
enabled = OSDisableInterrupts();
__AR_Callback = callback;
OSRestoreInterrupts(enabled);
return oldCb;
}
u32 ARGetSize() { return __AR_Size; }
u32 ARGetDMAStatus()
{
BOOL enabled;
u32 val;
enabled = OSDisableInterrupts();
val = __DSPRegs[5] & 0x0200;
OSRestoreInterrupts(enabled);
return val;
}
static void __ARHandler(__OSInterrupt interrupt, OSContext* context) {
void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length)
{
BOOL enabled;
OSContext exceptionContext;
u16 tmp;
enabled = OSDisableInterrupts();
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~0x00000088) | 0x20);
__DSPRegs[5] = tmp;
__DSPRegs[16] = (u16)(__DSPRegs[16] & ~0x3ff) | (u16)(mainmem_addr >> 16);
__DSPRegs[17] = (u16)(__DSPRegs[17] & ~0xffe0) | (u16)(mainmem_addr & 0xffff);
__DSPRegs[18] = (u16)(__DSPRegs[18] & ~0x3ff) | (u16)(aram_addr >> 16);
__DSPRegs[19] = (u16)(__DSPRegs[19] & ~0xffe0) | (u16)(aram_addr & 0xffff);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x8000) | (type << 15));
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x3ff) | (u16)(length >> 16);
__DSPRegs[21] = (u16)(__DSPRegs[21] & ~0xffe0) | (u16)(length & 0xffff);
OSRestoreInterrupts(enabled);
}
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
u32 ARAlloc(u32 length)
{
u32 tmp;
BOOL enabled;
if (__AR_Callback) {
(*__AR_Callback)();
}
enabled = OSDisableInterrupts();
tmp = __AR_StackPointer;
__AR_StackPointer += length;
*__AR_BlockLength = length;
__AR_BlockLength++;
__AR_FreeBlocks--;
OSRestoreInterrupts(enabled);
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
return tmp;
}
u32 ARFree(u32 *length)
{
BOOL old;
old = OSDisableInterrupts();
__AR_BlockLength--;
if (length) {
*length = *__AR_BlockLength;
}
__AR_StackPointer -= *__AR_BlockLength;
__AR_FreeBlocks++;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
BOOL ARCheckInit()
{
return __AR_init_flag;
}
u32 ARInit(u32 *stack_index_addr, u32 num_entries)
{
BOOL old;
u16 refresh;
if (__AR_init_flag == TRUE) {
return 0x4000;
}
old = OSDisableInterrupts();
__AR_Callback = NULL;
__OSSetInterruptHandler(__OS_INTERRUPT_DSP_ARAM, __ARHandler);
__OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_ARAM);
__AR_StackPointer = 0x4000;
__AR_FreeBlocks = num_entries;
__AR_BlockLength = stack_index_addr;
refresh = (u16)(__DSPRegs[13] & 0x000000ff);
__DSPRegs[13] = (u16)((__DSPRegs[13] & ~0x000000ff) | (refresh & 0x000000ff));
__ARChecksize();
__AR_init_flag = TRUE;
OSRestoreInterrupts(old);
return __AR_StackPointer;
}
void ARSetSize(void) { }
u32 ARGetBaseAddress(void)
{
return 0x4000;
}
u32 ARGetSize()
{
return __AR_Size;
}
static void __ARHandler(__OSInterrupt interrupt, OSContext *context)
{
OSContext exceptionContext;
u16 tmp;
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~0x00000088) | 0x20);
__DSPRegs[5] = tmp;
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
if (__AR_Callback) {
(*__AR_Callback)();
}
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
#define RoundUP32(x) (((u32)(x) + 32 - 1) & ~(32 - 1))
void __ARClearInterrupt(void) {
void __ARClearInterrupt(void)
{
u16 tmp;
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~(0x00000080 | 0x00000008)) | 0x00000020);
__DSPRegs[5] = tmp;
u16 tmp;
tmp = __DSPRegs[5];
tmp = (u16)((tmp & ~(0x00000080 | 0x00000008)) | 0x00000020);
__DSPRegs[5] = tmp;
}
u16 __ARGetInterruptStatus(void) { return ((u16)(__DSPRegs[5] & 0x0200)); }
static void __ARWaitForDMA(void) {
while (__DSPRegs[5] & 0x0200) {
}
u16 __ARGetInterruptStatus(void)
{
return ((u16)(__DSPRegs[5] & 0x0200));
}
static void __ARWriteDMA(u32 mmem_addr, u32 aram_addr, u32 length) {
static void __ARWaitForDMA(void)
{
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x8000);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__ARWaitForDMA();
__ARClearInterrupt();
while (__DSPRegs[5] & 0x0200) { }
}
static void __ARReadDMA(u32 mmem_addr, u32 aram_addr, u32 length) {
static void __ARWriteDMA(u32 mmem_addr, u32 aram_addr, u32 length)
{
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[20] = (u16)(__DSPRegs[20] | 0x8000);
__DSPRegs[20] = (u16)(__DSPRegs[20] & ~0x8000);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__ARWaitForDMA();
__ARWaitForDMA();
__ARClearInterrupt();
__ARClearInterrupt();
}
static void __ARChecksize(void) {
//TODO: Implement for this SDK version
}
static void __ARReadDMA(u32 mmem_addr, u32 aram_addr, u32 length)
{
__DSPRegs[16] = (u16)((__DSPRegs[16] & ~0x03ff) | (u16)(mmem_addr >> 16));
__DSPRegs[16 + 1] = (u16)((__DSPRegs[16 + 1] & ~0xffe0) | (u16)(mmem_addr & 0xffff));
__DSPRegs[18] = (u16)((__DSPRegs[18] & ~0x03ff) | (u16)(aram_addr >> 16));
__DSPRegs[18 + 1] = (u16)((__DSPRegs[18 + 1] & ~0xffe0) | (u16)(aram_addr & 0xffff));
__DSPRegs[20] = (u16)(__DSPRegs[20] | 0x8000);
__DSPRegs[20] = (u16)((__DSPRegs[20] & ~0x03ff) | (u16)(length >> 16));
__DSPRegs[20 + 1] = (u16)((__DSPRegs[20 + 1] & ~0xffe0) | (u16)(length & 0xffff));
__ARWaitForDMA();
__ARClearInterrupt();
}
void __ARChecksize(void)
{
u8 test_data_pad[0x20 + 31];
u8 dummy_data_pad[0x20 + 31];
u8 buffer_pad[0x20 + 31];
u32 *test_data;
u32 *dummy_data;
u32 *buffer;
u16 ARAM_mode;
u32 ARAM_size;
u32 i;
while (!(__DSPRegs[11] & 1))
;
ARAM_mode = 3;
ARAM_size = __AR_InternalSize = 0x1000000;
__DSPRegs[9] = (u16)((__DSPRegs[9] & ~(0x00000007 | 0x00000038)) | 0x20 | 2 | 1);
test_data = (u32 *)(RoundUP32((u32)(test_data_pad)));
dummy_data = (u32 *)(RoundUP32((u32)(dummy_data_pad)));
buffer = (u32 *)(RoundUP32((u32)(buffer_pad)));
for (i = 0; i < 8; i++) {
*(test_data + i) = 0xdeadbeef;
*(dummy_data + i) = 0xbad0bad0;
}
DCFlushRange((void *)test_data, 0x20);
DCFlushRange((void *)dummy_data, 0x20);
__AR_ExpansionSize = 0;
__ARWriteDMA((u32)dummy_data, ARAM_size, 0x20U);
__ARWriteDMA((u32)dummy_data, ARAM_size + 0x200000, 0x20U);
__ARWriteDMA((u32)dummy_data, ARAM_size + 0x01000000, 0x20U);
__ARWriteDMA((u32)dummy_data, ARAM_size + 0x200, 0x20U);
__ARWriteDMA((u32)dummy_data, ARAM_size + 0x400000, 0x20U);
memset((void *)buffer, 0, 0x20);
DCFlushRange((void *)buffer, 0x20);
__ARWriteDMA((u32)test_data, ARAM_size + 0x0000000, 0x20);
DCInvalidateRange((void *)buffer, 0x20);
__ARReadDMA((u32)buffer, ARAM_size + 0x0000000, 0x20);
PPCSync();
if (buffer[0] == test_data[0]) {
memset((void *)buffer, 0, 0x20);
DCFlushRange((void *)buffer, 0x20);
__ARReadDMA((u32)buffer, ARAM_size + 0x0200000, 0x20);
PPCSync();
if (buffer[0] == test_data[0]) {
ARAM_mode |= 0 << 1;
ARAM_size += 0x0200000;
__AR_ExpansionSize = 0x0200000;
}
else {
memset((void *)buffer, 0, 0x20);
DCFlushRange((void *)buffer, 0x20);
__ARReadDMA((u32)buffer, ARAM_size + 0x1000000, 0x20);
PPCSync();
if (buffer[0] == test_data[0]) {
ARAM_mode |= 4 << 1;
ARAM_size += 0x0400000;
__AR_ExpansionSize = 0x0400000;
}
else {
memset((void *)buffer, 0, 0x20);
DCFlushRange((void *)buffer, 0x20);
__ARReadDMA((u32)buffer, ARAM_size + 0x0000200, 0x20);
PPCSync();
if (buffer[0] == test_data[0]) {
ARAM_mode |= 8 << 1;
ARAM_size += 0x800000;
__AR_ExpansionSize = 0x0800000;
}
else {
memset((void *)buffer, 0, 0x20);
DCFlushRange((void *)buffer, 0x20);
__ARReadDMA((u32)buffer, ARAM_size + 0x0400000, 0x20);
PPCSync();
if (buffer[0] == test_data[0]) {
ARAM_mode |= 12 << 1;
ARAM_size += 0x1000000;
__AR_ExpansionSize = 0x1000000;
}
else {
ARAM_mode |= 16 << 1;
ARAM_size += 0x2000000;
__AR_ExpansionSize = 0x2000000;
}
}
}
}
__DSPRegs[9] = (u16)((__DSPRegs[9] & ~(0x07 | 0x38)) | ARAM_mode);
}
*(u32 *)OSPhysicalToUncached(0x00D0) = ARAM_size;
__AR_Size = ARAM_size;
}

586
src/dolphin/gx/GXAttr.c Normal file
View file

@ -0,0 +1,586 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
#define CHECK_ATTRPTR(line, attrPtr) ASSERTMSGLINE(line, (attrPtr) != NULL, "GXSetVtxDescv: attrPtr is NULL")
#define CHECK_ATTRNAME(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_PNMTXIDX && (attr) < GX_VA_MAX_ATTR, "GXSetVtxDesc: Invalid vertex attribute name")
#define CHECK_ATTRNAME2(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_POS && (attr) <= GX_VA_MAX_ATTR, "GXSetVtxAttrFmt: Invalid vertex attribute name")
#define CHECK_ATTRNAME3(line, attr) ASSERTMSGLINE(line, (attr) >= GX_VA_POS && (attr) <= GX_LIGHT_ARRAY, "GXSetArray: Invalid vertex attribute name")
#define CHECK_ATTRTYPE(line, type) ASSERTMSGLINE(line, (type) >= GX_NONE && (type) <= GX_INDEX16, "GXSetVtxDesc: Invalid vertex attribute type")
#define CHECK_VTXFMT(line, vtxfmt) ASSERTMSGLINE(line, (vtxfmt) < GX_MAX_VTXFMT, "GXSetVtxAttrFmt: Format Index is out of range")
#define CHECK_FRAC(line, frac) ASSERTMSGLINE(line, (frac) < 32, "GXSetVtxAttrFmt: Frac value is >= 32")
#define CHECK_LISTPTR(line, list) ASSERTMSGLINE(line, (list) != NULL, "GXSetVtxAttrFmt: list pointer is NULL")
static void __GXXfVtxSpecs(void)
{
u32 nCols = 0;
u32 nNrm;
u32 nTex;
u32 reg;
nCols = GET_REG_FIELD(gx->vcdLo, 2, 13) ? 1 : 0;
nCols += GET_REG_FIELD(gx->vcdLo, 2, 15) ? 1 : 0;
nNrm = gx->hasBiNrms ? 2 : gx->hasNrms ? 1 : 0;
nTex = 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 0) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 2) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 4) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 6) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 8) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 10) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 12) ? 1 : 0;
nTex += GET_REG_FIELD(gx->vcdHi, 2, 14) ? 1 : 0;
reg = (nCols) | (nNrm << 2) | (nTex << 4);
GX_WRITE_XF_REG(8, reg);
gx->bpSentNot = 1;
}
static inline void SETVCDATTR(GXAttr Attr, GXAttrType Type)
{
switch (Attr) {
case GX_VA_PNMTXIDX: SET_REG_FIELD(0xD4, gx->vcdLo, 1, 0, Type); break;
case GX_VA_TEX0MTXIDX: SET_REG_FIELD(0xD5, gx->vcdLo, 1, 1, Type); break;
case GX_VA_TEX1MTXIDX: SET_REG_FIELD(0xD6, gx->vcdLo, 1, 2, Type); break;
case GX_VA_TEX2MTXIDX: SET_REG_FIELD(0xD7, gx->vcdLo, 1, 3, Type); break;
case GX_VA_TEX3MTXIDX: SET_REG_FIELD(0xD8, gx->vcdLo, 1, 4, Type); break;
case GX_VA_TEX4MTXIDX: SET_REG_FIELD(0xD9, gx->vcdLo, 1, 5, Type); break;
case GX_VA_TEX5MTXIDX: SET_REG_FIELD(0xDA, gx->vcdLo, 1, 6, Type); break;
case GX_VA_TEX6MTXIDX: SET_REG_FIELD(0xDB, gx->vcdLo, 1, 7, Type); break;
case GX_VA_TEX7MTXIDX: SET_REG_FIELD(0xDC, gx->vcdLo, 1, 8, Type); break;
case GX_VA_POS: SET_REG_FIELD(0xDD, gx->vcdLo, 2, 9, Type); break;
case GX_VA_NRM:
if (Type != GX_NONE) {
gx->hasNrms = 1;
gx->hasBiNrms = 0;
gx->nrmType = Type;
} else {
gx->hasNrms = 0;
}
break;
case GX_VA_NBT:
if (Type != GX_NONE) {
gx->hasBiNrms = 1;
gx->hasNrms = 0;
gx->nrmType = Type;
} else {
gx->hasBiNrms = 0;
}
break;
case GX_VA_CLR0: SET_REG_FIELD(0xF6, gx->vcdLo, 2, 13, Type); break;
case GX_VA_CLR1: SET_REG_FIELD(0xF7, gx->vcdLo, 2, 15, Type); break;
case GX_VA_TEX0: SET_REG_FIELD(0xF8, gx->vcdHi, 2, 0, Type); break;
case GX_VA_TEX1: SET_REG_FIELD(0xF9, gx->vcdHi, 2, 2, Type); break;
case GX_VA_TEX2: SET_REG_FIELD(0xFA, gx->vcdHi, 2, 4, Type); break;
case GX_VA_TEX3: SET_REG_FIELD(0xFB, gx->vcdHi, 2, 6, Type); break;
case GX_VA_TEX4: SET_REG_FIELD(0xFC, gx->vcdHi, 2, 8, Type); break;
case GX_VA_TEX5: SET_REG_FIELD(0xFD, gx->vcdHi, 2, 10, Type); break;
case GX_VA_TEX6: SET_REG_FIELD(0xFE, gx->vcdHi, 2, 12, Type); break;
case GX_VA_TEX7: SET_REG_FIELD(0xFF, gx->vcdHi, 2, 14, Type); break;
}
}
void GXSetVtxDesc(GXAttr attr, GXAttrType type)
{
CHECK_GXBEGIN(0xCC, "GXSetVtxDesc");
CHECK_ATTRNAME(0xCF, attr);
CHECK_ATTRTYPE(0xD1, type);
SETVCDATTR(attr, type);
if (gx->hasNrms || gx->hasBiNrms) {
SET_REG_FIELD(0xD7, gx->vcdLo, 2, 11, gx->nrmType);
} else {
SET_REG_FIELD(0x00, gx->vcdLo, 2, 11, 0);
}
gx->dirtyState |= 8;
}
void GXSetVtxDescv(GXVtxDescList *attrPtr)
{
CHECK_GXBEGIN(0xF5, "GXSetVtxDescv");
CHECK_ATTRPTR(0xF6, attrPtr);
while (attrPtr->attr != 0xFF) {
CHECK_ATTRNAME(0xFB, attrPtr->attr);
CHECK_ATTRTYPE(0xFE, attrPtr->type);
SETVCDATTR(attrPtr->attr, attrPtr->type);
attrPtr++;
}
if (gx->hasNrms || gx->hasBiNrms) {
SET_REG_FIELD(0x107, gx->vcdLo, 2, 11, gx->nrmType);
} else {
SET_REG_FIELD(0x107, gx->vcdLo, 2, 11, 0);
}
gx->dirtyState |= 8;
}
void __GXSetVCD(void)
{
GX_WRITE_SOME_REG4(8, 0x50, gx->vcdLo, -12);
GX_WRITE_SOME_REG4(8, 0x60, gx->vcdHi, -12);
__GXXfVtxSpecs();
}
void __GXCalculateVLim() {
static u8 tbl1[] = { 0, 4, 1, 2 };
static u8 tbl2[] = { 0, 8, 1, 2 };
static u8 tbl3[] = { 0, 12, 1, 2 };
GXCompCnt nc = 0;
unsigned long vlm;
unsigned long b;
unsigned long vl;
unsigned long vh;
unsigned long va;
if (gx->vNum != 0) {
vl = gx->vcdLo;
vh = gx->vcdHi;
va = gx->vatA[0];
nc = GET_REG_FIELD(va, 1, 9);
vlm = GET_REG_FIELD(vl, 1, 0);
vlm += (u8)GET_REG_FIELD(vl, 1, 1);
vlm += (u8)GET_REG_FIELD(vl, 1, 2);
vlm += (u8)GET_REG_FIELD(vl, 1, 3);
vlm += (u8)GET_REG_FIELD(vl, 1, 4);
vlm += (u8)GET_REG_FIELD(vl, 1, 5);
vlm += (u8)GET_REG_FIELD(vl, 1, 6);
vlm += (u8)GET_REG_FIELD(vl, 1, 7);
vlm += (u8)GET_REG_FIELD(vl, 1, 8);
vlm += tbl3[(u8)GET_REG_FIELD(vl, 2, 9)];
if (nc == 1) {
b = 3;
} else {
b = 1;
}
vlm += tbl3[(u8)GET_REG_FIELD(vl, 2, 11)] * b;
vlm += tbl1[(u8)GET_REG_FIELD(vl, 2, 13)];
vlm += tbl1[(u8)GET_REG_FIELD(vl, 2, 15)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 0)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 2)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 4)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 6)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 8)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 10)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 12)];
vlm += tbl2[(u8)GET_REG_FIELD(vh, 2, 14)];
gx->vLim = vlm;
}
}
void GXGetVtxDesc(GXAttr attr, GXAttrType *type)
{
u32 cpType;
CHECK_GXBEGIN(0x185, "GXGetVtxDesc");
CHECK_ATTRNAME(0x187, attr);
switch (attr) {
case GX_VA_PNMTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 0); break;
case GX_VA_TEX0MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 1); break;
case GX_VA_TEX1MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 2); break;
case GX_VA_TEX2MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 3); break;
case GX_VA_TEX3MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 4); break;
case GX_VA_TEX4MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 5); break;
case GX_VA_TEX5MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 6); break;
case GX_VA_TEX6MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 7); break;
case GX_VA_TEX7MTXIDX: cpType = GET_REG_FIELD(gx->vcdLo, 1, 8); break;
case GX_VA_POS: cpType = GET_REG_FIELD(gx->vcdLo, 2, 9); break;
case GX_VA_NRM: cpType = gx->hasNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) : 0; break;
case GX_VA_NBT: cpType = gx->hasBiNrms ? GET_REG_FIELD(gx->vcdLo, 2, 11) : 0; break;
case GX_VA_CLR0: cpType = GET_REG_FIELD(gx->vcdLo, 2, 13); break;
case GX_VA_CLR1: cpType = GET_REG_FIELD(gx->vcdLo, 2, 15); break;
case GX_VA_TEX0: cpType = GET_REG_FIELD(gx->vcdHi, 2, 0); break;
case GX_VA_TEX1: cpType = GET_REG_FIELD(gx->vcdHi, 2, 2); break;
case GX_VA_TEX2: cpType = GET_REG_FIELD(gx->vcdHi, 2, 4); break;
case GX_VA_TEX3: cpType = GET_REG_FIELD(gx->vcdHi, 2, 6); break;
case GX_VA_TEX4: cpType = GET_REG_FIELD(gx->vcdHi, 2, 8); break;
case GX_VA_TEX5: cpType = GET_REG_FIELD(gx->vcdHi, 2, 10); break;
case GX_VA_TEX6: cpType = GET_REG_FIELD(gx->vcdHi, 2, 12); break;
case GX_VA_TEX7: cpType = GET_REG_FIELD(gx->vcdHi, 2, 14); break;
default: cpType = 0; break;
}
*type = cpType;
}
void GXGetVtxDescv(GXVtxDescList *vcd)
{
GXAttr attr;
CHECK_GXBEGIN(0x1BA, "GXGetVtxDescv");
CHECK_ATTRPTR(0x1BC, vcd);
for (attr = 0; attr < GX_VA_MAX_ATTR; attr++) {
vcd[attr].attr = attr;
GXGetVtxDesc(attr, &vcd[attr].type);
}
vcd[attr].attr = 0xFF;
}
void GXClearVtxDesc(void)
{
CHECK_GXBEGIN(0x1D3, "GXClearVtxDesc");
gx->vcdLo = 0;
SET_REG_FIELD(0x00, gx->vcdLo, 2, 9, 1);
gx->vcdHi = 0;
gx->hasNrms = 0;
gx->hasBiNrms = 0;
gx->dirtyState |= 8;
}
static inline void SETVAT(u32 *va, u32 *vb, u32 *vc, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 shft)
{
switch (attr) {
case GX_VA_POS:
SET_REG_FIELD(511, *va, 1, 0, cnt);
SET_REG_FIELD(512, *va, 3, 1, type);
SET_REG_FIELD(513, *va, 5, 4, shft);
break;
case GX_VA_NRM:
case GX_VA_NBT:
SET_REG_FIELD(521, *va, 3, 10, type);
if (cnt == GX_NRM_NBT3) {
SET_REG_FIELD(0, *va, 1, 9, 1);
SET_REG_FIELD(0, *va, 1, 31, 1);
} else {
SET_REG_FIELD(527, *va, 1, 9, cnt);
SET_REG_FIELD(528, *va, 1, 31, 0);
}
break;
case GX_VA_CLR0:
SET_REG_FIELD(0x215, *va, 1, 13, cnt);
SET_REG_FIELD(0x216, *va, 3, 14, type);
break;
case GX_VA_CLR1:
SET_REG_FIELD(0x219, *va, 1, 0x11, cnt);
SET_REG_FIELD(0x21A, *va, 3, 18, type);
break;
case GX_VA_TEX0:
SET_REG_FIELD(0x21D, *va, 1, 0x15, cnt);
SET_REG_FIELD(0x21E, *va, 3, 0x16, type);
SET_REG_FIELD(0x21F, *va, 5, 0x19, shft);
break;
case GX_VA_TEX1:
SET_REG_FIELD(0x222, *vb, 1, 0, cnt);
SET_REG_FIELD(0x223, *vb, 3, 1, type);
SET_REG_FIELD(0x224, *vb, 5, 4, shft);
break;
case GX_VA_TEX2:
SET_REG_FIELD(0x227, *vb, 1, 9, cnt);
SET_REG_FIELD(0x228, *vb, 3, 10, type);
SET_REG_FIELD(0x229, *vb, 5, 13, shft);
break;
case GX_VA_TEX3:
SET_REG_FIELD(0x22C, *vb, 1, 18, cnt);
SET_REG_FIELD(0x22D, *vb, 3, 19, type);
SET_REG_FIELD(0x22E, *vb, 5, 22, shft);
break;
case GX_VA_TEX4:
SET_REG_FIELD(0x231, *vb, 1, 27, cnt);
SET_REG_FIELD(0x232, *vb, 3, 28, type);
SET_REG_FIELD(0x233, *vc, 5, 0, shft);
break;
case GX_VA_TEX5:
SET_REG_FIELD(0x236, *vc, 1, 5, cnt);
SET_REG_FIELD(0x237, *vc, 3, 6, type);
SET_REG_FIELD(0x238, *vc, 5, 9, shft);
break;
case GX_VA_TEX6:
SET_REG_FIELD(0x23B, *vc, 1, 14, cnt);
SET_REG_FIELD(0x23C, *vc, 3, 15, type);
SET_REG_FIELD(0x23D, *vc, 5, 18, shft);
break;
case GX_VA_TEX7:
SET_REG_FIELD(0x240, *vc, 1, 23, cnt);
SET_REG_FIELD(0x241, *vc, 3, 24, type);
SET_REG_FIELD(0x242, *vc, 5, 27, shft);
break;
}
}
void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac)
{
u32 *va;
u32 *vb;
u32 *vc;
CHECK_GXBEGIN(0x252, "GXSetVtxAttrFmt");
CHECK_VTXFMT(0x253, vtxfmt);
CHECK_ATTRNAME2(0x255, attr);
CHECK_FRAC(0x256, frac);
va = &gx->vatA[vtxfmt];
vb = &gx->vatB[vtxfmt];
vc = &gx->vatC[vtxfmt];
SETVAT(va, vb, vc, attr, cnt, type, frac);
gx->dirtyState |= 0x10;
gx->dirtyVAT |= (u8)(1 << (u8)vtxfmt);
}
void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList *list)
{
u32 *va;
u32 *vb;
u32 *vc;
CHECK_GXBEGIN(0x27B, "GXSetVtxAttrFmtv");
CHECK_LISTPTR(0x27C, list);
CHECK_VTXFMT(0x27D, vtxfmt);
va = &gx->vatA[vtxfmt];
vb = &gx->vatB[vtxfmt];
vc = &gx->vatC[vtxfmt];
while (list->attr != GX_VA_NULL) {
CHECK_ATTRNAME2(0x286, list->attr);
CHECK_FRAC(0x287, list->frac);
SETVAT(va, vb, vc, list->attr, list->cnt, list->type, list->frac);
list++;
}
gx->dirtyState |= 0x10;
gx->dirtyVAT |= (u8)(1 << (u8)vtxfmt);
}
void __GXSetVAT(void)
{
u8 i;
for (i = 0; i < 8; i++) {
if (gx->dirtyVAT & (1 << (u8)i)) {
GX_WRITE_SOME_REG4(8, i | 0x70, gx->vatA[i], i - 12);
GX_WRITE_SOME_REG4(8, i | 0x80, gx->vatB[i], i - 12);
GX_WRITE_SOME_REG4(8, i | 0x90, gx->vatC[i], i - 12);
}
}
gx->dirtyVAT = 0;
}
void GXGetVtxAttrFmt(GXVtxFmt fmt, GXAttr attr, GXCompCnt *cnt, GXCompType *type, u8 *frac)
{
u32 *va;
u32 *vb;
u32 *vc;
CHECK_GXBEGIN(0x2CF, "GXGetVtxAttrFmt");
CHECK_VTXFMT(0x2D0, fmt);
va = &gx->vatA[fmt];
vb = &gx->vatB[fmt];
vc = &gx->vatC[fmt];
switch (attr) {
case GX_VA_POS:
*cnt = GET_REG_FIELD(*va, 1, 0);
*type = GET_REG_FIELD(*va, 3, 1);
*frac = (u8)(*va >> 4) & 0x1F; // GET_REG_FIELD(*va, 5, 4)
return;
case GX_VA_NRM:
case GX_VA_NBT:
*cnt = GET_REG_FIELD(*va, 1, 9);
if (*cnt == GX_TEX_ST && (u8)(*va >> 0x1F) != 0) {
*cnt = GX_NRM_NBT3;
}
*type = GET_REG_FIELD(*va, 3, 10);
*frac = 0;
return;
case GX_VA_CLR0:
*cnt = GET_REG_FIELD(*va, 1, 13);
*type = GET_REG_FIELD(*va, 3, 14);
*frac = 0;
return;
case GX_VA_CLR1:
*cnt = GET_REG_FIELD(*va, 1, 17);
*type = GET_REG_FIELD(*va, 3, 18);
*frac = 0;
return;
case GX_VA_TEX0:
*cnt = GET_REG_FIELD(*va, 1, 21);
*type = GET_REG_FIELD(*va, 3, 22);
*frac = (u8)(*va >> 0x19U) & 0x1F;
return;
case GX_VA_TEX1:
*cnt = GET_REG_FIELD(*vb, 1, 0);
*type = GET_REG_FIELD(*vb, 3, 1);
*frac = (u8)(*vb >> 4U) & 0x1F;
return;
case GX_VA_TEX2:
*cnt = GET_REG_FIELD(*vb, 1, 9);
*type = GET_REG_FIELD(*vb, 3, 10);
*frac = (u8)(*vb >> 0xDU) & 0x1F;
return;
case GX_VA_TEX3:
*cnt = GET_REG_FIELD(*vb, 1, 18);
*type = GET_REG_FIELD(*vb, 3, 19);
*frac = (u8)(*vb >> 0x16U) & 0x1F;
return;
case GX_VA_TEX4:
*cnt = GET_REG_FIELD(*vb, 1, 27);
*type = GET_REG_FIELD(*vb, 3, 28);
*frac = GET_REG_FIELD(*vc, 5, 0);
return;
case GX_VA_TEX5:
*cnt = GET_REG_FIELD(*vc, 1, 5);
*type = GET_REG_FIELD(*vc, 3, 6);
*frac = (u8)(*vc >> 9U) & 0x1F;
return;
case GX_VA_TEX6:
*cnt = GET_REG_FIELD(*vc, 1, 14);
*type = GET_REG_FIELD(*vc, 3, 15);
*frac = (u8)(*vc >> 0x12) & 0x1F;
return;
case GX_VA_TEX7:
*cnt = GET_REG_FIELD(*vc, 1, 23);
*type = GET_REG_FIELD(*vc, 3, 24);
*frac = (int)(*vc >> 0x1BU);
return;
default:
*cnt = GX_TEX_ST;
*type = GX_RGB565;
*frac = 0;
return;
}
}
void GXGetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList *vat)
{
GXAttr attr;
CHECK_GXBEGIN(0x330, "GXGetVtxAttrFmtv");
CHECK_LISTPTR(0x331, vat);
CHECK_VTXFMT(0x332, fmt);
for (attr = GX_VA_POS; attr < GX_VA_MAX_ATTR; attr++) {
vat->attr = attr;
GXGetVtxAttrFmt(fmt, attr, &vat->cnt, &vat->type, &vat->frac);
vat++;
}
vat->attr = GX_VA_NULL;
}
void GXSetArray(GXAttr attr, const void *base_ptr, u8 stride)
{
GXAttr cpAttr;
unsigned long phyAddr;
attr; // needed to match
CHECK_GXBEGIN(0x34F, "GXSetArray");
if (attr == GX_VA_NBT) {
attr = GX_VA_NRM;
}
CHECK_ATTRNAME3(0x352, attr);
cpAttr = attr - GX_VA_POS;
phyAddr = (u32)base_ptr & 0x3FFFFFFF;
GX_WRITE_SOME_REG2(8, cpAttr | 0xA0, phyAddr, cpAttr - 12);
GX_WRITE_SOME_REG3(8, cpAttr | 0xB0, stride, cpAttr - 12);
}
void GXInvalidateVtxCache(void)
{
CHECK_GXBEGIN(0x368, "GXInvalidateVtxCache");
GX_WRITE_U8(0x48);
}
void GXSetTexCoordGen2(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u32 mtx, GXBool normalize, u32 pt_texmtx)
{
u32 reg = 0;
u32 row;
u32 bumprow; // unused
u32 form;
GXAttr mtxIdAttr;
CHECK_GXBEGIN(0x392, "GXSetTexCoordGen");
ASSERTMSGLINE(0x393, dst_coord < 8, "GXSetTexCoordGen: Invalid coordinate Id");
form = 0;
row = 5;
switch (src_param) {
case GX_TG_POS: row = 0; form = 1; break;
case GX_TG_NRM: row = 1; form = 1; break;
case GX_TG_BINRM: row = 3; form = 1; break;
case GX_TG_TANGENT: row = 4; form = 1; break;
case GX_TG_COLOR0: row = 2; break;
case GX_TG_COLOR1: row = 2; break;
case GX_TG_TEX0: row = 5; break;
case GX_TG_TEX1: row = 6; break;
case GX_TG_TEX2: row = 7; break;
case GX_TG_TEX3: row = 8; break;
case GX_TG_TEX4: row = 9; break;
case GX_TG_TEX5: row = 10; break;
case GX_TG_TEX6: row = 11; break;
case GX_TG_TEX7: row = 12; break;
case GX_TG_TEXCOORD0: bumprow; break;
case GX_TG_TEXCOORD1: bumprow; break;
case GX_TG_TEXCOORD2: bumprow; break;
case GX_TG_TEXCOORD3: bumprow; break;
case GX_TG_TEXCOORD4: bumprow; break;
case GX_TG_TEXCOORD5: bumprow; break;
case GX_TG_TEXCOORD6: bumprow; break;
default:
ASSERTMSGLINE(0x3AF, 0, "GXSetTexCoordGen: Invalid source parameter");
break;
}
switch (func)
{
case GX_TG_MTX2x4:
SET_REG_FIELD(0x3B8, reg, 1, 1, 0);
SET_REG_FIELD(0x3B9, reg, 1, 2, form);
SET_REG_FIELD(0x3BA, reg, 3, 4, 0);
SET_REG_FIELD(0x3BB, reg, 5, 7, row);
break;
case GX_TG_MTX3x4:
SET_REG_FIELD(0x3BF, reg, 1, 1, 1);
SET_REG_FIELD(0x3C0, reg, 1, 2, form);
SET_REG_FIELD(0x3C1, reg, 3, 4, 0);
SET_REG_FIELD(0x3C2, reg, 5, 7, row);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
ASSERTMSGLINE(0x3CF, src_param >= 12 && src_param <= 18, "GXSetTexCoordGen: Bump source texture value is invalid");
SET_REG_FIELD(0x3D0, reg, 1, 1, 0);
SET_REG_FIELD(0x3D1, reg, 1, 2, form);
SET_REG_FIELD(0x3D2, reg, 3, 4, 1);
SET_REG_FIELD(0x3D3, reg, 5, 7, row);
SET_REG_FIELD(0x3D4, reg, 3, 12, src_param - 12);
SET_REG_FIELD(0x3D5, reg, 3, 15, func - 2);
break;
case GX_TG_SRTG:
SET_REG_FIELD(0x3D9, reg, 1, 1, 0);
SET_REG_FIELD(0x3DA, reg, 1, 2, form);
if (src_param == GX_TG_COLOR0) {
SET_REG_FIELD(0, reg, 3, 4, 2);
} else {
SET_REG_FIELD(0, reg, 3, 4, 3);
}
SET_REG_FIELD(0, reg, 5, 7, 2);
break;
default:
ASSERTMSGLINE(0x3E5, 0, "GXSetTexCoordGen: Invalid function");
break;
}
GX_WRITE_XF_REG(dst_coord + 0x40, reg);
reg = 0;
SET_REG_FIELD(0x3F8, reg, 6, 0, pt_texmtx - 64);
SET_REG_FIELD(0x3F9, reg, 1, 8, normalize);
GX_WRITE_XF_REG(dst_coord + 0x50, reg);
switch (dst_coord) {
case GX_TEXCOORD0: SET_REG_FIELD(0x402, gx->matIdxA, 6, 6, mtx); break;
case GX_TEXCOORD1: SET_REG_FIELD(0x403, gx->matIdxA, 6, 12, mtx); break;
case GX_TEXCOORD2: SET_REG_FIELD(0x404, gx->matIdxA, 6, 18, mtx); break;
case GX_TEXCOORD3: SET_REG_FIELD(0x405, gx->matIdxA, 6, 24, mtx); break;
case GX_TEXCOORD4: SET_REG_FIELD(0x406, gx->matIdxB, 6, 0, mtx); break;
case GX_TEXCOORD5: SET_REG_FIELD(0x407, gx->matIdxB, 6, 6, mtx); break;
case GX_TEXCOORD6: SET_REG_FIELD(0x408, gx->matIdxB, 6, 12, mtx); break;
default: SET_REG_FIELD(0x409, gx->matIdxB, 6, 18, mtx); break;
}
mtxIdAttr = dst_coord + 1;
__GXSetMatrixIndex(mtxIdAttr);
}
void GXSetNumTexGens(u8 nTexGens)
{
CHECK_GXBEGIN(0x41B, "GXSetNumTexGens");
SET_REG_FIELD(0x41D, gx->genMode, 4, 0, nTexGens);
GX_WRITE_XF_REG(0x3F, nTexGens);
gx->dirtyState |= 4;
}

335
src/dolphin/gx/GXBump.c Normal file
View file

@ -0,0 +1,335 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
#if DEBUG
#define GX_WRITE_SOME_REG5(a, b) \
do { \
GX_WRITE_U8(a); \
GX_WRITE_U32(b); \
__gxVerif->rasRegs[(b >> 24) & 0xFF] = b; \
} while (0)
#else
#define GX_WRITE_SOME_REG5(a, b) \
do { \
GX_WRITE_U8(a); \
GX_WRITE_U32(b); \
} while (0)
#endif
void GXSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexFormat format, GXIndTexBiasSel bias_sel, GXIndTexMtxID matrix_sel,
GXIndTexWrap wrap_s, GXIndTexWrap wrap_t, GXBool add_prev, GXBool utc_lod, GXIndTexAlphaSel alpha_sel)
{
u32 reg;
CHECK_GXBEGIN(0x92, "GXInitIndTexture");
reg = 0;
SET_REG_FIELD(0x81, reg, 2, 0, ind_stage);
SET_REG_FIELD(0x82, reg, 2, 2, format);
SET_REG_FIELD(0x83, reg, 3, 4, bias_sel);
SET_REG_FIELD(0x84, reg, 2, 7, alpha_sel);
SET_REG_FIELD(0x85, reg, 4, 9, matrix_sel);
SET_REG_FIELD(0x86, reg, 3, 13, wrap_s);
SET_REG_FIELD(0x87, reg, 3, 16, wrap_t);
SET_REG_FIELD(0x88, reg, 1, 19, utc_lod);
SET_REG_FIELD(0x89, reg, 1, 20, add_prev);
SET_REG_FIELD(0x8A, reg, 8, 24, tev_stage + 16);
GX_WRITE_SOME_REG5(0x61, reg);
gx->bpSentNot = 0;
}
void GXSetIndTexMtx(GXIndTexMtxID mtx_id, f32 offset[2][3], s8 scale_exp)
{
s32 mtx[6];
u32 reg;
u32 id;
CHECK_GXBEGIN(0xBA, "GXSetIndTexMtx");
switch (mtx_id) {
case GX_ITM_0:
case GX_ITM_1:
case GX_ITM_2:
id = mtx_id - 1;
break;
case GX_ITM_S0:
case GX_ITM_S1:
case GX_ITM_S2:
id = mtx_id - 5;
break;
case GX_ITM_T0:
case GX_ITM_T1:
case GX_ITM_T2:
id = mtx_id - 9;
break;
default:
id = 0;
break;
}
mtx[0] = (int)(1024.0f * offset[0][0]) & 0x7FF;
mtx[1] = (int)(1024.0f * offset[1][0]) & 0x7FF;
scale_exp += 0x11;
reg = 0;
SET_REG_FIELD(0xBD, reg, 11, 0, mtx[0]);
SET_REG_FIELD(0xBE, reg, 11, 11, mtx[1]);
SET_REG_FIELD(0xBF, reg, 2, 22, scale_exp & 3);
SET_REG_FIELD(0xC0, reg, 8, 24, id * 3 + 6);
GX_WRITE_SOME_REG5(0x61, reg);
mtx[2] = (int)(1024.0f * offset[0][1]) & 0x7FF;
mtx[3] = (int)(1024.0f * offset[1][1]) & 0x7FF;
reg = 0;
SET_REG_FIELD(0xC6, reg, 11, 0, mtx[2]);
SET_REG_FIELD(0xC7, reg, 11, 11, mtx[3]);
SET_REG_FIELD(0xC8, reg, 2, 22, (scale_exp >> 2) & 3);
SET_REG_FIELD(0xC9, reg, 8, 24, id * 3 + 7);
GX_WRITE_SOME_REG5(0x61, reg);
mtx[4] = (int)(1024.0f * offset[0][2]) & 0x7FF;
mtx[5] = (int)(1024.0f * offset[1][2]) & 0x7FF;
reg = 0;
SET_REG_FIELD(0xCF, reg, 11, 0, mtx[4]);
SET_REG_FIELD(0xD0, reg, 11, 11, mtx[5]);
SET_REG_FIELD(0xD1, reg, 2, 22, (scale_exp >> 4) & 3);
SET_REG_FIELD(0xD2, reg, 8, 24, id * 3 + 8);
GX_WRITE_SOME_REG5(0x61, reg);
gx->bpSentNot = 0;
}
void GXSetIndTexCoordScale(GXIndTexStageID ind_state, GXIndTexScale scale_s, GXIndTexScale scale_t)
{
CHECK_GXBEGIN(0xF9, "GXSetIndTexScale");
switch (ind_state) {
case GX_INDTEXSTAGE0:
SET_REG_FIELD(0xEA, gx->IndTexScale0, 4, 0, scale_s);
SET_REG_FIELD(0xEB, gx->IndTexScale0, 4, 4, scale_t);
SET_REG_FIELD(0xEC, gx->IndTexScale0, 8, 24, 0x25);
GX_WRITE_SOME_REG5(0x61, gx->IndTexScale0);
break;
case GX_INDTEXSTAGE1:
SET_REG_FIELD(0xF0, gx->IndTexScale0, 4, 8, scale_s);
SET_REG_FIELD(0xF1, gx->IndTexScale0, 4, 12, scale_t);
SET_REG_FIELD(0xF2, gx->IndTexScale0, 8, 24, 0x25);
GX_WRITE_SOME_REG5(0x61, gx->IndTexScale0);
break;
case GX_INDTEXSTAGE2:
SET_REG_FIELD(0xF6, gx->IndTexScale1, 4, 0, scale_s);
SET_REG_FIELD(0xF7, gx->IndTexScale1, 4, 4, scale_t);
SET_REG_FIELD(0xF8, gx->IndTexScale1, 8, 24, 0x26);
GX_WRITE_SOME_REG5(0x61, gx->IndTexScale1);
break;
case GX_INDTEXSTAGE3:
SET_REG_FIELD(0xFC, gx->IndTexScale1, 4, 8, scale_s);
SET_REG_FIELD(0xFD, gx->IndTexScale1, 4, 12, scale_t);
SET_REG_FIELD(0xFE, gx->IndTexScale1, 8, 24, 0x26);
GX_WRITE_SOME_REG5(0x61, gx->IndTexScale1);
break;
default:
ASSERTMSGLINE(0x115, 0, "GXSetIndTexCoordScale: Invalid Indirect Stage Id");
break;
}
gx->bpSentNot = 0;
}
void GXSetIndTexOrder(GXIndTexStageID ind_stage, GXTexCoordID tex_coord, GXTexMapID tex_map)
{
CHECK_GXBEGIN(0x12E, "GXSetIndTexOrder");
ASSERTMSGLINE(0x11D, tex_map < 8, "GXSetIndTexOrder: Invalid direct texture Id");
ASSERTMSGLINE(0x11E, tex_coord < 8, "GXSetIndTexOrder: Invalid texture coord");
switch (ind_stage) {
case GX_INDTEXSTAGE0:
SET_REG_FIELD(0x122, gx->iref, 3, 0, tex_map);
SET_REG_FIELD(0x123, gx->iref, 3, 3, tex_coord);
break;
case GX_INDTEXSTAGE1:
SET_REG_FIELD(0x126, gx->iref, 3, 6, tex_map);
SET_REG_FIELD(0x127, gx->iref, 3, 9, tex_coord);
break;
case GX_INDTEXSTAGE2:
SET_REG_FIELD(0x12A, gx->iref, 3, 12, tex_map);
SET_REG_FIELD(0x12B, gx->iref, 3, 15, tex_coord);
break;
case GX_INDTEXSTAGE3:
SET_REG_FIELD(0x12E, gx->iref, 3, 18, tex_map);
SET_REG_FIELD(0x12F, gx->iref, 3, 21, tex_coord);
break;
default:
ASSERTMSGLINE(0x132, 0, "GXSetIndTexOrder: Invalid Indirect Stage Id");
break;
}
GX_WRITE_SOME_REG5(0x61, gx->iref);
gx->dirtyState |= 3;
gx->bpSentNot = 0;
}
void GXSetNumIndStages(u8 nIndStages)
{
CHECK_GXBEGIN(0x144, "GXSetNumIndStages");
ASSERTMSGLINE(0x146, nIndStages <= 4, "GXSetNumIndStages: Exceeds max. number of indirect texture stages");
SET_REG_FIELD(0x147, gx->genMode, 3, 16, nIndStages);
gx->dirtyState |= 6;
}
#pragma dont_inline on
void GXSetTevDirect(GXTevStageID tev_stage)
{
CHECK_GXBEGIN(0x158, "GXSetTevDirect");
GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 0U, 0, 0);
}
void GXSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel)
{
GXIndTexWrap wrap = (replace_mode != 0) ? GX_ITW_0 : GX_ITW_OFF;
CHECK_GXBEGIN(0x16E, "GXSetTevIndWarp");
GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, (signed_offset != 0) ? GX_ITB_STU : GX_ITB_NONE, matrix_sel, wrap, wrap, 0U, 0, 0);
}
void GXSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u16 tilesize_s, u16 tilesize_t, u16 tilespacing_s, u16 tilespacing_t,
GXIndTexFormat format, GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel, GXIndTexAlphaSel alpha_sel)
{
GXIndTexWrap wrap_s;
GXIndTexWrap wrap_t;
f32 mtx[2][3];
CHECK_GXBEGIN(0x190, "GXSetTevIndTile");
ASSERTMSGLINE(0x191, tev_stage < 16, "GXSetTevIndTile: Invalid tev stage id");
ASSERTMSGLINE(0x192, ind_stage < 4, "GXSetTevIndTile: Invalid indirect stage id");
switch (tilesize_s) {
case 256:
wrap_s = GX_ITW_256;
break;
case 128:
wrap_s = GX_ITW_128;
break;
case 64:
wrap_s = GX_ITW_64;
break;
case 32:
wrap_s = GX_ITW_32;
break;
case 16:
wrap_s = GX_ITW_16;
break;
default:
ASSERTMSGLINE(0x19B, 0, "GXSetTevIndTile: Invalid tilesize for S coordinate");
wrap_s = GX_ITW_OFF;
break;
}
switch (tilesize_t) {
case 256:
wrap_t = GX_ITW_256;
break;
case 128:
wrap_t = GX_ITW_128;
break;
case 64:
wrap_t = GX_ITW_64;
break;
case 32:
wrap_t = GX_ITW_32;
break;
case 16:
wrap_t = GX_ITW_16;
break;
default:
ASSERTMSGLINE(0x1A7, 0, "GXSetTevIndTile: Invalid tilesize for T coordinate");
wrap_t = GX_ITW_OFF;
break;
}
mtx[0][0] = tilespacing_s / 1024.0f;
mtx[0][1] = mtx[0][2] = 0.0f;
mtx[1][1] = tilespacing_t / 1024.0f;
mtx[1][0] = mtx[1][2] = 0.0f;
GXSetIndTexMtx(matrix_sel, mtx, 0xA);
GXSetTevIndirect(tev_stage, ind_stage, format, bias_sel, matrix_sel, wrap_s, wrap_t, 0U, 1, alpha_sel);
}
#pragma dont_inline off
void GXSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel)
{
GXIndTexMtxID sm;
GXIndTexMtxID tm;
CHECK_GXBEGIN(0x1CF, "GXSetTevIndBumpST");
switch (matrix_sel) {
case GX_ITM_0:
sm = GX_ITM_S0;
tm = GX_ITM_T0;
break;
case GX_ITM_1:
sm = GX_ITM_S1;
tm = GX_ITM_T1;
break;
case GX_ITM_2:
sm = GX_ITM_S2;
tm = GX_ITM_T2;
break;
default:
ASSERTMSGLINE(0x1E0, 0, "GXSetTevIndBumpST: Invalid matrix selection");
break;
}
GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_ST, sm, GX_ITW_0, GX_ITW_0, 0U, 0, 0);
GXSetTevIndirect(tev_stage + 1, ind_stage, GX_ITF_8, GX_ITB_ST, tm, GX_ITW_0, GX_ITW_0, 1U, 0, 0);
GXSetTevIndirect(tev_stage + 2, ind_stage, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 1U, 0, 0);
}
void GXSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel)
{
CHECK_GXBEGIN(0x214, "GXSetTevIndBumpXYZ");
GXSetTevIndirect(tev_stage, ind_stage, GX_ITF_8, GX_ITB_STU, matrix_sel, GX_ITW_OFF, GX_ITW_OFF, 0U, 0, 0);
}
void GXSetTevIndRepeat(GXTevStageID tev_stage)
{
CHECK_GXBEGIN(0x231, "GXSetTevIndRepeat");
GXSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_0, GX_ITW_0, 1U, 0, 0);
}
void __GXUpdateBPMask(void)
{
u32 nIndStages;
u32 i;
u32 tmap;
u32 new_imask;
u32 nStages;
u32 new_dmask;
new_imask = 0;
new_dmask = 0;
nIndStages = GET_REG_FIELD(gx->genMode, 3, 16);
for (i = 0; i < nIndStages; i++) {
switch (i) {
case 0:
tmap = GET_REG_FIELD(gx->iref, 3, 0);
break;
case 1:
tmap = GET_REG_FIELD(gx->iref, 3, 6);
break;
case 2:
tmap = GET_REG_FIELD(gx->iref, 3, 12);
break;
case 3:
tmap = GET_REG_FIELD(gx->iref, 3, 18);
break;
}
new_imask |= 1 << tmap;
}
if ((u8)gx->bpMask != new_imask) {
SET_REG_FIELD(0x26E, gx->bpMask, 8, 0, new_imask);
GX_WRITE_SOME_REG5(0x61, gx->bpMask);
gx->bpSentNot = 0;
}
}
void __GXFlushTextureState(void)
{
GX_WRITE_SOME_REG5(0x61, gx->bpMask);
gx->bpSentNot = 0;
}

View file

@ -0,0 +1,83 @@
#include <string.h>
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
static struct __GXFifoObj DisplayListFifo;
static volatile struct __GXFifoObj *OldCPUFifo;
static struct __GXData_struct __savedGXdata;
void GXBeginDisplayList(void *list, u32 size)
{
struct __GXFifoObj *CPUFifo = (struct __GXFifoObj *)GXGetCPUFifo();
CHECK_GXBEGIN(0x89, "GXBeginDisplayList");
ASSERTMSGLINE(0x8A, !__GXData->inDispList, "GXBeginDisplayList: display list already in progress");
ASSERTMSGLINE(0x8B, (size & 0x1F) == 0, "GXBeginDisplayList: size is not 32 byte aligned");
ASSERTMSGLINE(0x8C, ((u32)list & 0x1F) == 0, "GXBeginDisplayList: list is not 32 byte aligned");
if (gx->dirtyState != 0) {
__GXSetDirtyState();
}
if (gx->dlSaveContext != 0) {
memcpy(&__savedGXdata, gx, sizeof(__savedGXdata));
}
DisplayListFifo.base = (u8 *)list;
DisplayListFifo.top = (u8 *)list + size - 4;
DisplayListFifo.size = size;
DisplayListFifo.count = 0;
DisplayListFifo.rdPtr = list;
DisplayListFifo.wrPtr = list;
gx->inDispList = 1;
GXSaveCPUFifo((GXFifoObj *)CPUFifo);
OldCPUFifo = CPUFifo;
GXSetCPUFifo((GXFifoObj *)&DisplayListFifo);
}
unsigned long GXEndDisplayList(void)
{
u32 ov;
BOOL enabled;
u32 cpenable;
CHECK_GXBEGIN(0xB5, "GXEndDisplayList");
ASSERTMSGLINE(0xB6, gx->inDispList == TRUE, "GXEndDisplayList: no display list in progress");
if (gx->dirtyState != 0) {
__GXSetDirtyState();
}
ov = (__piReg[5] >> 26) & 1;
__GXSaveCPUFifoAux(&DisplayListFifo);
ASSERTMSGLINE(0xC3, !ov, "GXEndDisplayList: display list commands overflowed buffer");
GXSetCPUFifo((GXFifoObj *)OldCPUFifo);
if (gx->dlSaveContext != 0) {
enabled = OSDisableInterrupts();
cpenable = gx->cpEnable;
memcpy(gx, &__savedGXdata, sizeof(*gx));
gx->cpEnable = cpenable;
OSRestoreInterrupts(enabled);
}
gx->inDispList = 0;
if (!ov) {
return DisplayListFifo.count;
}
return 0;
}
void GXCallDisplayList(const void *list, u32 nbytes)
{
CHECK_GXBEGIN(0xEC, "GXCallDisplayList");
ASSERTMSGLINE(0xED, !gx->inDispList, "GXCallDisplayList: display list already in progress");
ASSERTMSGLINE(0xEE, (nbytes & 0x1F) == 0, "GXCallDisplayList: nbytes is not 32 byte aligned");
ASSERTMSGLINE(0xEF, ((u32)list & 0x1F) == 0, "GXCallDisplayList: list is not 32 byte aligned");
if (gx->dirtyState != 0) {
__GXSetDirtyState();
}
if (*(u32 *)&gx->vNumNot == 0) { // checks both vNum and bpSent
__GXSendFlushPrim();
}
GX_WRITE_U8(0x40);
GX_WRITE_U32((u32)list);
GX_WRITE_U32(nbytes);
}

559
src/dolphin/gx/GXFifo.c Normal file
View file

@ -0,0 +1,559 @@
#include <dolphin/PPCArch.h>
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <stddef.h>
#include <dolphin/gx/GXPriv.h>
static OSThread *__GXCurrentThread;
static GXBool CPGPLinked;
static BOOL GXOverflowSuspendInProgress;
static GXBreakPtCallback BreakPointCB;
static u32 __GXOverflowCount;
struct __GXFifoObj *CPUFifo;
struct __GXFifoObj *GPFifo;
void *__GXCurrentBP;
static void __GXFifoReadEnable(void);
static void __GXFifoReadDisable(void);
static void __GXFifoLink(u8 arg0);
static void __GXWriteFifoIntEnable(u8 arg0, u8 arg1);
static void __GXWriteFifoIntReset(u8 arg0, u8 arg1);
static void GXOverflowHandler(s16 interrupt, OSContext *context)
{
ASSERTLINE(0x179, !GXOverflowSuspendInProgress);
__GXOverflowCount++;
__GXWriteFifoIntEnable(0, 1);
__GXWriteFifoIntReset(1, 0);
GXOverflowSuspendInProgress = TRUE;
OSSuspendThread(__GXCurrentThread);
}
static void GXUnderflowHandler(s16 interrupt, OSContext *context)
{
ASSERTLINE(0x1A3, GXOverflowSuspendInProgress);
OSResumeThread(__GXCurrentThread);
GXOverflowSuspendInProgress = FALSE;
__GXWriteFifoIntReset(1U, 1U);
__GXWriteFifoIntEnable(1U, 0U);
}
#define SOME_SET_REG_MACRO(reg, size, shift, val) \
do { \
(reg) = (u32)__rlwimi((u32)(reg), (val), (shift), (32 - (shift) - (size)), (31 - (shift))); \
} while (0);
static void GXBreakPointHandler(s16 interrupt, OSContext *context)
{
OSContext exceptionContext;
SOME_SET_REG_MACRO(gx->cpEnable, 1, 5, 0);
GX_SET_CP_REG(1, gx->cpEnable);
if (BreakPointCB != NULL) {
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
BreakPointCB();
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
}
static void GXCPInterruptHandler(s16 interrupt, OSContext *context)
{
gx->cpStatus = GX_GET_CP_REG(0);
if (GET_REG_FIELD(gx->cpEnable, 1, 3) && GET_REG_FIELD(gx->cpStatus, 1, 1)) {
GXUnderflowHandler(interrupt, context);
}
if (GET_REG_FIELD(gx->cpEnable, 1, 2) && GET_REG_FIELD(gx->cpStatus, 1, 0)) {
GXOverflowHandler(interrupt, context);
}
if (GET_REG_FIELD(gx->cpEnable, 1, 5) && GET_REG_FIELD(gx->cpStatus, 1, 4)) {
GXBreakPointHandler(interrupt, context);
}
}
void GXInitFifoBase(GXFifoObj *fifo, void *base, u32 size)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
ASSERTMSGLINE(0x21E, realFifo != CPUFifo, "GXInitFifoBase: fifo is attached to CPU");
ASSERTMSGLINE(0x220, realFifo != GPFifo, "GXInitFifoBase: fifo is attached to GP");
ASSERTMSGLINE(0x222, ((u32)base & 0x1F) == 0, "GXInitFifoBase: base must be 32B aligned");
ASSERTMSGLINE(0x224, base != NULL, "GXInitFifoBase: base pointer is NULL");
ASSERTMSGLINE(0x226, (size & 0x1F) == 0, "GXInitFifoBase: size must be 32B aligned");
ASSERTMSGLINE(0x228, size >= 0x10000, "GXInitFifoBase: fifo is not large enough");
realFifo->base = base;
realFifo->top = (u8 *)base + size - 4;
realFifo->size = size;
realFifo->count = 0;
GXInitFifoLimits(fifo, size - 0x4000, (size >> 1) & ~0x1F);
GXInitFifoPtrs(fifo, base, base);
}
void GXInitFifoPtrs(GXFifoObj *fifo, void *readPtr, void *writePtr)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
BOOL enabled;
ASSERTMSGLINE(0x250, realFifo != CPUFifo, "GXInitFifoPtrs: fifo is attached to CPU");
ASSERTMSGLINE(0x252, realFifo != GPFifo, "GXInitFifoPtrs: fifo is attached to GP");
ASSERTMSGLINE(0x254, ((u32)readPtr & 0x1F) == 0, "GXInitFifoPtrs: readPtr not 32B aligned");
ASSERTMSGLINE(0x256, ((u32)writePtr & 0x1F) == 0, "GXInitFifoPtrs: writePtr not 32B aligned");
ASSERTMSGLINE(0x259, realFifo->base <= readPtr && readPtr < realFifo->top, "GXInitFifoPtrs: readPtr not in fifo range");
ASSERTMSGLINE(0x25C, realFifo->base <= writePtr && writePtr < realFifo->top, "GXInitFifoPtrs: writePtr not in fifo range");
enabled = OSDisableInterrupts();
realFifo->rdPtr = readPtr;
realFifo->wrPtr = writePtr;
realFifo->count = (u8 *)writePtr - (u8 *)readPtr;
if (realFifo->count < 0) {
realFifo->count += realFifo->size;
}
OSRestoreInterrupts(enabled);
}
void GXInitFifoLimits(GXFifoObj *fifo, u32 hiWatermark, u32 loWatermark)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
ASSERTMSGLINE(0x281, realFifo != GPFifo, "GXInitFifoLimits: fifo is attached to GP");
ASSERTMSGLINE(0x283, (hiWatermark & 0x1F) == 0, "GXInitFifoLimits: hiWatermark not 32B aligned");
ASSERTMSGLINE(0x285, (loWatermark & 0x1F) == 0, "GXInitFifoLimits: loWatermark not 32B aligned");
ASSERTMSGLINE(0x287, hiWatermark < realFifo->top - realFifo->base, "GXInitFifoLimits: hiWatermark too large");
ASSERTMSGLINE(0x289, loWatermark < hiWatermark, "GXInitFifoLimits: hiWatermark below lo watermark");
realFifo->hiWatermark = hiWatermark;
realFifo->loWatermark = loWatermark;
}
void GXSetCPUFifo(GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
BOOL enabled = OSDisableInterrupts();
CPUFifo = realFifo;
if (CPUFifo == GPFifo)
{
u32 reg = 0;
__piReg[3] = (u32)realFifo->base & 0x3FFFFFFF;
__piReg[4] = (u32)realFifo->top & 0x3FFFFFFF;
SET_REG_FIELD(0x294, reg, 21, 5, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 5);
SET_REG_FIELD(0x295, reg, 1, 26, 0);
__piReg[5] = reg;
CPGPLinked = GX_TRUE;
__GXWriteFifoIntReset(1, 1);
__GXWriteFifoIntEnable(1, 0);
__GXFifoLink(1);
}
else
{
u32 reg;
if (CPGPLinked)
{
__GXFifoLink(0);
CPGPLinked = GX_FALSE;
}
__GXWriteFifoIntEnable(0, 0);
reg = 0;
__piReg[3] = (u32)realFifo->base & 0x3FFFFFFF;
__piReg[4] = (u32)realFifo->top & 0x3FFFFFFF;
SET_REG_FIELD(0x2B7, reg, 21, 5, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 5);
SET_REG_FIELD(0x2B8, reg, 1, 26, 0);
__piReg[5] = reg;
}
__sync();
OSRestoreInterrupts(enabled);
}
void GXSetGPFifo(GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
BOOL enabled = OSDisableInterrupts();
__GXFifoReadDisable();
__GXWriteFifoIntEnable(0, 0);
GPFifo = realFifo;
GX_SET_CP_REG(16, (u32)realFifo->base & 0xFFFF);
GX_SET_CP_REG(18, (u32)realFifo->top & 0xFFFF);
GX_SET_CP_REG(24, realFifo->count & 0xFFFF);
GX_SET_CP_REG(26, (u32)realFifo->wrPtr & 0xFFFF);
GX_SET_CP_REG(28, (u32)realFifo->rdPtr & 0xFFFF);
GX_SET_CP_REG(20, (u32)realFifo->hiWatermark & 0xFFFF);
GX_SET_CP_REG(22, (u32)realFifo->loWatermark & 0xFFFF);
GX_SET_CP_REG(17, ((u32)realFifo->base & 0x3FFFFFFF) >> 16);
GX_SET_CP_REG(19, ((u32)realFifo->top & 0x3FFFFFFF) >> 16);
GX_SET_CP_REG(25, realFifo->count >> 16);
GX_SET_CP_REG(27, ((u32)realFifo->wrPtr & 0x3FFFFFFF) >> 16);
GX_SET_CP_REG(29, ((u32)realFifo->rdPtr & 0x3FFFFFFF) >> 16);
GX_SET_CP_REG(21, (u32)realFifo->hiWatermark >> 16);
GX_SET_CP_REG(23, (u32)realFifo->loWatermark >> 16);
__sync();
if (CPUFifo == GPFifo) {
CPGPLinked = GX_TRUE;
__GXWriteFifoIntEnable(1, 0);
__GXFifoLink(1);
}
else {
CPGPLinked = GX_FALSE;
__GXWriteFifoIntEnable(0, 0);
__GXFifoLink(0);
}
__GXWriteFifoIntReset(1, 1);
__GXFifoReadEnable();
OSRestoreInterrupts(enabled);
}
void GXSaveCPUFifo(GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
ASSERTMSGLINE(0x343, realFifo == CPUFifo, "GXSaveCPUFifo: fifo is not attached to CPU");
__GXSaveCPUFifoAux(realFifo);
}
#define SOME_MACRO1(fifo) \
do { \
u32 temp = GX_GET_CP_REG(29) << 16; \
temp |= GX_GET_CP_REG(28); \
fifo->rdPtr = OSPhysicalToCached(temp); \
} while (0)
#define SOME_MACRO2(fifo) \
do { \
u32 temp = GX_GET_CP_REG(25) << 16; \
temp |= GX_GET_CP_REG(24); \
fifo->count = temp; \
} while (0)
void __GXSaveCPUFifoAux(struct __GXFifoObj *realFifo)
{
BOOL enabled = OSDisableInterrupts();
GXFlush();
realFifo->base = OSPhysicalToCached(__piReg[3]);
realFifo->top = OSPhysicalToCached(__piReg[4]);
realFifo->wrPtr = OSPhysicalToCached(__piReg[5] & 0xFBFFFFFF);
if (CPGPLinked) {
SOME_MACRO1(realFifo);
SOME_MACRO2(realFifo);
} else {
realFifo->count = (u8 *)realFifo->wrPtr - (u8 *)realFifo->rdPtr;
if (realFifo->count < 0)
realFifo->count += realFifo->size;
}
OSRestoreInterrupts(enabled);
}
void GXSaveGPFifo(GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
unsigned long cpStatus;
unsigned char readIdle;
unsigned long temp;
ASSERTMSGLINE(0x38C, realFifo == GPFifo, "GXSaveGPFifo: fifo is not attached to GP");
cpStatus = GX_GET_CP_REG(0);
readIdle = GET_REG_FIELD(cpStatus, 1, 2);
ASSERTMSGLINE(0x393, readIdle, "GXSaveGPFifo: GP is not idle");
SOME_MACRO1(realFifo);
SOME_MACRO2(realFifo);
}
void GXGetGPStatus(GXBool *overhi, GXBool *underlow, GXBool *readIdle, GXBool *cmdIdle, GXBool *brkpt)
{
gx->cpStatus = GX_GET_CP_REG(0);
*overhi = GET_REG_FIELD(gx->cpStatus, 1, 0);
*underlow = (int)GET_REG_FIELD(gx->cpStatus, 1, 1);
*readIdle = (int)GET_REG_FIELD(gx->cpStatus, 1, 2);
*cmdIdle = (int)GET_REG_FIELD(gx->cpStatus, 1, 3);
*brkpt = (int)GET_REG_FIELD(gx->cpStatus, 1, 4);
}
void GXGetFifoStatus(GXFifoObj *fifo, GXBool *overhi, GXBool *underflow, u32 *fifoCount, GXBool *cpuWrite, GXBool *gpRead, GXBool *fifowrap)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
*underflow = GX_FALSE;
*overhi = GX_FALSE;
*fifoCount = 0;
*fifowrap = GX_FALSE;
if (realFifo == GPFifo) {
SOME_MACRO1(realFifo);
SOME_MACRO2(realFifo);
}
if (realFifo == CPUFifo) {
GXFlush();
__GXSaveCPUFifoAux(realFifo);
*fifowrap = (int)GET_REG_FIELD(GX_GET_PI_REG(5), 1, 26);
}
*overhi = (realFifo->count > realFifo->hiWatermark);
*underflow = (realFifo->count < realFifo->loWatermark);
*fifoCount = (realFifo->count);
*cpuWrite = (CPUFifo == realFifo);
*gpRead = (GPFifo == realFifo);
}
void GXGetFifoPtrs(GXFifoObj *fifo, void **readPtr, void **writePtr)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
if (realFifo == CPUFifo) {
realFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF);
}
if (realFifo == GPFifo) {
SOME_MACRO1(realFifo);
SOME_MACRO2(realFifo);
}
else {
realFifo->count = (u8 *)realFifo->wrPtr - (u8 *)realFifo->rdPtr;
if (realFifo->count < 0) {
realFifo->count += realFifo->size;
}
}
*readPtr = realFifo->rdPtr;
*writePtr = realFifo->wrPtr;
}
void *GXGetFifoBase(const GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
return realFifo->base;
}
u32 GXGetFifoSize(const GXFifoObj *fifo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
return realFifo->size;
}
void GXGetFifoLimits(const GXFifoObj *fifo, u32 *hi, u32 *lo)
{
struct __GXFifoObj *realFifo = (struct __GXFifoObj *)fifo;
*hi = realFifo->hiWatermark;
*lo = realFifo->loWatermark;
}
GXBreakPtCallback GXSetBreakPtCallback(GXBreakPtCallback cb)
{
GXBreakPtCallback oldcb = BreakPointCB;
BOOL enabled = OSDisableInterrupts();
BreakPointCB = cb;
OSRestoreInterrupts(enabled);
return oldcb;
}
void *__GXCurrentBP;
void GXEnableBreakPt(void *break_pt)
{
BOOL enabled = OSDisableInterrupts();
__GXFifoReadDisable();
GX_SET_CP_REG(30, (u32)break_pt);
GX_SET_CP_REG(31, ((u32)break_pt >> 16) & 0x3FFF);
SOME_SET_REG_MACRO(gx->cpEnable, 1, 1, 1);
SOME_SET_REG_MACRO(gx->cpEnable, 1, 5, 1);
GX_SET_CP_REG(1, gx->cpEnable);
__GXCurrentBP = break_pt;
__GXFifoReadEnable();
OSRestoreInterrupts(enabled);
}
void GXDisableBreakPt(void)
{
BOOL enabled = OSDisableInterrupts();
SOME_SET_REG_MACRO(gx->cpEnable, 1, 1, 0);
SOME_SET_REG_MACRO(gx->cpEnable, 1, 5, 0);
GX_SET_CP_REG(1, gx->cpEnable);
__GXCurrentBP = NULL;
OSRestoreInterrupts(enabled);
}
void __GXFifoInit(void)
{
__OSSetInterruptHandler(0x11, GXCPInterruptHandler);
__OSUnmaskInterrupts(0x4000);
__GXCurrentThread = OSGetCurrentThread();
GXOverflowSuspendInProgress = FALSE;
CPUFifo = NULL;
GPFifo = NULL;
}
static void __GXFifoReadEnable(void)
{
SET_REG_FIELD(0, gx->cpEnable, 1, 0, 1);
GX_SET_CP_REG(1, gx->cpEnable);
}
static void __GXFifoReadDisable(void)
{
SET_REG_FIELD(0, gx->cpEnable, 1, 0, 0);
GX_SET_CP_REG(1, gx->cpEnable);
}
static void __GXFifoLink(u8 en)
{
SET_REG_FIELD(0x4DA, gx->cpEnable, 1, 4, (en != 0) ? 1 : 0);
GX_SET_CP_REG(1, gx->cpEnable);
}
static void __GXWriteFifoIntEnable(u8 hiWatermarkEn, u8 loWatermarkEn)
{
SET_REG_FIELD(0x4F0, gx->cpEnable, 1, 2, hiWatermarkEn);
SET_REG_FIELD(0x4F1, gx->cpEnable, 1, 3, loWatermarkEn);
GX_SET_CP_REG(1, gx->cpEnable);
}
static void __GXWriteFifoIntReset(u8 hiWatermarkClr, u8 loWatermarkClr)
{
SET_REG_FIELD(0x508, gx->cpClr, 1, 0, hiWatermarkClr);
SET_REG_FIELD(0x509, gx->cpClr, 1, 1, loWatermarkClr);
GX_SET_CP_REG(2, gx->cpClr);
}
void __GXInsaneWatermark(void)
{
struct __GXFifoObj *realFifo = GPFifo;
realFifo->hiWatermark = realFifo->loWatermark + 512;
GX_SET_CP_REG(20, (realFifo->hiWatermark & 0x3FFFFFFF) & 0xFFFF);
GX_SET_CP_REG(21, (realFifo->hiWatermark & 0x3FFFFFFF) >> 16);
}
void __GXCleanGPFifo(void)
{
GXFifoObj dummyFifo;
GXFifoObj *gpFifo = GXGetGPFifo();
GXFifoObj *cpuFifo = GXGetCPUFifo();
void *base = GXGetFifoBase(gpFifo);
dummyFifo = *gpFifo;
GXInitFifoPtrs(&dummyFifo, base, base);
GXSetGPFifo(&dummyFifo);
if (cpuFifo == gpFifo) {
GXSetCPUFifo(&dummyFifo);
}
GXInitFifoPtrs(gpFifo, base, base);
GXSetGPFifo(gpFifo);
if (cpuFifo == gpFifo) {
GXSetCPUFifo(cpuFifo);
}
}
OSThread *GXSetCurrentGXThread(void)
{
BOOL enabled;
struct OSThread *prev;
enabled = OSDisableInterrupts();
prev = __GXCurrentThread;
ASSERTMSGLINE(0x561, !GXOverflowSuspendInProgress, "GXSetCurrentGXThread: Two threads cannot generate GX commands at the same time!");
__GXCurrentThread = OSGetCurrentThread();
OSRestoreInterrupts(enabled);
return prev;
}
OSThread *GXGetCurrentGXThread(void)
{
return __GXCurrentThread;
}
GXFifoObj *GXGetCPUFifo(void)
{
return (GXFifoObj *)CPUFifo;
}
GXFifoObj *GXGetGPFifo(void)
{
return (GXFifoObj *)GPFifo;
}
u32 GXGetOverflowCount(void)
{
return __GXOverflowCount;
}
u32 GXResetOverflowCount(void)
{
u32 oldcount;
oldcount = __GXOverflowCount;
__GXOverflowCount = 0;
return oldcount;
}
// NONMATCHING
volatile void *GXRedirectWriteGatherPipe(void *ptr)
{
u32 reg = 0;
BOOL enabled = OSDisableInterrupts();
CHECK_GXBEGIN(0x5D5, "GXRedirectWriteGatherPipe");
ASSERTLINE(0x5D6, OFFSET(ptr, 32) == 0);
ASSERTLINE(0x5D8, !IsWGPipeRedirected);
GXFlush();
while (PPCMfwpar() & 1) { }
PPCMtwpar((u32)OSUncachedToPhysical((void *)GXFIFO_ADDR));
if (CPGPLinked) {
__GXFifoLink(0);
__GXWriteFifoIntEnable(0, 0);
}
CPUFifo->wrPtr = OSPhysicalToCached(GX_GET_PI_REG(5) & 0xFBFFFFFF);
GX_SET_PI_REG(3, 0);
GX_SET_PI_REG(4, 0x04000000);
SET_REG_FIELD(0x5F7, reg, 21, 5, ((u32)ptr & 0x3FFFFFFF) >> 5);
reg &= 0xFBFFFFFF;
GX_SET_PI_REG(5, reg);
PPCSync();
OSRestoreInterrupts(enabled);
return (volatile void *)GXFIFO_ADDR;
}
// NONMATCHING
void GXRestoreWriteGatherPipe(void)
{
u32 reg = 0; // r31
u32 i; // r29
BOOL enabled; // r28
ASSERTLINE(0x610, IsWGPipeRedirected);
enabled = OSDisableInterrupts();
for (i = 0; i < 31; i++) {
GXWGFifo.u8 = 0;
}
PPCSync();
while (PPCMfwpar() & 1) { }
PPCMtwpar((u32)OSUncachedToPhysical((void *)GXFIFO_ADDR));
GX_SET_PI_REG(3, (u32)CPUFifo->base & 0x3FFFFFFF);
GX_SET_PI_REG(4, (u32)CPUFifo->top & 0x3FFFFFFF);
SET_REG_FIELD(0x62A, reg, 21, 5, ((u32)CPUFifo->wrPtr & 0x3FFFFFFF) >> 5);
reg &= 0xFBFFFFFF;
GX_SET_PI_REG(5, reg);
if (CPGPLinked) {
__GXWriteFifoIntReset(1, 1);
__GXWriteFifoIntEnable(1, 0);
__GXFifoLink(1);
}
PPCSync();
OSRestoreInterrupts(enabled);
}

604
src/dolphin/gx/GXFrameBuf.c Normal file
View file

@ -0,0 +1,604 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
GXRenderModeObj GXNtsc240Ds = { 1, 640, 240, 240, 40, 0, 640, 480, 0, 0, 0,
{ 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 GXNtsc240DsAa = { 1, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXNtsc240Int = { 0, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0,
{ 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 GXNtsc240IntAa = { 0, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXNtsc480IntDf = { 0, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 = { 0, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 GXNtsc480IntAa = { 0, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } };
GXRenderModeObj GXNtsc480Prog = { 2, 640, 480, 480, 40, 0, 640, 480, 0, 0, 0,
{ 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 GXNtsc480ProgSoft = { 2, 640, 480, 480, 40, 0, 640, 480, 0, 0, 0,
{ 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 GXNtsc480ProgAa = { 2, 640, 242, 480, 40, 0, 640, 480, 0, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } };
GXRenderModeObj GXMpal240Ds = { 9, 640, 240, 240, 40, 0, 640, 480, 0, 0, 0,
{ 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 GXMpal240DsAa = { 9, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXMpal240Int = { 8, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0,
{ 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 GXMpal240IntAa = { 8, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXMpal480IntDf = { 8, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 GXMpal480Int = { 8, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 GXMpal480IntAa = { 8, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } };
GXRenderModeObj GXPal264Ds = { 5, 640, 264, 264, 40, 11, 640, 528, 0, 0, 0,
{ 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 GXPal264DsAa = { 5, 640, 264, 264, 40, 11, 640, 528, 0, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXPal264Int = { 4, 640, 264, 264, 40, 23, 640, 528, 0, 1, 0,
{ 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 GXPal264IntAa = { 4, 640, 264, 264, 40, 23, 640, 528, 0, 1, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXPal528IntDf = { 4, 640, 528, 528, 40, 23, 640, 528, 1, 0, 0,
{ 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 GXPal528Int = { 4, 640, 528, 528, 40, 23, 640, 528, 1, 0, 0,
{ 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 GXPal524IntAa = { 4, 640, 264, 524, 40, 23, 640, 524, 1, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } };
GXRenderModeObj GXEurgb60Hz240Ds = { 21, 640, 240, 240, 40, 0, 640, 480, 0, 0, 0,
{ 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 GXEurgb60Hz240DsAa = { 21, 640, 240, 240, 40, 0, 640, 480, 0, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXEurgb60Hz240Int = { 20, 640, 240, 240, 40, 0, 640, 480, 0, 1, 0,
{ 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 GXEurgb60Hz240IntAa = { 20, 640, 240, 240, 40, 0, 640, 480, 0, 1, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 0, 0, 21, 22, 21, 0, 0 } };
GXRenderModeObj GXEurgb60Hz480IntDf = { 20, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 GXEurgb60Hz480Int = { 20, 640, 480, 480, 40, 0, 640, 480, 1, 0, 0,
{ 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 GXEurgb60Hz480IntAa = { 20, 640, 242, 480, 40, 0, 640, 480, 1, 0, 1,
{ 3, 2, 9, 6, 3, 10, 3, 2, 9, 6, 3, 10, 9, 2, 3, 6, 9, 10, 9, 2, 3, 6, 9, 10 }, { 4, 8, 12, 16, 12, 8, 4 } };
GXRenderModeObj GXRmHW = { 1, 320, 240, 240, 40, 0, 640, 480, 0, 0, 0, { 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 } };
void GXAdjustForOverscan(GXRenderModeObj *rmin, GXRenderModeObj *rmout, u16 hor, u16 ver)
{
u16 hor2 = hor * 2;
u16 ver2 = ver * 2;
u32 verf;
u32 mode;
if (rmin != rmout) {
*rmout = *rmin;
}
mode = rmin->viTVmode & 3;
rmout->fbWidth = rmin->fbWidth - hor2;
verf = (ver2 * rmin->efbHeight) / (u32)rmin->xfbHeight;
rmout->efbHeight = rmin->efbHeight - verf;
if (rmin->xFBmode == VI_XFBMODE_SF && ((rmin->viTVmode & 2) != 2)) {
rmout->xfbHeight = rmin->xfbHeight - ver;
}
else {
rmout->xfbHeight = rmin->xfbHeight - ver2;
}
rmout->viWidth = rmin->viWidth - hor2;
rmout->viHeight = rmin->viHeight - ver2;
rmout->viXOrigin = rmin->viXOrigin + hor;
rmout->viYOrigin = rmin->viYOrigin + ver;
}
void GXSetDispCopySrc(u16 left, u16 top, u16 wd, u16 ht)
{
CHECK_GXBEGIN(0x4D3, "GXSetDispCopySrc");
gx->cpDispSrc = 0;
SET_REG_FIELD(0x4D6, gx->cpDispSrc, 10, 0, left);
SET_REG_FIELD(0x4D7, gx->cpDispSrc, 10, 10, top);
SET_REG_FIELD(0x4D7, gx->cpDispSrc, 8, 24, 0x49);
gx->cpDispSize = 0;
SET_REG_FIELD(0x4DB, gx->cpDispSize, 10, 0, wd - 1);
SET_REG_FIELD(0x4DC, gx->cpDispSize, 10, 10, ht - 1);
SET_REG_FIELD(0x4DC, gx->cpDispSize, 8, 24, 0x4A);
}
void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht)
{
CHECK_GXBEGIN(0x4EF, "GXSetTexCopySrc");
gx->cpTexSrc = 0;
SET_REG_FIELD(0x4F2, gx->cpTexSrc, 10, 0, left);
SET_REG_FIELD(0x4F3, gx->cpTexSrc, 10, 10, top);
SET_REG_FIELD(0x4F3, gx->cpTexSrc, 8, 24, 0x49);
gx->cpTexSize = 0;
SET_REG_FIELD(0x4F7, gx->cpTexSize, 10, 0, wd - 1);
SET_REG_FIELD(0x4F8, gx->cpTexSize, 10, 10, ht - 1);
SET_REG_FIELD(0x4F8, gx->cpTexSize, 8, 24, 0x4A);
}
void GXSetDispCopyDst(u16 wd, u16 ht)
{
u16 stride;
ASSERTMSGLINE(0x50D, (wd & 0xF) == 0, "GXSetDispCopyDst: Width must be a multiple of 16");
CHECK_GXBEGIN(0x50E, "GXSetDispCopyDst");
stride = (int)wd * 2;
gx->cpDispStride = 0;
SET_REG_FIELD(0x514, gx->cpDispStride, 10, 0, (stride >> 5));
SET_REG_FIELD(0x514, gx->cpDispStride, 8, 24, 0x4D);
}
void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap)
{
u32 rowTiles;
u32 colTiles;
u32 cmpTiles;
u32 peTexFmt;
u32 peTexFmtH;
CHECK_GXBEGIN(0x52F, "GXSetTexCopyDst");
gx->cpTexZ = 0;
peTexFmt = fmt & 0xF;
ASSERTMSGLINEV(0x54E, peTexFmt < 13, "%s: invalid texture format", "GXSetTexCopyDst");
if (fmt == GX_TF_Z16) {
peTexFmt = 0xB;
}
switch (fmt) {
case GX_TF_I4:
case GX_TF_I8:
case GX_TF_IA4:
case GX_TF_IA8:
case GX_CTF_YUVA8:
SET_REG_FIELD(0, gx->cpTex, 2, 15, 3);
break;
default:
SET_REG_FIELD(0, gx->cpTex, 2, 15, 2);
break;
}
gx->cpTexZ = (fmt & _GX_TF_ZTF) == _GX_TF_ZTF;
peTexFmtH = (peTexFmt >> 3) & 1;
!peTexFmt;
SET_REG_FIELD(0x565, gx->cpTex, 1, 3, peTexFmtH);
peTexFmt = peTexFmt & 7;
__GetImageTileCount(fmt, wd, ht, &rowTiles, &colTiles, &cmpTiles);
gx->cpTexStride = 0;
SET_REG_FIELD(0x56E, gx->cpTexStride, 10, 0, rowTiles * cmpTiles);
SET_REG_FIELD(0x570, gx->cpTexStride, 8, 24, 0x4D);
SET_REG_FIELD(0x570, gx->cpTex, 1, 9, mipmap);
SET_REG_FIELD(0x571, gx->cpTex, 3, 4, peTexFmt);
}
void GXSetDispCopyFrame2Field(GXCopyMode mode)
{
CHECK_GXBEGIN(0x582, "GXSetDispCopyFrame2Field");
SET_REG_FIELD(0x583, gx->cpDisp, 2, 12, mode);
SET_REG_FIELD(0x583, gx->cpTex, 2, 12, 0);
}
void GXSetCopyClamp(GXFBClamp clamp)
{
u8 clmpB;
u8 clmpT;
CHECK_GXBEGIN(0x597, "GXSetCopyClamp");
clmpT = (clamp & 1) == 1;
clmpB = (clamp & 2) == 2;
SET_REG_FIELD(0x59B, gx->cpDisp, 1, 0, clmpT);
SET_REG_FIELD(0x59C, gx->cpDisp, 1, 1, clmpB);
SET_REG_FIELD(0x59E, gx->cpTex, 1, 0, clmpT);
SET_REG_FIELD(0x59F, gx->cpTex, 1, 1, clmpB);
}
static u32 __GXGetNumXfbLines(u32 efbHt, u32 iScale)
{
u32 count;
u32 realHt;
u32 iScaleD;
count = (efbHt - 1) * 0x100;
realHt = (count / iScale) + 1;
iScaleD = iScale;
if (iScaleD > 0x80 && iScaleD < 0x100) {
while (iScaleD % 2 == 0) {
iScaleD /= 2;
}
if (efbHt % iScaleD == 0) {
realHt++;
}
}
if (realHt > 0x400) {
realHt = 0x400;
}
return realHt;
}
u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale)
{
u32 iScale;
ASSERTMSGLINE(0x5CE, yScale >= 1.0f, "GXGetNumXfbLines: Vertical scale must be >= 1.0");
iScale = (u32)(256.0f / yScale) & 0x1FF;
return __GXGetNumXfbLines(efbHeight, iScale);
}
f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight)
{
f32 fScale;
f32 yScale;
u32 iScale;
u32 tgtHt;
u32 realHt;
ASSERTMSGLINE(0x5E6, xfbHeight <= 1024, "GXGetYScaleFactor: Display copy only supports up to 1024 lines.\n");
ASSERTMSGLINE(0x5E8, efbHeight <= xfbHeight, "GXGetYScaleFactor: EFB height should not be greater than XFB height.\n");
tgtHt = xfbHeight;
yScale = (f32)xfbHeight / (f32)efbHeight;
iScale = (u32)(256.0f / yScale) & 0x1FF;
realHt = __GXGetNumXfbLines(efbHeight, iScale);
while (realHt > xfbHeight) {
tgtHt--;
yScale = (f32)tgtHt / (f32)efbHeight;
iScale = (u32)(256.0f / yScale) & 0x1FF;
realHt = __GXGetNumXfbLines(efbHeight, iScale);
}
fScale = yScale;
while (realHt < xfbHeight) {
fScale = yScale;
tgtHt++;
yScale = (f32)tgtHt / (f32)efbHeight;
iScale = (u32)(256.0f / yScale) & 0x1FF;
realHt = __GXGetNumXfbLines(efbHeight, iScale);
}
return fScale;
}
u32 GXSetDispCopyYScale(f32 vscale)
{
u8 enable;
u32 iScale;
u32 ht;
u32 reg;
CHECK_GXBEGIN(0x615, "GXSetDispCopyYScale");
ASSERTMSGLINE(0x617, vscale >= 1.0f, "GXSetDispCopyYScale: Vertical scale must be >= 1.0");
iScale = (u32)(256.0f / vscale) & 0x1FF;
enable = (iScale != 256);
reg = 0;
SET_REG_FIELD(0x61E, reg, 9, 0, iScale);
SET_REG_FIELD(0x61E, reg, 8, 24, 0x4E);
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
SET_REG_FIELD(0x623, gx->cpDisp, 1, 10, enable);
ht = GET_REG_FIELD(gx->cpDispSize, 10, 10) + 1;
return __GXGetNumXfbLines(ht, iScale);
}
void GXSetCopyClear(GXColor clear_clr, u32 clear_z)
{
u32 reg;
CHECK_GXBEGIN(0x63C, "GXSetCopyClear");
ASSERTMSGLINE(0x63E, clear_z <= 0xFFFFFF, "GXSetCopyClear: Z clear value is out of range");
reg = 0;
SET_REG_FIELD(0x641, reg, 8, 0, clear_clr.r);
SET_REG_FIELD(0x642, reg, 8, 8, clear_clr.a);
SET_REG_FIELD(0x642, reg, 8, 24, 0x4F);
GX_WRITE_RAS_REG(reg);
reg = 0;
SET_REG_FIELD(0x647, reg, 8, 0, clear_clr.b);
SET_REG_FIELD(0x648, reg, 8, 8, clear_clr.g);
SET_REG_FIELD(0x648, reg, 8, 24, 0x50);
GX_WRITE_RAS_REG(reg);
reg = 0;
SET_REG_FIELD(0x64D, reg, 24, 0, clear_z);
SET_REG_FIELD(0x64D, reg, 8, 24, 0x51);
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXSetCopyFilter(GXBool aa, u8 sample_pattern[12][2], GXBool vf, u8 vfilter[7])
{
u32 msLoc[4];
u32 coeff0;
u32 coeff1;
CHECK_GXBEGIN(0x669, "GXSetCopyFilter");
if (aa != 0) {
msLoc[0] = 0;
SET_REG_FIELD(0x66D, msLoc[0], 4, 0, sample_pattern[0][0]);
SET_REG_FIELD(0x66E, msLoc[0], 4, 4, sample_pattern[0][1]);
SET_REG_FIELD(0x66F, msLoc[0], 4, 8, sample_pattern[1][0]);
SET_REG_FIELD(0x670, msLoc[0], 4, 12, sample_pattern[1][1]);
SET_REG_FIELD(0x671, msLoc[0], 4, 16, sample_pattern[2][0]);
SET_REG_FIELD(0x672, msLoc[0], 4, 20, sample_pattern[2][1]);
SET_REG_FIELD(0x673, msLoc[0], 8, 24, 1);
msLoc[1] = 0;
SET_REG_FIELD(0x676, msLoc[1], 4, 0, sample_pattern[3][0]);
SET_REG_FIELD(0x677, msLoc[1], 4, 4, sample_pattern[3][1]);
SET_REG_FIELD(0x678, msLoc[1], 4, 8, sample_pattern[4][0]);
SET_REG_FIELD(0x679, msLoc[1], 4, 12, sample_pattern[4][1]);
SET_REG_FIELD(0x67A, msLoc[1], 4, 16, sample_pattern[5][0]);
SET_REG_FIELD(0x67B, msLoc[1], 4, 20, sample_pattern[5][1]);
SET_REG_FIELD(0x67C, msLoc[1], 8, 24, 2);
msLoc[2] = 0;
SET_REG_FIELD(0x67F, msLoc[2], 4, 0, sample_pattern[6][0]);
SET_REG_FIELD(0x680, msLoc[2], 4, 4, sample_pattern[6][1]);
SET_REG_FIELD(0x681, msLoc[2], 4, 8, sample_pattern[7][0]);
SET_REG_FIELD(0x682, msLoc[2], 4, 12, sample_pattern[7][1]);
SET_REG_FIELD(0x683, msLoc[2], 4, 16, sample_pattern[8][0]);
SET_REG_FIELD(0x684, msLoc[2], 4, 20, sample_pattern[8][1]);
SET_REG_FIELD(0x685, msLoc[2], 8, 24, 3);
msLoc[3] = 0;
SET_REG_FIELD(0x688, msLoc[3], 4, 0, sample_pattern[9][0]);
SET_REG_FIELD(0x689, msLoc[3], 4, 4, sample_pattern[9][1]);
SET_REG_FIELD(0x68A, msLoc[3], 4, 8, sample_pattern[10][0]);
SET_REG_FIELD(0x68B, msLoc[3], 4, 12, sample_pattern[10][1]);
SET_REG_FIELD(0x68C, msLoc[3], 4, 16, sample_pattern[11][0]);
SET_REG_FIELD(0x68D, msLoc[3], 4, 20, sample_pattern[11][1]);
SET_REG_FIELD(0x68E, msLoc[3], 8, 24, 4);
}
else {
msLoc[0] = 0x01666666;
msLoc[1] = 0x02666666;
msLoc[2] = 0x03666666;
msLoc[3] = 0x04666666;
}
GX_WRITE_RAS_REG(msLoc[0]);
GX_WRITE_RAS_REG(msLoc[1]);
GX_WRITE_RAS_REG(msLoc[2]);
GX_WRITE_RAS_REG(msLoc[3]);
coeff0 = 0;
SET_REG_FIELD(0, coeff0, 8, 24, 0x53);
coeff1 = 0;
SET_REG_FIELD(0, coeff1, 8, 24, 0x54);
if (vf != 0) {
SET_REG_FIELD(0x6A6, coeff0, 6, 0, vfilter[0]);
SET_REG_FIELD(0x6A7, coeff0, 6, 6, vfilter[1]);
SET_REG_FIELD(0x6A8, coeff0, 6, 12, vfilter[2]);
SET_REG_FIELD(0x6A9, coeff0, 6, 18, vfilter[3]);
SET_REG_FIELD(0x6AA, coeff1, 6, 0, vfilter[4]);
SET_REG_FIELD(0x6AB, coeff1, 6, 6, vfilter[5]);
SET_REG_FIELD(0x6AC, coeff1, 6, 12, vfilter[6]);
}
else {
SET_REG_FIELD(0, coeff0, 6, 0, 0);
SET_REG_FIELD(0, coeff0, 6, 6, 0);
SET_REG_FIELD(0, coeff0, 6, 12, 21);
SET_REG_FIELD(0, coeff0, 6, 18, 22);
SET_REG_FIELD(0, coeff1, 6, 0, 21);
SET_REG_FIELD(0, coeff1, 6, 6, 0);
SET_REG_FIELD(0, coeff1, 6, 12, 0);
}
GX_WRITE_RAS_REG(coeff0);
GX_WRITE_RAS_REG(coeff1);
gx->bpSentNot = 0;
}
void GXSetDispCopyGamma(GXGamma gamma)
{
CHECK_GXBEGIN(0x6CD, "GXSetDispCopyGamma");
SET_REG_FIELD(0x6CE, gx->cpDisp, 2, 7, gamma);
}
#if DEBUG
static void __GXVerifCopy(void *dest, u8 clear)
{
u8 clmpT;
u8 clmpB;
u32 x0;
u32 y0;
u32 dx;
u32 dy;
CHECK_GXBEGIN(0x6E2, "GXCopyDisp");
clmpT = GET_REG_FIELD(gx->cpDisp, 1, 0);
clmpB = (u32)GET_REG_FIELD(gx->cpDisp, 1, 1);
x0 = GET_REG_FIELD(gx->cpDispSrc, 10, 0);
dx = GET_REG_FIELD(gx->cpDispSize, 10, 0) + 1;
y0 = GET_REG_FIELD(gx->cpDispSrc, 10, 10);
dy = GET_REG_FIELD(gx->cpDispSize, 10, 10) + 1;
ASSERTMSGLINE(0x6EC, clmpT || y0 != 0, "GXCopy: Have to set GX_CLAMP_TOP if source top == 0");
ASSERTMSGLINE(0x6EE, clmpB || y0 + dy <= 528, "GXCopy: Have to set GX_CLAMP_BOTTOM if source bottom > 528");
ASSERTMSGLINE(0x6F3, (gx->peCtrl & 7) != 3 || clear == 0, "GXCopy: Can not do clear while pixel type is Z");
if ((u32)(gx->peCtrl & 7) == 5) {
ASSERTMSGLINE(0x6F9, clear == 0, "GXCopy: Can not clear YUV framebuffer");
ASSERTMSGLINE(0x6FB, (x0 & 3) == 0, "GXCopy: Source x is not multiple of 4 for YUV copy");
ASSERTMSGLINE(0x6FD, (y0 & 3) == 0, "GXCopy: Source y is not multiple of 4 for YUV copy");
ASSERTMSGLINE(0x6FF, (dx & 3) == 0, "GXCopy: Source width is not multiple of 4 for YUV copy");
ASSERTMSGLINE(0x701, (dy & 3) == 0, "GXCopy: Source height is not multiple of 4 for YUV copy");
}
else {
ASSERTMSGLINE(0x705, (x0 & 1) == 0, "GXCopy: Source x is not multiple of 2 for RGB copy");
ASSERTMSGLINE(0x707, (y0 & 1) == 0, "GXCopy: Source y is not multiple of 2 for RGB copy");
ASSERTMSGLINE(0x709, (dx & 1) == 0, "GXCopy: Source width is not multiple of 2 for RGB copy");
ASSERTMSGLINE(0x70B, (dy & 1) == 0, "GXCopy: Source height is not multiple of 2 for RGB copy");
}
ASSERTMSGLINE(0x70F, ((u32)dest & 0x1F) == 0, "GXCopy: Display destination address not 32B aligned");
}
#endif
void GXCopyDisp(void *dest, GXBool clear)
{
u32 reg;
u32 tempPeCtrl;
u32 phyAddr;
u8 changePeCtrl;
CHECK_GXBEGIN(0x729, "GXCopyDisp");
#if DEBUG
__GXVerifCopy(dest, clear);
#endif
if (clear) {
reg = gx->zmode;
SET_REG_FIELD(0, reg, 1, 0, 1);
SET_REG_FIELD(0, reg, 3, 1, 7);
GX_WRITE_RAS_REG(reg);
reg = gx->cmode0;
SET_REG_FIELD(0, reg, 1, 0, 0);
SET_REG_FIELD(0, reg, 1, 1, 0);
GX_WRITE_RAS_REG(reg);
}
changePeCtrl = FALSE;
if ((clear || (u32)GET_REG_FIELD(gx->peCtrl, 3, 0) == 3) && (u32)GET_REG_FIELD(gx->peCtrl, 1, 6) == 1) {
changePeCtrl = TRUE;
tempPeCtrl = gx->peCtrl;
SET_REG_FIELD(0, tempPeCtrl, 1, 6, 0);
GX_WRITE_RAS_REG(tempPeCtrl);
}
GX_WRITE_RAS_REG(gx->cpDispSrc);
GX_WRITE_RAS_REG(gx->cpDispSize);
GX_WRITE_RAS_REG(gx->cpDispStride);
phyAddr = (u32)dest & 0x3FFFFFFF;
reg = 0;
SET_REG_FIELD(0x750, reg, 21, 0, phyAddr >> 5);
SET_REG_FIELD(0x754, reg, 8, 24, 0x4B);
GX_WRITE_RAS_REG(reg);
SET_REG_FIELD(0x754, gx->cpDisp, 1, 11, clear);
SET_REG_FIELD(0x754, gx->cpDisp, 1, 14, 1);
SET_REG_FIELD(0x754, gx->cpDisp, 8, 24, 0x52);
GX_WRITE_RAS_REG(gx->cpDisp);
if (clear) {
GX_WRITE_RAS_REG(gx->zmode);
GX_WRITE_RAS_REG(gx->cmode0);
}
if (changePeCtrl) {
GX_WRITE_RAS_REG(gx->peCtrl);
}
gx->bpSentNot = 0;
}
void GXCopyTex(void *dest, GXBool clear)
{
u32 reg;
u32 tempPeCtrl;
u32 phyAddr;
u8 changePeCtrl;
CHECK_GXBEGIN(0x77C, "GXCopyTex");
#if DEBUG
__GXVerifCopy(dest, clear);
#endif
if (clear) {
reg = gx->zmode;
SET_REG_FIELD(0, reg, 1, 0, 1);
SET_REG_FIELD(0, reg, 3, 1, 7);
GX_WRITE_RAS_REG(reg);
reg = gx->cmode0;
SET_REG_FIELD(0, reg, 1, 0, 0);
SET_REG_FIELD(0, reg, 1, 1, 0);
GX_WRITE_RAS_REG(reg);
}
changePeCtrl = 0;
tempPeCtrl = gx->peCtrl;
if (gx->cpTexZ && ((tempPeCtrl & 7) != 3)) {
changePeCtrl = 1;
SET_REG_FIELD(0, tempPeCtrl, 3, 0, 3);
}
if (((clear != 0) || ((u32)(tempPeCtrl & 7) == 3)) && ((u32)((tempPeCtrl >> 6U) & 1) == 1)) {
changePeCtrl = 1;
SET_REG_FIELD(0, tempPeCtrl, 1, 6, 0);
}
if (changePeCtrl) {
GX_WRITE_RAS_REG(tempPeCtrl);
}
GX_WRITE_RAS_REG(gx->cpTexSrc);
GX_WRITE_RAS_REG(gx->cpTexSize);
GX_WRITE_RAS_REG(gx->cpTexStride);
phyAddr = (u32)dest & 0x3FFFFFFF;
reg = 0;
SET_REG_FIELD(0x7AD, reg, 21, 0, phyAddr >> 5);
SET_REG_FIELD(0x7AD, reg, 8, 24, 0x4B);
GX_WRITE_RAS_REG(reg);
SET_REG_FIELD(0x7B1, gx->cpTex, 1, 11, clear);
SET_REG_FIELD(0x7B1, gx->cpTex, 1, 14, 0);
SET_REG_FIELD(0x7B1, gx->cpTex, 8, 24, 0x52);
GX_WRITE_RAS_REG(gx->cpTex);
if (clear != 0) {
GX_WRITE_RAS_REG(gx->zmode);
GX_WRITE_RAS_REG(gx->cmode0);
}
if (changePeCtrl) {
GX_WRITE_RAS_REG(gx->peCtrl);
}
gx->bpSentNot = 0;
}
void GXClearBoundingBox(void)
{
u32 reg;
CHECK_GXBEGIN(0x7D3, "GXClearBoundingBox");
reg = 0x550003FF;
GX_WRITE_RAS_REG(reg);
reg = 0x560003FF;
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXReadBoundingBox(u16 *left, u16 *top, u16 *right, u16 *bottom)
{
*left = GX_GET_PE_REG(8);
*top = GX_GET_PE_REG(10);
*right = GX_GET_PE_REG(9);
*bottom = GX_GET_PE_REG(11);
}

146
src/dolphin/gx/GXGeometry.c Normal file
View file

@ -0,0 +1,146 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <stddef.h>
#include <dolphin/gx/GXPriv.h>
void __GXSetDirtyState(void)
{
if (gx->dirtyState & 1) {
__GXSetSUTexRegs();
}
if (gx->dirtyState & 2) {
__GXUpdateBPMask();
}
if (gx->dirtyState & 4) {
__GXSetGenMode();
}
if (gx->dirtyState & 8) {
__GXSetVCD();
}
if (gx->dirtyState & 0x10) {
__GXSetVAT();
}
if (gx->dirtyState & 0x18) {
__GXCalculateVLim();
}
gx->dirtyState = 0;
}
void GXBegin(GXPrimitive type, GXVtxFmt vtxfmt, u16 nverts)
{
ASSERTMSGLINE(0x167, vtxfmt < 8, "GXBegin: Format Index is out of range");
ASSERTMSGLINE(0x168, !__GXinBegin, "GXBegin: called inside another GXBegin/GXEnd");
if (gx->dirtyState != 0) {
__GXSetDirtyState();
}
if (*(u32 *)&gx->vNumNot == 0) { // checks both vNum and bpSentNot
__GXSendFlushPrim();
}
GX_WRITE_U8(vtxfmt | type);
GX_WRITE_U16(nverts);
}
void __GXSendFlushPrim(void)
{
u32 i;
u32 numD = gx->vNum * gx->vLim;
GX_WRITE_U8(0x98);
GX_WRITE_U16(gx->vNum);
for (i = 0; i < numD; i += 4) {
GX_WRITE_U32(0);
}
gx->bpSentNot = 1;
}
void GXSetLineWidth(u8 width, GXTexOffset texOffsets)
{
CHECK_GXBEGIN(0x1B8, "GXSetLineWidth");
SET_REG_FIELD(0x1B9, gx->lpSize, 8, 0, width);
SET_REG_FIELD(0x1BA, gx->lpSize, 3, 16, texOffsets);
GX_WRITE_RAS_REG(gx->lpSize);
gx->bpSentNot = 0;
}
void GXGetLineWidth(u8 *width, GXTexOffset *texOffsets)
{
ASSERTMSGLINE(0x1CF, width != NULL && texOffsets != NULL, "GXGet*: invalid null pointer");
*width = GET_REG_FIELD(gx->lpSize, 8, 0);
*texOffsets = GET_REG_FIELD(gx->lpSize, 3, 16);
}
void GXSetPointSize(u8 pointSize, GXTexOffset texOffsets)
{
CHECK_GXBEGIN(0x1E4, "GXSetPointSize");
SET_REG_FIELD(0x1E5, gx->lpSize, 8, 8, pointSize);
SET_REG_FIELD(0x1E6, gx->lpSize, 3, 19, texOffsets);
GX_WRITE_RAS_REG(gx->lpSize);
gx->bpSentNot = 0;
}
void GXGetPointSize(u8 *pointSize, GXTexOffset *texOffsets)
{
ASSERTMSGLINE(0x1FB, pointSize != NULL && texOffsets != NULL, "GXGet*: invalid null pointer");
*pointSize = (int)GET_REG_FIELD(gx->lpSize, 8, 8);
*texOffsets = GET_REG_FIELD(gx->lpSize, 3, 19);
}
void GXEnableTexOffsets(GXTexCoordID coord, u8 line_enable, u8 point_enable)
{
CHECK_GXBEGIN(0x211, "GXEnableTexOffsets");
ASSERTMSGLINE(0x213, coord < 8, "GXEnableTexOffsets: Invalid coordinate Id");
SET_REG_FIELD(0x215, gx->suTs0[coord], 1, 18, line_enable);
SET_REG_FIELD(0x216, gx->suTs0[coord], 1, 19, point_enable);
GX_WRITE_RAS_REG(gx->suTs0[coord]);
gx->bpSentNot = 0;
}
void GXSetCullMode(GXCullMode mode)
{
GXCullMode hwMode;
CHECK_GXBEGIN(0x21D, "GXSetCullMode");
switch (mode) {
case GX_CULL_FRONT:
hwMode = GX_CULL_BACK;
break;
case GX_CULL_BACK:
hwMode = GX_CULL_FRONT;
break;
default:
hwMode = mode;
break;
}
SET_REG_FIELD(0x225, gx->genMode, 2, 14, hwMode);
gx->dirtyState |= 4;
}
void GXGetCullMode(GXCullMode *mode)
{
GXCullMode hwMode = gx->genMode;
*mode = ((hwMode >> 0xD) & 0x2) | (((((int)hwMode >> 0xE) & 0x2) >> 0x1));
}
void GXSetCoPlanar(GXBool enable)
{
u32 reg;
CHECK_GXBEGIN(0x265, "GXSetCoPlanar");
SET_REG_FIELD(0x267, gx->genMode, 1, 19, enable);
reg = 0xFE080000;
GX_WRITE_RAS_REG(reg);
GX_WRITE_RAS_REG(gx->genMode);
}
void __GXSetGenMode(void)
{
GX_WRITE_RAS_REG(gx->genMode);
gx->bpSentNot = 0;
}

372
src/dolphin/gx/GXInit.c Normal file
View file

@ -0,0 +1,372 @@
#include <string.h>
#include <dolphin/PPCArch.h>
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/vi.h>
#include <dolphin/gx/GXPriv.h>
void __GXInitGX();
static struct __GXData_struct gxData;
struct __GXData_struct *gx = &gxData;
// DWARF info lists all of these as "void *", but these types make more sense.
u16 *__memReg;
u16 *__peReg;
u16 *__cpReg;
u32 *__piReg;
// clang-format off
asm BOOL IsWriteGatherBufferEmpty(void)
{
sync
mfspr r3, WPAR
andi. r3, r3, 1
}
// clang-format on
static void EnableWriteGatherPipe(void)
{
u32 hid2 = PPCMfhid2();
PPCMtwpar(OSUncachedToPhysical((void *)GXFIFO_ADDR));
hid2 |= 0x40000000;
PPCMthid2(hid2);
}
static void DisableWriteGatherPipe(void)
{
u32 hid2 = PPCMfhid2();
hid2 &= ~0x40000000;
PPCMthid2(hid2);
}
static GXTexRegion *__GXDefaultTexRegionCallback(GXTexObj *t_obj, GXTexMapID unused)
{
GXTexFmt fmt = GXGetTexObjFmt(t_obj);
if (fmt != GX_TF_C4 && fmt != GX_TF_C8 && fmt != GX_TF_C14X2) {
return &gx->TexRegions[gx->nextTexRgn++ & 7];
}
else {
return &gx->TexRegionsCI[gx->nextTexRgnCI++ & 3];
}
}
static GXTlutRegion *__GXDefaultTlutRegionCallback(u32 idx)
{
if (idx >= 0x14U) {
return NULL;
}
return &gx->TlutRegions[idx];
}
GXFifoObj FifoObj;
GXFifoObj *GXInit(void *base, u32 size)
{
u32 i;
u32 reg;
u32 freqBase;
// OSRegisterVersion(__GXVersion);
gx->inDispList = FALSE;
gx->dlSaveContext = TRUE;
// gx->abtWaitPECopy = 1;
#if DEBUG
__GXinBegin = FALSE;
#endif
gx->tcsManEnab = FALSE;
gx->tevTcEnab = FALSE;
GXSetMisc(GX_MT_XF_FLUSH, 0);
__piReg = OSPhysicalToUncached(0xC003000);
__cpReg = OSPhysicalToUncached(0xC000000);
__peReg = OSPhysicalToUncached(0xC001000);
__memReg = OSPhysicalToUncached(0xC004000);
// __GXFifoInit();
// GXInitFifoBase(&FifoObj, base, size);
// GXSetCPUFifo(&FifoObj);
// GXSetGPFifo(&FifoObj);
// if (!resetFuncRegistered) {
// OSRegisterResetFunction(&GXResetFuncInfo);
// resetFuncRegistered = 1;
// }
// __GXPEInit();
// EnableWriteGatherPipe();
gx->genMode = 0;
SET_REG_FIELD(0, gx->genMode, 8, 24, 0);
gx->bpMask = 255;
SET_REG_FIELD(0, gx->bpMask, 8, 24, 0x0F);
gx->lpSize = 0;
SET_REG_FIELD(0, gx->lpSize, 8, 24, 0x22);
for (i = 0; i < 16; ++i) {
gx->tevc[i] = 0;
gx->teva[i] = 0;
gx->tref[i / 2] = 0;
gx->texmapId[i] = GX_TEXMAP_NULL;
SET_REG_FIELD(0x46A, gx->tevc[i], 8, 24, 0xC0 + i * 2);
SET_REG_FIELD(0x46B, gx->teva[i], 8, 24, 0xC1 + i * 2);
SET_REG_FIELD(0x46D, gx->tevKsel[i / 2], 8, 24, 0xF6 + i / 2);
SET_REG_FIELD(0x46F, gx->tref[i / 2], 8, 24, 0x28 + i / 2);
}
gx->iref = 0;
SET_REG_FIELD(0, gx->iref, 8, 24, 0x27);
for (i = 0; i < 8; ++i) {
gx->suTs0[i] = 0;
gx->suTs1[i] = 0;
SET_REG_FIELD(0x478, gx->suTs0[i], 8, 24, 0x30 + i * 2);
SET_REG_FIELD(0x479, gx->suTs1[i], 8, 24, 0x31 + i * 2);
}
SET_REG_FIELD(0, gx->suScis0, 8, 24, 0x20);
SET_REG_FIELD(0, gx->suScis1, 8, 24, 0x21);
SET_REG_FIELD(0, gx->cmode0, 8, 24, 0x41);
SET_REG_FIELD(0, gx->cmode1, 8, 24, 0x42);
SET_REG_FIELD(0, gx->zmode, 8, 24, 0x40);
SET_REG_FIELD(0, gx->peCtrl, 8, 24, 0x43);
SET_REG_FIELD(0, gx->cpTex, 2, 7, 0);
// gx->zScale = 1.6777216E7f;
// gx->zOffset = 0.0f;
gx->dirtyState = 0;
gx->dirtyVAT = FALSE;
#if DEBUG
__gxVerif->verifyLevel = GX_WARN_NONE;
GXSetVerifyCallback((GXVerifyCallback)__GXDefaultVerifyCallback);
for (i = 0; i < 256; i++) {
SET_REG_FIELD(0, __gxVerif->rasRegs[i], 8, 24, 0xFF);
}
memset(__gxVerif->xfRegsDirty, 0, 0x50);
memset(__gxVerif->xfMtxDirty, 0, 0x100);
memset(__gxVerif->xfNrmDirty, 0, 0x60);
memset(__gxVerif->xfLightDirty, 0, 0x80);
#endif
freqBase = __OSBusClock / 500;
// __GXFlushTextureState();
reg = (freqBase >> 11) | 0x400 | 0x69000000;
GX_WRITE_RAS_REG(reg);
// __GXFlushTextureState();
reg = (freqBase / 0x1080) | 0x200 | 0x46000000;
GX_WRITE_RAS_REG(reg);
// __GXInitRevisionBits();
// for (i = 0; i < 8; i++) {
// GXInitTexCacheRegion(&gx->TexRegions0[i], GX_FALSE, GXTexRegionAddrTable[i],
// GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 8], GX_TEXCACHE_32K);
// GXInitTexCacheRegion(&gx->TexRegions1[i], GX_FALSE, GXTexRegionAddrTable[i + 16],
// GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 24], GX_TEXCACHE_32K);
// GXInitTexCacheRegion(&gx->TexRegions2[i], GX_TRUE, GXTexRegionAddrTable[i + 32],
// GX_TEXCACHE_32K, GXTexRegionAddrTable[i + 40], GX_TEXCACHE_32K);
// }
// for (i = 0; i < 16; i++) {
// GXInitTlutRegion(&gx->TlutRegions[i], 0xC0000 + 0x2000 * i, GX_TLUT_256);
// }
// for (i = 0; i < 4; i++) {
// GXInitTlutRegion(&gx->TlutRegions[i + 16], 0xE0000 + 0x8000 * i, GX_TLUT_1K);
// }
{
u32 reg = 0;
#if DEBUG
s32 regAddr;
#endif
GX_SET_CP_REG(3, reg);
SET_REG_FIELD(0, gx->perfSel, 4, 4, 0);
GX_WRITE_U8(0x8);
GX_WRITE_U8(0x20);
GX_WRITE_U32(gx->perfSel);
#if DEBUG
regAddr = -12;
#endif
reg = 0;
GX_WRITE_XF_REG(6, reg);
reg = 0x23000000;
GX_WRITE_RAS_REG(reg);
reg = 0x24000000;
GX_WRITE_RAS_REG(reg);
reg = 0x67000000;
GX_WRITE_RAS_REG(reg);
}
__GXSetIndirectMask(0);
__GXSetTmemConfig(2);
__GXInitGX();
return &FifoObj;
}
void __GXInitGX()
{
GXRenderModeObj *rmode;
GXAttr var_r30;
f32 identity_mtx[3][4];
GXColor clear = { 64, 64, 64, 255 };
GXColor black = { 0, 0, 0, 0 };
GXColor white = { 255, 255, 255, 255 };
u32 i;
switch (VIGetTvFormat()) {
case 0:
rmode = &GXNtsc480IntDf;
break;
case 1:
rmode = &GXPal528IntDf;
break;
case 5:
rmode = &GXEurgb60Hz480IntDf;
break;
case 2:
rmode = &GXMpal480IntDf;
break;
default:
rmode = &GXNtsc480IntDf;
break;
}
GXSetCopyClear(clear, 0xFFFFFF);
GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, 0x3CU);
GXSetTexCoordGen(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, 0x3CU);
GXSetNumTexGens(1);
GXClearVtxDesc();
GXInvalidateVtxCache();
for (var_r30 = GX_VA_POS; (u32)var_r30 <= 0x18; var_r30++) {
GXSetArray(var_r30, gx, 0);
}
GXSetLineWidth(6, 0);
GXSetPointSize(6, 0);
GXEnableTexOffsets(0, 0, 0);
GXEnableTexOffsets(1, 0, 0);
GXEnableTexOffsets(2, 0, 0);
GXEnableTexOffsets(3, 0, 0);
GXEnableTexOffsets(4, 0, 0);
GXEnableTexOffsets(5, 0, 0);
GXEnableTexOffsets(6, 0, 0);
GXEnableTexOffsets(7, 0, 0);
identity_mtx[0][0] = 1.0f;
identity_mtx[0][1] = 0.0f;
identity_mtx[0][2] = 0.0f;
identity_mtx[0][3] = 0.0f;
identity_mtx[1][0] = 0.0f;
identity_mtx[1][1] = 1.0f;
identity_mtx[1][2] = 0.0f;
identity_mtx[1][3] = 0.0f;
identity_mtx[2][0] = 0.0f;
identity_mtx[2][1] = 0.0f;
identity_mtx[2][2] = 1.0f;
identity_mtx[2][3] = 0.0f;
GXLoadPosMtxImm(identity_mtx, GX_PNMTX0);
GXLoadNrmMtxImm(identity_mtx, GX_PNMTX0);
GXSetCurrentMtx(GX_PNMTX0);
GXLoadTexMtxImm(identity_mtx, GX_IDENTITY, GX_MTX3x4);
GXLoadTexMtxImm(identity_mtx, GX_PTIDENTITY, GX_MTX3x4);
GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f);
GXSetCoPlanar(GX_DISABLE);
GXSetCullMode(GX_CULL_BACK);
GXSetClipMode(GX_CLIP_ENABLE);
GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight);
GXSetScissorBoxOffset(0, 0);
GXSetNumChans(0);
GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
GXSetChanAmbColor(GX_COLOR0A0, black);
GXSetChanMatColor(GX_COLOR0A0, white);
GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
GXSetChanAmbColor(GX_COLOR1A1, black);
GXSetChanMatColor(GX_COLOR1A1, white);
GXInvalidateTexAll();
gx->nextTexRgnCI = gx->nextTexRgn = i = GX_TEVSTAGE0;
GXSetTexRegionCallback((void *)__GXDefaultTexRegionCallback);
GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD2, GX_TEXMAP2, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD3, GX_TEXMAP3, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD4, GX_TEXMAP4, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD5, GX_TEXMAP5, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD6, GX_TEXMAP6, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD7, GX_TEXMAP7, GX_COLOR0A0);
GXSetTevOrder(GX_TEVSTAGE8, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE9, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE10, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE11, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE12, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE13, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE14, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetTevOrder(GX_TEVSTAGE15, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
GXSetNumTevStages(1);
GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0);
for (; i < GX_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 = GX_TEVSTAGE0; 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, black);
GXSetFogRangeAdj(GX_DISABLE, 0, 0);
GXSetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GXSetColorUpdate(GX_ENABLE);
GXSetAlphaUpdate(GX_ENABLE);
GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
GXSetZCompLoc(GX_TRUE);
GXSetDither(GX_ENABLE);
GXSetDstAlpha(GX_DISABLE, 0);
GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
GXSetFieldMask(GX_ENABLE, GX_ENABLE);
GXSetFieldMode(rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
GXSetDispCopyDst(rmode->fbWidth, rmode->efbHeight);
GXSetDispCopyYScale((f32)(rmode->xfbHeight) / (f32)(rmode->efbHeight));
GXSetCopyClamp((GXFBClamp)(GX_CLAMP_TOP | GX_CLAMP_BOTTOM));
GXSetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
GXSetDispCopyGamma(GX_GM_1_0);
GXSetDispCopyFrame2Field(GX_COPY_PROGRESSIVE);
GXClearBoundingBox();
GXPokeColorUpdate(GX_TRUE);
GXPokeAlphaUpdate(GX_TRUE);
GXPokeDither(GX_FALSE);
GXPokeBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ONE, GX_LO_SET);
GXPokeAlphaMode(GX_ALWAYS, 0);
GXPokeAlphaRead(GX_READ_FF);
GXPokeDstAlpha(GX_DISABLE, 0);
GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE);
GXSetGPMetric(GX_PERF0_NONE, GX_PERF1_NONE);
GXClearGPMetric();
}

620
src/dolphin/gx/GXLight.c Normal file
View file

@ -0,0 +1,620 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
float cosf(float x);
inline float sqrtf(float x)
{
static const double _half = .5;
static const double _three = 3.0;
volatile float y;
if (x > 0.0f)
{
double guess = __frsqrte((double)x); // returns an approximation to
guess = _half*guess*(_three - guess*guess*x); // now have 12 sig bits
guess = _half*guess*(_three - guess*guess*x); // now have 24 sig bits
guess = _half*guess*(_three - guess*guess*x); // now have 32 sig bits
y = (float)(x*guess);
return y ;
}
return x;
}
// GXLightObj private data
struct __GXLightObjInt_struct {
u32 reserved[3];
u32 Color;
f32 a[3];
f32 k[3];
f32 lpos[3];
f32 ldir[3];
};
void GXInitLightAttn(GXLightObj *lt_obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x62, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x63, "GXInitLightAttn");
obj->a[0] = a0;
obj->a[1] = a1;
obj->a[2] = a2;
obj->k[0] = k0;
obj->k[1] = k1;
obj->k[2] = k2;
}
void GXInitLightAttnA(GXLightObj *lt_obj, f32 a0, f32 a1, f32 a2)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x70, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x71, "GXInitLightAttnA");
obj->a[0] = a0;
obj->a[1] = a1;
obj->a[2] = a2;
}
void GXGetLightAttnA(GXLightObj *lt_obj, f32 *a0, f32 *a1, f32 *a2)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x7A, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x7B, "GXGetLightAttnA");
*a0 = obj->a[0];
*a1 = obj->a[1];
*a2 = obj->a[2];
}
void GXInitLightAttnK(GXLightObj *lt_obj, f32 k0, f32 k1, f32 k2)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x84, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x85, "GXInitLightAttnK");
obj->k[0] = k0;
obj->k[1] = k1;
obj->k[2] = k2;
}
void GXGetLightAttnK(GXLightObj *lt_obj, f32 *k0, f32 *k1, f32 *k2)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x8E, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x8F, "GXGetLightAttnK");
*k0 = obj->k[0];
*k1 = obj->k[1];
*k2 = obj->k[2];
}
void GXInitLightSpot(GXLightObj *lt_obj, f32 cutoff, GXSpotFn spot_func)
{
float a0, a1, a2;
float d;
float cr;
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0xA7, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0xA9, "GXInitLightSpot");
if (cutoff <= 0.0f || cutoff > 90.0f)
spot_func = GX_SP_OFF;
cr = cosf((3.1415927f * cutoff) / 180.0f);
switch (spot_func) {
case GX_SP_FLAT:
a0 = -1000.0f * cr;
a1 = 1000.0f;
a2 = 0.0f;
break;
case GX_SP_COS:
a0 = -cr / (1.0f - cr);
a1 = 1.0f / (1.0f - cr);
a2 = 0.0f;
break;
case GX_SP_COS2:
a0 = 0.0f;
a1 = -cr / (1.0f - cr);
a2 = 1.0f / (1.0f - cr);
break;
case GX_SP_SHARP:
d = (1.0f - cr) * (1.0f - cr);
a0 = (cr * (cr - 2.0f)) / d;
a1 = 2.0f / d;
a2 = -1.0f / d;
break;
case GX_SP_RING1:
d = (1.0f - cr) * (1.0f - cr);
a0 = (-4.0f * cr) / d;
a1 = (4.0f * (1.0f + cr)) / d;
a2 = -4.0f / d;
break;
case GX_SP_RING2:
d = (1.0f - cr) * (1.0f - cr);
a0 = 1.0f - ((2.0f * cr * cr) / d);
a1 = (4.0f * cr) / d;
a2 = -2.0f / d;
break;
case GX_SP_OFF:
default:
a0 = 1.0f;
a1 = 0.0f;
a2 = 0.0f;
break;
}
obj->a[0] = a0;
obj->a[1] = a1;
obj->a[2] = a2;
}
void GXInitLightDistAttn(GXLightObj *lt_obj, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func)
{
f32 k0, k1, k2;
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0xF2, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0xF4, "GXInitLightDistAttn");
if (ref_dist < 0.0f)
dist_func = GX_DA_OFF;
if (ref_br <= 0.0f || ref_br >= 1.0f)
dist_func = GX_DA_OFF;
switch (dist_func) {
case GX_DA_GENTLE:
k0 = 1.0f;
k1 = (1.0f - ref_br) / (ref_br * ref_dist);
k2 = 0.0f;
break;
case GX_DA_MEDIUM:
k0 = 1.0f;
k1 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist);
k2 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist * ref_dist);
break;
case GX_DA_STEEP:
k0 = 1.0f;
k1 = 0.0f;
k2 = (1.0f - ref_br) / (ref_br * ref_dist * ref_dist);
break;
case GX_DA_OFF:
default:
k0 = 1.0f;
k1 = 0.0f;
k2 = 0.0f;
break;
}
obj->k[0] = k0;
obj->k[1] = k1;
obj->k[2] = k2;
}
void GXInitLightPos(GXLightObj *lt_obj, f32 x, f32 y, f32 z)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x129, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x12B, "GXInitLightPos");
obj->lpos[0] = x;
obj->lpos[1] = y;
obj->lpos[2] = z;
}
void GXGetLightPos(const GXLightObj *lt_obj, f32 *x, f32 *y, f32 *z)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x134, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x136, "GXGetLightPos");
*x = obj->lpos[0];
*y = obj->lpos[1];
*z = obj->lpos[2];
}
void GXInitLightDir(GXLightObj *lt_obj, f32 nx, f32 ny, f32 nz)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x149, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
obj->ldir[0] = -nx;
obj->ldir[1] = -ny;
obj->ldir[2] = -nz;
}
void GXGetLightDir(GXLightObj *lt_obj, f32 *nx, f32 *ny, f32 *nz)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x155, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
*nx = -obj->ldir[0];
*ny = -obj->ldir[1];
*nz = -obj->ldir[2];
}
void GXInitSpecularDir(GXLightObj *lt_obj, f32 nx, f32 ny, f32 nz)
{
float mag;
float vx;
float vy;
float vz;
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x16F, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x170, "GXInitSpecularDir");
vx = -nx;
vy = -ny;
vz = -nz + 1.0f;
mag = 1.0f / sqrtf((vx * vx) + (vy * vy) + (vz * vz));
obj->ldir[0] = vx * mag;
obj->ldir[1] = vy * mag;
obj->ldir[2] = vz * mag;
obj->lpos[0] = -nx * 1048576.0f;
obj->lpos[1] = -ny * 1048576.0f;
obj->lpos[2] = -nz * 1048576.0f;
}
void GXInitSpecularDirHA(GXLightObj *lt_obj, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x18E, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x18F, "GXInitSpecularHA");
obj->ldir[0] = hx;
obj->ldir[1] = hy;
obj->ldir[2] = hz;
obj->lpos[0] = -nx * 1048576.0f;
obj->lpos[1] = -ny * 1048576.0f;
obj->lpos[2] = -nz * 1048576.0f;
}
void GXInitLightColor(GXLightObj *lt_obj, GXColor color)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x1A8, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x1A9, "GXInitLightColor");
obj->Color = (color.r << 24) | (color.g << 16) | (color.b << 8) | color.a;
}
void GXGetLightColor(const GXLightObj *lt_obj, GXColor *color)
{
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x1B2, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x1B3, "GXGetLightColor");
color->r = (obj->Color >> 24) & 0xFF;
color->g = (obj->Color >> 16) & 0xFF;
color->b = (obj->Color >> 8) & 0xFF;
color->a = obj->Color & 0xFF;
}
#if DEBUG
#define WRITE_SOME_LIGHT_REG1(val, addr) \
do { \
u32 xfData = val; \
GX_WRITE_U32(val); \
VERIF_MTXLIGHT(addr, xfData); \
} while (0)
#define WRITE_SOME_LIGHT_REG2(val, addr) \
do { \
f32 xfData = val; \
GX_WRITE_F32(val); \
VERIF_MTXLIGHT(addr, *(u32 *)&xfData); \
} while (0)
#else
#define WRITE_SOME_LIGHT_REG1(val, addr) GX_WRITE_U32(val)
#define WRITE_SOME_LIGHT_REG2(val, addr) GX_WRITE_F32(val)
#endif
void GXLoadLightObjImm(GXLightObj *lt_obj, GXLightID light)
{
unsigned long addr;
unsigned long idx;
struct __GXLightObjInt_struct *obj;
ASSERTMSGLINE(0x1C9, lt_obj != NULL, "Light Object Pointer is null");
obj = (struct __GXLightObjInt_struct *)lt_obj;
CHECK_GXBEGIN(0x1CA, "GXLoadLightObjImm");
switch (light) {
case GX_LIGHT0:
idx = 0;
break;
case GX_LIGHT1:
idx = 1;
break;
case GX_LIGHT2:
idx = 2;
break;
case GX_LIGHT3:
idx = 3;
break;
case GX_LIGHT4:
idx = 4;
break;
case GX_LIGHT5:
idx = 5;
break;
case GX_LIGHT6:
idx = 6;
break;
case GX_LIGHT7:
idx = 7;
break;
default:
idx = 0;
ASSERTMSGLINE(0x1DA, 0, "GXLoadLightStateImm: Invalid Light Id");
break;
}
addr = idx * 0x10 + 0x600;
GX_WRITE_U8(0x10);
GX_WRITE_U32(addr | 0xF0000);
WRITE_SOME_LIGHT_REG1(0, addr);
WRITE_SOME_LIGHT_REG1(0, addr + 1);
WRITE_SOME_LIGHT_REG1(0, addr + 2);
WRITE_SOME_LIGHT_REG1(obj->Color, addr + 3);
WRITE_SOME_LIGHT_REG2(obj->a[0], addr + 4);
WRITE_SOME_LIGHT_REG2(obj->a[1], addr + 5);
WRITE_SOME_LIGHT_REG2(obj->a[2], addr + 6);
WRITE_SOME_LIGHT_REG2(obj->k[0], addr + 7);
WRITE_SOME_LIGHT_REG2(obj->k[1], addr + 8);
WRITE_SOME_LIGHT_REG2(obj->k[2], addr + 9);
WRITE_SOME_LIGHT_REG2(obj->lpos[0], addr + 10);
WRITE_SOME_LIGHT_REG2(obj->lpos[1], addr + 11);
WRITE_SOME_LIGHT_REG2(obj->lpos[2], addr + 12);
WRITE_SOME_LIGHT_REG2(obj->ldir[0], addr + 13);
WRITE_SOME_LIGHT_REG2(obj->ldir[1], addr + 14);
WRITE_SOME_LIGHT_REG2(obj->ldir[2], addr + 15);
gx->bpSentNot = 1;
}
void GXLoadLightObjIndx(u32 lt_obj_indx, GXLightID light)
{
unsigned long reg;
unsigned long addr;
unsigned long idx;
CHECK_GXBEGIN(0x209, "GXLoadLightObjIndx");
switch (light) {
case GX_LIGHT0:
idx = 0;
break;
case GX_LIGHT1:
idx = 1;
break;
case GX_LIGHT2:
idx = 2;
break;
case GX_LIGHT3:
idx = 3;
break;
case GX_LIGHT4:
idx = 4;
break;
case GX_LIGHT5:
idx = 5;
break;
case GX_LIGHT6:
idx = 6;
break;
case GX_LIGHT7:
idx = 7;
break;
default:
idx = 0;
ASSERTMSGLINE(0x216, 0, "GXLoadLightObjIndx: Invalid Light Id");
break;
}
addr = idx * 0x10 + 0x600;
reg = 0;
SET_REG_FIELD(0x21C, reg, 12, 0, addr);
SET_REG_FIELD(0x21D, reg, 4, 12, 0xF);
SET_REG_FIELD(0x21E, reg, 16, 16, lt_obj_indx);
GX_WRITE_U8(0x38);
GX_WRITE_U32(reg);
#if DEBUG
__GXShadowIndexState(7, reg);
#endif
gx->bpSentNot = 1;
}
void GXSetChanAmbColor(GXChannelID chan, GXColor amb_color)
{
u32 reg = 0;
u32 colIdx;
u32 alpha;
CHECK_GXBEGIN(0x239, "GXSetChanAmbColor");
switch (chan) {
case GX_COLOR0:
alpha = gx->ambColor[0] & 0xFF;
SET_REG_FIELD(0x23E, reg, 8, 0, alpha);
SET_REG_FIELD(0x23F, reg, 8, 8, amb_color.b);
SET_REG_FIELD(0x240, reg, 8, 16, amb_color.g);
SET_REG_FIELD(0x241, reg, 8, 24, amb_color.r);
colIdx = 0;
break;
case GX_COLOR1:
alpha = gx->ambColor[1] & 0xFF;
SET_REG_FIELD(0x247, reg, 8, 0, alpha);
SET_REG_FIELD(0x248, reg, 8, 8, amb_color.b);
SET_REG_FIELD(0x249, reg, 8, 16, amb_color.g);
SET_REG_FIELD(0x24A, reg, 8, 24, amb_color.r);
colIdx = 1;
break;
case GX_ALPHA0:
reg = gx->ambColor[0];
SET_REG_FIELD(0x250, reg, 8, 0, amb_color.a);
colIdx = 0;
break;
case GX_ALPHA1:
reg = gx->ambColor[1];
SET_REG_FIELD(0x256, reg, 8, 0, amb_color.a);
colIdx = 1;
break;
case GX_COLOR0A0:
SET_REG_FIELD(0x25B, reg, 8, 0, amb_color.a);
SET_REG_FIELD(0x25C, reg, 8, 8, amb_color.b);
SET_REG_FIELD(0x25D, reg, 8, 16, amb_color.g);
SET_REG_FIELD(0x25E, reg, 8, 24, amb_color.r);
colIdx = 0;
break;
case GX_COLOR1A1:
SET_REG_FIELD(0x263, reg, 8, 0, amb_color.a);
SET_REG_FIELD(0x264, reg, 8, 8, amb_color.b);
SET_REG_FIELD(0x265, reg, 8, 16, amb_color.g);
SET_REG_FIELD(0x266, reg, 8, 24, amb_color.r);
colIdx = 1;
break;
default:
ASSERTMSGLINE(0x26B, 0, "GXSetChanAmbColor: Invalid Channel Id");
return;
}
GX_WRITE_XF_REG(colIdx + 10, reg);
gx->bpSentNot = 1;
gx->ambColor[colIdx] = reg;
}
void GXSetChanMatColor(GXChannelID chan, GXColor mat_color)
{
u32 reg = 0;
u32 alpha;
u32 colIdx;
CHECK_GXBEGIN(0x28A, "GXSetChanMatColor");
switch (chan) {
case GX_COLOR0:
alpha = gx->matColor[0] & 0xFF;
SET_REG_FIELD(0x28F, reg, 8, 0, alpha);
SET_REG_FIELD(0x290, reg, 8, 8, mat_color.b);
SET_REG_FIELD(0x291, reg, 8, 16, mat_color.g);
SET_REG_FIELD(0x292, reg, 8, 24, mat_color.r);
colIdx = 0;
break;
case GX_COLOR1:
alpha = gx->matColor[1] & 0xFF;
SET_REG_FIELD(0x298, reg, 8, 0, alpha);
SET_REG_FIELD(0x299, reg, 8, 8, mat_color.b);
SET_REG_FIELD(0x29A, reg, 8, 16, mat_color.g);
SET_REG_FIELD(0x29B, reg, 8, 24, mat_color.r);
colIdx = 1;
break;
case GX_ALPHA0:
reg = gx->matColor[0];
SET_REG_FIELD(0x2A1, reg, 8, 0, mat_color.a);
colIdx = 0;
break;
case GX_ALPHA1:
reg = gx->matColor[1];
SET_REG_FIELD(0x2A7, reg, 8, 0, mat_color.a);
colIdx = 1;
break;
case GX_COLOR0A0:
SET_REG_FIELD(0x2AC, reg, 8, 0, mat_color.a);
SET_REG_FIELD(0x2AD, reg, 8, 8, mat_color.b);
SET_REG_FIELD(0x2AE, reg, 8, 16, mat_color.g);
SET_REG_FIELD(0x2AF, reg, 8, 24, mat_color.r);
colIdx = 0;
break;
case GX_COLOR1A1:
SET_REG_FIELD(0x2B4, reg, 8, 0, mat_color.a);
SET_REG_FIELD(0x2B5, reg, 8, 8, mat_color.b);
SET_REG_FIELD(0x2B6, reg, 8, 16, mat_color.g);
SET_REG_FIELD(0x2B7, reg, 8, 24, mat_color.r);
colIdx = 1;
break;
default:
ASSERTMSGLINE(0x2BC, 0, "GXSetChanMatColor: Invalid Channel Id");
return;
}
GX_WRITE_XF_REG(colIdx + 12, reg);
gx->bpSentNot = 1;
gx->matColor[colIdx] = reg;
}
void GXSetNumChans(u8 nChans)
{
CHECK_GXBEGIN(0x2D5, "GXSetNumChans");
ASSERTMSGLINE(0x2D6, nChans <= 2, "GXSetNumChans: nChans > 2");
SET_REG_FIELD(0x2D8, gx->genMode, 3, 4, nChans);
GX_WRITE_XF_REG(9, nChans);
gx->dirtyState |= 4;
}
void GXSetChanCtrl(GXChannelID chan, GXBool enable, GXColorSrc amb_src, GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn, GXAttnFn attn_fn)
{
u32 reg; // r31
u32 idx; // r26
CHECK_GXBEGIN(0x2F8, "GXSetChanCtrl");
ASSERTMSGLINE(0x2FB, chan >= 0 && chan <= 5, "GXSetChanCtrl: Invalid Channel Id");
if (chan == 4)
idx = 0;
else if (chan == 5)
idx = 1;
else
idx = chan;
reg = 0;
SET_REG_FIELD(0x302, reg, 1, 1, enable);
SET_REG_FIELD(0x303, reg, 1, 0, mat_src);
SET_REG_FIELD(0x304, reg, 1, 6, amb_src);
SET_REG_FIELD(0x305, reg, 1, 2, (light_mask & GX_LIGHT0) != 0);
SET_REG_FIELD(0x306, reg, 1, 3, (light_mask & GX_LIGHT1) != 0);
SET_REG_FIELD(0x307, reg, 1, 4, (light_mask & GX_LIGHT2) != 0);
SET_REG_FIELD(0x308, reg, 1, 5, (light_mask & GX_LIGHT3) != 0);
SET_REG_FIELD(0x309, reg, 1, 11, (light_mask & GX_LIGHT4) != 0);
SET_REG_FIELD(0x30A, reg, 1, 12, (light_mask & GX_LIGHT5) != 0);
SET_REG_FIELD(0x30B, reg, 1, 13, (light_mask & GX_LIGHT6) != 0);
SET_REG_FIELD(0x30C, reg, 1, 14, (light_mask & GX_LIGHT7) != 0);
SET_REG_FIELD(0x30E, reg, 2, 7, (attn_fn == 0) ? 0 : diff_fn);
SET_REG_FIELD(0x30F, reg, 1, 9, (attn_fn != 2));
SET_REG_FIELD(0x310, reg, 1, 10, (attn_fn != 0));
GX_WRITE_XF_REG(idx + 14, reg);
gx->bpSentNot = 1;
if (chan == GX_COLOR0A0) {
GX_WRITE_XF_REG(16, reg);
}
else if (chan == GX_COLOR1A1) {
GX_WRITE_XF_REG(17, reg);
}
}

485
src/dolphin/gx/GXMisc.c Normal file
View file

@ -0,0 +1,485 @@
#include <dolphin/PPCArch.h>
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <stddef.h>
#include <dolphin/gx/GXPriv.h>
static GXDrawSyncCallback TokenCB;
static GXDrawDoneCallback DrawDoneCB;
static u8 DrawDone;
static OSThreadQueue FinishQueue;
void GXSetMisc(GXMiscToken token, u32 val)
{
switch (token) {
case GX_MT_XF_FLUSH:
gx->vNum = val;
gx->vNumNot = !gx->vNum;
gx->bpSentNot = 1;
if (gx->vNum != 0) {
gx->dirtyState |= 8;
}
break;
case GX_MT_DL_SAVE_CONTEXT:
ASSERTMSGLINE(0xC4, !gx->inDispList, "GXSetMisc: Cannot change DL context setting while making a display list");
gx->dlSaveContext = (val > 0);
break;
case GX_MT_NULL:
break;
default:
break;
}
}
void GXFlush(void)
{
CHECK_GXBEGIN(0x10E, "GXFlush");
if (gx->dirtyState) {
__GXSetDirtyState();
}
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();
}
void GXResetWriteGatherPipe(void)
{
while (PPCMfwpar() & 1) { }
PPCMtwpar(OSUncachedToPhysical((void *)GXFIFO_ADDR));
}
static inline void __GXAbortWait(u32 clocks)
{
OSTime time0;
OSTime time1;
time0 = OSGetTime();
do {
time1 = OSGetTime();
} while (time1 - time0 <= (clocks / 4));
}
void __GXAbortWaitPECopyDone(void)
{
__piReg[6] = 1;
__GXAbortWait(0xC8U);
__piReg[6] = 0;
__GXAbortWait(0x14U);
__GXCleanGPFifo();
}
void GXSetDrawSync(u16 token)
{
BOOL enabled;
u32 reg;
CHECK_GXBEGIN(0x162, "GXSetDrawSync");
enabled = OSDisableInterrupts();
reg = token | 0x48000000;
GX_WRITE_RAS_REG(reg);
SET_REG_FIELD(0x16F, reg, 16, 0, token);
SET_REG_FIELD(0x170, reg, 8, 24, 0x47);
GX_WRITE_RAS_REG(reg);
GXFlush();
OSRestoreInterrupts(enabled);
gx->bpSentNot = 0;
}
u16 GXReadDrawSync(void)
{
u16 token = __peReg[7];
return token;
}
void GXSetDrawDone(void)
{
u32 reg;
BOOL enabled;
CHECK_GXBEGIN(0x19C, "GXSetDrawDone");
enabled = OSDisableInterrupts();
reg = 0x45000002;
GX_WRITE_RAS_REG(reg);
GXFlush();
DrawDone = 0;
OSRestoreInterrupts(enabled);
}
void GXWaitDrawDone(void)
{
BOOL enabled;
CHECK_GXBEGIN(0x1CA, "GXWaitDrawDone");
enabled = OSDisableInterrupts();
while (!DrawDone) {
OSSleepThread(&FinishQueue);
}
OSRestoreInterrupts(enabled);
}
void GXDrawDone(void)
{
CHECK_GXBEGIN(0x1EA, "GXDrawDone");
GXSetDrawDone();
GXWaitDrawDone();
}
void GXPixModeSync(void)
{
CHECK_GXBEGIN(0x20D, "GXPixModeSync");
GX_WRITE_RAS_REG(gx->peCtrl);
gx->bpSentNot = 0;
}
void GXTexModeSync(void)
{
u32 reg;
CHECK_GXBEGIN(0x225, "GXTexModeSync");
reg = 0x63000000;
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXPokeAlphaMode(GXCompare func, u8 threshold)
{
u32 reg;
CHECK_GXBEGIN(0x25F, "GXPokeAlphaMode");
reg = (func << 8) | threshold;
__peReg[3] = reg;
}
void GXPokeAlphaRead(GXAlphaReadMode mode)
{
u32 reg;
CHECK_GXBEGIN(0x26A, "GXPokeAlphaRead");
reg = 0;
SET_REG_FIELD(0x26D, reg, 2, 0, mode);
SET_REG_FIELD(0x26E, reg, 1, 2, 1);
__peReg[4] = reg;
}
void GXPokeAlphaUpdate(GXBool update_enable)
{
u32 reg;
CHECK_GXBEGIN(0x277, "GXPokeAlphaUpdate");
reg = __peReg[1];
SET_REG_FIELD(0x27A, reg, 1, 4, update_enable);
__peReg[1] = reg;
}
void GXPokeBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op)
{
u32 reg;
CHECK_GXBEGIN(0x284, "GXPokeBlendUpdate");
reg = __peReg[1];
SET_REG_FIELD(0x28C, reg, 1, 0, (type == GX_BM_BLEND) || (type == GX_BM_SUBTRACT));
SET_REG_FIELD(0x28D, reg, 1, 11, (type == GX_BM_SUBTRACT));
SET_REG_FIELD(0x28F, reg, 1, 1, (type == GX_BM_LOGIC));
SET_REG_FIELD(0x290, reg, 4, 12, op);
SET_REG_FIELD(0x291, reg, 3, 8, src_factor);
SET_REG_FIELD(0x292, reg, 3, 5, dst_factor);
SET_REG_FIELD(0x293, reg, 8, 24, 0x41);
__peReg[1] = reg;
}
void GXPokeColorUpdate(GXBool update_enable)
{
u32 reg;
CHECK_GXBEGIN(0x29D, "GXPokeColorUpdate");
reg = __peReg[1];
SET_REG_FIELD(0x2A0, reg, 1, 3, update_enable);
__peReg[1] = reg;
}
void GXPokeDstAlpha(GXBool enable, u8 alpha)
{
u32 reg = 0;
CHECK_GXBEGIN(0x2A9, "GXPokeDstAlpha");
SET_REG_FIELD(0x2AB, reg, 8, 0, alpha);
SET_REG_FIELD(0x2AC, reg, 1, 8, enable);
__peReg[2] = reg;
}
void GXPokeDither(GXBool dither)
{
u32 reg;
CHECK_GXBEGIN(0x2B5, "GXPokeDither");
reg = __peReg[1];
SET_REG_FIELD(0x2B8, reg, 1, 2, dither);
__peReg[1] = reg;
}
void GXPokeZMode(GXBool compare_enable, GXCompare func, GXBool update_enable)
{
u32 reg = 0;
CHECK_GXBEGIN(0x2C1, "GXPokeZMode");
SET_REG_FIELD(0x2C3, reg, 1, 0, compare_enable);
SET_REG_FIELD(0x2C4, reg, 3, 1, func);
SET_REG_FIELD(0x2C5, reg, 1, 4, update_enable);
__peReg[0] = reg;
}
void GXPeekARGB(u16 x, u16 y, u32 *color)
{
u32 addr = (u32)OSPhysicalToUncached(0x08000000);
SET_REG_FIELD(0x2DC, addr, 10, 2, x);
SET_REG_FIELD(0x2DD, addr, 10, 12, y);
SET_REG_FIELD(0x2DE, addr, 2, 22, 0);
*color = *(u32 *)addr;
}
void GXPokeARGB(u16 x, u16 y, u32 color)
{
u32 addr = (u32)OSPhysicalToUncached(0x08000000);
SET_REG_FIELD(0x2E6, addr, 10, 2, x);
SET_REG_FIELD(0x2E7, addr, 10, 12, y);
SET_REG_FIELD(0x2E8, addr, 2, 22, 0);
*(u32 *)addr = color;
}
void GXPeekZ(u16 x, u16 y, u32 *z)
{
u32 addr = (u32)OSPhysicalToUncached(0x08000000);
SET_REG_FIELD(0x2F0, addr, 10, 2, x);
SET_REG_FIELD(0x2F1, addr, 10, 12, y);
SET_REG_FIELD(0x2F2, addr, 2, 22, 1);
*z = *(u32 *)addr;
}
void GXPokeZ(u16 x, u16 y, u32 z)
{
u32 addr = (u32)OSPhysicalToUncached(0x08000000);
SET_REG_FIELD(0x2FA, addr, 10, 2, x);
SET_REG_FIELD(0x2FB, addr, 10, 12, y);
SET_REG_FIELD(0x2FC, addr, 2, 22, 1);
*(u32 *)addr = z;
}
GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback cb)
{
GXDrawSyncCallback oldcb;
BOOL enabled;
oldcb = TokenCB;
enabled = OSDisableInterrupts();
TokenCB = cb;
OSRestoreInterrupts(enabled);
return oldcb;
}
static void GXTokenInterruptHandler(__OSInterrupt interrupt, OSContext *context)
{
u16 token;
OSContext exceptionContext;
u32 reg;
token = __peReg[7];
if (TokenCB != NULL) {
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
TokenCB(token);
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
reg = __peReg[5];
SET_REG_FIELD(0, reg, 1, 2, 1);
__peReg[5] = reg;
}
GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb)
{
GXDrawDoneCallback oldcb;
BOOL enabled;
oldcb = DrawDoneCB;
enabled = OSDisableInterrupts();
DrawDoneCB = cb;
OSRestoreInterrupts(enabled);
return oldcb;
}
static void GXFinishInterruptHandler(__OSInterrupt interrupt, OSContext *context)
{
OSContext exceptionContext;
u32 reg;
reg = __peReg[5];
SET_REG_FIELD(0, reg, 1, 3, 1);
__peReg[5] = reg;
DrawDone = 1;
if (DrawDoneCB != NULL) {
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
DrawDoneCB();
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
}
OSWakeupThread(&FinishQueue);
}
void __GXPEInit(void)
{
u32 reg;
__OSSetInterruptHandler(0x12, GXTokenInterruptHandler);
__OSSetInterruptHandler(0x13, GXFinishInterruptHandler);
OSInitThreadQueue(&FinishQueue);
__OSUnmaskInterrupts(0x2000);
__OSUnmaskInterrupts(0x1000);
reg = __peReg[5];
SET_REG_FIELD(0, reg, 1, 2, 1);
SET_REG_FIELD(0, reg, 1, 3, 1);
SET_REG_FIELD(0, reg, 1, 0, 1);
SET_REG_FIELD(0, reg, 1, 1, 1);
__peReg[5] = reg;
}
u32 GXCompressZ16(u32 z24, GXZFmt16 zfmt)
{
u32 z16;
u32 z24n;
s32 exp;
s32 shift;
s32 temp;
u8 unused[4];
z24n = ~(z24 << 8);
temp = __cntlzw(z24n);
switch (zfmt) {
case GX_ZC_LINEAR:
z16 = (z24 >> 8) & 0xFFFF;
break;
case GX_ZC_NEAR:
if (temp > 3) {
exp = 3;
}
else {
exp = temp;
}
if (exp == 3) {
shift = 7;
}
else {
shift = 9 - exp;
}
z16 = ((z24 >> shift) & 0x3FFF & ~0xFFFFC000) | (exp << 14);
break;
case GX_ZC_MID:
if (temp > 7) {
exp = 7;
}
else {
exp = temp;
}
if (exp == 7) {
shift = 4;
}
else {
shift = 10 - exp;
}
z16 = ((z24 >> shift) & 0x1FFF & ~0xFFFFE000) | (exp << 13);
break;
case GX_ZC_FAR:
if (temp > 12) {
exp = 12;
}
else {
exp = temp;
}
if (exp == 12) {
shift = 0;
}
else {
shift = 11 - exp;
}
z16 = ((z24 >> shift) & 0xFFF & ~0xFFFFF000) | (exp << 12);
break;
default:
OSPanic(__FILE__, 0x3B0, "GXCompressZ16: Invalid Z format\n");
break;
}
return z16;
}
u32 GXDecompressZ16(u32 z16, GXZFmt16 zfmt)
{
u32 z24;
u32 cb1;
long exp;
long shift;
cb1;
cb1;
cb1;
z16;
z16;
z16; // needed to match
switch (zfmt) {
case GX_ZC_LINEAR:
z24 = (z16 << 8) & 0xFFFF00;
break;
case GX_ZC_NEAR:
exp = (z16 >> 14) & 3;
if (exp == 3) {
shift = 7;
}
else {
shift = 9 - exp;
}
cb1 = -1 << (24 - exp);
z24 = (cb1 | ((z16 & 0x3FFF) << shift)) & 0xFFFFFF;
break;
case GX_ZC_MID:
exp = (z16 >> 13) & 7;
if (exp == 7) {
shift = 4;
}
else {
shift = 10 - exp;
}
cb1 = -1 << (24 - exp);
z24 = (cb1 | ((z16 & 0x1FFF) << shift)) & 0xFFFFFF;
break;
case GX_ZC_FAR:
exp = (z16 >> 12) & 0xF;
if (exp == 12) {
shift = 0;
}
else {
shift = 11 - exp;
}
cb1 = -1 << (24 - exp);
z24 = (cb1 | ((z16 & 0xFFF) << shift)) & 0xFFFFFF;
break;
default:
OSPanic(__FILE__, 0x3E2, "GXDecompressZ16: Invalid Z format\n");
break;
}
return z24;
}

577
src/dolphin/gx/GXPerf.c Normal file
View file

@ -0,0 +1,577 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
void GXSetGPMetric(GXPerf0 perf0, GXPerf1 perf1)
{
u32 reg;
CHECK_GXBEGIN(0x6A, "GXSetGPMetric");
switch (gx->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:
reg = 0;
GX_WRITE_XF_REG(6, reg);
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:
reg = 0x23000000;
GX_WRITE_RAS_REG(reg);
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:
reg = 0x24000000;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_NONE:
break;
default:
ASSERTMSGLINE(0xA6, 0, "GXSetGPMetric: Invalid GXPerf0 metric name");
break;
}
switch (gx->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:
reg = 0x67000000;
GX_WRITE_RAS_REG(reg);
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:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 0);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_FIFO_REQ:
case GX_PERF1_CALL_REQ:
case GX_PERF1_VC_MISS_REQ:
case GX_PERF1_CP_ALL_REQ:
reg = 0;
GX_SET_CP_REG(3, reg);
break;
case GX_PERF1_NONE:
break;
default:
ASSERTMSGLINE(0xD8, 0, "GXSetGPMetric: Invalid GXPerf1 metric name");
break;
}
gx->perf0 = perf0;
switch (gx->perf0) {
case GX_PERF0_VERTICES:
reg = 0x273;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_CLIP_VTX:
reg = 0x14A;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_CLIP_CLKS:
reg = 0x16B;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_WAIT_IN:
reg = 0x84;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_WAIT_OUT:
reg = 0xC6;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_XFRM_CLKS:
reg = 0x210;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_LIT_CLKS:
reg = 0x252;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_BOT_CLKS:
reg = 0x231;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_REGLD_CLKS:
reg = 0x1AD;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_XF_REGRD_CLKS:
reg = 0x1CE;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_CLOCKS:
reg = 0x21;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_CLIP_RATIO:
reg = 0x153;
GX_WRITE_XF_REG(6, reg);
break;
case GX_PERF0_TRIANGLES:
reg = 0x2300AE7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_CULLED:
reg = 0x23008E7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_PASSED:
reg = 0x23009E7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_SCISSORED:
reg = 0x23001E7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_0TEX:
reg = 0x2300AC3F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_1TEX:
reg = 0x2300AC7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_2TEX:
reg = 0x2300ACBF;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_3TEX:
reg = 0x2300ACFF;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_4TEX:
reg = 0x2300AD3F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_5TEX:
reg = 0x2300AD7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_6TEX:
reg = 0x2300ADBF;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_7TEX:
reg = 0x2300ADFF;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_8TEX:
reg = 0x2300AE3F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_0CLR:
reg = 0x2300A27F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_1CLR:
reg = 0x2300A67F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_TRIANGLES_2CLR:
reg = 0x2300AA7F;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_0CVG:
reg = 0x2402C0C6;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_NON0CVG:
reg = 0x2402C16B;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_1CVG:
reg = 0x2402C0E7;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_2CVG:
reg = 0x2402C108;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_3CVG:
reg = 0x2402C129;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_QUAD_4CVG:
reg = 0x2402C14A;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_AVG_QUAD_CNT:
reg = 0x2402C1AD;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF0_NONE:
break;
default:
ASSERTMSGLINE(0x1DA, 0, "GXSetGPMetric: Invalid GXPerf0 metric name");
break;
}
gx->perf1 = perf1;
switch (gx->perf1) {
case GX_PERF1_TEXELS:
reg = 0x67000042;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TX_IDLE:
reg = 0x67000084;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TX_REGS:
reg = 0x67000063;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TX_MEMSTALL:
reg = 0x67000129;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TC_MISS:
reg = 0x67000252;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_CLOCKS:
reg = 0x67000021;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TC_CHECK1_2:
reg = 0x6700014B;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TC_CHECK3_4:
reg = 0x6700018D;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TC_CHECK5_6:
reg = 0x670001CF;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_TC_CHECK7_8:
reg = 0x67000211;
GX_WRITE_RAS_REG(reg);
break;
case GX_PERF1_VC_ELEMQ_FULL:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 2);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_MISSQ_FULL:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 3);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_MEMREQ_FULL:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 4);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_STATUS7:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 5);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_MISSREP_FULL:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 6);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_STREAMBUF_LOW:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 7);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VC_ALL_STALLS:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 9);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_VERTICES:
SET_REG_FIELD(0, gx->perfSel, 4, 4, 8);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
break;
case GX_PERF1_FIFO_REQ:
reg = 2;
GX_SET_CP_REG(3, reg);
break;
case GX_PERF1_CALL_REQ:
reg = 3;
GX_SET_CP_REG(3, reg);
break;
case GX_PERF1_VC_MISS_REQ:
reg = 4;
GX_SET_CP_REG(3, reg);
break;
case GX_PERF1_CP_ALL_REQ:
reg = 5;
GX_SET_CP_REG(3, reg);
break;
case GX_PERF1_NONE:
break;
default:
ASSERTMSGLINE(0x26B, 0, "GXSetGPMetric: Invalid GXPerf1 metric name");
break;
}
gx->bpSentNot = 0;
}
#pragma scheduling off
void GXReadGPMetric(u32 *cnt0, u32 *cnt1)
{
u32 cpCtr0, cpCtr1, cpCtr2, cpCtr3;
ASSERTMSGLINE(0x286, !gx->inDispList, "GXReadGPMetric: don't use in a display list");
cpCtr0 = __GXReadCPCounterU32(32, 33);
cpCtr1 = __GXReadCPCounterU32(34, 35);
cpCtr2 = __GXReadCPCounterU32(36, 37);
cpCtr3 = __GXReadCPCounterU32(38, 39);
switch (gx->perf0) {
case GX_PERF0_CLIP_RATIO:
*cnt0 = cpCtr1 * 0x3E8 / cpCtr0;
break;
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_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:
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:
case GX_PERF0_CLOCKS:
*cnt0 = cpCtr0;
break;
case GX_PERF0_NONE:
*cnt0 = 0;
break;
default:
ASSERTMSGLINE(0x2CF, 0, "GXReadGPMetric: Invalid GXPerf0 metric name");
*cnt0 = 0;
break;
}
switch (gx->perf1) {
case GX_PERF1_TEXELS:
*cnt1 = cpCtr3 * 4;
break;
case GX_PERF1_TC_CHECK1_2:
*cnt1 = cpCtr2 + (cpCtr3 * 2);
break;
case GX_PERF1_TC_CHECK3_4:
*cnt1 = (cpCtr2 * 3) + (cpCtr3 * 4);
break;
case GX_PERF1_TC_CHECK5_6:
*cnt1 = (cpCtr2 * 5) + (cpCtr3 * 6);
break;
case GX_PERF1_TC_CHECK7_8:
*cnt1 = (cpCtr2 * 7) + (cpCtr3 * 8);
break;
case GX_PERF1_TX_IDLE:
case GX_PERF1_TX_REGS:
case GX_PERF1_TX_MEMSTALL:
case GX_PERF1_TC_MISS:
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:
case GX_PERF1_CLOCKS:
*cnt1 = cpCtr3;
break;
case GX_PERF1_FIFO_REQ:
case GX_PERF1_CALL_REQ:
case GX_PERF1_VC_MISS_REQ:
case GX_PERF1_CP_ALL_REQ:
*cnt1 = cpCtr2;
break;
case GX_PERF1_NONE:
*cnt1 = 0;
break;
default:
ASSERTMSGLINE(0x30A, 0, "GXReadGPMetric: Invalid GXPerf1 metric name");
*cnt1 = 0;
break;
}
}
#pragma scheduling reset
void GXClearGPMetric(void)
{
u32 reg;
ASSERTMSGLINE(0x322, !gx->inDispList, "GXClearGPMetric: don't use in a display list");
reg = 4;
__cpReg[2] = reg;
}
u32 GXReadGP0Metric(void)
{
u32 cnt0, cnt1;
GXReadGPMetric(&cnt0, &cnt1);
return cnt0;
}
u32 GXReadGP1Metric(void)
{
u32 cnt0, cnt1;
GXReadGPMetric(&cnt0, &cnt1);
return cnt1;
}
#pragma scheduling off
void GXReadMemMetric(
u32 *cp_req, u32 *tc_req, u32 *cpu_rd_req, u32 *cpu_wr_req, u32 *dsp_req, u32 *io_req, u32 *vi_req, u32 *pe_req, u32 *rf_req, u32 *fi_req)
{
ASSERTMSGLINE(0x380, !gx->inDispList, "GXReadMemMetric: don't use in a display list");
*cp_req = __GXReadMEMCounterU32(26, 25);
*tc_req = __GXReadMEMCounterU32(28, 27);
*cpu_rd_req = __GXReadMEMCounterU32(30, 29);
*cpu_wr_req = __GXReadMEMCounterU32(32, 31);
*dsp_req = __GXReadMEMCounterU32(34, 33);
*io_req = __GXReadMEMCounterU32(36, 35);
*vi_req = __GXReadMEMCounterU32(38, 37);
*pe_req = __GXReadMEMCounterU32(40, 39);
*rf_req = __GXReadMEMCounterU32(42, 41);
*fi_req = __GXReadMEMCounterU32(44, 43);
}
#pragma scheduling reset
void GXClearMemMetric(void)
{
ASSERTMSGLINE(0x3B9, !gx->inDispList, "GXClearMemMetric: don't use in a display list");
GX_SET_MEM_REG(25, 0);
GX_SET_MEM_REG(26, 0);
GX_SET_MEM_REG(27, 0);
GX_SET_MEM_REG(28, 0);
GX_SET_MEM_REG(30, 0);
GX_SET_MEM_REG(29, 0);
GX_SET_MEM_REG(32, 0);
GX_SET_MEM_REG(31, 0);
GX_SET_MEM_REG(34, 0);
GX_SET_MEM_REG(33, 0);
GX_SET_MEM_REG(36, 0);
GX_SET_MEM_REG(35, 0);
GX_SET_MEM_REG(38, 0);
GX_SET_MEM_REG(37, 0);
GX_SET_MEM_REG(40, 0);
GX_SET_MEM_REG(39, 0);
GX_SET_MEM_REG(42, 0);
GX_SET_MEM_REG(41, 0);
GX_SET_MEM_REG(44, 0);
GX_SET_MEM_REG(43, 0);
}
#pragma scheduling off
void GXReadPixMetric(u32 *top_pixels_in, u32 *top_pixels_out, u32 *bot_pixels_in, u32 *bot_pixels_out, u32 *clr_pixels_in, u32 *copy_clks)
{
*top_pixels_in = __GXReadPECounterU32(12, 13) * 4;
*top_pixels_out = __GXReadPECounterU32(14, 15) * 4;
*bot_pixels_in = __GXReadPECounterU32(16, 17) * 4;
*bot_pixels_out = __GXReadPECounterU32(18, 19) * 4;
*clr_pixels_in = __GXReadPECounterU32(20, 21) * 4;
*copy_clks = __GXReadPECounterU32(22, 23);
}
#pragma scheduling reset
void GXClearPixMetric(void)
{
u32 reg;
CHECK_GXBEGIN(0x48B, "GXClearPixMetric");
reg = 0x57000000;
GX_WRITE_RAS_REG(reg);
reg = 0x57000AAA;
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXSetVCacheMetric(GXVCachePerf attr)
{
u32 reg;
SET_REG_FIELD(0x43C, gx->perfSel, 4, 0, attr);
GX_WRITE_SOME_REG4(8, 0x20, gx->perfSel, -12);
reg = 1;
GX_WRITE_SOME_REG4(8, 0x10, reg, -12);
}
#pragma scheduling off
void GXReadVCacheMetric(u32 *check, u32 *miss, u32 *stall)
{
*check = __GXReadCPCounterU32(40, 41);
*miss = __GXReadCPCounterU32(42, 43);
*stall = __GXReadCPCounterU32(44, 45);
}
#pragma scheduling on
void GXClearVCacheMetric(void)
{
GX_WRITE_SOME_REG4(8, 0, 0, -12);
}

290
src/dolphin/gx/GXPixel.c Normal file
View file

@ -0,0 +1,290 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <math.h>
#include <dolphin/gx/GXPriv.h>
void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color)
{
u32 fogclr;
u32 fog0;
u32 fog1;
u32 fog2;
u32 fog3;
f32 A;
f32 B;
f32 B_mant;
f32 C;
f32 a;
f32 c;
u32 B_expn;
u32 b_m;
u32 b_s;
u32 a_hex;
u32 c_hex;
CHECK_GXBEGIN(0x8A, "GXSetFog");
ASSERTMSGLINE(0x8C, farz >= 0.0f, "GXSetFog: The farz should be positive value");
ASSERTMSGLINE(0x8D, farz >= nearz, "GXSetFog: The farz should be larger than nearz");
if (farz == nearz || endz == startz) {
A = 0.0f;
B = 0.5f;
C = 0.0f;
}
else {
A = (farz * nearz) / ((farz - nearz) * (endz - startz));
B = farz / (farz - nearz);
C = startz / (endz - startz);
}
B_mant = B;
B_expn = 0;
while (B_mant > 1.0) {
B_mant *= 0.5f;
B_expn++;
}
while (B_mant > 0.0f && B_mant < 0.5) {
B_mant *= 2.0f;
B_expn--;
}
a = A / (f32)(1 << (B_expn + 1));
b_m = 8.388638e6f * B_mant;
b_s = B_expn + 1;
c = C;
fog1 = 0;
SET_REG_FIELD(0x94, fog1, 24, 0, b_m);
SET_REG_FIELD(0x95, fog1, 8, 24, 0xEF);
fog2 = 0;
SET_REG_FIELD(0x98, fog2, 5, 0, b_s);
SET_REG_FIELD(0x99, fog2, 8, 24, 0xF0);
a_hex = *(u32 *)&a;
c_hex = *(u32 *)&c;
fog0 = 0;
SET_REG_FIELD(0xA0, fog0, 11, 0, (a_hex >> 12) & 0x7FF);
SET_REG_FIELD(0xA1, fog0, 8, 11, (a_hex >> 23) & 0xFF);
SET_REG_FIELD(0xA2, fog0, 1, 19, (a_hex >> 31));
SET_REG_FIELD(0xA3, fog0, 8, 24, 0xEE);
fog3 = 0;
SET_REG_FIELD(0xA6, fog3, 11, 0, (c_hex >> 12) & 0x7FF);
SET_REG_FIELD(0xA7, fog3, 8, 11, (c_hex >> 23) & 0xFF);
SET_REG_FIELD(0xA8, fog3, 1, 19, (c_hex >> 31));
SET_REG_FIELD(0xA9, fog3, 1, 20, 0);
SET_REG_FIELD(0xAA, fog3, 3, 21, type);
SET_REG_FIELD(0xAB, fog3, 8, 24, 0xF1);
fogclr = 0;
SET_REG_FIELD(0xAE, fogclr, 8, 0, color.b);
SET_REG_FIELD(0xAF, fogclr, 8, 8, color.g);
SET_REG_FIELD(0xB0, fogclr, 8, 16, color.r);
SET_REG_FIELD(0xB1, fogclr, 8, 24, 0xF2);
GX_WRITE_RAS_REG(fog0);
GX_WRITE_RAS_REG(fog1);
GX_WRITE_RAS_REG(fog2);
GX_WRITE_RAS_REG(fog3);
GX_WRITE_RAS_REG(fogclr);
gx->bpSentNot = 0;
}
void GXSetFogColor(GXColor color)
{
unsigned long rgba;
unsigned long fogclr = 0xF2000000;
rgba = *(u32 *)&color;
SET_REG_FIELD(0xFA, fogclr, 24, 0, rgba >> 8);
GX_WRITE_RAS_REG(fogclr);
gx->bpSentNot = 0;
}
void GXInitFogAdjTable(GXFogAdjTable *table, u16 width, const f32 projmtx[4][4])
{
f32 xi;
f32 iw;
f32 rangeVal;
f32 nearZ;
f32 sideX;
u32 i;
CHECK_GXBEGIN(0x113, "GXInitFogAdjTable");
ASSERTMSGLINE(0x114, table != NULL, "GXInitFogAdjTable: table pointer is null");
ASSERTMSGLINE(0x115, width <= 640, "GXInitFogAdjTable: invalid width value");
if (0.0 == projmtx[3][3]) {
nearZ = projmtx[2][3] / (projmtx[2][2] - 1.0f);
sideX = nearZ / projmtx[0][0];
}
else {
sideX = 1.0f / projmtx[0][0];
nearZ = 1.73205f * sideX;
}
iw = 2.0f / width;
for (i = 0; i < 10; i++) {
xi = (i + 1) << 5;
xi *= iw;
xi *= sideX;
rangeVal = sqrtf(1.0f + ((xi * xi) / (nearZ * nearZ)));
table->r[i] = (u32)(256.0f * rangeVal) & 0xFFF;
}
}
void GXSetFogRangeAdj(GXBool enable, u16 center, const GXFogAdjTable *table)
{
u32 i;
u32 range_adj;
u32 range_c;
CHECK_GXBEGIN(0x14B, "GXSetFogRangeAdj");
if (enable) {
ASSERTMSGLINE(0x14E, table != NULL, "GXSetFogRangeAdj: table pointer is null");
for (i = 0; i < 10; i += 2) {
range_adj = 0;
SET_REG_FIELD(0x152, range_adj, 12, 0, table->r[i]);
SET_REG_FIELD(0x153, range_adj, 12, 12, table->r[i + 1]);
SET_REG_FIELD(0x154, range_adj, 8, 24, (i >> 1) + 0xE9);
GX_WRITE_RAS_REG(range_adj);
}
}
range_c = 0;
SET_REG_FIELD(0x15A, range_c, 10, 0, center + 342);
SET_REG_FIELD(0x15B, range_c, 1, 10, enable);
SET_REG_FIELD(0x15C, range_c, 8, 24, 0xE8);
GX_WRITE_RAS_REG(range_c);
gx->bpSentNot = 0;
}
void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op)
{
CHECK_GXBEGIN(0x177, "GXSetBlendMode");
SET_REG_FIELD(0x135, gx->cmode0, 1, 0, (type == GX_BM_BLEND || type == GX_BM_SUBTRACT));
SET_REG_FIELD(0x136, gx->cmode0, 1, 11, (type == GX_BM_SUBTRACT));
SET_REG_FIELD(0x138, gx->cmode0, 1, 1, (type == GX_BM_LOGIC));
SET_REG_FIELD(0x139, gx->cmode0, 4, 12, op);
SET_REG_FIELD(0x13A, gx->cmode0, 3, 8, src_factor);
SET_REG_FIELD(0x13B, gx->cmode0, 3, 5, dst_factor);
SET_REG_FIELD(0x13C, gx->cmode0, 8, 24, 0x41);
GX_WRITE_RAS_REG(gx->cmode0);
gx->bpSentNot = 0;
}
void GXSetColorUpdate(GXBool update_enable)
{
CHECK_GXBEGIN(0x1A3, "GXSetColorUpdate");
SET_REG_FIELD(0x150, gx->cmode0, 1, 3, update_enable);
GX_WRITE_RAS_REG(gx->cmode0);
gx->bpSentNot = 0;
}
void GXSetAlphaUpdate(GXBool update_enable)
{
CHECK_GXBEGIN(0x1B0, "GXSetAlphaUpdate");
SET_REG_FIELD(0x159, gx->cmode0, 1, 4, update_enable);
GX_WRITE_RAS_REG(gx->cmode0);
gx->bpSentNot = 0;
}
void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable)
{
CHECK_GXBEGIN(0x1CB, "GXSetZMode");
SET_REG_FIELD(0x171, gx->zmode, 1, 0, compare_enable);
SET_REG_FIELD(0x172, gx->zmode, 3, 1, func);
SET_REG_FIELD(0x173, gx->zmode, 1, 4, update_enable);
GX_WRITE_RAS_REG(gx->zmode);
gx->bpSentNot = 0;
}
void GXSetZCompLoc(GXBool before_tex)
{
CHECK_GXBEGIN(0x1DA, "GXSetZCompLoc");
SET_REG_FIELD(0x1DB, gx->peCtrl, 1, 6, before_tex);
GX_WRITE_RAS_REG(gx->peCtrl);
gx->bpSentNot = 0;
}
void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt)
{
u32 oldPeCtrl;
u8 aa;
static u32 p2f[8] = { 0, 1, 2, 3, 4, 4, 4, 5 };
CHECK_GXBEGIN(0x1FF, "GXSetPixelFmt");
oldPeCtrl = gx->peCtrl;
ASSERTMSGLINE(0x203, pix_fmt >= 0 && pix_fmt <= 7, "Invalid Pixel format");
SET_REG_FIELD(0x205, gx->peCtrl, 3, 0, p2f[pix_fmt]);
SET_REG_FIELD(0x206, gx->peCtrl, 3, 3, z_fmt);
if (oldPeCtrl != gx->peCtrl) {
GX_WRITE_RAS_REG(gx->peCtrl);
if (pix_fmt == GX_PF_RGB565_Z16)
aa = 1;
else
aa = 0;
SET_REG_FIELD(0x20F, gx->genMode, 1, 9, aa);
gx->dirtyState |= 4;
}
if (p2f[pix_fmt] == 4) {
SET_REG_FIELD(0x216, gx->cmode1, 2, 9, (pix_fmt - 4) & 0x3);
SET_REG_FIELD(0x216, gx->cmode1, 8, 24, 0x42);
GX_WRITE_RAS_REG(gx->cmode1);
}
gx->bpSentNot = 0;
}
void GXSetDither(GXBool dither)
{
CHECK_GXBEGIN(0x22C, "GXSetDither");
SET_REG_FIELD(0x1CE, gx->cmode0, 1, 2, dither);
GX_WRITE_RAS_REG(gx->cmode0);
gx->bpSentNot = 0;
}
void GXSetDstAlpha(GXBool enable, u8 alpha)
{
CHECK_GXBEGIN(0x245, "GXSetDstAlpha");
SET_REG_FIELD(0x1E2, gx->cmode1, 8, 0, alpha);
SET_REG_FIELD(0x1E3, gx->cmode1, 1, 8, enable);
GX_WRITE_RAS_REG(gx->cmode1);
gx->bpSentNot = 0;
}
void GXSetFieldMask(GXBool odd_mask, GXBool even_mask)
{
u32 reg;
CHECK_GXBEGIN(0x260, "GXSetFieldMask");
reg = 0;
SET_REG_FIELD(0x262, reg, 1, 0, even_mask);
SET_REG_FIELD(0x263, reg, 1, 1, odd_mask);
SET_REG_FIELD(0x263, reg, 8, 24, 0x44);
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio)
{
u32 reg;
CHECK_GXBEGIN(0x27D, "GXSetFieldMode");
SET_REG_FIELD(0x281, gx->lpSize, 1, 22, half_aspect_ratio);
GX_WRITE_RAS_REG(gx->lpSize);
__GXFlushTextureState();
reg = field_mode | 0x68000000;
GX_WRITE_RAS_REG(reg);
__GXFlushTextureState();
}

5
src/dolphin/gx/GXStubs.c Normal file
View file

@ -0,0 +1,5 @@
#include <dolphin/gx.h>
#include <dolphin/gx/GXPriv.h>
void __GXSetRange(float nearz, float fgSideX) {}

403
src/dolphin/gx/GXTev.c Normal file
View file

@ -0,0 +1,403 @@
#include <dolphin/gx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
void GXSetTevOp(GXTevStageID id, GXTevMode mode)
{
GXTevColorArg carg = GX_CC_RASC;
GXTevAlphaArg aarg = GX_CA_RASA;
CHECK_GXBEGIN(0x1A4, "GXSetTevOp");
ASSERTMSGLINE(0x1A5, id < 16, "GXSetTevColor*: Invalid Tev Stage Index");
ASSERTMSGLINE(0x1A6, mode <= 4, "GXSetTevOp: Invalid Tev Mode");
if (id != GX_TEVSTAGE0) {
carg = GX_CC_CPREV;
aarg = GX_CA_APREV;
}
switch (mode) {
case GX_MODULATE:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_TEXC, carg, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO);
break;
case GX_DECAL:
GXSetTevColorIn(id, carg, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg);
break;
case GX_BLEND:
GXSetTevColorIn(id, carg, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO);
break;
case GX_REPLACE:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
break;
case GX_PASSCLR:
GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, carg);
GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg);
break;
}
GXSetTevColorOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
}
void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d)
{
u32 *pTevReg;
CHECK_GXBEGIN(0x242, "GXSetTevColorIn");
ASSERTMSGLINE(0x243, stage < 16, "GXSetTevColor*: Invalid Tev Stage Index");
ASSERTMSGLINE(0x244, a <= 15, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x245, b <= 15, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x246, c <= 15, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x247, d <= 15, "GXSetTev*In: A/B/C/D argument out of range");
pTevReg = &gx->tevc[stage];
SET_REG_FIELD(0xED, *pTevReg, 4, 12, a);
SET_REG_FIELD(0xEE, *pTevReg, 4, 8, b);
SET_REG_FIELD(0xEF, *pTevReg, 4, 4, c);
SET_REG_FIELD(0xF0, *pTevReg, 4, 0, d);
GX_WRITE_RAS_REG(*pTevReg);
gx->bpSentNot = 0;
}
void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d)
{
u32 *pTevReg;
CHECK_GXBEGIN(0x266, "GXSetTevAlphaIn");
ASSERTMSGLINE(0x267, stage < 16, "GXSetTevAlpha*: Invalid Tev Stage Index");
ASSERTMSGLINE(0x268, a <= 7, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x269, b <= 7, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x26A, c <= 7, "GXSetTev*In: A/B/C/D argument out of range");
ASSERTMSGLINE(0x26B, d <= 7, "GXSetTev*In: A/B/C/D argument out of range");
pTevReg = &gx->teva[stage];
SET_REG_FIELD(0x110, *pTevReg, 3, 13, a);
SET_REG_FIELD(0x111, *pTevReg, 3, 10, b);
SET_REG_FIELD(0x112, *pTevReg, 3, 7, c);
SET_REG_FIELD(0x113, *pTevReg, 3, 4, d);
GX_WRITE_RAS_REG(*pTevReg);
gx->bpSentNot = 0;
}
void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg)
{
u32 *pTevReg;
CHECK_GXBEGIN(0x28D, "GXSetTevColorOp");
ASSERTMSGLINE(0x28E, stage < 16, "GXSetTevColor*: Invalid Tev Stage Index");
pTevReg = &gx->tevc[stage];
SET_REG_FIELD(0x137, *pTevReg, 1, 18, op & 1);
if (op <= 1) {
SET_REG_FIELD(0x139, *pTevReg, 2, 20, scale);
SET_REG_FIELD(0x13A, *pTevReg, 2, 16, bias);
}
else {
SET_REG_FIELD(0x13C, *pTevReg, 2, 20, (op >> 1) & 3);
SET_REG_FIELD(0x13D, *pTevReg, 2, 16, 3);
}
SET_REG_FIELD(0x140, *pTevReg, 1, 19, clamp & 0xFF);
SET_REG_FIELD(0x141, *pTevReg, 2, 22, out_reg);
GX_WRITE_RAS_REG(*pTevReg);
gx->bpSentNot = 0;
}
void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, GXTevRegID out_reg)
{
u32 *pTevReg;
CHECK_GXBEGIN(0x2BB, "GXSetTevAlphaOp");
ASSERTMSGLINE(0x2BC, stage < 16, "GXSetTevAlpha*: Invalid Tev Stage Index");
pTevReg = &gx->teva[stage];
SET_REG_FIELD(0x163, *pTevReg, 1, 18, op & 1);
if (op <= 1) {
SET_REG_FIELD(0x165, *pTevReg, 2, 20, scale);
SET_REG_FIELD(0x166, *pTevReg, 2, 16, bias);
}
else {
SET_REG_FIELD(0x168, *pTevReg, 2, 20, (op >> 1) & 3);
SET_REG_FIELD(0x169, *pTevReg, 2, 16, 3);
}
SET_REG_FIELD(0x16C, *pTevReg, 1, 19, clamp & 0xFF);
SET_REG_FIELD(0x16D, *pTevReg, 2, 22, out_reg);
GX_WRITE_RAS_REG(*pTevReg);
gx->bpSentNot = 0;
}
void GXSetTevColor(GXTevRegID id, GXColor color)
{
u32 regRA;
u32 regBG;
CHECK_GXBEGIN(0x2E4, "GXSetTevColor");
regRA = 0;
SET_REG_FIELD(0x185, regRA, 11, 0, color.r);
SET_REG_FIELD(0x186, regRA, 11, 12, color.a);
SET_REG_FIELD(0x187, regRA, 8, 24, 224 + id * 2);
regBG = 0;
SET_REG_FIELD(0x18A, regBG, 11, 0, color.b);
SET_REG_FIELD(0x18B, regBG, 11, 12, color.g);
SET_REG_FIELD(0x18C, regBG, 8, 24, 225 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
GX_WRITE_RAS_REG(regBG);
GX_WRITE_RAS_REG(regBG);
gx->bpSentNot = 0;
}
void GXSetTevColorS10(GXTevRegID id, GXColorS10 color)
{
u32 regRA;
u32 regBG;
ASSERTMSGLINE(0x309, color.r >= -1024 && color.r < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023");
ASSERTMSGLINE(0x30A, color.g >= -1024 && color.g < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023");
ASSERTMSGLINE(0x30B, color.b >= -1024 && color.b < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023");
ASSERTMSGLINE(0x30C, color.a >= -1024 && color.a < 1024, "GXSetTevColorS10: Color not in range -1024 to +1023");
CHECK_GXBEGIN(0x30E, "GXSetTevColorS10");
regRA = 0;
SET_REG_FIELD(0x1AF, regRA, 11, 0, color.r & 0x7FF);
SET_REG_FIELD(0x1B0, regRA, 11, 12, color.a & 0x7FF);
SET_REG_FIELD(0x1B1, regRA, 8, 24, 224 + id * 2);
regBG = 0;
SET_REG_FIELD(0x1B4, regBG, 11, 0, color.b & 0x7FF);
SET_REG_FIELD(0x1B5, regBG, 11, 12, color.g & 0x7FF);
SET_REG_FIELD(0x1B6, regBG, 8, 24, 225 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
GX_WRITE_RAS_REG(regBG);
GX_WRITE_RAS_REG(regBG);
gx->bpSentNot = 0;
}
void GXSetTevKColor(GXTevKColorID id, GXColor color)
{
u32 regRA;
u32 regBG;
CHECK_GXBEGIN(0x341, "GXSetTevKColor");
regRA = 0;
SET_REG_FIELD(0x1E0, regRA, 8, 0, color.r);
SET_REG_FIELD(0x1E1, regRA, 8, 12, color.a);
SET_REG_FIELD(0x1E2, regRA, 4, 20, 8);
SET_REG_FIELD(0x1E3, regRA, 8, 24, 224 + id * 2);
regBG = 0;
SET_REG_FIELD(0x1E6, regBG, 8, 0, color.b);
SET_REG_FIELD(0x1E7, regBG, 8, 12, color.g);
SET_REG_FIELD(0x1E8, regBG, 4, 20, 8);
SET_REG_FIELD(0x1E9, regBG, 8, 24, 225 + id * 2);
GX_WRITE_RAS_REG(regRA);
GX_WRITE_RAS_REG(regBG);
gx->bpSentNot = 0;
}
void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel)
{
u32 *Kreg;
CHECK_GXBEGIN(0x368, "GXSetTevKColorSel");
ASSERTMSGLINE(0x369, stage < 16, "GXSetTevKColor*: Invalid Tev Stage Index");
Kreg = &gx->tevKsel[stage >> 1];
if (stage & 1) {
SET_REG_FIELD(0x20A, *Kreg, 5, 14, sel);
}
else {
SET_REG_FIELD(0x20C, *Kreg, 5, 4, sel);
}
GX_WRITE_RAS_REG(*Kreg);
gx->bpSentNot = 0;
}
void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel)
{
u32 *Kreg;
CHECK_GXBEGIN(0x389, "GXSetTevKAlphaSel");
ASSERTMSGLINE(0x38A, stage < 16, "GXSetTevKColor*: Invalid Tev Stage Index");
Kreg = &gx->tevKsel[stage >> 1];
if (stage & 1) {
SET_REG_FIELD(0x22B, *Kreg, 5, 19, sel);
}
else {
SET_REG_FIELD(0x22D, *Kreg, 5, 9, sel);
}
GX_WRITE_RAS_REG(*Kreg);
gx->bpSentNot = 0;
}
void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel ras_sel, GXTevSwapSel tex_sel)
{
u32 *pTevReg;
CHECK_GXBEGIN(0x3AE, "GXSetTevSwapMode");
ASSERTMSGLINE(0x3AF, stage < 16, "GXSetTevSwapMode: Invalid Tev Stage Index");
pTevReg = &gx->teva[stage];
SET_REG_FIELD(0x24E, *pTevReg, 2, 0, ras_sel);
SET_REG_FIELD(0x24F, *pTevReg, 2, 2, tex_sel);
GX_WRITE_RAS_REG(*pTevReg);
gx->bpSentNot = 0;
}
void GXSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, GXTevColorChan green, GXTevColorChan blue, GXTevColorChan alpha)
{
u32 *Kreg;
#if !DEBUG
// not a real variable, but needed to match release
int index = table * 2;
#endif
CHECK_GXBEGIN(0x3D2, "GXSetTevSwapModeTable");
ASSERTMSGLINE(0x3D3, table < 4, "GXSetTevSwapModeTable: Invalid Swap Selection Index");
#if DEBUG
Kreg = &gx->tevKsel[table * 2];
#else
Kreg = &gx->tevKsel[index];
#endif
SET_REG_FIELD(0x272, *Kreg, 2, 0, red);
SET_REG_FIELD(0x273, *Kreg, 2, 2, green);
GX_WRITE_RAS_REG(*Kreg);
Kreg = &gx->tevKsel[table * 2 + 1];
SET_REG_FIELD(0x277, *Kreg, 2, 0, blue);
SET_REG_FIELD(0x278, *Kreg, 2, 2, alpha);
GX_WRITE_RAS_REG(*Kreg);
gx->bpSentNot = 0;
}
void GXSetTevClampMode(void)
{
ASSERTMSGLINE(0x3F4, 0, "GXSetTevClampMode: not available on this hardware");
}
void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1)
{
u32 reg = 0;
CHECK_GXBEGIN(0x416, "GXSetAlphaCompare");
SET_REG_FIELD(0x2B4, reg, 8, 0, ref0);
SET_REG_FIELD(0x2B5, reg, 8, 8, ref1);
SET_REG_FIELD(0x2B6, reg, 3, 16, comp0);
SET_REG_FIELD(0x2B7, reg, 3, 19, comp1);
SET_REG_FIELD(0x2B8, reg, 2, 22, op);
SET_REG_FIELD(0x2B9, reg, 8, 24, 0xF3);
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias)
{
u32 zenv0;
u32 zenv1;
u32 type;
CHECK_GXBEGIN(0x435, "GXSetZTexture");
zenv0 = 0;
SET_REG_FIELD(0x2D4, zenv0, 24, 0, bias);
SET_REG_FIELD(0x2D5, zenv0, 8, 24, 0xF4);
zenv1 = 0;
switch (fmt) {
case GX_TF_Z8:
type = 0;
break;
case GX_TF_Z16:
type = 1;
break;
case GX_TF_Z24X8:
type = 2;
break;
default:
ASSERTMSGLINE(0x441, 0, "GXSetZTexture: Invalid z-texture format");
type = 2;
break;
}
SET_REG_FIELD(0x2E0, zenv1, 2, 0, type);
SET_REG_FIELD(0x2E1, zenv1, 2, 2, op);
SET_REG_FIELD(0x2E2, zenv1, 8, 24, 0xF5);
GX_WRITE_RAS_REG(zenv0);
GX_WRITE_RAS_REG(zenv1);
gx->bpSentNot = 0;
}
void GXSetTevOrder(GXTevStageID stage, GXTexCoordID coord, GXTexMapID map, GXChannelID color)
{
u32 *ptref;
u32 tmap;
u32 tcoord;
static int c2r[] = { 0, 1, 0, 1, 0, 1, 7, 5, 6 };
CHECK_GXBEGIN(0x46B, "GXSetTevOrder");
ASSERTMSGLINE(0x46C, stage < 16, "GXSetTevOrder: Invalid Tev Stage Index");
ASSERTMSGLINE(0x46E, coord < 8 || coord == 0xFF, "GXSetTevOrder: Invalid Texcoord");
ASSERTMSGLINE(0x470, (map & ~0x100) < 8 || map == 0xFF, "GXSetTevOrder: Invalid Tex Map");
ASSERTMSGLINE(0x472, color >= 4 && color <= 0xFF, "GXSetTevOrder: Invalid Color Channel ID");
ptref = &gx->tref[stage / 2];
gx->texmapId[stage] = map;
tmap = map & ~0x100;
tmap = (tmap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tmap;
if (coord >= GX_MAX_TEXCOORD) {
tcoord = GX_TEXCOORD0;
gx->tevTcEnab = gx->tevTcEnab & ~(1 << stage);
}
else {
tcoord = coord;
gx->tevTcEnab = gx->tevTcEnab | (1 << stage);
}
if (stage & 1) {
SET_REG_FIELD(0x486, *ptref, 3, 12, tmap);
SET_REG_FIELD(0x487, *ptref, 3, 15, tcoord);
SET_REG_FIELD(0x489, *ptref, 3, 19, (color == GX_COLOR_NULL) ? 7 : c2r[color]);
SET_REG_FIELD(0x48B, *ptref, 1, 18, (map != GX_TEXMAP_NULL && !(map & 0x100)));
}
else {
SET_REG_FIELD(0x48E, *ptref, 3, 0, tmap);
SET_REG_FIELD(0x48F, *ptref, 3, 3, tcoord);
SET_REG_FIELD(0x491, *ptref, 3, 7, (color == GX_COLOR_NULL) ? 7 : c2r[color]);
SET_REG_FIELD(0x493, *ptref, 1, 6, (map != GX_TEXMAP_NULL && !(map & 0x100)));
}
GX_WRITE_RAS_REG(*ptref);
gx->bpSentNot = 0;
gx->dirtyState |= 1;
}
void GXSetNumTevStages(u8 nStages)
{
CHECK_GXBEGIN(0x4A3, "GXSetNumTevStages");
ASSERTMSGLINE(0x4A5, nStages != 0 && nStages <= 16, "GXSetNumTevStages: Exceed max number of tex stages");
SET_REG_FIELD(0x334, gx->genMode, 4, 10, nStages - 1);
gx->dirtyState |= 4;
}

1269
src/dolphin/gx/GXTexture.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,372 @@
#include <dolphin/gx.h>
#include <dolphin/mtx.h>
#include <dolphin/os.h>
#include <dolphin/gx/GXPriv.h>
void GXProject(f32 x, f32 y, f32 z, const f32 mtx[3][4], const f32 *pm, const f32 *vp, f32 *sx, f32 *sy, f32 *sz)
{
Vec peye;
f32 xc;
f32 yc;
f32 zc;
f32 wc;
ASSERTMSGLINE(0xA8, pm && vp && sx && sy && sz, "GXGet*: invalid null pointer");
peye.x = mtx[0][3] + ((mtx[0][2] * z) + ((mtx[0][0] * x) + (mtx[0][1] * y)));
peye.y = mtx[1][3] + ((mtx[1][2] * z) + ((mtx[1][0] * x) + (mtx[1][1] * y)));
peye.z = mtx[2][3] + ((mtx[2][2] * z) + ((mtx[2][0] * x) + (mtx[2][1] * y)));
if (pm[0] == 0.0f) {
xc = (peye.x * pm[1]) + (peye.z * pm[2]);
yc = (peye.y * pm[3]) + (peye.z * pm[4]);
zc = pm[6] + (peye.z * pm[5]);
wc = 1.0f / -peye.z;
}
else {
xc = pm[2] + (peye.x * pm[1]);
yc = pm[4] + (peye.y * pm[3]);
zc = pm[6] + (peye.z * pm[5]);
wc = 1.0f;
}
*sx = (vp[2] / 2.0f) + (vp[0] + (wc * (xc * vp[2] / 2.0f)));
*sy = (vp[3] / 2.0f) + (vp[1] + (wc * (-yc * vp[3] / 2.0f)));
*sz = vp[5] + (wc * (zc * (vp[5] - vp[4])));
}
static void WriteProjPS(const register f32 proj[6], register volatile void *dest)
{
register f32 p01, p23, p45;
asm {
psq_l p01, 0(proj), 0, 0
psq_l p23, 8(proj), 0, 0
psq_l p45, 16(proj), 0, 0
psq_st p01, 0(dest), 0, 0
psq_st p23, 0(dest), 0, 0
psq_st p45, 0(dest), 0, 0
}
}
static void __GXSetProjection(void)
{
u32 reg = 0x00061020;
GX_WRITE_U8(0x10);
GX_WRITE_U32(reg);
GX_WRITE_XF_REG_F(32, gx->projMtx[0]);
GX_WRITE_XF_REG_F(33, gx->projMtx[1]);
GX_WRITE_XF_REG_F(34, gx->projMtx[2]);
GX_WRITE_XF_REG_F(35, gx->projMtx[3]);
GX_WRITE_XF_REG_F(36, gx->projMtx[4]);
GX_WRITE_XF_REG_F(37, gx->projMtx[5]);
GX_WRITE_XF_REG_2(38, gx->projType);
}
void GXSetProjection(f32 mtx[4][4], GXProjectionType type)
{
CHECK_GXBEGIN(0x127, "GXSetProjection");
gx->projType = type;
gx->projMtx[0] = mtx[0][0];
gx->projMtx[2] = mtx[1][1];
gx->projMtx[4] = mtx[2][2];
gx->projMtx[5] = mtx[2][3];
if (type == GX_ORTHOGRAPHIC) {
gx->projMtx[1] = mtx[0][3];
gx->projMtx[3] = mtx[1][3];
}
else {
gx->projMtx[1] = mtx[0][2];
gx->projMtx[3] = mtx[1][2];
}
__GXSetProjection();
gx->bpSentNot = 1;
}
#define qr0 0
void GXGetProjectionv(f32 *ptr)
{
ASSERTMSGLINE(0x172, ptr, "GXGet*: invalid null pointer");
ptr[0] = gx->projType;
ptr[1] = gx->projMtx[0];
ptr[2] = gx->projMtx[1];
ptr[3] = gx->projMtx[2];
ptr[4] = gx->projMtx[3];
ptr[5] = gx->projMtx[4];
ptr[6] = gx->projMtx[5];
}
static void WriteMTXPS4x3(const register f32 mtx[3][4], register volatile f32 *dest)
{
register f32 a00_a01;
register f32 a02_a03;
register f32 a10_a11;
register f32 a12_a13;
register f32 a20_a21;
register f32 a22_a23;
asm {
psq_l a00_a01, 0x00(mtx), 0, qr0
psq_l a02_a03, 0x08(mtx), 0, qr0
psq_l a10_a11, 0x10(mtx), 0, qr0
psq_l a12_a13, 0x18(mtx), 0, qr0
psq_l a20_a21, 0x20(mtx), 0, qr0
psq_l a22_a23, 0x28(mtx), 0, qr0
psq_st a00_a01, 0(dest), 0, qr0
psq_st a02_a03, 0(dest), 0, qr0
psq_st a10_a11, 0(dest), 0, qr0
psq_st a12_a13, 0(dest), 0, qr0
psq_st a20_a21, 0(dest), 0, qr0
psq_st a22_a23, 0(dest), 0, qr0
}
}
static void WriteMTXPS3x3from3x4(register f32 mtx[3][4], register volatile f32 *dest)
{
register f32 a00_a01;
register f32 a02_a03;
register f32 a10_a11;
register f32 a12_a13;
register f32 a20_a21;
register f32 a22_a23;
asm {
psq_l a00_a01, 0x00(mtx), 0, qr0
lfs a02_a03, 0x08(mtx)
psq_l a10_a11, 0x10(mtx), 0, qr0
lfs a12_a13, 0x18(mtx)
psq_l a20_a21, 0x20(mtx), 0, qr0
lfs a22_a23, 0x28(mtx)
psq_st a00_a01, 0(dest), 0, qr0
stfs a02_a03, 0(dest)
psq_st a10_a11, 0(dest), 0, qr0
stfs a12_a13, 0(dest)
psq_st a20_a21, 0(dest), 0, qr0
stfs a22_a23, 0(dest)
}
}
static void WriteMTXPS4x2(const register f32 mtx[2][4], register volatile f32 *dest)
{
register f32 a00_a01;
register f32 a02_a03;
register f32 a10_a11;
register f32 a12_a13;
asm {
psq_l a00_a01, 0x00(mtx), 0, qr0
psq_l a02_a03, 0x08(mtx), 0, qr0
psq_l a10_a11, 0x10(mtx), 0, qr0
psq_l a12_a13, 0x18(mtx), 0, qr0
psq_st a00_a01, 0(dest), 0, qr0
psq_st a02_a03, 0(dest), 0, qr0
psq_st a10_a11, 0(dest), 0, qr0
psq_st a12_a13, 0(dest), 0, qr0
}
}
#pragma peephole off
#pragma dont_inline on
void GXLoadPosMtxImm(f32 mtx[3][4], u32 id)
{
u32 reg;
u32 addr;
CHECK_GXBEGIN(0x1FB, "GXLoadPosMtxImm");
addr = id * 4;
reg = addr | 0xB0000;
GX_WRITE_U8(0x10);
GX_WRITE_U32(reg);
WriteMTXPS4x3(mtx, &GXWGFifo.f32);
}
void GXLoadNrmMtxImm(f32 mtx[3][4], u32 id)
{
u32 reg;
u32 addr;
CHECK_GXBEGIN(0x24C, "GXLoadNrmMtxImm");
addr = id * 3 + 0x400;
reg = addr | 0x80000;
GX_WRITE_U8(0x10);
GX_WRITE_U32(reg);
WriteMTXPS3x3from3x4((void *)mtx, &GXWGFifo.f32);
}
void GXSetCurrentMtx(u32 id)
{
CHECK_GXBEGIN(0x2C4, "GXSetCurrentMtx");
SET_REG_FIELD(0x2C8, gx->matIdxA, 6, 0, id);
__GXSetMatrixIndex(GX_VA_PNMTXIDX);
}
void GXLoadTexMtxImm(f32 mtx[][4], u32 id, GXTexMtxType type)
{
u32 reg;
u32 addr;
u32 count;
CHECK_GXBEGIN(0x2E5, "GXLoadTexMtxImm");
if (id >= GX_PTTEXMTX0) {
addr = (id - GX_PTTEXMTX0) * 4 + 0x500;
ASSERTMSGLINE(0x2EF, type == GX_MTX3x4, "GXLoadTexMtx: Invalid matrix type");
}
else {
addr = id * 4;
}
count = (type == GX_MTX2x4) ? 8 : 12;
reg = addr | ((count - 1) << 16);
GX_WRITE_U8(0x10);
GX_WRITE_U32(reg);
if (type == GX_MTX3x4) {
WriteMTXPS4x3(mtx, &GXWGFifo.f32);
}
else {
WriteMTXPS4x2(mtx, &GXWGFifo.f32);
}
}
#pragma dont_inline reset
void GXSetViewportJitter(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz, u32 field)
{
f32 sx;
f32 sy;
f32 sz;
f32 ox;
f32 oy;
f32 oz;
f32 zmin;
f32 zmax;
u32 reg;
CHECK_GXBEGIN(0x387, "GXSetViewport"); // not the correct function name
if (field == 0) {
top -= 0.5f;
}
sx = wd / 2.0f;
sy = -ht / 2.0f;
ox = 342.0f + (left + (wd / 2.0f));
oy = 342.0f + (top + (ht / 2.0f));
zmin = 1.6777215e7f * nearz;
zmax = 1.6777215e7f * farz;
sz = zmax - zmin;
oz = zmax;
gx->vpLeft = left;
gx->vpTop = top;
gx->vpWd = wd;
gx->vpHt = ht;
gx->vpNearz = nearz;
gx->vpFarz = farz;
if (gx->fgRange != 0) {
__GXSetRange(nearz, gx->fgSideX);
}
reg = 0x5101A;
GX_WRITE_U8(0x10);
GX_WRITE_U32(reg);
GX_WRITE_XF_REG_F(26, sx);
GX_WRITE_XF_REG_F(27, sy);
GX_WRITE_XF_REG_F(28, sz);
GX_WRITE_XF_REG_F(29, ox);
GX_WRITE_XF_REG_F(30, oy);
GX_WRITE_XF_REG_F(31, oz);
gx->bpSentNot = 1;
}
void GXSetViewport(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz)
{
GXSetViewportJitter(left, top, wd, ht, nearz, farz, 1U);
}
void GXGetViewportv(f32 *vp)
{
ASSERTMSGLINE(0x3C8, vp, "GXGet*: invalid null pointer");
vp[0] = gx->vpLeft;
vp[1] = gx->vpTop;
vp[2] = gx->vpWd;
vp[3] = gx->vpHt;
vp[4] = gx->vpNearz;
vp[5] = gx->vpFarz;
}
// maybe get it from melee?
void GXSetScissor(u32 left, u32 top, u32 wd, u32 ht)
{
u32 tp;
u32 lf;
u32 bm;
u32 rt;
CHECK_GXBEGIN(0x418, "GXSetScissor");
ASSERTMSGLINE(0x419, left < 1706, "GXSetScissor: Left origin > 1708");
ASSERTMSGLINE(0x41A, top < 1706, "GXSetScissor: top origin > 1708");
ASSERTMSGLINE(0x41B, left + wd < 1706, "GXSetScissor: right edge > 1708");
ASSERTMSGLINE(0x41C, top + ht < 1706, "GXSetScissor: bottom edge > 1708");
tp = top + 342;
lf = left + 342;
bm = tp + ht - 1;
rt = lf + wd - 1;
SET_REG_FIELD(0x423, gx->suScis0, 11, 0, tp);
SET_REG_FIELD(0x424, gx->suScis0, 11, 12, lf);
SET_REG_FIELD(0x426, gx->suScis1, 11, 0, bm);
SET_REG_FIELD(0x427, gx->suScis1, 11, 12, rt);
GX_WRITE_RAS_REG(gx->suScis0);
GX_WRITE_RAS_REG(gx->suScis1);
gx->bpSentNot = 0;
}
void GXSetScissorBoxOffset(s32 x_off, s32 y_off)
{
u32 reg = 0;
u32 hx;
u32 hy;
CHECK_GXBEGIN(0x45F, "GXSetScissorBoxOffset");
ASSERTMSGLINE(0x462, (u32)(x_off + 342) < 2048, "GXSetScissorBoxOffset: Invalid X offset");
ASSERTMSGLINE(0x464, (u32)(y_off + 342) < 2048, "GXSetScissorBoxOffset: Invalid Y offset");
hx = (u32)(x_off + 342) >> 1;
hy = (u32)(y_off + 342) >> 1;
SET_REG_FIELD(0x469, reg, 10, 0, hx);
SET_REG_FIELD(0x46A, reg, 10, 10, hy);
SET_REG_FIELD(0x46B, reg, 8, 24, 0x59);
GX_WRITE_RAS_REG(reg);
gx->bpSentNot = 0;
}
#pragma peephole on
void GXSetClipMode(GXClipMode mode)
{
CHECK_GXBEGIN(0x47F, "GXSetClipMode");
GX_WRITE_XF_REG(5, mode);
gx->bpSentNot = 1;
}
void __GXSetMatrixIndex(GXAttr matIdxAttr)
{
if (matIdxAttr < GX_VA_TEX4MTXIDX) {
GX_WRITE_SOME_REG4(8, 0x30, gx->matIdxA, -12);
GX_WRITE_XF_REG(24, gx->matIdxA);
}
else {
GX_WRITE_SOME_REG4(8, 0x40, gx->matIdxB, -12);
GX_WRITE_XF_REG(25, gx->matIdxB);
}
gx->bpSentNot = 1;
}

View file

@ -27,7 +27,7 @@ void PSQUATNormalize(void);
void OSTicksToCalendarTime(void);
void GXWaitDrawDone(void);
void GXProject(void);
void GXSetProjectionv(void);
void GXGetProjectionv(void);
void GXGetViewportv(void);
void GXPixModeSync(void);
void GXSetIndTexOrder(void);
@ -1044,7 +1044,7 @@ extern void _kerjmp_PSQUATNormalize(void);
extern void _kerjmp_OSTicksToCalendarTime(void);
extern void _kerjmp_GXWaitDrawDone(void);
extern void _kerjmp_GXProject(void);
extern void _kerjmp_GXSetProjectionv(void);
extern void _kerjmp_GXGetProjectionv(void);
extern void _kerjmp_GXGetViewportv(void);
extern void _kerjmp_GXPixModeSync(void);
extern void _kerjmp_GXSetIndTexOrder(void);
@ -2093,8 +2093,8 @@ asm void _kerent(void) {
b GXWaitDrawDone
entry _kerjmp_GXProject
b GXProject
entry _kerjmp_GXSetProjectionv
b GXSetProjectionv
entry _kerjmp_GXGetProjectionv
b GXGetProjectionv
entry _kerjmp_GXGetViewportv
b GXGetViewportv
entry _kerjmp_GXPixModeSync