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
This commit is contained in:
parent
9e31e3796a
commit
e069e5997a
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
while (fake_GPWatchdogLastToken == fifo.Fake_GPWDToken && fifo.bFF_GPReadEnable && (fifo.CPReadWriteDistance > 0) && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint))
|
||||
;
|
||||
//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);
|
||||
}
|
||||
// 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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue