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

View file

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

View file

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

View file

@ -117,6 +117,60 @@ void Thread::SetCurrentThreadAffinity(int 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
Event::Event()
{
@ -164,6 +218,7 @@ void Event::MsgWait()
if (msg.message == WM_QUIT)
return;
// Otherwise, dispatch the message.
TranslateMessage(&msg);
DispatchMessage(&msg);
}

View file

@ -137,7 +137,31 @@ private:
#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
{
@ -182,9 +206,10 @@ private:
void InitThreading();
void SleepCurrentThread(int ms);
// YieldCPU: Use this function during a spin-wait to make the current thread
// relax while another thread is working. This may be more efficient than using
// events because event functions use kernel calls.
// YieldCPU: This function is only effective on HyperThreading CPU
// Use this function during a spin-wait to make the current thread
// relax while another thread is working. This may be more efficient
// than using events because event functions use kernel calls.
inline void YieldCPU()
{
#ifdef _WIN32

View file

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

View file

@ -132,13 +132,7 @@ int
// This is completely arbitrary. If we find that we need lower latency, we can just
// increase this number.
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;
IPC_HLE_PERIOD;
@ -227,7 +221,7 @@ void AdvanceCallback(int cyclesExecuted)
void FakeGPWatchdogCallback(u64 userdata, int cyclesLate)
{
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)
@ -235,7 +229,7 @@ void PatchEngineCallback(u64 userdata, int cyclesLate)
// Patch mem and run the Action Replay
PatchEngine::ApplyFramePatches();
PatchEngine::ApplyARPatches();
CoreTiming::ScheduleEvent((GetTicksPerSecond() / 5000) - cyclesLate, et_PatchEngine);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame() - cyclesLate, et_PatchEngine);
}
void Init()
@ -271,8 +265,6 @@ void Init()
if (UsingDSPLLE)
DSP_PERIOD = 12000; // TO BE TWEAKED
FAKE_GP_WATCHDOG_PERIOD = GetTicksPerSecond() / 60;
// This is the biggest question mark.
AI_PERIOD = GetTicksPerSecond() / 80;
@ -297,16 +289,14 @@ void Init()
CoreTiming::ScheduleEvent(AI_PERIOD, et_AI);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_VI);
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);
// For DC watchdog hack
if (Core::GetStartupParameter().bCPUThread)
{
CoreTiming::ScheduleEvent(FAKE_GP_WATCHDOG_PERIOD, et_FakeGPWD);
}
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_FakeGPWD);
CoreTiming::ScheduleEvent(GetTicksPerSecond() / 60, et_PatchEngine);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerFrame(), et_PatchEngine);
if (Core::GetStartupParameter().bWii)
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);

View file

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

View file

@ -187,7 +187,7 @@ void CLogWindow::LoadSettings()
m_verbosity->SetSelection(verbosity - 1);
ini.Get("Options", "Font", &font, 0);
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())));
ini.Get("Options", "WriteToFile", &m_writeFile, true);
m_writeFileCB->SetValue(m_writeFile);
@ -303,7 +303,7 @@ wxTextCtrl* CLogWindow::CreateTextCtrl(wxPanel* parent, wxWindowID id, long Styl
TC->SetBackgroundColour(*wxBLACK);
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())));
}
return TC;

View file

@ -105,7 +105,7 @@ int m_bboxbottom;
u16 m_tokenReg;
static u32 fake_GPWatchdogLastToken = 0;
static Common::Event s_fifoIdleEvent;
static Common::EventEx s_fifoIdleEvent;
static Common::CriticalSection sFifoCritical;
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
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)));
{
s_fifoIdleEvent.MsgWait();
s_fifoIdleEvent.Wait();
}
fake_GPWatchdogLastToken = fifo.Fake_GPWDToken;
@ -618,7 +618,7 @@ void STACKALIGN GatherPipeBursted()
// Wait for GPU to catch up
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

View file

@ -36,7 +36,7 @@ namespace
static volatile bool fifoStateRun = false;
static volatile bool EmuRunning = false;
static u8 *videoBuffer;
static Common::Event fifo_run_event;
static Common::EventEx fifo_run_event;
// STATE_TO_SAVE
static int size = 0;
} // namespace
@ -170,6 +170,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
{
Common::AtomicStore(_fifo.bFF_Breakpoint, 1);
CommandProcessor::UpdateInterruptsFromVideoPlugin(true);
CommandProcessor::FifoCriticalLeave();
break;
}
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.
VideoFifo_CheckEFBAccess();
VideoFifo_CheckSwapRequest();
CommandProcessor::SetFifoIdleFromVideoPlugin();
}
CommandProcessor::SetFifoIdleFromVideoPlugin();
if (EmuRunning)
Common::YieldCPU();