This could alleviate the suffering of dual core synchronization a bit.

But I doubt you would notice it in most cases.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4830 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
ayuanx 2010-01-14 10:52:14 +00:00
parent b186f0821e
commit 571a47ef9a
11 changed files with 108 additions and 49 deletions

View File

@ -106,7 +106,6 @@ void DSound::SoundLoop()
while (!threadData) while (!threadData)
{ {
// No blocking inside the csection // No blocking inside the csection
soundCriticalSection.Enter();
dsBuffer->GetCurrentPosition((DWORD*)&currentPos, 0); dsBuffer->GetCurrentPosition((DWORD*)&currentPos, 0);
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos)); int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
if (numBytesToRender >= 256) if (numBytesToRender >= 256)
@ -117,7 +116,6 @@ void DSound::SoundLoop()
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender); WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
lastPos = ModBufferSize(lastPos + numBytesToRender); lastPos = ModBufferSize(lastPos + numBytesToRender);
} }
soundCriticalSection.Leave();
soundSyncEvent.Wait(); soundSyncEvent.Wait();
} }
} }
@ -149,10 +147,8 @@ void DSound::SetVolume(int volume)
// This is in "dBA attenuation" from 0 to -10000, logarithmic // This is in "dBA attenuation" from 0 to -10000, logarithmic
m_volume = (int)floor(log10((float)volume) * 5000.0f) - 10000; m_volume = (int)floor(log10((float)volume) * 5000.0f) - 10000;
soundCriticalSection.Enter();
if (dsBuffer != NULL) if (dsBuffer != NULL)
dsBuffer->SetVolume(m_volume); dsBuffer->SetVolume(m_volume);
soundCriticalSection.Leave();
} }
void DSound::Update() void DSound::Update()
@ -164,7 +160,6 @@ void DSound::Clear(bool mute)
{ {
m_muted = mute; m_muted = mute;
soundCriticalSection.Enter();
if (m_muted) if (m_muted)
{ {
dsBuffer->Stop(); dsBuffer->Stop();
@ -173,7 +168,6 @@ void DSound::Clear(bool mute)
{ {
dsBuffer->Play(0, 0, DSBPLAY_LOOPING); dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
} }
soundCriticalSection.Leave();
} }
void DSound::Stop() void DSound::Stop()
@ -182,13 +176,11 @@ void DSound::Stop()
// kick the thread if it's waiting // kick the thread if it's waiting
soundSyncEvent.Set(); soundSyncEvent.Set();
soundCriticalSection.Enter();
delete thread; delete thread;
thread = NULL; thread = NULL;
dsBuffer->Stop(); dsBuffer->Stop();
dsBuffer->Release(); dsBuffer->Release();
ds->Release(); ds->Release();
soundCriticalSection.Leave();
soundSyncEvent.Shutdown(); soundSyncEvent.Shutdown();
} }

View File

