diff --git a/Makefile b/Makefile index 894ace70a..5919c815d 100644 --- a/Makefile +++ b/Makefile @@ -519,6 +519,7 @@ else ifeq ($(COMPILER), gcc) -Wno-address \ -Wno-aggressive-loop-optimizations \ -Wno-array-bounds \ + -Wno-comment \ -Wno-int-in-bool-context \ -Wno-int-to-pointer-cast \ -Wno-maybe-uninitialized \ diff --git a/include/PR/sched.h b/include/PR/sched.h index 166a81b73..2777fb9a1 100644 --- a/include/PR/sched.h +++ b/include/PR/sched.h @@ -91,18 +91,15 @@ typedef struct { OSScMsg prenmiMsg; OSMesgQueue interruptQ; OSMesg intBuf[OS_SC_MAX_MESGS]; - OSMesgQueue cmdQ; - OSMesg cmdMsgBuf[OS_SC_MAX_MESGS]; OSThread *thread; - OSScClient *clientList; - OSScTask *audioListHead; - OSScTask *gfxListHead; - OSScTask *audioListTail; - OSScTask *gfxListTail; + OSScTask *nextAudTask; + OSScTask *nextGfxTask; + OSScTask *nextGfxTask2; OSScTask *curRSPTask; OSScTask *curRDPTask; - u32 frameCount; - s32 doAudio; + u32 alt; + OSMesgQueue *audmq; + OSMesgQueue *gfxmq; } OSSched; void osCreateScheduler(OSSched *s, OSThread *thread, u8 mode, u32 numFields); diff --git a/ld/libfiles.ntsc-final.inc b/ld/libfiles.ntsc-final.inc index c7d84b86b..b17cccd22 100644 --- a/ld/libfiles.ntsc-final.inc +++ b/ld/libfiles.ntsc-final.inc @@ -2,6 +2,7 @@ build/ROMID/lib/tlb.o (section); \ build/ROMID/lib/segments.o (section); \ build/ROMID/lib/boot.o (section); \ + build/ROMID/lib/artifacts.o (section); \ build/ROMID/lib/sched.o (section); \ build/ROMID/lib/reset.o (section); \ build/ROMID/lib/ultra/os/maptlbrdb.o (section); \ diff --git a/src/include/bss.h b/src/include/bss.h index e1055222f..bd0be4251 100644 --- a/src/include/bss.h +++ b/src/include/bss.h @@ -60,7 +60,6 @@ extern OSTimer __osEepromTimer; extern OSMesgQueue __osEepromTimerQ; extern OSMesg __osEepromTimerMsg; extern u32 var8009ca84; -extern u16 *g_FrameBuffers[2]; extern u8 var8009caec; extern u8 var8009caed; extern u8 var8009caee; diff --git a/src/include/lib/sched.h b/src/include/lib/sched.h index 4dafd676a..276012519 100644 --- a/src/include/lib/sched.h +++ b/src/include/lib/sched.h @@ -3,16 +3,8 @@ #include #include -void schedSetCrashEnable2(s32 enable); -void schedAppendTasks(OSSched *sc, OSScTask *t); -void __scHandleRetrace(OSSched *sc); -void __scHandleRSP(OSSched *sc); -void __scHandleRDP(OSSched *sc); -void __scHandleTasks(OSSched *sc); -void __scAppendList(OSSched *sc, OSScTask *t); -void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp, s32 resuming); -void __scMain(void *arg); -void __scYield(OSSched *sc); +void schedSubmitAudTask(OSSched *sc, OSScTask *t); +void schedSubmitGfxTask(OSSched *sc, OSScTask *t); void schedInitArtifacts(void); void schedResetArtifacts(void); struct artifact *schedGetWriteArtifacts(void); @@ -20,6 +12,5 @@ struct artifact *schedGetFrontArtifacts(void); void schedIncrementWriteArtifacts(void); void schedIncrementFrontArtifacts(void); void schedUpdatePendingArtifacts(void); -void schedConsiderScreenshot(void); #endif diff --git a/src/lib/artifacts.c b/src/lib/artifacts.c new file mode 100644 index 000000000..45c535dd5 --- /dev/null +++ b/src/lib/artifacts.c @@ -0,0 +1,117 @@ +#include +#include "lib/boot.h" +#include "lib/sched.h" +#include "constants.h" +#include "game/menugfx.h" +#include "bss.h" +#include "lib/args.h" +#include "lib/audiomgr.h" +#include "lib/reset.h" +#include "lib/rzip.h" +#include "lib/main.h" +#include "lib/snd.h" +#include "lib/pimgr.h" +#include "lib/profile.h" +#include "lib/lib_48150.h" +#include "lib/vi.h" +#include "lib/joy.h" +#include "data.h" +#include "types.h" + +struct artifact g_ArtifactLists[3][120]; +u8 g_SchedSpecialArtifactIndexes[3]; +s32 g_SchedWriteArtifactsIndex; +s32 g_SchedFrontArtifactsIndex; +s32 g_SchedPendingArtifactsIndex; + +void schedInitArtifacts(void) +{ + s32 i; + s32 j; + + for (i = 0; i < 3; i++) { + for (j = 0; j < MAX_ARTIFACTS; j++) { + g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE; + } + + g_SchedSpecialArtifactIndexes[i] = 0; + } +} + +/** + * The write list is an artifact list that is not currently being displayed on + * the screen. Update logic can write here to put artifacts on the next frame. + */ +struct artifact *schedGetWriteArtifacts(void) +{ + return g_ArtifactLists[g_SchedWriteArtifactsIndex]; +} + +/** + * The front list is the artifact list that is currently being displayed on the + * screen. Rendering logic reads this list. The list may be re-used for multiple + * frames in a row during lag. + */ +struct artifact *schedGetFrontArtifacts(void) +{ + return g_ArtifactLists[g_SchedFrontArtifactsIndex]; +} + +struct artifact *schedGetPendingArtifacts(void) +{ + return g_ArtifactLists[g_SchedPendingArtifactsIndex]; +} + +void schedIncrementWriteArtifacts(void) +{ + g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3; +} + +void schedIncrementFrontArtifacts(void) +{ + g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3; +} + +void schedIncrementPendingArtifacts(void) +{ + g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3; +} + +void schedResetArtifacts(void) +{ + g_SchedWriteArtifactsIndex = 0; + g_SchedFrontArtifactsIndex = 1; + g_SchedPendingArtifactsIndex = 0; +} + +void schedUpdatePendingArtifacts(void) +{ + struct artifact *artifacts = schedGetPendingArtifacts(); + s32 i; + + for (i = 0; i < MAX_ARTIFACTS; i++) { + struct artifact *artifact = &artifacts[i]; + + if (artifact->type != ARTIFACTTYPE_FREE) { + u16 *unk08 = artifact->unk08; + u16 value08 = unk08[0]; + + if (g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] == 1) { + u16 *unk0c = artifact->unk0c.u16p; + u16 value0c = unk0c[0]; + + if (value0c > value08) { + artifact->unk02 = value08; + } else { + artifact->unk02 = value0c; + } + } else { + artifact->unk02 = value08; + } + } + } + + g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0; + + schedIncrementPendingArtifacts(); +} diff --git a/src/lib/audiomgr.c b/src/lib/audiomgr.c index aa9528e35..789eae961 100644 --- a/src/lib/audiomgr.c +++ b/src/lib/audiomgr.c @@ -218,7 +218,7 @@ void amgrHandleFrameMsg(AudioInfo *info, AudioInfo *previnfo) extern u8 aspDataStart; if (g_AmgrCurrentCmdList) { - schedAppendTasks(&g_Sched, g_AmgrCurrentCmdList); + schedSubmitAudTask(&g_Sched, g_AmgrCurrentCmdList); } admaBeginFrame(); diff --git a/src/lib/boot.c b/src/lib/boot.c index d6f74f835..59cb13104 100644 --- a/src/lib/boot.c +++ b/src/lib/boot.c @@ -20,9 +20,7 @@ OSThread g_MainThread; OSThread g_SchedThread; OSMesgQueue g_SchedMesgQueue; OSMesg var8008db48[32]; -OSMesgQueue *g_SchedCmdQ; u32 var8008dbcc; -OSSched g_Sched; OSScClient var8008dca8; u32 g_OsMemSize; @@ -36,6 +34,8 @@ u8 *g_StackAllocatedPos = (u8 *) K0BASE + 4 * 1024 * 1024; u32 var8005ce4c = 0x00000002; u32 var8005ce50 = 0x10000000; +extern OSSched g_Sched; + extern u8 *_libSegmentStart; extern u8 *_datazipSegmentRomStart; extern u8 *_datazipSegmentRomEnd; @@ -204,7 +204,6 @@ void bootCreateSchedThread(void) } osScAddClient(&g_Sched, &var8008dca8, &g_SchedMesgQueue, 0); - g_SchedCmdQ = osScGetCmdQ(&g_Sched); } void bootPhase2(void *arg) diff --git a/src/lib/rdp.c b/src/lib/rdp.c index fdb2d69db..4eefc7277 100644 --- a/src/lib/rdp.c +++ b/src/lib/rdp.c @@ -100,7 +100,7 @@ void rdpCreateTask(Gfx *gdlstart, Gfx *gdlend, u32 arg2, void *msg) sctask->framebuffer = g_RdpCurTask->framebuffer; osWritebackDCacheAll(); - schedAppendTasks(&g_Sched, sctask); + schedSubmitGfxTask(&g_Sched, sctask); // Swap g_RdpCurTask g_RdpCurTask = (struct rdptask *)((u32)g_RdpCurTask ^ (u32) &g_RdpTaskA ^ (u32) &g_RdpTaskB); diff --git a/src/lib/sched.c b/src/lib/sched.c index 6205982d6..a75fcffff 100644 --- a/src/lib/sched.c +++ b/src/lib/sched.c @@ -18,46 +18,13 @@ #include "data.h" #include "types.h" -/* - * private typedefs and defines - */ -#define VIDEO_MSG 666 -#define RSP_DONE_MSG 667 -#define RDP_DONE_MSG 668 -#define PRE_NMI_MSG 669 - /* * OSScTask state */ -#define OS_SC_DP 0x0001 /* set if still needs dp */ -#define OS_SC_SP 0x0002 /* set if still needs sp */ #define OS_SC_YIELD 0x0010 /* set if yield requested */ #define OS_SC_YIELDED 0x0020 /* set if yield completed */ -/* - * OSScTask->flags type identifier - */ -#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP) -#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST) -#define OS_SC_DP_XBUS (OS_SC_SP) -#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST) -#define OS_SC_SP_XBUS (OS_SC_DP) -#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST) - -/* - * private functions - */ -void __scMain(void *arg); -void __scHandleTasks(OSSched *s); -void __scHandleRSP(OSSched *s); -void __scHandleRDP(OSSched *s); -void __scAppendList(OSSched *s, OSScTask *t); -OSScTask *__scTaskReady(OSScTask *t); -s32 __scTaskComplete(OSSched *s,OSScTask *t); -void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp, s32 resuming); -void __scYield(OSSched *s); -s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP); - +OSSched g_Sched; OSViMode var8008dcc0[2]; OSViMode *var8008dd60[2]; OSViMode var8008dd68[2]; @@ -66,12 +33,6 @@ s32 var8008de0c; s32 var8008de10; u32 var8008de14; OSTimer g_SchedRspTimer; -u32 g_SchedDpCounters[4]; -struct artifact g_ArtifactLists[3][120]; -u8 g_SchedSpecialArtifactIndexes[3]; -s32 g_SchedWriteArtifactsIndex; -s32 g_SchedFrontArtifactsIndex; -s32 g_SchedPendingArtifactsIndex; s32 var8005ce74 = 0; f32 g_ViXScalesBySlot[2] = {1, 1}; @@ -86,16 +47,281 @@ u32 var8005cea4 = 0; OSScMsg g_SchedRspMsg = {OS_SC_RSP_MSG}; bool g_SchedIsFirstTask = true; +static void __scExec(OSSched *sc, OSScTask *t) +{ + if (t->list.t.type == M_GFXTASK) { + if ((t->state & OS_SC_YIELD) == 0) { + profileHandleRspEvent(RSPEVENT_GFX_START); + } + } else { + osWritebackDCacheAll(); + profileHandleRspEvent(RSPEVENT_AUD_START); + } + + t->state &= ~(OS_SC_YIELD | OS_SC_YIELDED); + + osSpTaskLoad(&t->list); + osSpTaskStartGo(&t->list); + + sc->curRSPTask = t; + + if (t->list.t.type == M_GFXTASK) { + sc->curRDPTask = t; + } +} + +static void __scTryDispatch(OSSched *sc) +{ + if (sc->curRSPTask == NULL) { + if (sc->nextAudTask) { + OSScTask *t = sc->nextAudTask; + sc->nextAudTask = NULL; + __scExec(sc, t); + } else if (sc->curRDPTask == NULL) { + OSScTask *t = sc->nextGfxTask; + + if (t) { + sc->nextGfxTask = sc->nextGfxTask2; + sc->nextGfxTask2 = NULL; + __scExec(sc, t); + } + } + } +} + +static void __scTaskComplete(OSSched *sc, OSScTask *t) +{ + if (t->list.t.type == M_AUDTASK) { + profileHandleRspEvent(RSPEVENT_AUD_FINISH); + } else { + profileHandleRspEvent(RSPEVENT_GFX_FINISH); + + if (g_SchedIsFirstTask) { + osViBlack(false); + g_SchedIsFirstTask = false; + } + + var8005ce74 = (var8005ce74 + 1) % 2; + + if (g_SchedViModesPending[1 - var8005ce74]) { + if (var8008dd60[1 - var8005ce74]->comRegs.width != var8008dcc0[1 - var8005ce74].comRegs.width + || var8008dd60[1 - var8005ce74]->comRegs.xScale != var8008dcc0[1 - var8005ce74].comRegs.xScale + || var8008dd60[1 - var8005ce74]->fldRegs[0].yScale != var8008dcc0[1 - var8005ce74].fldRegs[0].yScale + || var8008dd60[1 - var8005ce74]->fldRegs[1].yScale != var8008dcc0[1 - var8005ce74].fldRegs[1].yScale + || var8008dd60[1 - var8005ce74]->fldRegs[0].origin != var8008dcc0[1 - var8005ce74].fldRegs[0].origin + || var8008dd60[1 - var8005ce74]->fldRegs[1].origin != var8008dcc0[1 - var8005ce74].fldRegs[1].origin) { + s32 mask = osSetIntMask(0x80401); + + *var8008dd60[1 - var8005ce74] = var8008dcc0[1 - var8005ce74]; + + osSetIntMask(mask); + + osViSetMode(var8008dd60[1 - var8005ce74]); + osViBlack(g_ViUnblackTimer); + osViSetXScale(g_ViXScalesBySlot[1 - var8005ce74]); + osViSetYScale(g_ViYScalesBySlot[1 - var8005ce74]); + +#ifdef ANTIALIAS + osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_ON); +#else + osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_OFF); +#endif + } + + g_SchedViModesPending[1 - var8005ce74] = false; + } + + if (g_ViUnblackTimer != 0 && g_ViUnblackTimer < 3) { + g_ViUnblackTimer--; + } + + osViSwapBuffer(t->framebuffer); + } + + osSendMesg(t->msgQ, t->msg, OS_MESG_BLOCK); +} + +//-----------------------------------------------------------------------------\ +//-- Event handlers -----------------------------------------------------------/ +//----------------------------------------------------------------------------/ + +static void __scHandleRetrace(OSSched *sc) +{ + if (osViGetCurrentFramebuffer() == osViGetNextFramebuffer()) { + osDpSetStatus(DPC_CLR_FREEZE); + } + + sc->alt ^= 1; + +#if PAL + if (!g_Resetting && sc->alt) { + osStopTimer(&g_SchedRspTimer); + osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#else + if (!g_Resetting && sc->alt) { + osStopTimer(&g_SchedRspTimer); + osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); + } +#endif + + if (!g_Resetting) { + vi00009ed4(); + } + + joysTick(); + + if (sc->gfxmq) { + osSendMesg(sc->gfxmq, (OSMesg) &sc->retraceMsg, OS_MESG_NOBLOCK); + } +} + +static void __scHandleRSP(OSSched *sc) +{ + if (!g_Resetting) { + OSScTask *t = sc->curRSPTask; + sc->curRSPTask = NULL; + + if ((t->state & OS_SC_YIELD) && osSpTaskYielded(&t->list)) { + t->state |= OS_SC_YIELDED; + + sc->nextGfxTask2 = sc->nextGfxTask; + sc->nextGfxTask = t; + sc->curRDPTask = NULL; + } else { + t->state &= ~OS_SC_NEEDS_RSP; + + if ((t->state & OS_SC_RCP_MASK) == 0) { + __scTaskComplete(sc, t); + } + } + + __scTryDispatch(sc); + } +} + +static void __scHandleRDP(OSSched *sc) +{ + OSScTask *t; + + osDpSetStatus(DPC_SET_FREEZE); + + schedUpdatePendingArtifacts(); + + if (var8005dd18 == 0) { + if (g_MenuData.screenshottimer == 1) { + menugfxCreateBlur(); + + g_MenuData.screenshottimer = 0; + } + + if (g_MenuData.screenshottimer >= 2) { + g_MenuData.screenshottimer--; + } + } + + t = sc->curRDPTask; + sc->curRDPTask = NULL; + t->state &= ~OS_SC_NEEDS_RDP; + + if ((t->state & OS_SC_RCP_MASK) == 0) { + __scTaskComplete(sc, t); + } + + __scTryDispatch(sc); + + osSendMesg(sc->gfxmq, (OSMesg) &sc->retraceMsg, OS_MESG_NOBLOCK); +} + +static void __scMain(void *arg) +{ + void (*msg)(OSSched *sc); + OSSched *sc = (OSSched *)arg; + + schedInitArtifacts(); + + while (1) { + osRecvMesg(&sc->interruptQ, (OSMesg *) &msg, OS_MESG_BLOCK); + msg(sc); + } +} + +//-----------------------------------------------------------------------------\ +//-- Public functions ---------------------------------------------------------/ +//----------------------------------------------------------------------------/ + +void schedSubmitAudTask(OSSched *sc, OSScTask *t) +{ + OSPri prevpri = osGetThreadPri(0); + osSetThreadPri(0, THREADPRI_SCHED + 1); + + if (sc->curRSPTask == NULL) { + __scExec(sc, t); + } else { + if (sc->curRSPTask->list.t.type == M_GFXTASK) { + osSpTaskYield(); + sc->curRSPTask->state |= OS_SC_YIELD; + } + + t->state = OS_SC_NEEDS_RSP; + sc->nextAudTask = t; + } + + osSetThreadPri(0, prevpri); +} + +void schedSubmitGfxTask(OSSched *sc, OSScTask *t) +{ + OSPri prevpri = osGetThreadPri(0); + osSetThreadPri(0, THREADPRI_SCHED + 1); + + t->state = OS_SC_NEEDS_RSP | OS_SC_NEEDS_RDP; + + //if (sc->curRSPTask == NULL && sc->curRDPTask == NULL) { + // __scExec(sc, t); + //} else { + // if (sc->nextGfxTask == NULL) { + // sc->nextGfxTask = t; + // } else { + // sc->nextGfxTask2 = t; + // } + //} + + if (sc->nextGfxTask == NULL) { + sc->nextGfxTask = t; + } else { + sc->nextGfxTask2 = t; + } + __scTryDispatch(sc); + + osSetThreadPri(0, prevpri); +} + +void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, int is8mb) +{ + OSIntMask mask; + + mask = osSetIntMask(1); + + if (is8mb) { + sc->audmq = msgQ; + } else { + sc->gfxmq = msgQ; + } + + osSetIntMask(mask); +} + void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields) { - sc->curRSPTask = 0; - sc->curRDPTask = 0; - sc->clientList = 0; - sc->frameCount = 0; - sc->audioListHead = 0; - sc->gfxListHead = 0; - sc->audioListTail = 0; - sc->gfxListTail = 0; + sc->audmq = NULL; + sc->gfxmq = NULL; + sc->curRSPTask = NULL; + sc->curRDPTask = NULL; + sc->alt = 0; + sc->nextAudTask = NULL; + sc->nextGfxTask = NULL; + sc->nextGfxTask2 = NULL; sc->retraceMsg.type = OS_SC_RETRACE_MSG; sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG; sc->thread = thread; @@ -103,7 +329,6 @@ void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields) resetThreadCreate(); osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS); - osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS); osCreateViManager(OS_PRIORITY_VIMGR); @@ -117,598 +342,10 @@ void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields) var8008dd68[0] = osViModeTable[mode]; var8008dd68[1] = osViModeTable[mode]; - osSetEventMesg(OS_EVENT_SP, &sc->interruptQ, (OSMesg)RSP_DONE_MSG); - osSetEventMesg(OS_EVENT_DP, &sc->interruptQ, (OSMesg)RDP_DONE_MSG); + osSetEventMesg(OS_EVENT_SP, &sc->interruptQ, (OSMesg) &__scHandleRSP); + osSetEventMesg(OS_EVENT_DP, &sc->interruptQ, (OSMesg) &__scHandleRDP); - osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields); + osViSetEvent(&sc->interruptQ, (OSMesg) &__scHandleRetrace, numFields); osCreateThread(sc->thread, THREAD_SCHED, &__scMain, sc, bootAllocateStack(THREAD_SCHED, STACKSIZE_SCHED), THREADPRI_SCHED); osStartThread(sc->thread); } - -void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, int is8mb) -{ - OSIntMask mask; - - mask = osSetIntMask(1); - - c->msgQ = msgQ; - c->is8mb = is8mb; - c->next = sc->clientList; - sc->clientList = c; - - osSetIntMask(mask); -} - -OSMesgQueue *osScGetCmdQ(OSSched *sc) -{ - return &sc->cmdQ; -} - -/** - * The scheduler's main loop. - * - * Most N64 games do the task scheduling on retrace (VIDEO_MSG), but PD does - * task scheduling both at retrace and when the RDP completes a task. - */ -void __scMain(void *arg) -{ - OSMesg msg = 0; - OSSched *sc = (OSSched *)arg; - int done = 0; - - schedInitArtifacts(); - - while (!done) { - osRecvMesg(&sc->interruptQ, (OSMesg *)&msg, OS_MESG_BLOCK); - - switch ((int) msg) { - case VIDEO_MSG: - if (osViGetCurrentFramebuffer() == osViGetNextFramebuffer()) { - osDpSetStatus(DPC_CLR_FREEZE); - } - - __scHandleRetrace(sc); - __scHandleTasks(sc); - break; - case RSP_DONE_MSG: - __scHandleRSP(sc); - break; - case RDP_DONE_MSG: - osDpSetStatus(DPC_SET_FREEZE); - __scHandleRDP(sc); - __scHandleTasks(sc); - break; - } - } -} - -void schedAppendTasks(OSSched *sc, OSScTask *t) -{ - s32 state; - OSScTask *sp = 0; - OSScTask *dp = 0; - - OSPri prevpri = osGetThreadPri(0); - osSetThreadPri(0, THREADPRI_SCHED + 1); - - __scAppendList(sc, t); - - if (sc->doAudio && sc->curRSPTask) { - __scYield(sc); - } else { - state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0); - - if (__scSchedule(sc, &sp, &dp, state) != state) { - __scExec(sc, sp, dp, false); - } - } - - osSetThreadPri(0, prevpri); -} - -/** - * Handle a retrace (vsync) event. - * - * Audio tasks are scheduled based on retrace + a timer (approximately 6ms). - * On NTSC, this is done on every second frame if 8MB, or every second frame - * if 4MB. I guess less memory means the audio queue has to be kept smaller - * and processed more frequently. On PAL, it's every second frame regardless. - * - * Controller input is polled here. - * - * Lastly, if there's crash information available then it will be checked and - * rendered periodically (once every 16 retraces). I guess this makes it render - * if the RDP has hung. - */ -void __scHandleRetrace(OSSched *sc) -{ - sc->frameCount++; - -#if PAL - if (!g_Resetting && (sc->frameCount & 1)) { - osStopTimer(&g_SchedRspTimer); - osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); - } -#else - if (!g_Resetting && (sc->frameCount & 1)) { - osStopTimer(&g_SchedRspTimer); - osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg); - } -#endif - - if (!g_Resetting) { - vi00009ed4(); - } - - joysTick(); -} - -extern struct sndcache g_SndCache; - -/** - * __scHandleTasks is called both on retrace and when the RDP completes a task. - */ -void __scHandleTasks(OSSched *sc) -{ - s32 state; - OSScTask *rspTask = 0; - OSScClient *client; - OSScTask *sp = 0; - OSScTask *dp = 0; - - /** - * Read the task command queue and schedule tasks - */ - while (osRecvMesg(&sc->cmdQ, (OSMesg*)&rspTask, OS_MESG_NOBLOCK) != -1) { - __scAppendList(sc, rspTask); - } - - if (sc->doAudio && sc->curRSPTask) { - /** - * Preempt the running gfx task. Note: if the RSP - * component of the graphics task has finished, but the - * RDP component is still running, we can start an audio - * task which will freeze the RDP (and save the RDP cmd - * FIFO) while the audio RSP code is running. - */ - __scYield(sc); - } else { - state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0); - - if (__scSchedule(sc, &sp, &dp, state) != state) { - __scExec(sc, sp, dp, false); - } - } - - /** - * Notify audio and graphics threads to start building the command - * lists for the next frame (client threads may choose not to - * build the list in overrun case) - */ - for (client = sc->clientList; client != 0; client = client->next) { - if ((*((s32*)client + 2) == 0) || ((sc->frameCount & 1) == 0)) { - osSendMesg(client->msgQ, (OSMesg) &sc->retraceMsg, OS_MESG_NOBLOCK); - } - } -} - -/** - * __scHandleRSP is called when an RSP task signals that it has - * finished or yielded (at the hosts request). - */ -void __scHandleRSP(OSSched *sc) -{ - OSScTask *t, *sp = 0, *dp = 0; - s32 state; - - if (!g_Resetting) { - t = sc->curRSPTask; - sc->curRSPTask = 0; - - if ((t->state & OS_SC_YIELD) && osSpTaskYielded(&t->list)) { - t->state |= OS_SC_YIELDED; - - if ((t->flags & OS_SC_TYPE_MASK) == OS_SC_XBUS) { - // Push the task back on the list - t->next = sc->gfxListHead; - sc->gfxListHead = t; - - if (sc->gfxListTail == 0) { - sc->gfxListTail = t; - } - } - } else { - t->state &= ~OS_SC_NEEDS_RSP; - __scTaskComplete(sc, t); - } - - state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0); - - if (__scSchedule(sc, &sp, &dp, state) != state) { - __scExec(sc, sp, dp, true); - } - } -} - -void schedInitArtifacts(void) -{ - s32 i; - s32 j; - - for (i = 0; i < 3; i++) { - for (j = 0; j < MAX_ARTIFACTS; j++) { - g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE; - } - - g_SchedSpecialArtifactIndexes[i] = 0; - } -} - -/** - * The write list is an artifact list that is not currently being displayed on - * the screen. Update logic can write here to put artifacts on the next frame. - */ -struct artifact *schedGetWriteArtifacts(void) -{ - return g_ArtifactLists[g_SchedWriteArtifactsIndex]; -} - -/** - * The front list is the artifact list that is currently being displayed on the - * screen. Rendering logic reads this list. The list may be re-used for multiple - * frames in a row during lag. - */ -struct artifact *schedGetFrontArtifacts(void) -{ - return g_ArtifactLists[g_SchedFrontArtifactsIndex]; -} - -/** - * The pending list is possibly misnamed. I'm not sure how this list works. - * - * @TODO: Investigate. - */ -struct artifact *schedGetPendingArtifacts(void) -{ - return g_ArtifactLists[g_SchedPendingArtifactsIndex]; -} - -void schedIncrementWriteArtifacts(void) -{ - g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3; -} - -void schedIncrementFrontArtifacts(void) -{ - g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3; -} - -void schedIncrementPendingArtifacts(void) -{ - g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3; -} - -void schedResetArtifacts(void) -{ - g_SchedWriteArtifactsIndex = 0; - g_SchedFrontArtifactsIndex = 1; - g_SchedPendingArtifactsIndex = 0; -} - -void schedUpdatePendingArtifacts(void) -{ - struct artifact *artifacts = schedGetPendingArtifacts(); - s32 i; - - for (i = 0; i < MAX_ARTIFACTS; i++) { - struct artifact *artifact = &artifacts[i]; - - if (artifact->type != ARTIFACTTYPE_FREE) { - u16 *unk08 = artifact->unk08; - u16 value08 = unk08[0]; - - if (g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] == 1) { - u16 *unk0c = artifact->unk0c.u16p; - u16 value0c = unk0c[0]; - - if (value0c > value08) { - artifact->unk02 = value08; - } else { - artifact->unk02 = value0c; - } - } else { - artifact->unk02 = value08; - } - } - } - - g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0; - - schedIncrementPendingArtifacts(); -} - -/** - * __scHandleRDP is called when an RDP task signals that it has finished. - */ -void __scHandleRDP(OSSched *sc) -{ - OSScTask *t, *sp = NULL, *dp = NULL; - s32 state; - - if (sc->curRDPTask != NULL) { - schedUpdatePendingArtifacts(); - - if (var8005dd18 == 0) { - schedConsiderScreenshot(); - } - - osDpGetCounters(g_SchedDpCounters); - - t = sc->curRDPTask; - sc->curRDPTask = NULL; - t->state &= ~OS_SC_NEEDS_RDP; - - __scTaskComplete(sc, t); - - state = ((sc->curRSPTask == 0) << 1) | (sc->curRDPTask == 0); - - if (__scSchedule(sc, &sp, &dp, state) != state) { - __scExec(sc, sp, dp, false); - } - } -} - -/** - * __scTaskReady checks to see if the graphics task is able to run - * based on the current state of the RCP. - */ -OSScTask *__scTaskReady(OSScTask *t) -{ - void *a; - void *b; - - if (t) { - if ((osDpGetStatus() & DPC_STATUS_FREEZE) == 0) { - if (osViGetCurrentFramebuffer() != osViGetNextFramebuffer()) { - return 0; - } - } - - return t; - } - - return 0; -} - -/* - * __scTaskComplete checks to see if the task is complete (all RCP - * operations have been performed) and sends the done message to the - * client if it is. - */ -s32 __scTaskComplete(OSSched *sc, OSScTask *t) -{ - if ((t->state & OS_SC_RCP_MASK) == 0) { - if (t->list.t.type == M_AUDTASK) { - profileHandleRspEvent(RSPEVENT_AUD_FINISH); - } else { - profileHandleRspEvent(RSPEVENT_GFX_FINISH); - } - - if (t->list.t.type == 1 - && (t->flags & OS_SC_SWAPBUFFER) - && (t->flags & OS_SC_LAST_TASK)) { - if (g_SchedIsFirstTask) { - osViBlack(false); - g_SchedIsFirstTask = false; - } - - var8005ce74 = (var8005ce74 + 1) % 2; - - if (g_SchedViModesPending[1 - var8005ce74]) { - if (var8008dd60[1 - var8005ce74]->comRegs.width != var8008dcc0[1 - var8005ce74].comRegs.width - || var8008dd60[1 - var8005ce74]->comRegs.xScale != var8008dcc0[1 - var8005ce74].comRegs.xScale - || var8008dd60[1 - var8005ce74]->fldRegs[0].yScale != var8008dcc0[1 - var8005ce74].fldRegs[0].yScale - || var8008dd60[1 - var8005ce74]->fldRegs[1].yScale != var8008dcc0[1 - var8005ce74].fldRegs[1].yScale - || var8008dd60[1 - var8005ce74]->fldRegs[0].origin != var8008dcc0[1 - var8005ce74].fldRegs[0].origin - || var8008dd60[1 - var8005ce74]->fldRegs[1].origin != var8008dcc0[1 - var8005ce74].fldRegs[1].origin) { - s32 mask = osSetIntMask(0x80401); - - *var8008dd60[1 - var8005ce74] = var8008dcc0[1 - var8005ce74]; - - osSetIntMask(mask); - - osViSetMode(var8008dd60[1 - var8005ce74]); - osViBlack(g_ViUnblackTimer); - osViSetXScale(g_ViXScalesBySlot[1 - var8005ce74]); - osViSetYScale(g_ViYScalesBySlot[1 - var8005ce74]); - -#ifdef ANTIALIAS - osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_ON); -#else - osViSetSpecialFeatures(OS_VI_GAMMA_OFF | OS_VI_DITHER_FILTER_OFF); -#endif - } - - g_SchedViModesPending[1 - var8005ce74] = false; - } - - if (g_ViUnblackTimer != 0 && g_ViUnblackTimer < 3) { - g_ViUnblackTimer--; - } - - osViSwapBuffer(t->framebuffer); - } - - osSendMesg(t->msgQ, t->msg, OS_MESG_BLOCK); - - return 1; - } - - return 0; -} - -/** - * Place task on either the audio or graphics queue. - */ -void __scAppendList(OSSched *sc, OSScTask *t) -{ - long type = t->list.t.type; - - if (type == M_AUDTASK) { - if (sc->audioListTail) { - sc->audioListTail->next = t; - } else { - sc->audioListHead = t; - } - - sc->audioListTail = t; - sc->doAudio = 1; - } else { - if (sc->gfxListTail) { - sc->gfxListTail->next = t; - } else { - sc->gfxListHead = t; - } - - sc->gfxListTail = t; - } - - t->next = NULL; - t->state = t->flags & OS_SC_RCP_MASK; -} - -void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp, s32 resuming) -{ - if (sp) { - if (sp->list.t.type == M_GFXTASK) { - if ((sp->state & OS_SC_YIELD) == 0) { - profileHandleRspEvent(RSPEVENT_GFX_START); - } - } else { - osWritebackDCacheAll(); - profileHandleRspEvent(RSPEVENT_AUD_START); - } - - sp->state &= ~(OS_SC_YIELD | OS_SC_YIELDED); - - osSpTaskLoad(&sp->list); - osSpTaskStartGo(&sp->list); - - sc->curRSPTask = sp; - - if (sp->list.t.type != M_AUDTASK) { - sc->curRDPTask = dp; - } - } -} - -void __scYield(OSSched *sc) -{ - if (sc->curRSPTask->list.t.type == M_GFXTASK) { - sc->curRSPTask->state |= OS_SC_YIELD; - osSpTaskYield(); - } else { - // empty - } -} - -/* - * Schedules the tasks to be run on the RCP. - */ -s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP) -{ - s32 avail = availRCP; - OSScTask *gfx = sc->gfxListHead; - OSScTask *audio = sc->audioListHead; - - if (sc->doAudio && (avail & OS_SC_SP)) { - if (gfx && (gfx->flags & OS_SC_PARALLEL_TASK)) { - *sp = gfx; - avail &= ~OS_SC_SP; - } else { - *sp = audio; - avail &= ~OS_SC_SP; - sc->doAudio = 0; - sc->audioListHead = sc->audioListHead->next; - - if (sc->audioListHead == NULL) { - sc->audioListTail = NULL; - } - } - } else if (__scTaskReady(gfx)) { - switch (gfx->flags & OS_SC_TYPE_MASK) { - case OS_SC_XBUS: - if (gfx->state & OS_SC_YIELDED) { - if (avail & OS_SC_SP) { - *sp = gfx; - avail &= ~OS_SC_SP; - - if (gfx->state & OS_SC_DP) { - *dp = gfx; - avail &= ~OS_SC_DP; - } - - sc->gfxListHead = sc->gfxListHead->next; - - if (sc->gfxListHead == NULL) { - sc->gfxListTail = NULL; - } - } - } else { - if (avail == (OS_SC_SP | OS_SC_DP)) { - *sp = *dp = gfx; - avail &= ~(OS_SC_SP | OS_SC_DP); - sc->gfxListHead = sc->gfxListHead->next; - - if (sc->gfxListHead == NULL) { - sc->gfxListTail = NULL; - } - } - } - break; - case OS_SC_DRAM: - case OS_SC_DP_DRAM: - case OS_SC_DP_XBUS: - if (gfx->state & OS_SC_SP) { - if (avail & OS_SC_SP) { - *sp = gfx; - avail &= ~OS_SC_SP; - } - } else if (gfx->state & OS_SC_DP) { - if (avail & OS_SC_DP) { - *dp = gfx; - avail &= ~OS_SC_DP; - sc->gfxListHead = sc->gfxListHead->next; - - if (sc->gfxListHead == NULL) { - sc->gfxListTail = NULL; - } - } - } - break; - case OS_SC_SP_DRAM: - case OS_SC_SP_XBUS: - default: - break; - } - } - - if (avail != availRCP) { - avail = __scSchedule(sc, sp, dp, avail); - } - - return avail; -} - -void schedConsiderScreenshot(void) -{ - if (g_MenuData.screenshottimer == 1) { - menugfxCreateBlur(); - - g_MenuData.screenshottimer = 0; - } - - if (g_MenuData.screenshottimer >= 2) { - g_MenuData.screenshottimer--; - } -}