diff --git a/Source/Core/VideoCommon/BPMemory.h b/Source/Core/VideoCommon/BPMemory.h index 21636224c0..fdd32746a9 100644 --- a/Source/Core/VideoCommon/BPMemory.h +++ b/Source/Core/VideoCommon/BPMemory.h @@ -2205,7 +2205,7 @@ struct BPMemory extern BPMemory bpmem; -void LoadBPReg(u32 value0); -void LoadBPRegPreprocess(u32 value0); +void LoadBPReg(u32 value0, int cycles_into_future); +void LoadBPRegPreprocess(u32 value0, int cycles_into_future); std::pair GetBPRegInfo(u8 cmd, u32 cmddata); diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 1ec097fe6e..0fc4ca6785 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -50,7 +50,7 @@ void BPInit() bpmem.bpMask = 0xFFFFFF; } -static void BPWritten(const BPCmd& bp) +static void BPWritten(const BPCmd& bp, int cycles_into_future) { /* ---------------------------------------------------------------------------------------------------------------- @@ -180,7 +180,7 @@ static void BPWritten(const BPCmd& bp) g_texture_cache->FlushEFBCopies(); g_framebuffer_manager->InvalidatePeekCache(false); if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetFinish(); // may generate interrupt + PixelEngine::SetFinish(cycles_into_future); // may generate interrupt DEBUG_LOG_FMT(VIDEO, "GXSetDrawDone SetPEFinish (value: {:#04X})", bp.newvalue & 0xFFFF); return; @@ -193,14 +193,14 @@ static void BPWritten(const BPCmd& bp) g_texture_cache->FlushEFBCopies(); g_framebuffer_manager->InvalidatePeekCache(false); if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), false); + PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), false, cycles_into_future); DEBUG_LOG_FMT(VIDEO, "SetPEToken {:#06X}", bp.newvalue & 0xFFFF); return; case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID g_texture_cache->FlushEFBCopies(); g_framebuffer_manager->InvalidatePeekCache(false); if (!Fifo::UseDeterministicGPUThread()) - PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), true); + PixelEngine::SetToken(static_cast(bp.newvalue & 0xFFFF), true, cycles_into_future); DEBUG_LOG_FMT(VIDEO, "SetPEToken + INT {:#06X}", bp.newvalue & 0xFFFF); return; @@ -717,7 +717,7 @@ static void BPWritten(const BPCmd& bp) } // Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() -void LoadBPReg(u32 value0) +void LoadBPReg(u32 value0, int cycles_into_future) { int regNum = value0 >> 24; int oldval = ((u32*)&bpmem)[regNum]; @@ -730,10 +730,10 @@ void LoadBPReg(u32 value0) if (regNum != BPMEM_BP_MASK) bpmem.bpMask = 0xFFFFFF; - BPWritten(bp); + BPWritten(bp, cycles_into_future); } -void LoadBPRegPreprocess(u32 value0) +void LoadBPRegPreprocess(u32 value0, int cycles_into_future) { int regNum = value0 >> 24; // masking could hypothetically be a problem @@ -742,13 +742,13 @@ void LoadBPRegPreprocess(u32 value0) { case BPMEM_SETDRAWDONE: if ((newval & 0xff) == 0x02) - PixelEngine::SetFinish(); + PixelEngine::SetFinish(cycles_into_future); break; case BPMEM_PE_TOKEN_ID: - PixelEngine::SetToken(newval & 0xffff, false); + PixelEngine::SetToken(newval & 0xffff, false, cycles_into_future); break; case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID - PixelEngine::SetToken(newval & 0xffff, true); + PixelEngine::SetToken(newval & 0xffff, true, cycles_into_future); break; } } diff --git a/Source/Core/VideoCommon/OpcodeDecoding.cpp b/Source/Core/VideoCommon/OpcodeDecoding.cpp index 00f470d5f4..a1abacc4c6 100644 --- a/Source/Core/VideoCommon/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/OpcodeDecoding.cpp @@ -221,11 +221,11 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list) const u32 bp_cmd = src.Read(); if constexpr (is_preprocess) { - LoadBPRegPreprocess(bp_cmd); + LoadBPRegPreprocess(bp_cmd, total_cycles); } else { - LoadBPReg(bp_cmd); + LoadBPReg(bp_cmd, total_cycles); INCSTAT(g_stats.this_frame.num_bp_loads); } } diff --git a/Source/Core/VideoCommon/PixelEngine.cpp b/Source/Core/VideoCommon/PixelEngine.cpp index 87d58eb010..747328b3c6 100644 --- a/Source/Core/VideoCommon/PixelEngine.cpp +++ b/Source/Core/VideoCommon/PixelEngine.cpp @@ -277,7 +277,7 @@ static void SetTokenFinish_OnMainThread(u64 userdata, s64 cyclesLate) // Raise the event handler above on the CPU thread. // s_token_finish_mutex must be locked. // THIS IS EXECUTED FROM VIDEO THREAD -static void RaiseEvent() +static void RaiseEvent(int cycles_into_future) { if (s_event_raised) return; @@ -285,14 +285,21 @@ static void RaiseEvent() s_event_raised = true; CoreTiming::FromThread from = CoreTiming::FromThread::NON_CPU; + s64 cycles = 0; // we don't care about timings for dual core mode. if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread()) + { from = CoreTiming::FromThread::CPU; - CoreTiming::ScheduleEvent(0, et_SetTokenFinishOnMainThread, 0, from); + + // Hack: Dolphin's single-core gpu timings are way too fast. Enforce a minimum delay to give + // games time to setup any interrupt state + cycles = std::max(500, cycles_into_future); + } + CoreTiming::ScheduleEvent(cycles, et_SetTokenFinishOnMainThread, 0, from); } // SetToken // THIS IS EXECUTED FROM VIDEO THREAD -void SetToken(const u16 token, const bool interrupt) +void SetToken(const u16 token, const bool interrupt, int cycles_into_future) { DEBUG_LOG_FMT(PIXELENGINE, "VIDEO Backend raises INT_CAUSE_PE_TOKEN (btw, token: {:04x})", token); @@ -301,12 +308,12 @@ void SetToken(const u16 token, const bool interrupt) s_token_pending = token; s_token_interrupt_pending |= interrupt; - RaiseEvent(); + RaiseEvent(cycles_into_future); } // SetFinish // THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn -void SetFinish() +void SetFinish(int cycles_into_future) { DEBUG_LOG_FMT(PIXELENGINE, "VIDEO Set Finish"); @@ -314,7 +321,7 @@ void SetFinish() s_finish_interrupt_pending |= true; - RaiseEvent(); + RaiseEvent(cycles_into_future); } UPEAlphaReadReg GetAlphaReadMode() diff --git a/Source/Core/VideoCommon/PixelEngine.h b/Source/Core/VideoCommon/PixelEngine.h index afbc8ddbe9..7444ddb3c2 100644 --- a/Source/Core/VideoCommon/PixelEngine.h +++ b/Source/Core/VideoCommon/PixelEngine.h @@ -61,8 +61,8 @@ void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); // gfx backend support -void SetToken(const u16 token, const bool interrupt); -void SetFinish(); +void SetToken(const u16 token, const bool interrupt, int cycle_delay); +void SetFinish(int cycle_delay); UPEAlphaReadReg GetAlphaReadMode(); } // namespace PixelEngine