@ -32,8 +32,7 @@ class DSound : public SoundStream
{ {
#ifdef _WIN32 #ifdef _WIN32
Common::Thread *thread; Common::Thread *thread;
Common::CriticalSection soundCriticalSection; Common::EventEx soundSyncEvent;
Common::Event soundSyncEvent;
void *hWnd; void *hWnd;
IDirectSound8* ds; IDirectSound8* ds;

View File

@ -64,8 +64,7 @@ public:
private: private:
Common::Thread *thread; Common::Thread *thread;
Common::CriticalSection soundCriticalSection; Common::EventEx soundSyncEvent;
Common::Event soundSyncEvent;
short realtimeBuffer[OAL_MAX_SAMPLES * 2]; short realtimeBuffer[OAL_MAX_SAMPLES * 2];
ALuint uiBuffers[OAL_NUM_BUFFERS]; ALuint uiBuffers[OAL_NUM_BUFFERS];

View File

@ -117,6 +117,60 @@ void Thread::SetCurrentThreadAffinity(int mask)
SetThreadAffinityMask(GetCurrentThread(), mask); SetThreadAffinityMask(GetCurrentThread(), mask);
} }
#ifdef _WIN32
EventEx::EventEx()
{
InterlockedExchange(&m_Lock, 1);
}
void EventEx::Init()
{
InterlockedExchange(&m_Lock, 1);
}
void EventEx::Shutdown()
{
InterlockedExchange(&m_Lock, 0);
}
void EventEx::Set()
{
InterlockedExchange(&m_Lock, 0);
}
void EventEx::Spin()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
// This only yields when there is a runnable thread on this core
// If not, spin
SwitchToThread();
}
void EventEx::Wait()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
// This directly enters Ring0 and enforces a sleep about 15ms
SleepCurrentThread(1);
}
bool EventEx::MsgWait()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) return false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// This directly enters Ring0 and enforces a sleep about 15ms
SleepCurrentThread(1);
}
return true;
}
#endif
// Regular same thread loop based waiting // Regular same thread loop based waiting
Event::Event() Event::Event()
{ {
@ -164,6 +218,7 @@ void Event::MsgWait()
if (msg.message == WM_QUIT) if (msg.message == WM_QUIT)
return; return;
// Otherwise, dispatch the message. // Otherwise, dispatch the message.
TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }

View File

@ -137,7 +137,31 @@ private:
#endif #endif
}; };
#ifdef _WIN32
// Event(WaitForSingleObject) is too expensive
// as it always enters Ring0 regardless of the state of lock
// This EventEx will try to stay in Ring3 as much as possible
// If the lock can be obtained in the first time, Ring0 won't be entered at all
class EventEx
{
public:
EventEx();
void Init();
void Shutdown();
void Set();
// Infinite wait
void Spin();
// Infinite wait with sleep
void Wait();
// Wait with message processing and sleep
bool MsgWait();
private:
volatile long m_Lock;
};
#else
// TODO: implement for Linux
#define EventEx Event
#endif
class Event class Event
{ {
@ -182,9 +206,10 @@ private:
void InitThreading(); void InitThreading();
void SleepCurrentThread(int ms); void SleepCurrentThread(int ms);
// YieldCPU: Use this function during a spin-wait to make the current thread // YieldCPU: This function is only effective on HyperThreading CPU
// relax while another thread is working. This may be more efficient than using // Use this function during a spin-wait to make the current thread
// events because event functions use kernel calls. // relax while another thread is working. This may be more efficient
// than using events because event functions use kernel calls.
inline void YieldCPU() inline void YieldCPU()
{ {
#ifdef _WIN32 #ifdef _WIN32

View File

@ -548,13 +548,14 @@ void ScreenShot()
// This should only be called from VI // This should only be called from VI
void VideoThrottle() void VideoThrottle()
{ {
u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 1) ? SConfig::GetInstance().m_Framelimit * 10 u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 1) ?
: VideoInterface::TargetRefreshRate; SConfig::GetInstance().m_Framelimit * 10 : VideoInterface::TargetRefreshRate;
// When frame limit is NOT off // When frame limit is NOT off
if (SConfig::GetInstance().m_Framelimit) if (SConfig::GetInstance().m_Framelimit)
{ {
u32 frametime = DrawnVideo * 1000 / TargetVPS; // Make the limiter a bit loose
u32 frametime = DrawnVideo * 1000 / ++TargetVPS;
while ((u32)Timer.GetTimeDifference() < frametime) while ((u32)Timer.GetTimeDifference() < frametime)
Common::YieldCPU(); Common::YieldCPU();
//Common::SleepCurrentThread(1); //Common::SleepCurrentThread(1);
@ -567,7 +568,7 @@ void VideoThrottle()
SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime; u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime;
u32 VPS = DrawnVideo * 1000 / ElapseTime; u32 VPS = --DrawnVideo * 1000 / ElapseTime;
u32 Speed = VPS * 100 / VideoInterface::TargetRefreshRate; u32 Speed = VPS * 100 / VideoInterface::TargetRefreshRate;
// Settings are shown the same for both extended and summary info // Settings are shown the same for both extended and summary info
@ -611,7 +612,7 @@ void VideoThrottle()
SystemTimers::GetTicksPerSecond() / 1000000, SystemTimers::GetTicksPerSecond() / 1000000,
_CoreParameter.bSkipIdle ? "~" : "", _CoreParameter.bSkipIdle ? "~" : "",
TicksPercentage); TicksPercentage);
#else // Summary information #else // Summary information
std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
#endif #endif
@ -630,7 +631,7 @@ void VideoThrottle()
Common::AtomicStore(DrawnFrame, 0); Common::AtomicStore(DrawnFrame, 0);
DrawnVideo = 0; DrawnVideo = 0;
} }
DrawnVideo++; DrawnVideo++;
} }

