mirror of
https://github.com/zeldaret/mm.git
synced 2026-06-10 12:54:55 -04:00
Irqmgr + scheduler Docs (#1527)
* irqmgr docs * Sched_FlushTaskQueue * scheduler docs
This commit is contained in:
@@ -33,8 +33,8 @@ void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
|
||||
audioMgr->audioTask.msgQ = &audioMgr->cmdQueue;
|
||||
|
||||
audioMgr->audioTask.msg = NULL;
|
||||
osSendMesg(&audioMgr->sched->cmdQ, &audioMgr->audioTask, OS_MESG_BLOCK);
|
||||
Sched_SendEntryMsg(audioMgr->sched);
|
||||
osSendMesg(&audioMgr->sched->cmdQueue, &audioMgr->audioTask, OS_MESG_BLOCK);
|
||||
Sched_SendNotifyMsg(audioMgr->sched);
|
||||
}
|
||||
|
||||
if (SREG(20) >= 2) {
|
||||
@@ -125,7 +125,7 @@ void AudioMgr_Unlock(AudioMgr* audioMgr) {
|
||||
osRecvMesg(&audioMgr->lockQueue, NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, SchedContext* sched, IrqMgr* irqMgr) {
|
||||
void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, Scheduler* sched, IrqMgr* irqMgr) {
|
||||
bzero(audioMgr, sizeof(AudioMgr));
|
||||
|
||||
audioMgr->sched = sched;
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "global.h"
|
||||
|
||||
// Blocks the current thread until all currently queued scheduler tasks have been completed
|
||||
void MsgEvent_SendNullTask(void) {
|
||||
OSScTask task;
|
||||
OSMesgQueue queue;
|
||||
OSMesg msg;
|
||||
|
||||
task.next = NULL;
|
||||
task.flags = OS_SC_RCP_MASK;
|
||||
task.msgQ = &queue;
|
||||
task.msg = NULL;
|
||||
task.framebuffer = NULL;
|
||||
task.list.t.type = M_NULTASK;
|
||||
|
||||
osCreateMesgQueue(task.msgQ, &msg, 1);
|
||||
osSendMesg(&gSchedContext.cmdQ, &task, OS_MESG_BLOCK);
|
||||
Sched_SendEntryMsg(&gSchedContext);
|
||||
osRecvMesg(&queue, NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
+6
-6
@@ -154,7 +154,7 @@ retry:
|
||||
osSyncPrintf("GRAPH SP TIMEOUT\n");
|
||||
if (retryCount >= 0) {
|
||||
retryCount--;
|
||||
Sched_SendGfxCancelMsg(&gSchedContext);
|
||||
Sched_SendGfxCancelMsg(&gScheduler);
|
||||
goto retry;
|
||||
} else {
|
||||
// graph.c: No more! die!
|
||||
@@ -202,13 +202,13 @@ retry:
|
||||
cfb = &sGraphCfbInfos[cfbIdx];
|
||||
cfbIdx = (cfbIdx + 1) % ARRAY_COUNT(sGraphCfbInfos);
|
||||
|
||||
cfb->fb1 = gfxCtx->curFrameBuffer;
|
||||
cfb->framebuffer = gfxCtx->curFrameBuffer;
|
||||
cfb->swapBuffer = gfxCtx->curFrameBuffer;
|
||||
|
||||
if (gfxCtx->updateViMode) {
|
||||
gfxCtx->updateViMode = false;
|
||||
cfb->viMode = gfxCtx->viMode;
|
||||
cfb->features = gfxCtx->viConfigFeatures;
|
||||
cfb->viFeatures = gfxCtx->viConfigFeatures;
|
||||
cfb->xScale = gfxCtx->xScale;
|
||||
cfb->yScale = gfxCtx->yScale;
|
||||
} else {
|
||||
@@ -223,9 +223,9 @@ retry:
|
||||
osRecvMesg(&gfxCtx->queue, NULL, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
gfxCtx->schedMsgQ = &gSchedContext.cmdQ;
|
||||
osSendMesg(&gSchedContext.cmdQ, scTask, OS_MESG_BLOCK);
|
||||
Sched_SendEntryMsg(&gSchedContext);
|
||||
gfxCtx->schedMsgQ = &gScheduler.cmdQueue;
|
||||
osSendMesg(&gScheduler.cmdQueue, (OSMesg)scTask, OS_MESG_BLOCK);
|
||||
Sched_SendNotifyMsg(&gScheduler);
|
||||
}
|
||||
|
||||
void Graph_UpdateGame(GameState* gameState) {
|
||||
|
||||
+3
-4
@@ -12,7 +12,7 @@
|
||||
OSMesgQueue sSerialEventQueue;
|
||||
OSMesg sSerialMsgBuf[1];
|
||||
u32 gSegments[NUM_SEGMENTS];
|
||||
SchedContext gSchedContext;
|
||||
Scheduler gScheduler;
|
||||
IrqMgrClient sIrqClient;
|
||||
OSMesgQueue sIrqMgrMsgQueue;
|
||||
OSMesg sIrqMgrMsgBuf[60];
|
||||
@@ -68,15 +68,14 @@ void Main(void* arg) {
|
||||
osCreateMesgQueue(&sIrqMgrMsgQueue, sIrqMgrMsgBuf, ARRAY_COUNT(sIrqMgrMsgBuf));
|
||||
|
||||
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
|
||||
Sched_Init(&gSchedContext, STACK_TOP(sSchedStack), Z_PRIORITY_SCHED, gViConfigModeType, 1, &gIrqMgr);
|
||||
Sched_Init(&gScheduler, STACK_TOP(sSchedStack), Z_PRIORITY_SCHED, gViConfigModeType, 1, &gIrqMgr);
|
||||
|
||||
CIC6105_AddRomInfoFaultPage();
|
||||
|
||||
IrqMgr_AddClient(&gIrqMgr, &sIrqClient, &sIrqMgrMsgQueue);
|
||||
|
||||
StackCheck_Init(&sAudioStackInfo, sAudioStack, STACK_TOP(sAudioStack), 0, 0x100, "audio");
|
||||
AudioMgr_Init(&sAudioMgr, STACK_TOP(sAudioStack), Z_PRIORITY_AUDIOMGR, Z_THREAD_ID_AUDIOMGR, &gSchedContext,
|
||||
&gIrqMgr);
|
||||
AudioMgr_Init(&sAudioMgr, STACK_TOP(sAudioStack), Z_PRIORITY_AUDIOMGR, Z_THREAD_ID_AUDIOMGR, &gScheduler, &gIrqMgr);
|
||||
|
||||
StackCheck_Init(&sPadMgrStackInfo, sPadMgrStack, STACK_TOP(sPadMgrStack), 0, 0x100, "padmgr");
|
||||
PadMgr_Init(&sSerialEventQueue, &gIrqMgr, Z_THREAD_ID_PADMGR, Z_PRIORITY_PADMGR, STACK_TOP(sPadMgrStack));
|
||||
|
||||
+141
-100
@@ -1,8 +1,9 @@
|
||||
#include "scheduler.h"
|
||||
#include "fault.h"
|
||||
#include "idle.h"
|
||||
#include "libc64/sleep.h"
|
||||
#include "macros.h"
|
||||
#include "viconfig.h"
|
||||
#include "z64.h"
|
||||
|
||||
// Variables are put before most headers as a hacky way to bypass bss reordering
|
||||
FaultClient sSchedFaultClient;
|
||||
@@ -16,26 +17,28 @@ u64* gAudioSPDataPtr;
|
||||
u32 gAudioSPDataSize;
|
||||
|
||||
#include "functions.h"
|
||||
#include "variables.h"
|
||||
#include "stackcheck.h"
|
||||
#include "z64speed_meter.h"
|
||||
#include "z64thread.h"
|
||||
|
||||
#define RSP_DONE_MSG 667
|
||||
#define RDP_DONE_MSG 668
|
||||
#define ENTRY_MSG 670
|
||||
#define NOTIFY_MSG 670
|
||||
#define RDP_AUDIO_CANCEL_MSG 671
|
||||
#define RSP_GFX_CANCEL_MSG 672
|
||||
|
||||
void Sched_SwapFramebuffer(CfbInfo* cfbInfo) {
|
||||
/**
|
||||
* Set the current framebuffer to the swapbuffer pointed to by the provided cfb
|
||||
*/
|
||||
void Sched_SwapFramebufferImpl(CfbInfo* cfbInfo) {
|
||||
if (cfbInfo->swapBuffer != NULL) {
|
||||
osViSwapBuffer(cfbInfo->swapBuffer);
|
||||
cfbInfo->updateRate2 = cfbInfo->updateRate;
|
||||
cfbInfo->updateTimer = cfbInfo->updateRate;
|
||||
|
||||
if ((SREG(62) == 0) && (cfbInfo->viMode != NULL)) {
|
||||
D_80096B20 = 1;
|
||||
osViSetMode(cfbInfo->viMode);
|
||||
osViSetSpecialFeatures(cfbInfo->features);
|
||||
osViSetSpecialFeatures(cfbInfo->viFeatures);
|
||||
osViSetXScale(cfbInfo->xScale);
|
||||
osViSetYScale(cfbInfo->yScale);
|
||||
cfbInfo->viMode = NULL;
|
||||
@@ -44,21 +47,21 @@ void Sched_SwapFramebuffer(CfbInfo* cfbInfo) {
|
||||
cfbInfo->unk_10 = 0;
|
||||
}
|
||||
|
||||
void Sched_RetraceUpdateFramebuffer(SchedContext* sched, CfbInfo* cfbInfo) {
|
||||
if (sched->shouldUpdateVi) {
|
||||
sched->shouldUpdateVi = false;
|
||||
void Sched_SwapFramebuffer(Scheduler* sched, CfbInfo* cfbInfo) {
|
||||
if (sched->isFirstSwap) {
|
||||
sched->isFirstSwap = false;
|
||||
|
||||
if (gIrqMgrResetStatus == 0) {
|
||||
if (gIrqMgrResetStatus == IRQ_RESET_STATUS_IDLE) {
|
||||
ViConfig_UpdateVi(false);
|
||||
}
|
||||
}
|
||||
Sched_SwapFramebuffer(cfbInfo);
|
||||
Sched_SwapFramebufferImpl(cfbInfo);
|
||||
}
|
||||
|
||||
void Sched_HandleReset(SchedContext* sched) {
|
||||
void Sched_HandlePreNMI(Scheduler* sched) {
|
||||
}
|
||||
|
||||
void Sched_HandleStop(SchedContext* sched) {
|
||||
void Sched_HandleNMI(Scheduler* sched) {
|
||||
ViConfig_UpdateVi(true);
|
||||
}
|
||||
|
||||
@@ -69,7 +72,7 @@ void Sched_HandleStop(SchedContext* sched) {
|
||||
* If there was no currently running audio task, it will dequeue the currently waiting
|
||||
* audio task and notify the sender if the task is associated with a message queue.
|
||||
*/
|
||||
void Sched_HandleAudioCancel(SchedContext* sched) {
|
||||
void Sched_HandleAudioCancel(Scheduler* sched) {
|
||||
s32 i;
|
||||
|
||||
// AUDIO SP Cancel
|
||||
@@ -99,7 +102,7 @@ void Sched_HandleAudioCancel(SchedContext* sched) {
|
||||
}
|
||||
|
||||
send_mesg:
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)RSP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)RSP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,7 +135,7 @@ void Sched_HandleAudioCancel(SchedContext* sched) {
|
||||
* If there is an RDP task, the output buffer will be cleared and the scheduler will send
|
||||
* an RDP_DONE_MSG back to itself.
|
||||
*/
|
||||
void Sched_HandleGfxCancel(SchedContext* sched) {
|
||||
void Sched_HandleGfxCancel(Scheduler* sched) {
|
||||
s32 i;
|
||||
|
||||
// GRAPH SP Cancel
|
||||
@@ -162,7 +165,7 @@ void Sched_HandleGfxCancel(SchedContext* sched) {
|
||||
}
|
||||
|
||||
send_mesg:
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)RSP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)RSP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
goto halt_rdp;
|
||||
}
|
||||
|
||||
@@ -191,15 +194,15 @@ halt_rdp:
|
||||
// Try to stop DP
|
||||
osSyncPrintf("DP止めようとします\n");
|
||||
bzero(dpTask->outputBuff, (uintptr_t)dpTask->outputBuffSize - (uintptr_t)dpTask->outputBuff);
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)RDP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)RDP_DONE_MSG, OS_MESG_NOBLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a scheduler task to the appropriate linked list.
|
||||
* Enqueue a task to either the audio task list or the gfx task list
|
||||
*/
|
||||
void Sched_QueueTask(SchedContext* sched, OSScTask* task) {
|
||||
void Sched_QueueTask(Scheduler* sched, OSScTask* task) {
|
||||
s32 type = task->list.t.type;
|
||||
|
||||
if (type == M_AUDTASK) {
|
||||
@@ -221,7 +224,7 @@ void Sched_QueueTask(SchedContext* sched, OSScTask* task) {
|
||||
task->state = task->flags & OS_SC_RCP_MASK;
|
||||
}
|
||||
|
||||
void Sched_Yield(SchedContext* sched) {
|
||||
void Sched_Yield(Scheduler* sched) {
|
||||
// Don't yield audio tasks
|
||||
if (sched->curRSPTask->list.t.type == M_AUDTASK) {
|
||||
// A new audio task has been entered even though the previous audio task has not been completed yet
|
||||
@@ -232,46 +235,56 @@ void Sched_Yield(SchedContext* sched) {
|
||||
}
|
||||
}
|
||||
|
||||
s32 Sched_TaskCheckFramebuffers(SchedContext* sched, OSScTask* task) {
|
||||
/**
|
||||
* Check if the framebuffer the task wants to use is allowed
|
||||
*/
|
||||
s32 Sched_TaskFramebuffersValid(Scheduler* sched, OSScTask* task) {
|
||||
void* nextFB = osViGetNextFramebuffer();
|
||||
void* curFB = osViGetCurrentFramebuffer();
|
||||
|
||||
if ((task == NULL) || (sched->pendingSwapBuf1 != NULL) ||
|
||||
((curFB == TASK_FRAMEBUFFER(task)->fb1) && (curFB != nextFB))) {
|
||||
return 0;
|
||||
((curFB == TASK_FRAMEBUFFER(task)->framebuffer) && (curFB != nextFB))) {
|
||||
return false;
|
||||
}
|
||||
return 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the next task from the appropriate linked list and returns it through spTask and dpTask.
|
||||
* Schedules the next tasks to run on the RSP and RDP
|
||||
*
|
||||
* @param sc Scheduler
|
||||
* @param spTaskOut Next task to run on the RSP
|
||||
* @param dpTaskOut Next task to run on the RDP
|
||||
* @param state Bits containing whether the RSP and RDP are currently in use
|
||||
* @return Bits containing whether the RSP and RDP will be in use after starting the next tasks
|
||||
*/
|
||||
s32 Sched_Schedule(SchedContext* sched, OSScTask** spTask, OSScTask** dpTask, s32 state) {
|
||||
s32 ret = state;
|
||||
s32 Sched_Schedule(Scheduler* sched, OSScTask** spTask, OSScTask** dpTask, s32 state) {
|
||||
s32 nextState = state;
|
||||
OSScTask* gfxTask = sched->gfxListHead;
|
||||
OSScTask* audioTask = sched->audioListHead;
|
||||
|
||||
if ((ret & OS_SC_SP) && (sched->audioListHead != NULL)) {
|
||||
if ((state & OS_SC_SP) && (sched->audioListHead != NULL)) {
|
||||
*spTask = audioTask;
|
||||
ret &= ~OS_SC_SP;
|
||||
nextState &= ~OS_SC_SP;
|
||||
sched->audioListHead = sched->audioListHead->next;
|
||||
if (sched->audioListHead == NULL) {
|
||||
sched->audioListTail = NULL;
|
||||
}
|
||||
} else if (gfxTask != NULL) {
|
||||
if ((gfxTask->state & OS_SC_YIELDED) || !(gfxTask->flags & OS_SC_NEEDS_RDP)) {
|
||||
if (ret & OS_SC_SP) {
|
||||
if (state & OS_SC_SP) {
|
||||
*spTask = gfxTask;
|
||||
ret &= ~OS_SC_SP;
|
||||
nextState &= ~OS_SC_SP;
|
||||
sched->gfxListHead = sched->gfxListHead->next;
|
||||
if (sched->gfxListHead == NULL) {
|
||||
sched->gfxListTail = NULL;
|
||||
}
|
||||
}
|
||||
} else if (ret == (OS_SC_SP | OS_SC_DP)) {
|
||||
if ((TASK_FRAMEBUFFER(gfxTask) == NULL) || Sched_TaskCheckFramebuffers(sched, gfxTask)) {
|
||||
} else if (state == (OS_SC_SP | OS_SC_DP)) {
|
||||
if ((TASK_FRAMEBUFFER(gfxTask) == NULL) || Sched_TaskFramebuffersValid(sched, gfxTask)) {
|
||||
*spTask = *dpTask = gfxTask;
|
||||
ret &= ~(OS_SC_SP | OS_SC_DP);
|
||||
nextState &= ~(OS_SC_SP | OS_SC_DP);
|
||||
sched->gfxListHead = sched->gfxListHead->next;
|
||||
if (sched->gfxListHead == NULL) {
|
||||
sched->gfxListTail = NULL;
|
||||
@@ -279,36 +292,49 @@ s32 Sched_Schedule(SchedContext* sched, OSScTask** spTask, OSScTask** dpTask, s3
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Sched_TaskUpdateFramebuffer(SchedContext* sched, OSScTask* task) {
|
||||
sched->pendingSwapBuf1 = TASK_FRAMEBUFFER(task);
|
||||
|
||||
if ((sched->curBuf != NULL) && (sched->curBuf->updateRate2 > 0)) {
|
||||
return;
|
||||
}
|
||||
Sched_RetraceUpdateFramebuffer(sched, sched->pendingSwapBuf1);
|
||||
return nextState;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the task has been marked as completed, notify the sender through the task's
|
||||
* associated message queue (if it has one) that the task has been completed. If the task
|
||||
* flags dictate it should swap the framebuffer, do so.
|
||||
* Sets the next framebuffer to the framebuffer associated to `task`.
|
||||
* If there is no current buffer or it is time to swap, this buffer will be swapped to
|
||||
* immediately, otherwise it will be swapped to later in Sched_HandleRetrace.
|
||||
*
|
||||
* @see Sched_HandleRetrace
|
||||
*/
|
||||
void Sched_NotifyDone(SchedContext* sched, OSScTask* task) {
|
||||
void Sched_SetNextFramebufferFromTask(Scheduler* sched, OSScTask* task) {
|
||||
sched->pendingSwapBuf1 = TASK_FRAMEBUFFER(task);
|
||||
|
||||
if ((sched->curBuf != NULL) && (sched->curBuf->updateTimer > 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sched_SwapFramebuffer(sched, sched->pendingSwapBuf1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the task is done, i.e. it is no longer running on either the RSP or RDP.
|
||||
* If so, send a message to the task's message queue if there is one, and swap the framebuffer
|
||||
* if required.
|
||||
*/
|
||||
void Sched_TaskComplete(Scheduler* sched, OSScTask* task) {
|
||||
if (!(task->state & (OS_SC_DP | OS_SC_SP))) {
|
||||
if (task->msgQ != NULL) {
|
||||
osSendMesg(task->msgQ, task->msg, OS_MESG_BLOCK);
|
||||
}
|
||||
if (task->flags & OS_SC_SWAPBUFFER) {
|
||||
Sched_TaskUpdateFramebuffer(sched, task);
|
||||
Sched_SetNextFramebufferFromTask(sched, task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sched_RunTask(SchedContext* sched, OSScTask* spTask, OSScTask* dpTask) {
|
||||
u64 time;
|
||||
/**
|
||||
* Runs the next tasks. The scheduler doesn't support running RDP tasks without
|
||||
* passthrough via the RSP, if there is no RSP task to run then the RDP task will
|
||||
* also do nothing.
|
||||
*/
|
||||
void Sched_RunTask(Scheduler* sched, OSScTask* spTask, OSScTask* dpTask) {
|
||||
OSTime time;
|
||||
|
||||
if (spTask != NULL) {
|
||||
if (spTask->list.t.type == M_NULTASK) {
|
||||
@@ -320,7 +346,7 @@ void Sched_RunTask(SchedContext* sched, OSScTask* spTask, OSScTask* dpTask) {
|
||||
spTask->state &= ~OS_SC_DP;
|
||||
sched->curRDPTask = NULL;
|
||||
}
|
||||
Sched_NotifyDone(sched, spTask);
|
||||
Sched_TaskComplete(sched, spTask);
|
||||
return;
|
||||
}
|
||||
// Write back the data cache to ensure imminent SP DMA does not miss anything
|
||||
@@ -365,18 +391,21 @@ void Sched_RunTask(SchedContext* sched, OSScTask* spTask, OSScTask* dpTask) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any tasks that have been sent to the scheduler down the command queue.
|
||||
* Runs when the scheduler has received a notification, either from another thread or
|
||||
* on VI Retrace. Tasks that have been sent to it will be enqueued onto the audio or
|
||||
* gfx task queue and one may be ran if the RSP is available.
|
||||
*/
|
||||
void Sched_HandleEntry(SchedContext* sched) {
|
||||
OSScTask* spTask = NULL;
|
||||
OSScTask* dpTask = NULL;
|
||||
OSMesg msg = NULL;
|
||||
void Sched_HandleNotify(Scheduler* sched) {
|
||||
OSScTask* nextRSP = NULL;
|
||||
OSScTask* nextRDP = NULL;
|
||||
OSScTask* task = NULL;
|
||||
s32 state;
|
||||
|
||||
// Fetch and enqueue waiting tasks
|
||||
while (osRecvMesg(&sched->cmdQ, &msg, OS_MESG_NOBLOCK) != -1) {
|
||||
Sched_QueueTask(sched, msg);
|
||||
while (osRecvMesg(&sched->cmdQueue, (OSMesg*)&task, OS_MESG_NOBLOCK) != -1) {
|
||||
Sched_QueueTask(sched, task);
|
||||
}
|
||||
|
||||
// If there is an audio task pending and an RSP task is running, yield the current task.
|
||||
if ((sched->audioListHead != NULL) && (sched->curRSPTask != NULL)) {
|
||||
Sched_Yield(sched);
|
||||
@@ -384,12 +413,12 @@ void Sched_HandleEntry(SchedContext* sched) {
|
||||
}
|
||||
// Schedule and run the next task
|
||||
state = ((sched->curRSPTask == NULL) << 1) | (sched->curRDPTask == NULL);
|
||||
if (Sched_Schedule(sched, &spTask, &dpTask, state) != state) {
|
||||
Sched_RunTask(sched, spTask, dpTask);
|
||||
if (Sched_Schedule(sched, &nextRSP, &nextRDP, state) != state) {
|
||||
Sched_RunTask(sched, nextRSP, nextRDP);
|
||||
}
|
||||
}
|
||||
|
||||
void Sched_HandleRetrace(SchedContext* sched) {
|
||||
void Sched_HandleRetrace(Scheduler* sched) {
|
||||
ViConfig_UpdateBlack();
|
||||
sched->retraceCount++;
|
||||
|
||||
@@ -404,23 +433,29 @@ void Sched_HandleRetrace(SchedContext* sched) {
|
||||
sched->curBuf = sched->pendingSwapBuf1;
|
||||
sched->pendingSwapBuf1 = NULL;
|
||||
}
|
||||
|
||||
if (sched->curBuf != NULL) {
|
||||
if (sched->curBuf->updateRate2 > 0) {
|
||||
sched->curBuf->updateRate2--;
|
||||
if (sched->curBuf->updateTimer > 0) {
|
||||
sched->curBuf->updateTimer--;
|
||||
}
|
||||
if ((sched->curBuf->updateRate2 <= 0) && (sched->pendingSwapBuf1 != NULL)) {
|
||||
Sched_RetraceUpdateFramebuffer(sched, sched->pendingSwapBuf1);
|
||||
if ((sched->curBuf->updateTimer <= 0) && (sched->pendingSwapBuf1 != NULL)) {
|
||||
Sched_SwapFramebuffer(sched, sched->pendingSwapBuf1);
|
||||
}
|
||||
}
|
||||
Sched_HandleEntry(sched);
|
||||
|
||||
// Run the notification handler to enqueue any waiting tasks and possibly run one
|
||||
Sched_HandleNotify(sched);
|
||||
}
|
||||
|
||||
void Sched_HandleRSPDone(SchedContext* sched) {
|
||||
/**
|
||||
* RSP has signalled that the task has either completed or yielded.
|
||||
*/
|
||||
void Sched_HandleRSPDone(Scheduler* sched) {
|
||||
OSScTask* curRSP;
|
||||
OSScTask* nextRSP = NULL;
|
||||
OSScTask* nextRDP = NULL;
|
||||
s32 state;
|
||||
u64 time;
|
||||
OSTime time;
|
||||
|
||||
if (sched->curRSPTask == NULL) {
|
||||
osSyncPrintf("__scHandleRSP:sc->curRSPTask == NULL\n");
|
||||
@@ -464,7 +499,7 @@ void Sched_HandleRSPDone(SchedContext* sched) {
|
||||
} else {
|
||||
// Mark task completed
|
||||
curRSP->state &= ~OS_SC_SP;
|
||||
Sched_NotifyDone(sched, curRSP);
|
||||
Sched_TaskComplete(sched, curRSP);
|
||||
}
|
||||
|
||||
// Schedule and run next task
|
||||
@@ -474,7 +509,10 @@ void Sched_HandleRSPDone(SchedContext* sched) {
|
||||
}
|
||||
}
|
||||
|
||||
void Sched_HandleRDPDone(SchedContext* sched) {
|
||||
/**
|
||||
* RDP has signalled task done upon reaching a DPFullSync command
|
||||
*/
|
||||
void Sched_HandleRDPDone(Scheduler* sched) {
|
||||
OSScTask* curRDP;
|
||||
OSScTask* nextRSP = NULL;
|
||||
OSScTask* nextRDP = NULL;
|
||||
@@ -493,7 +531,7 @@ void Sched_HandleRDPDone(SchedContext* sched) {
|
||||
sched->curRDPTask = NULL;
|
||||
curRDP->state &= ~OS_SC_DP;
|
||||
|
||||
Sched_NotifyDone(sched, curRDP);
|
||||
Sched_TaskComplete(sched, curRDP);
|
||||
|
||||
// Schedule and run next task
|
||||
state = ((sched->curRSPTask == NULL) << 1) | (sched->curRDPTask == NULL);
|
||||
@@ -503,35 +541,38 @@ void Sched_HandleRDPDone(SchedContext* sched) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the scheduler to inform it that a new task has
|
||||
* been sent down the command queue.
|
||||
* Called by other threads in order to wake the scheduler up immediately to enqueue and
|
||||
* possibly run a task that has been sent to the task queue. Otherwise, any pending tasks
|
||||
* will be enqueued on next vertical retrace.
|
||||
*
|
||||
* Original name: osScKickEntryMsg
|
||||
*/
|
||||
void Sched_SendEntryMsg(SchedContext* sched) {
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)ENTRY_MSG, OS_MESG_BLOCK);
|
||||
void Sched_SendNotifyMsg(Scheduler* sched) {
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)NOTIFY_MSG, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the scheduler to inform it that it should attempt
|
||||
* to stop the last dispatched audio task.
|
||||
*/
|
||||
void Sched_SendAudioCancelMsg(SchedContext* sched) {
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)RDP_AUDIO_CANCEL_MSG, OS_MESG_BLOCK);
|
||||
void Sched_SendAudioCancelMsg(Scheduler* sched) {
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)RDP_AUDIO_CANCEL_MSG, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the scheduler to inform it that it should attempt
|
||||
* to stop the last dispatched gfx task.
|
||||
*/
|
||||
void Sched_SendGfxCancelMsg(SchedContext* sched) {
|
||||
osSendMesg(&sched->interruptQ, (OSMesg)RSP_GFX_CANCEL_MSG, OS_MESG_BLOCK);
|
||||
void Sched_SendGfxCancelMsg(Scheduler* sched) {
|
||||
osSendMesg(&sched->interruptQueue, (OSMesg)RSP_GFX_CANCEL_MSG, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fault Client for the scheduler. Reports information about the state of the scheduler
|
||||
* and any current tasks in the crash debugger.
|
||||
*/
|
||||
void Sched_FaultClient(void* param1, void* param2) {
|
||||
SchedContext* sched = (SchedContext*)param1;
|
||||
void Sched_FaultClient(void* arg0, void* arg1) {
|
||||
Scheduler* sched = (Scheduler*)arg0;
|
||||
OSScTask* spTask;
|
||||
OSScTask* dpTask;
|
||||
|
||||
@@ -559,10 +600,10 @@ void Sched_FaultClient(void* param1, void* param2) {
|
||||
*/
|
||||
void Sched_ThreadEntry(void* arg) {
|
||||
s32 msg = 0;
|
||||
SchedContext* sched = (SchedContext*)arg;
|
||||
Scheduler* sched = (Scheduler*)arg;
|
||||
|
||||
while (true) {
|
||||
osRecvMesg(&sched->interruptQ, (OSMesg*)&msg, OS_MESG_BLOCK);
|
||||
osRecvMesg(&sched->interruptQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
|
||||
|
||||
// Check if it's a message from another thread or the OS
|
||||
switch (msg) {
|
||||
@@ -574,8 +615,8 @@ void Sched_ThreadEntry(void* arg) {
|
||||
Sched_HandleGfxCancel(sched);
|
||||
continue;
|
||||
|
||||
case ENTRY_MSG:
|
||||
Sched_HandleEntry(sched);
|
||||
case NOTIFY_MSG:
|
||||
Sched_HandleNotify(sched);
|
||||
continue;
|
||||
|
||||
case RSP_DONE_MSG:
|
||||
@@ -594,31 +635,31 @@ void Sched_ThreadEntry(void* arg) {
|
||||
continue;
|
||||
|
||||
case OS_SC_PRE_NMI_MSG:
|
||||
Sched_HandleReset(sched);
|
||||
Sched_HandlePreNMI(sched);
|
||||
continue;
|
||||
|
||||
case OS_SC_NMI_MSG:
|
||||
Sched_HandleStop(sched);
|
||||
Sched_HandleNMI(sched);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the SchedContext and scheduler thread.
|
||||
* Registers an IrqClient for the thread and fault client for the SchedContext.
|
||||
* Directs the OS to send SP and DP OS messages to interruptQ when the RSP or RDP signal task completion.
|
||||
* Initializes the Scheduler and scheduler thread.
|
||||
* Registers an IrqClient for the thread and fault client for the Scheduler.
|
||||
* Directs the OS to send SP and DP OS messages to interruptQueue when the RSP or RDP signal task completion.
|
||||
*/
|
||||
void Sched_Init(SchedContext* sched, void* stack, OSPri pri, u8 viModeType, UNK_TYPE arg4, IrqMgr* irqMgr) {
|
||||
bzero(sched, sizeof(SchedContext));
|
||||
void Sched_Init(Scheduler* sched, void* stack, OSPri pri, u8 viModeType, UNK_TYPE arg4, IrqMgr* irqMgr) {
|
||||
bzero(sched, sizeof(Scheduler));
|
||||
|
||||
sched->shouldUpdateVi = true;
|
||||
sched->isFirstSwap = true;
|
||||
|
||||
osCreateMesgQueue(&sched->interruptQ, sched->intBuf, ARRAY_COUNT(sched->intBuf));
|
||||
osCreateMesgQueue(&sched->cmdQ, sched->cmdMsgBuf, ARRAY_COUNT(sched->cmdMsgBuf));
|
||||
osSetEventMesg(OS_EVENT_SP, &sched->interruptQ, (OSMesg)RSP_DONE_MSG);
|
||||
osSetEventMesg(OS_EVENT_DP, &sched->interruptQ, (OSMesg)RDP_DONE_MSG);
|
||||
IrqMgr_AddClient(irqMgr, &sched->irqClient, &sched->interruptQ);
|
||||
osCreateMesgQueue(&sched->interruptQueue, sched->interruptMsgBuf, ARRAY_COUNT(sched->interruptMsgBuf));
|
||||
osCreateMesgQueue(&sched->cmdQueue, sched->cmdMsgBuf, ARRAY_COUNT(sched->cmdMsgBuf));
|
||||
osSetEventMesg(OS_EVENT_SP, &sched->interruptQueue, (OSMesg)RSP_DONE_MSG);
|
||||
osSetEventMesg(OS_EVENT_DP, &sched->interruptQueue, (OSMesg)RDP_DONE_MSG);
|
||||
IrqMgr_AddClient(irqMgr, &sched->irqClient, &sched->interruptQueue);
|
||||
Fault_AddClient(&sSchedFaultClient, Sched_FaultClient, sched, NULL);
|
||||
osCreateThread(&sched->thread, Z_THREAD_ID_SCHED, Sched_ThreadEntry, sched, stack, pri);
|
||||
osStartThread(&sched->thread);
|
||||
|
||||
+3
-3
@@ -65,8 +65,8 @@ void Jpeg_ScheduleDecoderTask(JpegContext* jpegCtx) {
|
||||
jpegCtx->scTask.framebuffer = NULL;
|
||||
jpegCtx->scTask.list.t = sJpegTask;
|
||||
|
||||
osSendMesg(&gSchedContext.cmdQ, (OSMesg*)&jpegCtx->scTask, OS_MESG_BLOCK);
|
||||
Sched_SendEntryMsg(&gSchedContext); // osScKickEntryMsg
|
||||
osSendMesg(&gScheduler.cmdQueue, (OSMesg*)&jpegCtx->scTask, OS_MESG_BLOCK);
|
||||
Sched_SendNotifyMsg(&gScheduler); // osScKickEntryMsg
|
||||
osRecvMesg(&jpegCtx->mq, NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ s32 Jpeg_Decode(void* data, void* zbuffer, void* work, u32 workSize) {
|
||||
}
|
||||
|
||||
osCreateMesgQueue(&jpegCtx.mq, &jpegCtx.msg, 1);
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
|
||||
jpegCtx.workBuf = workBuff;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "scheduler.h"
|
||||
|
||||
#include "macros.h"
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* Blocks the current thread until all queued scheduler tasks have completed.
|
||||
*/
|
||||
void Sched_FlushTaskQueue(void) {
|
||||
OSScTask task;
|
||||
OSMesgQueue queue;
|
||||
OSMesg msg[1];
|
||||
|
||||
// Prepare a "NULL" task
|
||||
task.next = NULL;
|
||||
task.flags = OS_SC_NEEDS_RDP | OS_SC_NEEDS_RSP;
|
||||
task.msgQ = &queue;
|
||||
task.msg = NULL;
|
||||
task.framebuffer = NULL;
|
||||
task.list.t.type = M_NULTASK;
|
||||
osCreateMesgQueue(task.msgQ, msg, ARRAY_COUNT(msg));
|
||||
|
||||
// Send it to and wake up the scheduler
|
||||
osSendMesg(&gScheduler.cmdQueue, (OSMesg)&task, OS_MESG_BLOCK);
|
||||
Sched_SendNotifyMsg(&gScheduler);
|
||||
|
||||
// Wait until the task has been processed, indicating that no task is
|
||||
// running and the task queue is now empty.
|
||||
osRecvMesg(&queue, NULL, OS_MESG_BLOCK);
|
||||
}
|
||||
+7
-6
@@ -371,7 +371,7 @@ void Play_Destroy(GameState* thisx) {
|
||||
GraphicsContext* gfxCtx = this->state.gfxCtx;
|
||||
|
||||
if (sBombersNotebookOpen) {
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
SysCfb_SetLoResMode();
|
||||
gfxCtx->curFrameBuffer = SysCfb_GetFramebuffer(gfxCtx->framebufferIndex % 2);
|
||||
gfxCtx->zbuffer = SysCfb_GetZBuffer();
|
||||
@@ -928,7 +928,7 @@ void Play_UpdateMain(PlayState* this) {
|
||||
|
||||
if (R_PICTO_PHOTO_STATE == PICTO_PHOTO_STATE_PROCESS) {
|
||||
R_PICTO_PHOTO_STATE = PICTO_PHOTO_STATE_READY;
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
Play_TakePictoPhoto(&this->pauseBgPreRender);
|
||||
R_PICTO_PHOTO_STATE = PICTO_PHOTO_STATE_OFF;
|
||||
}
|
||||
@@ -1067,7 +1067,8 @@ void Play_Update(PlayState* this) {
|
||||
}
|
||||
} else if (CHECK_BTN_ALL(CONTROLLER1(&this->state)->press.button, BTN_L) ||
|
||||
CHECK_BTN_ALL(CONTROLLER1(&this->state)->press.button, BTN_B) ||
|
||||
CHECK_BTN_ALL(CONTROLLER1(&this->state)->press.button, BTN_START) || (gIrqMgrResetStatus != 0)) {
|
||||
CHECK_BTN_ALL(CONTROLLER1(&this->state)->press.button, BTN_START) ||
|
||||
(gIrqMgrResetStatus != IRQ_RESET_STATUS_IDLE)) {
|
||||
sBombersNotebookOpen = false;
|
||||
this->pauseCtx.bombersNotebookOpen = false;
|
||||
sBombersNotebook.loadState = BOMBERS_NOTEBOOK_LOAD_STATE_NONE;
|
||||
@@ -1253,7 +1254,7 @@ void Play_DrawMain(PlayState* this) {
|
||||
PreRender_SetValues(&this->pauseBgPreRender, gCfbWidth, gCfbHeight, gfxCtx->curFrameBuffer, gfxCtx->zbuffer);
|
||||
|
||||
if (R_PAUSE_BG_PRERENDER_STATE == PAUSE_BG_PRERENDER_PROCESS) {
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
if (!gSaveContext.screenScaleFlag) {
|
||||
PreRender_ApplyFiltersSlowlyInit(&this->pauseBgPreRender);
|
||||
}
|
||||
@@ -1448,7 +1449,7 @@ void Play_Draw(PlayState* this) {
|
||||
|
||||
if (sBombersNotebookOpen) {
|
||||
if (gSysCfbHiResEnabled != 1) {
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
SysCfb_SetHiResMode();
|
||||
gfxCtx2->curFrameBuffer = SysCfb_GetFramebuffer(gfxCtx2->framebufferIndex % 2);
|
||||
gfxCtx2->zbuffer = SysCfb_GetZBuffer();
|
||||
@@ -1460,7 +1461,7 @@ void Play_Draw(PlayState* this) {
|
||||
}
|
||||
} else {
|
||||
if (gSysCfbHiResEnabled != 0) {
|
||||
MsgEvent_SendNullTask();
|
||||
Sched_FlushTaskQueue();
|
||||
SysCfb_SetLoResMode();
|
||||
gfxCtx2->curFrameBuffer = SysCfb_GetFramebuffer(gfxCtx2->framebufferIndex % 2);
|
||||
gfxCtx2->zbuffer = SysCfb_GetZBuffer();
|
||||
|
||||
Reference in New Issue
Block a user