From 31d24247741601042a5cdc0827111e966380a6f2 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Sat, 30 Mar 2024 22:44:08 -0400 Subject: [PATCH] Fixed issue with latency patch not always starting with the correct behavior --- patches/input_latency.c | 90 +++++++++++++++++------------------------ patches/syms.ld | 1 + ultramodern/events.cpp | 1 + 3 files changed, 40 insertions(+), 52 deletions(-) diff --git a/patches/input_latency.c b/patches/input_latency.c index e1fead0..0098192 100644 --- a/patches/input_latency.c +++ b/patches/input_latency.c @@ -2,7 +2,12 @@ #include "sys_cfb.h" #include "buffers.h" #include "fault.h" +#include "audiomgr.h" #include "z64speed_meter.h" +#include "z64vimode.h" +#include "z64viscvg.h" +#include "z64vismono.h" +#include "z64viszbuf.h" void recomp_set_current_frame_poll_id(); void PadMgr_HandleRetrace(void); @@ -34,6 +39,7 @@ void PadMgr_GetInput2(Input* inputs, s32 gameRequest) { extern CfbInfo sGraphCfbInfos[3]; u32 recomp_time_us(); void recomp_measure_latency(); +void* osViGetCurrentFramebuffer_recomp(); OSMesgQueue *rdp_queue_ptr = NULL; @@ -51,13 +57,10 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx, GameState* gameState) { static IrqMgrClient irq_client = {0}; static OSMesgQueue vi_queue = {0}; static OSMesg vi_buf[8] = {0}; - static OSMesgQueue rdp_queue = {0}; - static OSMesg rdp_mesg = NULL; static bool created = false; if (!created) { created = true; osCreateMesgQueue(&vi_queue, vi_buf, ARRAY_COUNT(vi_buf)); - osCreateMesgQueue(&rdp_queue, &rdp_mesg, 1); extern IrqMgr gIrqMgr; IrqMgr_AddClient(&gIrqMgr, &irq_client, &vi_queue); } @@ -65,9 +68,7 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx, GameState* gameState) { // @recomp Disable the wait here so that it can be moved after task submission for minimizing latency. // retry: // osSetTimer(&timer, OS_USEC_TO_CYCLES(3 * 1000 * 1000), 0, &gfxCtx->queue, (OSMesg)666); - u32 count_before = recomp_time_us(); - osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_BLOCK); - u32 count_after = recomp_time_us(); +// osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_BLOCK); // osStopTimer(&timer); // if (msg == (OSMesg)666) { @@ -143,66 +144,51 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx, GameState* gameState) { osRecvMesg(&gfxCtx->queue, NULL, OS_MESG_NOBLOCK); } - // @recomp Set up the dedicated RDP complete message queue pointer for the scheduler. - rdp_queue_ptr = &rdp_queue; - gfxCtx->schedMsgQ = &gSchedContext.cmdQ; - recomp_measure_latency(); osSendMesg(&gSchedContext.cmdQ, scTask, OS_MESG_BLOCK); Sched_SendEntryMsg(&gSchedContext); - // @recomp Wait for the RDP complete message to mitigate waiting between creating the next task and submitting it. - osRecvMesg(&rdp_queue, NULL, OS_MESG_BLOCK); - rdp_queue_ptr = NULL; + // @recomp Immediately wait on the task to complete to minimize latency for the next one. + osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_BLOCK); - // @recomp Manually wait the required number of VI periods after submitting the task - // so that the next frame doesn't need to wait before submitting its task. - u32 vi_count_before = recomp_time_us(); - for (int i = 0; i < cfb->updateRate; i++) { + // @recomp Wait on the VI framebuffer to change if this task has a framebuffer swap. + if (scTask->flags & OS_SC_SWAPBUFFER) { + while (osViGetCurrentFramebuffer_recomp() != cfb->fb1) { + osRecvMesg(&vi_queue, NULL, OS_MESG_BLOCK); + } + // Wait one extra VI afterwards. osRecvMesg(&vi_queue, NULL, OS_MESG_BLOCK); } - - // @recomp Flush any excess VI messages that came in. + + // @recomp Flush any extra messages from the VI queue. while (osRecvMesg(&vi_queue, NULL, OS_MESG_NOBLOCK) == 0) { ; } - u32 vi_count_after = recomp_time_us(); - - // recomp_printf("recv wait added %d us\nVI wait: %d us\n", count_after - count_before, vi_count_after - vi_count_before); } -extern OSTime sRDPStartTime; +extern SpeedMeter sGameSpeedMeter; +extern VisCvg sGameVisCvg; +extern VisZbuf sGameVisZbuf; +extern VisMono sGameVisMono; +extern ViMode sGameViMode; -// @recomp Patched to send a message to the dedicated RDP complete message queue. -void Sched_HandleRDPDone(SchedContext* sched) { - OSScTask* curRDP; - OSScTask* nextRSP = NULL; - OSScTask* nextRDP = NULL; - s32 state; +void GameState_Destroy(GameState* gameState) { + AudioMgr_StopAllSfxExceptSystem(); + Audio_Update(); - if (sched->curRDPTask == NULL) { - osSyncPrintf("__scHandleRDP:sc->curRDPTask == NULL\n"); - return; + // @recomp The wait for the gfx task was moved to directly after submission, so it's not needed here. + // osRecvMesg(&gameState->gfxCtx->queue, NULL, OS_MESG_BLOCK); + + if (gameState->destroy != NULL) { + gameState->destroy(gameState); } - // Log run time - gRDPTimeAcc = osGetTime() - sRDPStartTime; - - // Mark task done - curRDP = sched->curRDPTask; - sched->curRDPTask = NULL; - curRDP->state &= ~OS_SC_DP; - - // @recomp Send a message to the dedicated RDP complete message queue if it's currently set up. - if (rdp_queue_ptr) { - osSendMesg(rdp_queue_ptr, NULL, OS_MESG_BLOCK); - } - - Sched_NotifyDone(sched, curRDP); - - // Schedule and run next task - state = ((sched->curRSPTask == NULL) << 1) | (sched->curRDPTask == NULL); - if (Sched_Schedule(sched, &nextRSP, &nextRDP, state) != state) { - Sched_RunTask(sched, nextRSP, nextRDP); - } + Rumble_Destroy(); + SpeedMeter_Destroy(&sGameSpeedMeter); + VisCvg_Destroy(&sGameVisCvg); + VisZbuf_Destroy(&sGameVisZbuf); + VisMono_Destroy(&sGameVisMono); + ViMode_Destroy(&sGameViMode); + THA_Destroy(&gameState->tha); + GameAlloc_Cleanup(&gameState->alloc); } diff --git a/patches/syms.ld b/patches/syms.ld index 4412acf..c9fd76d 100644 --- a/patches/syms.ld +++ b/patches/syms.ld @@ -25,3 +25,4 @@ osCreateMesgQueue_recomp = 0x8F000048; recomp_set_current_frame_poll_id = 0x8F00004C; recomp_time_us = 0x8F000050; recomp_measure_latency = 0x8F000054; +osViGetCurrentFramebuffer_recomp = 0x8F000058; diff --git a/ultramodern/events.cpp b/ultramodern/events.cpp index dce03cc..c1a51f2 100644 --- a/ultramodern/events.cpp +++ b/ultramodern/events.cpp @@ -320,6 +320,7 @@ void gfx_thread_func(uint8_t* rdram, std::atomic_flag* thread_ready, ultramodern // is finished as well, so sending this early shouldn't be an issue in most cases. // If this causes issues then the logic can be replaced with responding to yield requests. sp_complete(); + ultramodern::measure_input_latency(); auto rt64_start = std::chrono::system_clock::now(); RT64SendDL(rdram, &task_action->task);