mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
DC "fix": "Better" watchdogThread. Need to be tested on others PC specs. Everything works with for me (nice Q6600 + 8800GT owners :p ). We may have to put some hardcoded value in GUI for helping debug on other PCs. If it doesn't work and if someone have time, tweak a bit the threshold "FourMsCount" in "GPWatchdogThread" and let me know.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1184 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -22,6 +22,8 @@
|
|||||||
#include "CoreTiming.h"
|
#include "CoreTiming.h"
|
||||||
#include "StringUtil.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
|
// TODO(ector): Replace new/delete in this file with a simple memory pool
|
||||||
// Don't expect a massive speedup though.
|
// Don't expect a massive speedup though.
|
||||||
|
|
||||||
@ -303,6 +305,10 @@ void Advance()
|
|||||||
|
|
||||||
globalTimer += cyclesExecuted;
|
globalTimer += cyclesExecuted;
|
||||||
|
|
||||||
|
// for DC watchdog hack
|
||||||
|
// TODO (mb2): add DC mode check
|
||||||
|
CommandProcessor::CheckGPWDInterruptForSpinlock();
|
||||||
|
|
||||||
while (first)
|
while (first)
|
||||||
{
|
{
|
||||||
if (first->time <= globalTimer)
|
if (first->time <= globalTimer)
|
||||||
|
@ -47,10 +47,10 @@
|
|||||||
|
|
||||||
// TODO (mb2):
|
// TODO (mb2):
|
||||||
// * raise watermark Ov/Un irq: POINTLESS since emulated GP timings can't be accuratly set.
|
// * raise watermark Ov/Un irq: POINTLESS since emulated GP timings can't be accuratly set.
|
||||||
// Only 3 choises IMHO for a correct emulated load balancing in DC mode:
|
// 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.
|
||||||
// - hack directly something in PPC timings (dunno how)
|
// - hack directly something in PPC timings (dunno how)
|
||||||
// - boost GP so we can consider it as infinitly fast compared to CPU.
|
// - 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)
|
// * raise ReadIdle/CmdIdle flags and observe behaviour of MP1 & ZTP (at least)
|
||||||
// * investigate VI and PI for fixing the DC ZTP bug.
|
// * 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
|
// * Clean useless comments and debug stuff in Read16, Write16, GatherPipeBursted when sync will be fixed for DC
|
||||||
@ -173,13 +173,31 @@ int et_UpdateInterrupts;
|
|||||||
// for GP watchdog hack
|
// for GP watchdog hack
|
||||||
void IncrementGPWDToken()
|
void IncrementGPWDToken()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef WIN32
|
||||||
InterlockedIncrement((LONG*)&fifo.Fake_GPWDToken);
|
InterlockedIncrement((LONG*)&fifo.Fake_GPWDToken);
|
||||||
#else
|
#else
|
||||||
Common::InterlockedIncrement((int*)&fifo.Fake_GPWDToken);
|
Common::InterlockedIncrement((int*)&fifo.Fake_GPWDToken);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckGPWDInterruptForSpinlock()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
@ -500,19 +518,8 @@ void GatherPipeBursted()
|
|||||||
if (Core::g_CoreStartupParameter.bUseDualCore)
|
if (Core::g_CoreStartupParameter.bUseDualCore)
|
||||||
{
|
{
|
||||||
// for GP watchdog hack
|
// for GP watchdog hack
|
||||||
if (fifo.Fake_GPWDInterrupt)
|
// not very safe to do that here
|
||||||
{
|
CheckGPWDInterruptForSpinlock();
|
||||||
// Wait for GPU to catch up
|
|
||||||
while (fifo.CPReadWriteDistance > 0) // TOCHECK: more checks could be needed
|
|
||||||
;
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// update the fifo-pointer
|
// update the fifo-pointer
|
||||||
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
fifo.CPWritePointer += GPFifo::GATHER_PIPE_SIZE;
|
||||||
@ -521,15 +528,15 @@ void GatherPipeBursted()
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
InterlockedExchangeAdd((LONG*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
||||||
#else
|
#else
|
||||||
Common::InterlockedExchangeAdd((int*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
Common::InterlockedExchangeAdd((int*)&fifo.CPReadWriteDistance, GPFifo::GATHER_PIPE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// High watermark overflow handling (hacked way)
|
// High watermark overflow handling (hacked way)
|
||||||
u32 ct=0;
|
u32 ct=0;
|
||||||
if (fifo.CPReadWriteDistance > (s32)fifo.CPHiWatermark)
|
if (fifo.CPReadWriteDistance > fifo.CPHiWatermark)
|
||||||
{
|
{
|
||||||
// we should raise an Ov interrupt for an accurate fifo emulation and let PPC deal with it.
|
// we should raise an Ov interrupt for an accurate fifo emulation and let PPC deal with it.
|
||||||
// But it slowdown things because of if(interrupt blah blah){} blocks for each 32B fifo transactions.
|
// But it slowdowns things because of if(interrupt blah blah){} blocks for each 32B fifo transactions.
|
||||||
// CPU would be a bit more loaded too by its interrupt handling...
|
// CPU would be a bit more loaded too by its interrupt handling...
|
||||||
// Eather way, CPU would have the ability to resume another thread.
|
// Eather way, CPU would have the ability to resume another thread.
|
||||||
// To be clear: this spin loop is like a critical section spin loop in the emulated GX thread hence "hacked way"
|
// To be clear: this spin loop is like a critical section spin loop in the emulated GX thread hence "hacked way"
|
||||||
@ -546,7 +553,7 @@ void GatherPipeBursted()
|
|||||||
|
|
||||||
// Wait for GPU to catch up
|
// Wait for GPU to catch up
|
||||||
//while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
|
//while (!(fifo.bFF_BPEnable && fifo.bFF_Breakpoint) && fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
|
||||||
while (fifo.CPReadWriteDistance > (s32)fifo.CPLoWatermark)
|
while (fifo.CPReadWriteDistance > fifo.CPLoWatermark)
|
||||||
{
|
{
|
||||||
ct++;
|
ct++;
|
||||||
// dunno if others threads (like the audio thread) really need a forced context switch here
|
// dunno if others threads (like the audio thread) really need a forced context switch here
|
||||||
|
@ -81,6 +81,7 @@ bool AllowIdleSkipping();
|
|||||||
|
|
||||||
// for GP watchdog hack
|
// for GP watchdog hack
|
||||||
void IncrementGPWDToken();
|
void IncrementGPWDToken();
|
||||||
|
void CheckGPWDInterruptForSpinlock();
|
||||||
|
|
||||||
} // end of namespace CommandProcessor
|
} // end of namespace CommandProcessor
|
||||||
|
|
||||||
|
@ -89,28 +89,38 @@ void Video_SendFifoData(u8* _uData, u32 len)
|
|||||||
THREAD_RETURN GPWatchdogThread(void *pArg)
|
THREAD_RETURN GPWatchdogThread(void *pArg)
|
||||||
{
|
{
|
||||||
const SCPFifoStruct &_fifo = *(SCPFifoStruct*)pArg;
|
const SCPFifoStruct &_fifo = *(SCPFifoStruct*)pArg;
|
||||||
u32 token = 0;
|
u32 lastToken = 0;
|
||||||
|
u32 currentToken = 0;
|
||||||
|
int FourMsCount = 0;
|
||||||
|
|
||||||
Common::SetCurrentThreadName("GPWatchdogThread");
|
Common::SetCurrentThreadName("GPWatchdogThread");
|
||||||
Common::Thread::SetCurrentThreadAffinity(2); //Force to second core
|
|
||||||
//int i=30*1000/16;
|
while (_fifo.bFF_GPReadEnable != ~0) // blah
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
Common::SleepCurrentThread(8); // about 1s/60/2 (less than twice a frame should be enough)
|
// 4 ms should be enough insignificant
|
||||||
//if (!_fifo.bFF_GPReadIdle)
|
Common::SleepCurrentThread(4);
|
||||||
|
currentToken = _fifo.Fake_GPWDToken;
|
||||||
// TODO (mb2): FIX this !!!
|
if (lastToken == currentToken)
|
||||||
//if (token == _fifo.Fake_GPWDToken)
|
|
||||||
{
|
{
|
||||||
|
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
|
#ifdef _WIN32
|
||||||
InterlockedExchange((LONG*)&_fifo.Fake_GPWDInterrupt, 1);
|
InterlockedExchange((LONG*)&_fifo.Fake_GPWDInterrupt, 1);
|
||||||
#else
|
#else
|
||||||
Common::InterlockedExchange((int*)&_fifo.Fake_GPWDInterrupt, 1);
|
Common::InterlockedExchange((int*)&_fifo.Fake_GPWDInterrupt, 1);
|
||||||
#endif
|
#endif
|
||||||
//__Log(LogTypes::VIDEO,"!!! Watchdog hit",_fifo.CPReadWriteDistance);
|
//__Log(LogTypes::VIDEO,"!!! Watchdog hit",_fifo.CPReadWriteDistance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
token = _fifo.Fake_GPWDToken;
|
else
|
||||||
//i--;
|
FourMsCount = 0;
|
||||||
|
|
||||||
|
lastToken = currentToken;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -119,6 +129,7 @@ THREAD_RETURN GPWatchdogThread(void *pArg)
|
|||||||
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
{
|
{
|
||||||
SCPFifoStruct &_fifo = *video_initialize.pCPFifo;
|
SCPFifoStruct &_fifo = *video_initialize.pCPFifo;
|
||||||
|
u32 distToSend;
|
||||||
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
||||||
HANDLE hEventOnIdle= OpenEventA(EVENT_ALL_ACCESS,FALSE,(LPCSTR)"EventOnIdle");
|
HANDLE hEventOnIdle= OpenEventA(EVENT_ALL_ACCESS,FALSE,(LPCSTR)"EventOnIdle");
|
||||||
if (hEventOnIdle==NULL) PanicAlert("Fifo_EnterLoop() -> EventOnIdle NULL");
|
if (hEventOnIdle==NULL) PanicAlert("Fifo_EnterLoop() -> EventOnIdle NULL");
|
||||||
@ -127,6 +138,14 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
// for GP watchdog hack
|
// for GP watchdog hack
|
||||||
Common::Thread *watchdogThread = NULL;
|
Common::Thread *watchdogThread = NULL;
|
||||||
watchdogThread = new Common::Thread(GPWatchdogThread, (void*)&_fifo);
|
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
|
#ifdef _WIN32
|
||||||
// TODO(ector): Don't peek so often!
|
// TODO(ector): Don't peek so often!
|
||||||
@ -139,8 +158,8 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
if (MsgWaitForMultipleObjects(1, &hEventOnIdle, FALSE, 1L, QS_ALLEVENTS) == WAIT_ABANDONED)
|
if (MsgWaitForMultipleObjects(1, &hEventOnIdle, FALSE, 1L, QS_ALLEVENTS) == WAIT_ABANDONED)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
if (_fifo.CPReadWriteDistance < 1)
|
//if (_fifo.CPReadWriteDistance < 1)
|
||||||
//if (_fifo.CPReadWriteDistance < _fifo.CPLoWatermark)
|
if (_fifo.CPReadWriteDistance < _fifo.CPLoWatermark)
|
||||||
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
||||||
continue;
|
continue;
|
||||||
#else
|
#else
|
||||||
@ -157,12 +176,20 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
while(_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance > 0) )
|
while(_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance > 0) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// check if we are on a breakpoint
|
// read the data and send it to the VideoPlugin
|
||||||
if (_fifo.bFF_BPEnable)
|
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 (_fifo.bFF_BPEnable)
|
||||||
{
|
{
|
||||||
if (_fifo.CPReadPointer == _fifo.CPBreakpoint)
|
distToSend = 32;
|
||||||
|
readPtr += 32;
|
||||||
|
if (readPtr == _fifo.CPBreakpoint)
|
||||||
{
|
{
|
||||||
video_initialize.pLog("!!! BP irq raised",FALSE);
|
video_initialize.pLog("!!! BP irq raised",FALSE);
|
||||||
|
//PanicAlert("!!! BP irq raised");
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
InterlockedExchange((LONG*)&_fifo.bFF_Breakpoint, 1);
|
InterlockedExchange((LONG*)&_fifo.bFF_Breakpoint, 1);
|
||||||
#else
|
#else
|
||||||
@ -172,24 +199,23 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the data and send it to the VideoPlugin
|
|
||||||
u8 *uData = video_initialize.pGetMemoryPointer(_fifo.CPReadPointer);
|
|
||||||
|
|
||||||
u32 dist = _fifo.CPReadWriteDistance;
|
|
||||||
u32 readPtr = _fifo.CPReadPointer;
|
|
||||||
if ( (dist+readPtr) > _fifo.CPEnd) // TODO: better
|
|
||||||
{
|
|
||||||
dist =_fifo.CPEnd - readPtr;
|
|
||||||
readPtr = _fifo.CPBase;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
readPtr += dist;
|
{
|
||||||
|
distToSend = _fifo.CPReadWriteDistance;
|
||||||
Video_SendFifoData(uData, dist);
|
if ( (distToSend+readPtr) > _fifo.CPEnd) // TODO: better
|
||||||
|
{
|
||||||
|
distToSend =_fifo.CPEnd - readPtr;
|
||||||
|
readPtr = _fifo.CPBase;
|
||||||
|
}
|
||||||
|
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
|
#ifdef _WIN32
|
||||||
InterlockedExchange((LONG*)&_fifo.CPReadPointer, readPtr);
|
InterlockedExchange((LONG*)&_fifo.CPReadPointer, readPtr);
|
||||||
InterlockedExchangeAdd((LONG*)&_fifo.CPReadWriteDistance, -dist);
|
InterlockedExchangeAdd((LONG*)&_fifo.CPReadWriteDistance, -distToSend);
|
||||||
#else
|
#else
|
||||||
Common::InterlockedExchange((int*)&_fifo.CPReadPointer, readPtr);
|
Common::InterlockedExchange((int*)&_fifo.CPReadPointer, readPtr);
|
||||||
Common::InterlockedExchangeAdd((int*)&_fifo.CPReadWriteDistance, -dist);
|
Common::InterlockedExchangeAdd((int*)&_fifo.CPReadWriteDistance, -dist);
|
||||||
@ -200,5 +226,11 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
#if defined(THREAD_VIDEO_WAKEUP_ONIDLE) && defined(_WIN32)
|
||||||
CloseHandle(hEventOnIdle);
|
CloseHandle(hEventOnIdle);
|
||||||
#endif
|
#endif
|
||||||
|
// for GP watchdog DC hack
|
||||||
|
// dummy finish signal to watchdog
|
||||||
|
_fifo.bFF_GPReadEnable = ~0;
|
||||||
|
if(watchdogThread)
|
||||||
|
watchdogThread->WaitForDeath();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ typedef struct
|
|||||||
volatile u32 CPEnd;
|
volatile u32 CPEnd;
|
||||||
u32 CPHiWatermark;
|
u32 CPHiWatermark;
|
||||||
u32 CPLoWatermark;
|
u32 CPLoWatermark;
|
||||||
volatile s32 CPReadWriteDistance;
|
volatile u32 CPReadWriteDistance;
|
||||||
volatile u32 CPWritePointer;
|
volatile u32 CPWritePointer;
|
||||||
volatile u32 CPReadPointer;
|
volatile u32 CPReadPointer;
|
||||||
volatile u32 CPBreakpoint;
|
volatile u32 CPBreakpoint;
|
||||||
|
Reference in New Issue
Block a user