View File

@ -132,13 +132,7 @@ int
// This is completely arbitrary. If we find that we need lower latency, we can just // This is completely arbitrary. If we find that we need lower latency, we can just
// increase this number. // increase this number.
IPC_HLE_PERIOD, IPC_HLE_PERIOD;
// For DC watchdog hack
// Once every 4 frame-period seems to be enough (arbitrary taking 60fps as the ref).
// TODO: make it VI output frame rate compliant (30/60 and 25/50)
// Assuming game's frame-finish-watchdog wait more than 4 emulated frame-period before starting its mess.
FAKE_GP_WATCHDOG_PERIOD;
@ -227,7 +221,7 @@ void AdvanceCallback(int cyclesExecuted)
void FakeGPWatchdogCallback(u64 userdata, int cyclesLate) void FakeGPWatchdogCallback(u64 userdata, int cyclesLate)
{ {
CPluginManager::GetInstance().GetVideo()->Video_WaitForFrameFinish(); // lock CPUThread until frame finish CPluginManager::GetInstance().GetVideo()->Video_WaitForFrameFinish(); // lock CPUThread until frame finish
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD-cyclesLate, et_FakeGPWD); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_FakeGPWD);
} }
void PatchEngineCallback(u64 userdata, int cyclesLate) void PatchEngineCallback(u64 userdata, int cyclesLate)
@ -235,7 +229,7 @@ void PatchEngineCallback(u64 userdata, int cyclesLate)
// Patch mem and run the Action Replay // Patch mem and run the Action Replay
PatchEngine::ApplyFramePatches(); PatchEngine::ApplyFramePatches();
PatchEngine::ApplyARPatches(); PatchEngine::ApplyARPatches();
CoreTiming::ScheduleEvent((GetTicksPerSecond() / 5000) - cyclesLate, et_PatchEngine); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_PatchEngine);
} }
void Init() void Init()
@ -271,8 +265,6 @@ void Init()
if (UsingDSPLLE) if (UsingDSPLLE)
DSP_PERIOD = 12000; // TO BE TWEAKED DSP_PERIOD = 12000; // TO BE TWEAKED
FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 60;
// This is the biggest question mark. // This is the biggest question mark.
AI_PERIOD = GetTicksPerSecond() / 80; AI_PERIOD = GetTicksPerSecond() / 80;
@ -297,16 +289,14 @@ void Init()
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI); CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_VI); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_VI);
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP); CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
CoreTiming::ScheduleEvent(GetTicksPerSecond() / 60, et_SI); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_SI);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA); CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
// For DC watchdog hack // For DC watchdog hack
if (Core::GetStartupParameter().bCPUThread) if (Core::GetStartupParameter().bCPUThread)
{ CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_FakeGPWD);
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD, et_FakeGPWD);
}
CoreTiming::ScheduleEvent(GetTicksPerSecond() / 60, et_PatchEngine); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_PatchEngine);
if (Core::GetStartupParameter().bWii) if (Core::GetStartupParameter().bWii)
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE); CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);

View File

