Merge pull request #10244 from phire/ban-timetravel

Delay singlecore gpu interrupts; Fixes Bomberman Jetters in single core mode.
This commit is contained in:
JMC47 2021-12-02 07:21:41 -05:00 committed by GitHub
commit c12e4e8ee0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 29 additions and 22 deletions

View File

@ -2205,7 +2205,7 @@ struct BPMemory
extern BPMemory bpmem; extern BPMemory bpmem;
void LoadBPReg(u32 value0); void LoadBPReg(u32 value0, int cycles_into_future);
void LoadBPRegPreprocess(u32 value0); void LoadBPRegPreprocess(u32 value0, int cycles_into_future);
std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata); std::pair<std::string, std::string> GetBPRegInfo(u8 cmd, u32 cmddata);

View File

@ -50,7 +50,7 @@ void BPInit()
bpmem.bpMask = 0xFFFFFF; 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_texture_cache->FlushEFBCopies();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
if (!Fifo::UseDeterministicGPUThread()) 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); DEBUG_LOG_FMT(VIDEO, "GXSetDrawDone SetPEFinish (value: {:#04X})", bp.newvalue & 0xFFFF);
return; return;
@ -193,14 +193,14 @@ static void BPWritten(const BPCmd& bp)
g_texture_cache->FlushEFBCopies(); g_texture_cache->FlushEFBCopies();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
if (!Fifo::UseDeterministicGPUThread()) if (!Fifo::UseDeterministicGPUThread())
PixelEngine::SetToken(static_cast<u16>(bp.newvalue & 0xFFFF), false); PixelEngine::SetToken(static_cast<u16>(bp.newvalue & 0xFFFF), false, cycles_into_future);
DEBUG_LOG_FMT(VIDEO, "SetPEToken {:#06X}", bp.newvalue & 0xFFFF); DEBUG_LOG_FMT(VIDEO, "SetPEToken {:#06X}", bp.newvalue & 0xFFFF);
return; return;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID
g_texture_cache->FlushEFBCopies(); g_texture_cache->FlushEFBCopies();
g_framebuffer_manager->InvalidatePeekCache(false); g_framebuffer_manager->InvalidatePeekCache(false);
if (!Fifo::UseDeterministicGPUThread()) if (!Fifo::UseDeterministicGPUThread())
PixelEngine::SetToken(static_cast<u16>(bp.newvalue & 0xFFFF), true); PixelEngine::SetToken(static_cast<u16>(bp.newvalue & 0xFFFF), true, cycles_into_future);
DEBUG_LOG_FMT(VIDEO, "SetPEToken + INT {:#06X}", bp.newvalue & 0xFFFF); DEBUG_LOG_FMT(VIDEO, "SetPEToken + INT {:#06X}", bp.newvalue & 0xFFFF);
return; return;
@ -717,7 +717,7 @@ static void BPWritten(const BPCmd& bp)
} }
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg() // Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
void LoadBPReg(u32 value0) void LoadBPReg(u32 value0, int cycles_into_future)
{ {
int regNum = value0 >> 24; int regNum = value0 >> 24;
int oldval = ((u32*)&bpmem)[regNum]; int oldval = ((u32*)&bpmem)[regNum];
@ -730,10 +730,10 @@ void LoadBPReg(u32 value0)
if (regNum != BPMEM_BP_MASK) if (regNum != BPMEM_BP_MASK)
bpmem.bpMask = 0xFFFFFF; 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; int regNum = value0 >> 24;
// masking could hypothetically be a problem // masking could hypothetically be a problem
@ -742,13 +742,13 @@ void LoadBPRegPreprocess(u32 value0)
{ {
case BPMEM_SETDRAWDONE: case BPMEM_SETDRAWDONE:
if ((newval & 0xff) == 0x02) if ((newval & 0xff) == 0x02)
PixelEngine::SetFinish(); PixelEngine::SetFinish(cycles_into_future);
break; break;
case BPMEM_PE_TOKEN_ID: case BPMEM_PE_TOKEN_ID:
PixelEngine::SetToken(newval & 0xffff, false); PixelEngine::SetToken(newval & 0xffff, false, cycles_into_future);
break; break;
case BPMEM_PE_TOKEN_INT_ID: // Pixel Engine Interrupt Token ID 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; break;
} }
} }

View File

@ -221,11 +221,11 @@ u8* Run(DataReader src, u32* cycles, bool in_display_list)
const u32 bp_cmd = src.Read<u32>(); const u32 bp_cmd = src.Read<u32>();
if constexpr (is_preprocess) if constexpr (is_preprocess)
{ {
LoadBPRegPreprocess(bp_cmd); LoadBPRegPreprocess(bp_cmd, total_cycles);
} }
else else
{ {
LoadBPReg(bp_cmd); LoadBPReg(bp_cmd, total_cycles);
INCSTAT(g_stats.this_frame.num_bp_loads); INCSTAT(g_stats.this_frame.num_bp_loads);
} }
} }

View File

@ -277,7 +277,7 @@ static void SetTokenFinish_OnMainThread(u64 userdata, s64 cyclesLate)
// Raise the event handler above on the CPU thread. // Raise the event handler above on the CPU thread.
// s_token_finish_mutex must be locked. // s_token_finish_mutex must be locked.
// THIS IS EXECUTED FROM VIDEO THREAD // THIS IS EXECUTED FROM VIDEO THREAD
static void RaiseEvent() static void RaiseEvent(int cycles_into_future)
{ {
if (s_event_raised) if (s_event_raised)
return; return;
@ -285,14 +285,21 @@ static void RaiseEvent()
s_event_raised = true; s_event_raised = true;
CoreTiming::FromThread from = CoreTiming::FromThread::NON_CPU; 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()) if (!SConfig::GetInstance().bCPUThread || Fifo::UseDeterministicGPUThread())
{
from = CoreTiming::FromThread::CPU; 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 // SetToken
// THIS IS EXECUTED FROM VIDEO THREAD // 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); 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_pending = token;
s_token_interrupt_pending |= interrupt; s_token_interrupt_pending |= interrupt;
RaiseEvent(); RaiseEvent(cycles_into_future);
} }
// SetFinish // SetFinish
// THIS IS EXECUTED FROM VIDEO THREAD (BPStructs.cpp) when a new frame has been drawn // 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"); DEBUG_LOG_FMT(PIXELENGINE, "VIDEO Set Finish");
@ -314,7 +321,7 @@ void SetFinish()
s_finish_interrupt_pending |= true; s_finish_interrupt_pending |= true;
RaiseEvent(); RaiseEvent(cycles_into_future);
} }
UPEAlphaReadReg GetAlphaReadMode() UPEAlphaReadReg GetAlphaReadMode()

View File

@ -61,8 +61,8 @@ void DoState(PointerWrap& p);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base); void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
// gfx backend support // gfx backend support
void SetToken(const u16 token, const bool interrupt); void SetToken(const u16 token, const bool interrupt, int cycle_delay);
void SetFinish(); void SetFinish(int cycle_delay);
UPEAlphaReadReg GetAlphaReadMode(); UPEAlphaReadReg GetAlphaReadMode();
} // namespace PixelEngine } // namespace PixelEngine