diff options
Diffstat (limited to 'soh/src/code/graph.c')
| -rw-r--r-- | soh/src/code/graph.c | 610 |
1 files changed, 610 insertions, 0 deletions
diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c new file mode 100644 index 000000000..9d2886ef1 --- /dev/null +++ b/soh/src/code/graph.c @@ -0,0 +1,610 @@ +#include "global.h" +#include "vt.h" +#include "regs.h" + +#include <string.h> + +#include "soh/Enhancements/gameconsole.h" + +#define GFXPOOL_HEAD_MAGIC 0x1234 +#define GFXPOOL_TAIL_MAGIC 0x5678 + +OSTime sGraphUpdateTime; +OSTime sGraphSetTaskTime; +FaultClient sGraphFaultClient; +CfbInfo sGraphCfbInfos[3]; +FaultClient sGraphUcodeFaultClient; + +// clang-format off +UCodeInfo D_8012D230[3] = { + //{ UCODE_F3DZEX, D_80155F50 }, + { UCODE_UNK, NULL }, + //{ UCODE_S2DEX, D_80113070 }, +}; + +UCodeInfo D_8012D248[3] = { + //{ UCODE_F3DZEX, D_80155F50 }, + { UCODE_UNK, NULL }, + //{ UCODE_S2DEX, D_80113070 }, +}; +// clang-format on + +void Graph_FaultClient() { + void* nextFb = osViGetNextFramebuffer(); + void* newFb = ((uintptr_t)SysCfb_GetFbPtr(0) != (uintptr_t)nextFb) ? SysCfb_GetFbPtr(0) : SysCfb_GetFbPtr(1); + + osViSwapBuffer(newFb); + Fault_WaitForInput(); + osViSwapBuffer(nextFb); +} + +void Graph_DisassembleUCode(Gfx* workBuf) { + #if 0 + UCodeDisas disassembler; + + if (HREG(80) == 7 && HREG(81) != 0) { + UCodeDisas_Init(&disassembler); + disassembler.enableLog = HREG(83); + UCodeDisas_RegisterUCode(&disassembler, ARRAY_COUNT(D_8012D230), D_8012D230); + //UCodeDisas_SetCurUCode(&disassembler, D_80155F50); + UCodeDisas_Disassemble(&disassembler, workBuf); + HREG(93) = disassembler.dlCnt; + HREG(84) = disassembler.tri2Cnt * 2 + disassembler.tri1Cnt + (disassembler.quadCnt * 2) + disassembler.lineCnt; + HREG(85) = disassembler.vtxCnt; + HREG(86) = disassembler.spvtxCnt; + HREG(87) = disassembler.tri1Cnt; + HREG(88) = disassembler.tri2Cnt; + HREG(89) = disassembler.quadCnt; + HREG(90) = disassembler.lineCnt; + HREG(91) = disassembler.syncErr; + HREG(92) = disassembler.loaducodeCnt; + if (HREG(82) == 1 || HREG(82) == 2) { + osSyncPrintf("vtx_cnt=%d\n", disassembler.vtxCnt); + osSyncPrintf("spvtx_cnt=%d\n", disassembler.spvtxCnt); + osSyncPrintf("tri1_cnt=%d\n", disassembler.tri1Cnt); + osSyncPrintf("tri2_cnt=%d\n", disassembler.tri2Cnt); + osSyncPrintf("quad_cnt=%d\n", disassembler.quadCnt); + osSyncPrintf("line_cnt=%d\n", disassembler.lineCnt); + osSyncPrintf("sync_err=%d\n", disassembler.syncErr); + osSyncPrintf("loaducode_cnt=%d\n", disassembler.loaducodeCnt); + osSyncPrintf("dl_depth=%d\n", disassembler.dlDepth); + osSyncPrintf("dl_cnt=%d\n", disassembler.dlCnt); + } + UCodeDisas_Destroy(&disassembler); + } + #endif +} + +void Graph_UCodeFaultClient(Gfx* workBuf) { + #if 0 + UCodeDisas disassembler; + + UCodeDisas_Init(&disassembler); + disassembler.enableLog = true; + UCodeDisas_RegisterUCode(&disassembler, ARRAY_COUNT(D_8012D248), D_8012D248); + //UCodeDisas_SetCurUCode(&disassembler, D_80155F50); + UCodeDisas_Disassemble(&disassembler, workBuf); + UCodeDisas_Destroy(&disassembler); + #endif +} + +void Graph_InitTHGA(GraphicsContext* gfxCtx) { + GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx & 1]; + + pool->headMagic = GFXPOOL_HEAD_MAGIC; + pool->tailMagic = GFXPOOL_TAIL_MAGIC; + THGA_Ct(&gfxCtx->polyOpa, pool->polyOpaBuffer, sizeof(pool->polyOpaBuffer)); + THGA_Ct(&gfxCtx->polyXlu, pool->polyXluBuffer, sizeof(pool->polyXluBuffer)); + THGA_Ct(&gfxCtx->polyKal, pool->polyKalBuffer, sizeof(pool->polyKalBuffer)); + THGA_Ct(&gfxCtx->overlay, pool->overlayBuffer, sizeof(pool->overlayBuffer)); + THGA_Ct(&gfxCtx->work, pool->workBuffer, sizeof(pool->workBuffer)); + + gfxCtx->polyOpaBuffer = pool->polyOpaBuffer; + gfxCtx->polyXluBuffer = pool->polyXluBuffer; + gfxCtx->polyKalBuffer = pool->polyKalBuffer; + gfxCtx->overlayBuffer = pool->overlayBuffer; + gfxCtx->workBuffer = pool->workBuffer; + + gfxCtx->curFrameBuffer = (u16*)SysCfb_GetFbPtr(gfxCtx->fbIdx % 2); + gfxCtx->unk_014 = 0; +} + +GameStateOverlay* Graph_GetNextGameState(GameState* gameState) { + void* gameStateInitFunc = GameState_GetInit(gameState); + + if (gameStateInitFunc == TitleSetup_Init) { + return &gGameStateOverlayTable[0]; + } + if (gameStateInitFunc == Select_Init) { + return &gGameStateOverlayTable[1]; + } + if (gameStateInitFunc == Title_Init) { + return &gGameStateOverlayTable[2]; + } + if (gameStateInitFunc == Gameplay_Init) { + return &gGameStateOverlayTable[3]; + } + if (gameStateInitFunc == Opening_Init) { + return &gGameStateOverlayTable[4]; + } + if (gameStateInitFunc == FileChoose_Init) { + return &gGameStateOverlayTable[5]; + } + + LOG_ADDRESS("game_init_func", gameStateInitFunc, "../graph.c", 696); + return NULL; +} + +void Graph_Init(GraphicsContext* gfxCtx) { + memset(gfxCtx,0, sizeof(GraphicsContext)); + gfxCtx->gfxPoolIdx = 0; + gfxCtx->fbIdx = 0; + gfxCtx->viMode = NULL; + gfxCtx->viFeatures = gViConfigFeatures; + gfxCtx->xScale = gViConfigXScale; + gfxCtx->yScale = gViConfigYScale; + osCreateMesgQueue(&gfxCtx->queue, gfxCtx->msgBuff, ARRAY_COUNT(gfxCtx->msgBuff)); + func_800D31F0(); + Fault_AddClient(&sGraphFaultClient, Graph_FaultClient, 0, 0); +} + +void Graph_Destroy(GraphicsContext* gfxCtx) { + func_800D3210(); + Fault_RemoveClient(&sGraphFaultClient); +} + +void Graph_TaskSet00(GraphicsContext* gfxCtx) { + static Gfx* D_8012D260 = NULL; + static s32 sGraphCfbInfoIdx = 0; + + OSTime time; + OSTimer timer; + OSMesg msg; + OSTask_t* task = &gfxCtx->task.list.t; + OSScTask* scTask = &gfxCtx->task; + CfbInfo* cfb; + s32 pad1; + + D_8016A528 = osGetTime() - sGraphSetTaskTime - D_8016A558; + + osSetTimer(&timer, OS_USEC_TO_CYCLES(3000000), 0, &gfxCtx->queue, (OSMesg)666); + + osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_BLOCK); + osStopTimer(&timer); + //OTRTODO - Proper GFX crash handler + #if 0 + if (msg == (OSMesg)666) { + osSyncPrintf(VT_FGCOL(RED)); + osSyncPrintf("RCPが帰ってきませんでした。"); // "RCP did not return." + osSyncPrintf(VT_RST); + LogUtils_LogHexDump((void*)&HW_REG(SP_MEM_ADDR_REG, u32), 0x20); + LogUtils_LogHexDump((void*)&DPC_START_REG, 0x20); + LogUtils_LogHexDump(gGfxSPTaskYieldBuffer, sizeof(gGfxSPTaskYieldBuffer)); + + SREG(6) = -1; + if (D_8012D260 != NULL) { + HREG(80) = 7; + HREG(81) = 1; + HREG(83) = 2; + D_8012D260 = D_8012D260; + Graph_DisassembleUCode(D_8012D260); + } + Fault_AddHungupAndCrashImpl("RCP is HUNG UP!!", "Oh! MY GOD!!"); + } + #endif + osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_NOBLOCK); + + D_8012D260 = gfxCtx->workBuffer; + if (gfxCtx->callback != NULL) { + gfxCtx->callback(gfxCtx, gfxCtx->callbackParam); + } + + time = osGetTime(); + if (D_8016A550 != 0) { + D_8016A558 = (D_8016A558 + time) - D_8016A550; + D_8016A550 = time; + } + D_8016A520 = D_8016A558; + D_8016A558 = 0; + sGraphSetTaskTime = osGetTime(); + + task->type = M_GFXTASK; + task->flags = OS_SC_DRAM_DLIST; + task->ucode_boot = SysUcode_GetUCodeBoot(); + task->ucode_boot_size = SysUcode_GetUCodeBootSize(); + task->ucode = SysUcode_GetUCode(); + task->ucode_data = SysUcode_GetUCodeData(); + task->ucode_size = 0x1000; + task->ucode_data_size = 0x800; + task->dram_stack = (u64*)gGfxSPTaskStack; + task->dram_stack_size = sizeof(gGfxSPTaskStack); + task->output_buff = gGfxSPTaskOutputBuffer; + task->output_buff_size = (u64*)((u8*)gGfxSPTaskOutputBuffer + sizeof(gGfxSPTaskOutputBuffer)); + task->data_ptr = (u64*)gfxCtx->workBuffer; + + OPEN_DISPS(gfxCtx, "../graph.c", 828); + task->data_size = (uintptr_t)WORK_DISP - (uintptr_t)gfxCtx->workBuffer; + CLOSE_DISPS(gfxCtx, "../graph.c", 830); + + { s32 pad2; } // Necessary to match stack usage + + task->yield_data_ptr = (u64*)gGfxSPTaskYieldBuffer; + task->yield_data_size = sizeof(gGfxSPTaskYieldBuffer); + + scTask->next = NULL; + scTask->flags = OS_SC_RCP_MASK | OS_SC_SWAPBUFFER | OS_SC_LAST_TASK; + if (SREG(33) & 1) { + SREG(33) &= ~1; + scTask->flags &= ~OS_SC_SWAPBUFFER; + gfxCtx->fbIdx--; + } + + scTask->msgQ = &gfxCtx->queue; + scTask->msg = NULL; + + cfb = &sGraphCfbInfos[sGraphCfbInfoIdx++]; + cfb->fb1 = gfxCtx->curFrameBuffer; + cfb->swapBuffer = gfxCtx->curFrameBuffer; + cfb->viMode = gfxCtx->viMode; + cfb->features = gfxCtx->viFeatures; + cfb->xScale = gfxCtx->xScale; + cfb->yScale = gfxCtx->yScale; + cfb->unk_10 = 0; + cfb->updateRate = R_UPDATE_RATE; + + scTask->framebuffer = cfb; + sGraphCfbInfoIdx = sGraphCfbInfoIdx % ARRAY_COUNT(sGraphCfbInfos); + + if (1) {} + + gfxCtx->schedMsgQ = &gSchedContext.cmdQ; + + osSendMesg(&gSchedContext.cmdQ, scTask, OS_MESG_BLOCK); + Sched_SendEntryMsg(&gSchedContext); +} + +void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) { + u32 problem; + + gameState->unk_A0 = 0; + Graph_InitTHGA(gfxCtx); + + OPEN_DISPS(gfxCtx, "../graph.c", 966); + + gDPNoOpString(WORK_DISP++, "WORK_DISP 開始", 0); + gDPNoOpString(POLY_OPA_DISP++, "POLY_OPA_DISP 開始", 0); + gDPNoOpString(POLY_XLU_DISP++, "POLY_XLU_DISP 開始", 0); + gDPNoOpString(OVERLAY_DISP++, "OVERLAY_DISP 開始", 0); + + CLOSE_DISPS(gfxCtx, "../graph.c", 975); + + GameState_ReqPadData(gameState); + GameState_Update(gameState); + + OPEN_DISPS(gfxCtx, "../graph.c", 987); + + gDPNoOpString(WORK_DISP++, "WORK_DISP 終了", 0); + gDPNoOpString(POLY_OPA_DISP++, "POLY_OPA_DISP 終了", 0); + gDPNoOpString(POLY_XLU_DISP++, "POLY_XLU_DISP 終了", 0); + gDPNoOpString(OVERLAY_DISP++, "OVERLAY_DISP 終了", 0); + + CLOSE_DISPS(gfxCtx, "../graph.c", 996); + + OPEN_DISPS(gfxCtx, "../graph.c", 999); + + gSPBranchList(WORK_DISP++, gfxCtx->polyOpaBuffer); + gSPBranchList(POLY_OPA_DISP++, gfxCtx->polyXluBuffer); + gSPBranchList(POLY_XLU_DISP++, gfxCtx->polyKalBuffer); + gSPBranchList(POLY_KAL_DISP++, gfxCtx->overlayBuffer); + gDPPipeSync(OVERLAY_DISP++); + gDPFullSync(OVERLAY_DISP++); + gSPEndDisplayList(OVERLAY_DISP++); + + CLOSE_DISPS(gfxCtx, "../graph.c", 1028); + + if (HREG(80) == 10 && HREG(93) == 2) { + HREG(80) = 7; + HREG(81) = -1; + HREG(83) = HREG(92); + } + + if (HREG(80) == 7 && HREG(81) != 0) { + if (HREG(82) == 3) { + Fault_AddClient(&sGraphUcodeFaultClient, Graph_UCodeFaultClient, gfxCtx->workBuffer, "do_count_fault"); + } + + Graph_DisassembleUCode(gfxCtx->workBuffer); + + if (HREG(82) == 3) { + Fault_RemoveClient(&sGraphUcodeFaultClient); + } + + if (HREG(81) < 0) { + LogUtils_LogHexDump((void*)&HW_REG(SP_MEM_ADDR_REG, u32), 0x20); + LogUtils_LogHexDump((void*)&DPC_START_REG, 0x20); + } + + if (HREG(81) < 0) { + HREG(81) = 0; + } + } + + problem = false; + + { + GfxPool* pool = &gGfxPools[gfxCtx->gfxPoolIdx & 1]; + + if (pool->headMagic != GFXPOOL_HEAD_MAGIC) { + //! @bug (?) : "problem = true;" may be missing + osSyncPrintf("%c", 7); + // "Dynamic area head is destroyed" + osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域先頭が破壊されています\n" VT_RST); + Fault_AddHungupAndCrash("../graph.c", 1070); + } + if (pool->tailMagic != GFXPOOL_TAIL_MAGIC) { + problem = true; + osSyncPrintf("%c", 7); + // "Dynamic region tail is destroyed" + osSyncPrintf(VT_COL(RED, WHITE) "ダイナミック領域末尾が破壊されています\n" VT_RST); + Fault_AddHungupAndCrash("../graph.c", 1076); + } + } + + if (THGA_IsCrash(&gfxCtx->polyOpa)) { + problem = true; + osSyncPrintf("%c", 7); + // "Zelda 0 is dead" + osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ0は死んでしまった(graph_alloc is empty)\n" VT_RST); + } + if (THGA_IsCrash(&gfxCtx->polyXlu)) { + problem = true; + osSyncPrintf("%c", 7); + // "Zelda 1 is dead" + osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ1は死んでしまった(graph_alloc is empty)\n" VT_RST); + } + if (THGA_IsCrash(&gfxCtx->overlay)) { + problem = true; + osSyncPrintf("%c", 7); + // "Zelda 4 is dead" + osSyncPrintf(VT_COL(RED, WHITE) "ゼルダ4は死んでしまった(graph_alloc is empty)\n" VT_RST); + } + + if (!problem) { + Graph_TaskSet00(gfxCtx); + gfxCtx->gfxPoolIdx++; + gfxCtx->fbIdx++; + } + + func_800F3054(); + + { + OSTime time = osGetTime(); + s32 pad[4]; + + D_8016A538 = gRSPGFXTotalTime; + D_8016A530 = gRSPAudioTotalTime; + D_8016A540 = gRDPTotalTime; + gRSPGFXTotalTime = 0; + gRSPAudioTotalTime = 0; + gRDPTotalTime = 0; + + if (sGraphUpdateTime != 0) { + D_8016A548 = time - sGraphUpdateTime; + } + sGraphUpdateTime = time; + } + + if (CVar_GetS32("gDebugEnabled", 0)) + { + if (CHECK_BTN_ALL(gameState->input[0].press.button, BTN_Z) && + CHECK_BTN_ALL(gameState->input[0].cur.button, BTN_L | BTN_R)) { + gSaveContext.gameMode = 0; + SET_NEXT_GAMESTATE(gameState, Select_Init, SelectContext); + gameState->running = false; + } + } + + if (gIsCtrlr2Valid && PreNmiBuff_IsResetting(gAppNmiBufferPtr) && !gameState->unk_A0) { + // "To reset mode" + osSyncPrintf(VT_COL(YELLOW, BLACK) "PRE-NMIによりリセットモードに移行します\n" VT_RST); + SET_NEXT_GAMESTATE(gameState, PreNMI_Init, PreNMIContext); + gameState->running = false; + } +} + +uint64_t GetFrequency(); +uint64_t GetPerfCounter(); + +static struct RunFrameContext { + GraphicsContext gfxCtx; + GameState* gameState; + GameStateOverlay* nextOvl; + GameStateOverlay* ovl; + int state; +} runFrameContext; + + +extern AudioMgr gAudioMgr; + +static void RunFrame() +{ + u32 size; + char faultMsg[0x50]; + + switch (runFrameContext.state) { + case 0: + break; + case 1: + goto nextFrame; + } + + runFrameContext.nextOvl = &gGameStateOverlayTable[0]; + + osSyncPrintf("グラフィックスレッド実行開始\n"); // "Start graphic thread execution" + Graph_Init(&runFrameContext.gfxCtx); + + while (runFrameContext.nextOvl) + { + runFrameContext.ovl = runFrameContext.nextOvl; + Overlay_LoadGameState(runFrameContext.ovl); + + size = runFrameContext.ovl->instanceSize; + osSyncPrintf("クラスサイズ=%dバイト\n", size); // "Class size = %d bytes" + + runFrameContext.gameState = SystemArena_MallocDebug(size, "../graph.c", 1196); + + if (!runFrameContext.gameState) + { + osSyncPrintf("確保失敗\n"); // "Failure to secure" + + sprintf(faultMsg, "CLASS SIZE= %d bytes", size); + Fault_AddHungupAndCrashImpl("GAME CLASS MALLOC FAILED", faultMsg); + } + GameState_Init(runFrameContext.gameState, runFrameContext.ovl->init, &runFrameContext.gfxCtx); + + uint64_t freq = GetFrequency(); + + while (GameState_IsRunning(runFrameContext.gameState)) + { + uint64_t ticksA, ticksB; + ticksA = GetPerfCounter(); + + OTRSetFrameDivisor(R_UPDATE_RATE); + //OTRSetFrameDivisor(0); + + + //AudioMgr_ThreadEntry(&gAudioMgr); + // 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333.. + // in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528 + #define SAMPLES_HIGH 560 + #define SAMPLES_LOW 528 + // PAL values + //#define SAMPLES_HIGH 656 + //#define SAMPLES_LOW 624 + #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) + #define NUM_AUDIO_CHANNELS 2 + int samples_left = AudioPlayer_Buffered(); + u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; + // printf("Audio samples: %d %u\n", samples_left, num_audio_samples); + + // 3 is the maximum authentic frame divisor. + s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; + for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { + AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); + } + //for (uint32_t i = 0; i < 2 * num_audio_samples; i++) { + // audio_buffer[i] = Rand_Next() & 0xFF; + //} + // printf("Audio samples before submitting: %d\n", audio_api->buffered()); + AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); + + + PadMgr_ThreadEntry(&gPadMgr); + + Graph_Update(&runFrameContext.gfxCtx, runFrameContext.gameState); + ticksB = GetPerfCounter(); + + Graph_ProcessGfxCommands(runFrameContext.gfxCtx.workBuffer); + + + //uint64_t diff = (ticksB - ticksA) / (freq / 1000); + //printf("Frame simulated in %ims\n", diff); + runFrameContext.state = 1; + return; + nextFrame:; + } + + runFrameContext.nextOvl = Graph_GetNextGameState(runFrameContext.gameState); + GameState_Destroy(runFrameContext.gameState); + SystemArena_FreeDebug(runFrameContext.gameState, "../graph.c", 1227); + Overlay_FreeGameState(runFrameContext.ovl); + } + Graph_Destroy(&runFrameContext.gfxCtx); + osSyncPrintf("グラフィックスレッド実行終了\n"); // "End of graphic thread execution" + + //Graph_Update(gfxCtxTest, gameStateTest); + exit(0); +} + +void Graph_ThreadEntry(void* arg0) { + + Graph_ProcessFrame(RunFrame); +} + +void* Graph_Alloc(GraphicsContext* gfxCtx, size_t size) { + TwoHeadGfxArena* thga = &gfxCtx->polyOpa; + + if (HREG(59) == 1) { + osSyncPrintf("graph_alloc siz=%d thga size=%08x bufp=%08x head=%08x tail=%08x\n", size, thga->size, thga->bufp, + thga->p, thga->d); + } + return THGA_AllocEnd(&gfxCtx->polyOpa, ALIGN16(size)); +} + +void* Graph_Alloc2(GraphicsContext* gfxCtx, size_t size) { + TwoHeadGfxArena* thga = &gfxCtx->polyOpa; + + if (HREG(59) == 1) { + osSyncPrintf("graph_alloc siz=%d thga size=%08x bufp=%08x head=%08x tail=%08x\n", size, thga->size, thga->bufp, + thga->p, thga->d); + } + return THGA_AllocEnd(&gfxCtx->polyOpa, ALIGN16(size)); +} + +void Graph_OpenDisps(Gfx** dispRefs, GraphicsContext* gfxCtx, const char* file, s32 line) { + if (HREG(80) == 7 && HREG(82) != 4) { + dispRefs[0] = gfxCtx->polyOpa.p; + dispRefs[1] = gfxCtx->polyXlu.p; + dispRefs[2] = gfxCtx->overlay.p; + + gDPNoOpOpenDisp(gfxCtx->polyOpa.p++, file, line); + gDPNoOpOpenDisp(gfxCtx->polyXlu.p++, file, line); + gDPNoOpOpenDisp(gfxCtx->overlay.p++, file, line); + } +} + +void Graph_CloseDisps(Gfx** dispRefs, GraphicsContext* gfxCtx, const char* file, s32 line) { + if (HREG(80) == 7 && HREG(82) != 4) { + if (dispRefs[0] + 1 == gfxCtx->polyOpa.p) { + gfxCtx->polyOpa.p = dispRefs[0]; + } else { + gDPNoOpCloseDisp(gfxCtx->polyOpa.p++, file, line); + } + + if (dispRefs[1] + 1 == gfxCtx->polyXlu.p) { + gfxCtx->polyXlu.p = dispRefs[1]; + } else { + gDPNoOpCloseDisp(gfxCtx->polyXlu.p++, file, line); + } + + if (dispRefs[2] + 1 == gfxCtx->overlay.p) { + gfxCtx->overlay.p = dispRefs[2]; + } else { + gDPNoOpCloseDisp(gfxCtx->overlay.p++, file, line); + } + } +} + +Gfx* Graph_GfxPlusOne(Gfx* gfx) { + return gfx + 1; +} + +Gfx* Graph_BranchDlist(Gfx* gfx, Gfx* dst) { + gSPBranchList(gfx, dst); + return dst; +} + +void* Graph_DlistAlloc(Gfx** gfx, size_t size) { + u8* ptr; + Gfx* dst; + + size = ((size + 7) & ~7), + + ptr = (u8*)(*gfx + 1); + + dst = (Gfx*)(ptr + size); + gSPBranchList(*gfx, dst); + + *gfx = dst; + return ptr; +} |