@ -391,7 +391,7 @@ void CMemoryWindow::onSearch(wxCommandEvent& event){
} }
if(size){ if(size){
unsigned char* pnt=&Dest.front(); unsigned char* pnt=&Dest.front();
int k=0; unsigned int k=0;
//grab //grab
wxString txt = addrbox->GetValue(); wxString txt = addrbox->GetValue();

View File

@ -187,7 +187,7 @@ void CLogWindow::LoadSettings()
m_verbosity->SetSelection(verbosity - 1); m_verbosity->SetSelection(verbosity - 1);
ini.Get("Options", "Font", &font, 0); ini.Get("Options", "Font", &font, 0);
m_FontChoice->SetSelection(font); m_FontChoice->SetSelection(font);
if (m_FontChoice->GetSelection() < Font.size()) if (m_FontChoice->GetSelection() < (int)Font.size())
m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection()))); m_Log->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection())));
ini.Get("Options", "WriteToFile", &m_writeFile, true); ini.Get("Options", "WriteToFile", &m_writeFile, true);
m_writeFileCB->SetValue(m_writeFile); m_writeFileCB->SetValue(m_writeFile);
@ -303,7 +303,7 @@ wxTextCtrl* CLogWindow::CreateTextCtrl(wxPanel* parent, wxWindowID id, long Styl
TC->SetBackgroundColour(*wxBLACK); TC->SetBackgroundColour(*wxBLACK);
if (m_FontChoice) if (m_FontChoice)
{ {
if (m_FontChoice->GetSelection() < Font.size()) if (m_FontChoice->GetSelection() < (int)Font.size())
TC->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection()))); TC->SetDefaultStyle(wxTextAttr(wxNullColour, wxNullColour, Font.at(m_FontChoice->GetSelection())));
} }
return TC; return TC;

View File

@ -105,7 +105,7 @@ int m_bboxbottom;
u16 m_tokenReg; u16 m_tokenReg;
static u32 fake_GPWatchdogLastToken = 0; static u32 fake_GPWatchdogLastToken = 0;
static Common::Event s_fifoIdleEvent; static Common::EventEx s_fifoIdleEvent;
static Common::CriticalSection sFifoCritical; static Common::CriticalSection sFifoCritical;
void FifoCriticalEnter() void FifoCriticalEnter()
@ -381,7 +381,7 @@ void Write16(const u16 _Value, const u32 _Address)
// Touching that game is a no-go so I don't want to take the risk :p // Touching that game is a no-go so I don't want to take the risk :p
while (fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))) while (fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)))
{ {
s_fifoIdleEvent.MsgWait(); s_fifoIdleEvent.Wait();
} }
} }
} }
@ -573,7 +573,7 @@ void WaitForFrameFinish()
{ {
while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))); while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)));
{ {
s_fifoIdleEvent.MsgWait(); s_fifoIdleEvent.Wait();
} }
fake_GPWatchdogLastToken = fifo.Fake_GPWDToken; fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
@ -618,7 +618,7 @@ void STACKALIGN GatherPipeBursted()
// Wait for GPU to catch up // Wait for GPU to catch up
while (fifo.CPReadWriteDistance > fifo.CPLoWatermark && fifo.bFF_GPReadEnable && (!fifo.bFF_BPEnable || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))) while (fifo.CPReadWriteDistance > fifo.CPLoWatermark && fifo.bFF_GPReadEnable && (!fifo.bFF_BPEnable || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint)))
{ {
s_fifoIdleEvent.MsgWait(); s_fifoIdleEvent.Wait();
} }
} }
// check if we are in sync // check if we are in sync

View File

@ -36,7 +36,7 @@ namespace
static volatile bool fifoStateRun = false; static volatile bool fifoStateRun = false;
static volatile bool EmuRunning = false; static volatile bool EmuRunning = false;
static u8 *videoBuffer; static u8 *videoBuffer;
static Common::Event fifo_run_event; static Common::EventEx fifo_run_event;
// STATE_TO_SAVE // STATE_TO_SAVE
static int size = 0; static int size = 0;
} // namespace } // namespace
@ -170,6 +170,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
{ {
Common::AtomicStore(_fifo.bFF_Breakpoint, 1); Common::AtomicStore(_fifo.bFF_Breakpoint, 1);
CommandProcessor::UpdateInterruptsFromVideoPlugin(true); CommandProcessor::UpdateInterruptsFromVideoPlugin(true);
CommandProcessor::FifoCriticalLeave();
break; break;
} }
distToSend = 32; distToSend = 32;
@ -208,10 +209,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down. // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
VideoFifo_CheckEFBAccess(); VideoFifo_CheckEFBAccess();
VideoFifo_CheckSwapRequest(); VideoFifo_CheckSwapRequest();
CommandProcessor::SetFifoIdleFromVideoPlugin();
} }
CommandProcessor::SetFifoIdleFromVideoPlugin(); CommandProcessor::SetFifoIdleFromVideoPlugin();
if (EmuRunning) if (EmuRunning)
Common::YieldCPU(); Common::YieldCPU();