diff --git a/Source/Core/AudioCommon/Src/DSoundStream.cpp b/Source/Core/AudioCommon/Src/DSoundStream.cpp index 2e6cd69146..3d4c868cdb 100644 --- a/Source/Core/AudioCommon/Src/DSoundStream.cpp +++ b/Source/Core/AudioCommon/Src/DSoundStream.cpp @@ -106,7 +106,6 @@ void DSound::SoundLoop() while (!threadData) { // No blocking inside the csection - soundCriticalSection.Enter(); dsBuffer->GetCurrentPosition((DWORD*)¤tPos, 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(); } diff --git a/Source/Core/AudioCommon/Src/DSoundStream.h b/Source/Core/AudioCommon/Src/DSoundStream.h index fcf0413ee7..adbeaeb468 100644 --- a/Source/Core/AudioCommon/Src/DSoundStream.h +++ b/Source/Core/AudioCommon/Src/DSoundStream.h @@ -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; diff --git a/Source/Core/AudioCommon/Src/OpenALStream.h b/Source/Core/AudioCommon/Src/OpenALStream.h index 57bf2e34b7..8aebf32068 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.h +++ b/Source/Core/AudioCommon/Src/OpenALStream.h @@ -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]; diff --git a/Source/Core/Common/Src/Thread.cpp b/Source/Core/Common/Src/Thread.cpp index bb0d591771..37f52e9ce9 100644 --- a/Source/Core/Common/Src/Thread.cpp +++ b/Source/Core/Common/Src/Thread.cpp @@ -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); } diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h index 4df20da844..f667cc170c 100644 --- a/Source/Core/Common/Src/Thread.h +++ b/Source/Core/Common/Src/Thread.h @@ -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 diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 17c8ba38c9..a5fc0a91dd 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -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++; } diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index 8661bd7408..d284e2ef0c 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -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); diff --git a/Source/Core/DebuggerWX/Src/MemoryWindow.cpp b/Source/Core/DebuggerWX/Src/MemoryWindow.cpp index 474fac90ef..729c76ecd3 100644 --- a/Source/Core/DebuggerWX/Src/MemoryWindow.cpp +++ b/Source/Core/DebuggerWX/Src/MemoryWindow.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Src/LogWindow.cpp b/Source/Core/DolphinWX/Src/LogWindow.cpp index eecae934c5..ea3bc012ad 100644 --- a/Source/Core/DolphinWX/Src/LogWindow.cpp +++ b/Source/Core/DolphinWX/Src/LogWindow.cpp @@ -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; diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index c02fd492c7..ea153180c3 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -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 diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 172d6095fa..6ca7c3f259 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -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();