summaryrefslogtreecommitdiff
path: root/soh/src/code/graph.c
diff options
context:
space:
mode:
authorM4xw <m4x@m4xw.net>2022-03-22 02:51:23 +0100
committerM4xw <m4x@m4xw.net>2022-03-22 02:51:23 +0100
commit39cc86c2608e2f75ace33fc7f43bc4f2ad743f1a (patch)
tree0d3fd9e995d7484eaaeb158ac808bd6a39121189 /soh/src/code/graph.c
parent0bb0e7b53bd80bdc7f78e08c441691737e039b2b (diff)
git subrepo clone https://github.com/HarbourMasters/soh.git
subrepo: subdir: "soh" merged: "ba904bbd0" upstream: origin: "https://github.com/HarbourMasters/soh.git" branch: "master" commit: "ba904bbd0" git-subrepo: version: "0.4.1" origin: "???" commit: "???"
Diffstat (limited to 'soh/src/code/graph.c')
-rw-r--r--soh/src/code/graph.c610
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;
+}