From e069e5997a2682c4295d46872ddf8e887c6935ca Mon Sep 17 00:00:00 2001 From: "memberTwo.mb2" Date: Tue, 18 Nov 2008 13:08:46 +0000 Subject: [PATCH] DC fix: Since game's frame-finish-watchdog have nothing to do with RTC, the faked GP watchdog moved in scheduler. DC should work for everyone now, we just may need to adjust FAKE_GP_WATCHDOG_PERIOD. TODO if it worth it: the actual re-scheduling of the new callback is stupid, so... + Some clean up. + Remove the unused GPUCallBack. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1210 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/CoreTiming.cpp | 6 -- Source/Core/Core/Src/HW/CommandProcessor.cpp | 36 ++++------ Source/Core/Core/Src/HW/CommandProcessor.h | 4 +- Source/Core/Core/Src/HW/PixelEngine.cpp | 2 +- Source/Core/Core/Src/HW/SystemTimers.cpp | 26 ++++--- Source/Core/VideoCommon/Src/Fifo.cpp | 76 +++----------------- 6 files changed, 43 insertions(+), 107 deletions(-) diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index 021ca18e26..1f1617a9d3 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -22,8 +22,6 @@ #include "CoreTiming.h" #include "StringUtil.h" -#include "HW/CommandProcessor.h" // <- for DC watchdog hack - // TODO(ector): Replace new/delete in this file with a simple memory pool // Don't expect a massive speedup though. @@ -305,10 +303,6 @@ void Advance() globalTimer += cyclesExecuted; - // for DC watchdog hack - // TODO (mb2): add DC mode check - CommandProcessor::CheckGPWDInterruptForSpinlock(); - while (first) { if (first->time <= globalTimer) diff --git a/Source/Core/Core/Src/HW/CommandProcessor.cpp b/Source/Core/Core/Src/HW/CommandProcessor.cpp index 7d1812f897..2dd1440cce 100644 --- a/Source/Core/Core/Src/HW/CommandProcessor.cpp +++ b/Source/Core/Core/Src/HW/CommandProcessor.cpp @@ -48,11 +48,10 @@ // TODO (mb2): // * raise watermark Ov/Un irq: POINTLESS since emulated GP timings can't be accuratly set. // Only 3 choices IMHO for a correct emulated load balancing in DC mode: -// - make our own GP watchdog hack that can lock CPU if GP too slow. +// - make our own GP watchdog hack that can lock CPU if GP too slow. STARTED // - hack directly something in PPC timings (dunno how) // - boost GP so we can consider it as infinitely fast compared to CPU. // * raise ReadIdle/CmdIdle flags and observe behaviour of MP1 & ZTP (at least) -// * investigate VI and PI for fixing the DC ZTP bug. // * Clean useless comments and debug stuff in Read16, Write16, GatherPipeBursted when sync will be fixed for DC // * (reminder) do the same in: // PeripheralInterface.cpp, PixelEngine.cpp, OGL->BPStructs.cpp, fifo.cpp... ok just check change log >> @@ -173,31 +172,28 @@ int et_UpdateInterrupts; // for GP watchdog hack void IncrementGPWDToken() { -#ifdef WIN32 +#ifdef _WIN32 InterlockedIncrement((LONG*)&fifo.Fake_GPWDToken); #else Common::InterlockedIncrement((int*)&fifo.Fake_GPWDToken); #endif } -void CheckGPWDInterruptForSpinlock() +// Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occured +// if not then lock CPUThread until GP finish a frame. +u32 fake_GPWatchdogLastToken = 0; +void WaitForFrameFinish() { - if (fifo.Fake_GPWDInterrupt) - { - // Wait for GPU to catch up - while (fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint)) - //while (fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0)) - ; - //if (!fifo.bFF_GPReadEnable) PanicAlert("WARNING: Fake_GPWDInterrupt raised but can't flush fifo. Fake_GPWDToken %i",fifo.Fake_GPWDToken); -#ifdef _WIN32 - InterlockedExchange((LONG*)&fifo.Fake_GPWDInterrupt, 0); -#else - Common::InterlockedExchange((int*)&fifo.Fake_GPWDInterrupt, 0); -#endif - LOGV(COMMANDPROCESSOR, 2, "!!! Fake_GPWDInterrupt raised. Fake_GPWDToken %i",fifo.Fake_GPWDToken); - } + while (fake_GPWatchdogLastToken == fifo.Fake_GPWDToken && fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint)) + ; + // oh well, should be safe. + // Assuming: time between 2 GP-frame-finish (ie. increment of fifo.Fake_GPWDToken) + // will be EVER way superior to time between + // "while (g_FAKE_GPWatchdogToken == fifo.Fake_GPWDToken..." and this line. :p + fake_GPWatchdogLastToken = fifo.Fake_GPWDToken; } + void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate) { UpdateInterrupts(); @@ -517,10 +513,6 @@ void GatherPipeBursted() if (Core::g_CoreStartupParameter.bUseDualCore) { - // for GP watchdog hack - // not very safe to do that here - CheckGPWDInterruptForSpinlock(); - // update the fifo-pointer fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE; if (fifo.CPWritePointer >= fifo.CPEnd) diff --git a/Source/Core/Core/Src/HW/CommandProcessor.h b/Source/Core/Core/Src/HW/CommandProcessor.h index 79b6024353..9b06f1347d 100644 --- a/Source/Core/Core/Src/HW/CommandProcessor.h +++ b/Source/Core/Core/Src/HW/CommandProcessor.h @@ -79,9 +79,9 @@ void UpdateInterruptsFromVideoPlugin(); bool AllowIdleSkipping(); -// for GP watchdog hack +// for DC GP watchdog hack void IncrementGPWDToken(); -void CheckGPWDInterruptForSpinlock(); +void WaitForFrameFinish(); } // end of namespace CommandProcessor diff --git a/Source/Core/Core/Src/HW/PixelEngine.cpp b/Source/Core/Core/Src/HW/PixelEngine.cpp index f46e88f967..71fbcff764 100644 --- a/Source/Core/Core/Src/HW/PixelEngine.cpp +++ b/Source/Core/Core/Src/HW/PixelEngine.cpp @@ -177,7 +177,6 @@ void SetFinish_OnMainThread(u64 userdata, int cyclesLate) { g_bSignalFinishInterrupt = 1; UpdateInterrupts(); - CommandProcessor::IncrementGPWDToken(); } // SetToken @@ -192,6 +191,7 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge) // THIS IS EXECUTED FROM VIDEO THREAD void SetFinish() { + CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack CoreTiming::ScheduleEvent_Threadsafe( 0, et_SetFinishOnMainThread); LOGV(PIXELENGINE, 2, "VIDEO Set Finish"); diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index acc21f4098..7da6cc1dec 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -24,6 +24,7 @@ #include "../HW/AudioInterface.h" #include "../HW/VideoInterface.h" #include "../HW/SerialInterface.h" +#include "../HW/CommandProcessor.h" // for DC watchdog hack #include "../PowerPC/PowerPC.h" #include "../CoreTiming.h" #include "../Core.h" @@ -42,6 +43,7 @@ s64 fakeDec; // With TB clk at 1/4 of BUS clk // and it seems BUS clk is really 1/3 of CPU clk // note: ZWW is ok and faster with TIMER_RATIO=8 though. +// !!! POSSIBLE STABLE PERF BOOST HACK THERE !!! enum { TIMER_RATIO = 12 }; @@ -53,7 +55,7 @@ int et_AI; int et_AudioFifo; int et_DSP; int et_IPC_HLE; -int et_GPU; +int et_FakeGPWD; // for DC watchdog hack // These are badly educated guesses // Feel free to experiment @@ -77,8 +79,10 @@ int // increase this number. IPC_HLE_PERIOD = GetTicksPerSecond() / 250, - // This one is also fairly arbitrary. Every N cycles, run the GPU until it starves (in single core mode only). - GPU_PERIOD = 10000; + // For DC watchdog hack + // Once every 2 frame-period should be enough. + // Assuming game's frame-finish-watchdog wait more than 2 emulated frame-period before starting its mess. + FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 30; u32 GetTicksPerSecond() { @@ -161,9 +165,12 @@ void AdvanceCallback(int cyclesExecuted) PowerPC::ppcState.spr[SPR_DEC] = (u32)fakeDec / TIMER_RATIO; } -void GPUCallback(u64 userdata, int cyclesLate) + +// For DC watchdog hack +void FakeGPWatchdogCallback(u64 userdata, int cyclesLate) { - CoreTiming::ScheduleEvent(GPU_PERIOD-cyclesLate, et_GPU); + CommandProcessor::WaitForFrameFinish(); // lock CPUThread until frame finish + CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD-cyclesLate, et_FakeGPWD); } void Init() @@ -197,7 +204,6 @@ void Init() et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); et_SI = CoreTiming::RegisterEvent("SICallback", SICallback); et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback); - et_GPU = CoreTiming::RegisterEvent("GPUCallback", GPUCallback); et_AudioFifo = CoreTiming::RegisterEvent("AudioFifoCallback", AudioFifoCallback); et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); @@ -207,8 +213,12 @@ void Init() CoreTiming::ScheduleEvent(SI_PERIOD, et_SI); CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), et_AudioFifo); - if (!Core::GetStartupParameter().bUseDualCore) - CoreTiming::ScheduleEvent(GPU_PERIOD, et_GPU); + // For DC watchdog hack + if (Core::GetStartupParameter().bUseDualCore) + { + et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback); + CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD, et_FakeGPWD); + } if (Core::GetStartupParameter().bWii) CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE); diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 534a840a16..ef2cab1b07 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -85,47 +85,6 @@ void Video_SendFifoData(u8* _uData, u32 len) OpcodeDecoder_Run(); } -// for GP watchdog hack -THREAD_RETURN GPWatchdogThread(void *pArg) -{ - const SCPFifoStruct &_fifo = *(SCPFifoStruct*)pArg; - u32 lastToken = 0; - u32 currentToken = 0; - int FourMsCount = 0; - - Common::SetCurrentThreadName("GPWatchdogThread"); - - while (_fifo.bFF_GPReadEnable != ~0UL) // blah - { - // 4 ms should be enough insignificant - Common::SleepCurrentThread(4); - currentToken = _fifo.Fake_GPWDToken; - if (lastToken == currentToken) - { - FourMsCount++; - // Threshold quite arbitrary. - // Assuming the PPC-frame-finish-watchdog use RTC(TOCHECK) and throw its exception after several times the normal frame rate - // I tested higher frame-periode-factor but 3 might be safe enough for DC stability for everyone. - // I may be wrong, so TOTEST on different machine like hell !!! - if (FourMsCount >= 3*16/4)// frame_periode_factor(3) * frame_periode(~16ms) / ms_step(4) - { -#ifdef _WIN32 - InterlockedExchange((LONG*)&_fifo.Fake_GPWDInterrupt, 1); -#else - Common::InterlockedExchange((int*)&_fifo.Fake_GPWDInterrupt, 1); -#endif - //__Log(LogTypes::VIDEO,"!!! Watchdog hit",_fifo.CPReadWriteDistance); - } - } - else - FourMsCount = 0; - - lastToken = currentToken; - } - return 0; -} - - void Fifo_EnterLoop(const SVideoInitialize &video_initialize) { SCPFifoStruct &_fifo = *video_initialize.pCPFifo; @@ -135,18 +94,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) if (hEventOnIdle==NULL) PanicAlert("Fifo_EnterLoop() -> EventOnIdle NULL"); #endif - // for GP watchdog hack - Common::Thread *watchdogThread = NULL; - watchdogThread = new Common::Thread(GPWatchdogThread, (void*)&_fifo); - // TODO (mb2): figure out why doesn't work on core 2 ??? - // may have to force it for DualCores - //watchdogThread->SetAffinity(1); -#ifdef _WIN32 - SetThreadPriority(watchdogThread, THREAD_PRIORITY_ABOVE_NORMAL); -#else - //TODO -#endif - #ifdef _WIN32 // TODO(ector): Don't peek so often! while (video_initialize.pPeekMessages()) @@ -158,7 +105,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) if (MsgWaitForMultipleObjects(1, &hEventOnIdle, FALSE, 1L, QS_ALLEVENTS) == WAIT_ABANDONED) break; #endif - //if (_fifo.CPReadWriteDistance < 1) if (_fifo.CPReadWriteDistance < _fifo.CPLoWatermark) #if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32) continue; @@ -180,16 +126,13 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) u8 *uData = video_initialize.pGetMemoryPointer(_fifo.CPReadPointer); u32 readPtr = _fifo.CPReadPointer; - // if we are on BP mode we must send 32B chunks to Video plugin - // for BP checking + // if we are on BP mode we must send 32B chunks to Video plugin for BP checking + // TODO (mb2): test & check if MP1/MP2 are ok with that (It may happens the whole fifo RW dist is send too iirc). if (_fifo.bFF_BPEnable) { - distToSend = 32; - readPtr += 32; if (readPtr == _fifo.CPBreakpoint) { video_initialize.pLog("!!! BP irq raised",FALSE); - //PanicAlert("!!! BP irq raised"); #ifdef _WIN32 InterlockedExchange((LONG*)&_fifo.bFF_Breakpoint, 1); #else @@ -198,11 +141,16 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) video_initialize.pUpdateInterrupts(); break; } + distToSend = 32; + readPtr += 32; + if ( readPtr > _fifo.CPEnd) + readPtr = _fifo.CPBase; } else { + // sending the whole CPReadWriteDistance distToSend = _fifo.CPReadWriteDistance; - if ( (distToSend+readPtr) > _fifo.CPEnd) // TODO: better + if ( (distToSend+readPtr) > _fifo.CPEnd) // TODO: better? { distToSend =_fifo.CPEnd - readPtr; readPtr = _fifo.CPBase; @@ -210,8 +158,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) else readPtr += distToSend; } - // TODO (mb2): add warning comments here for BP irq - // sending the whole CPReadWriteDistance most of the time Video_SendFifoData(uData, distToSend); #ifdef _WIN32 InterlockedExchange((LONG*)&_fifo.CPReadPointer, readPtr); @@ -226,11 +172,5 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) #if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32) CloseHandle(hEventOnIdle); #endif - // for GP watchdog DC hack - // dummy finish signal to watchdog - _fifo.bFF_GPReadEnable = ~0; - if(watchdogThread) - watchdogThread->WaitForDeath(); - }