From 10b5d2371c97c63cf12b3d88bdd40b341c4fa8ac Mon Sep 17 00:00:00 2001 From: Marcos Vitali Date: Thu, 24 Jun 2010 13:28:54 +0000 Subject: [PATCH] My first commit :D Dual Core sync fix. When the FIFO is processing data we must not advance the cpu cycles in CoreTiming because in this way the VI will be desynchronized. So, We are waiting until the FIFO finish and while we process only the events required by the FIFO. This should fix Issue 2072 . This affect to all games in dual core mode. Please, You can test all games with VPS limiter auto, 60, 50 depending of the game and compare with prev revision. For example now NSMB in the video Intro has 60 fps (prev 30 fps) :D or SMG does't need anymore FPS Limitter Hack to get 55-60 fps Beside the slowdowns now are more softly and the fps more stables because the VI sync is almost perfect. The Core Timing and Fifo modifications are delicated. Please report if this hang any game. Don't forget check with prev revision. Enjoy it! Thanks to Rodolfo for teach me all about dolphin. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5777 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/PluginVideo.cpp | 7 ++- Source/Core/Common/Src/PluginVideo.h | 3 +- Source/Core/Core/Src/CoreTiming.cpp | 54 +++++++++++++++++-- Source/Core/Core/Src/CoreTiming.h | 4 +- .../Core/VideoCommon/Src/CommandProcessor.cpp | 8 +-- .../Core/VideoCommon/Src/CommandProcessor.h | 5 +- Source/Core/VideoCommon/Src/Fifo.cpp | 13 ++++- Source/Core/VideoCommon/Src/PixelEngine.cpp | 4 +- Source/PluginSpecs/pluginspecs_video.h | 11 +++- Source/Plugins/Plugin_VideoDX11/Src/main.cpp | 5 ++ Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 5 ++ Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 4 ++ .../Src/CommandProcessor.cpp | 2 +- .../Plugin_VideoSoftware/Src/PixelEngine.cpp | 4 +- .../Plugins/Plugin_VideoSoftware/Src/main.cpp | 5 ++ 15 files changed, 112 insertions(+), 22 deletions(-) diff --git a/Source/Core/Common/Src/PluginVideo.cpp b/Source/Core/Common/Src/PluginVideo.cpp index bc8a2e9164..08174fefcb 100644 --- a/Source/Core/Common/Src/PluginVideo.cpp +++ b/Source/Core/Common/Src/PluginVideo.cpp @@ -38,6 +38,7 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo Video_PixelEngineWrite32 = 0; Video_GatherPipeBursted = 0; Video_WaitForFrameFinish = 0; + Video_IsFifoBusy = 0; Video_Prepare = reinterpret_cast (LoadSymbol("Video_Prepare")); @@ -71,7 +72,8 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo (LoadSymbol("Video_GatherPipeBursted")); Video_WaitForFrameFinish = reinterpret_cast (LoadSymbol("Video_WaitForFrameFinish")); - + Video_IsFifoBusy = reinterpret_cast + (LoadSymbol("Video_IsFifoBusy")); if ((Video_Prepare != 0) && (Video_BeginField != 0) && (Video_EndField != 0) && @@ -88,7 +90,8 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo (Video_PixelEngineWrite16 != 0) && (Video_PixelEngineWrite32 != 0) && (Video_GatherPipeBursted != 0) && - (Video_WaitForFrameFinish != 0)) + (Video_WaitForFrameFinish != 0) && + (Video_IsFifoBusy != 0)) validVideo = true; } diff --git a/Source/Core/Common/Src/PluginVideo.h b/Source/Core/Common/Src/PluginVideo.h index bee2ea7153..04a69aec92 100644 --- a/Source/Core/Common/Src/PluginVideo.h +++ b/Source/Core/Common/Src/PluginVideo.h @@ -39,6 +39,7 @@ typedef void (__cdecl* TVideo_Read32)(u32& _rReturnValue, const u32 _Address); typedef void (__cdecl* TVideo_Write32)(const u32 _Data, const u32 _Address); typedef void (__cdecl* TVideo_GatherPipeBursted)(); typedef void (__cdecl* TVideo_WaitForFrameFinish)(); +typedef bool (__cdecl* TVideo_IsFifoBusy)(); class PluginVideo : public CPlugin { @@ -66,7 +67,7 @@ public: TVideo_Write32 Video_PixelEngineWrite32; TVideo_GatherPipeBursted Video_GatherPipeBursted; TVideo_WaitForFrameFinish Video_WaitForFrameFinish; - + TVideo_IsFifoBusy Video_IsFifoBusy; private: bool validVideo; }; diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index a8ef993bd8..8dd4dcbbd7 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -22,6 +22,7 @@ #include "CoreTiming.h" #include "Core.h" #include "StringUtil.h" +#include "PluginManager.h" #define MAX_SLICE_LENGTH 20000 @@ -41,6 +42,7 @@ struct BaseEvent s64 time; u64 userdata; int type; + bool fifoWait; // Event *next; }; @@ -208,7 +210,7 @@ u64 GetIdleTicks() // This is to be called when outside threads, such as the graphics thread, wants to // schedule things to be executed on the main thread. -void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata) +void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata, bool fifoWait) { externalEventSection.Enter(); Event *ne = GetNewTsEvent(); @@ -216,6 +218,7 @@ void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata ne->type = event_type; ne->next = 0; ne->userdata = userdata; + ne->fifoWait = fifoWait; if(!tsFirst) tsFirst = ne; if(tsLast) @@ -235,7 +238,7 @@ void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) externalEventSection.Leave(); } else - ScheduleEvent_Threadsafe(0, event_type, userdata); + ScheduleEvent_Threadsafe(0, event_type, userdata, false); } void ClearPendingEvents() @@ -275,7 +278,7 @@ void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata) ne->userdata = userdata; ne->type = event_type; ne->time = globalTimer + cyclesIntoFuture; - + ne->fifoWait = false; AddEventToQueue(ne); } @@ -337,8 +340,33 @@ void ResetSliceLength() maxSliceLength = MAX_SLICE_LENGTH; } -void Advance() -{ + +//This raise only the events required while the fifo is processing data +void ProcessFifoWaitEvents() +{ + MoveEvents(); + + while (first) + { + if ((first->time <= globalTimer) && first->fifoWait) + { + + Event* evt = first; + first = first->next; + event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); + FreeEvent(evt); + } + else + { + break; + } + } + +} + +void MoveEvents() +{ + externalEventSection.Enter(); // Move events from async queue into main queue while (tsFirst) @@ -360,6 +388,13 @@ void Advance() } externalEventSection.Leave(); +} + +void Advance() +{ + + MoveEvents(); + int cyclesExecuted = slicelength - downcount; globalTimer += cyclesExecuted; downcount = slicelength; @@ -410,6 +445,15 @@ void Idle() { //DEBUG_LOG(POWERPC, "Idle"); + //When the FIFO is processing data we must not advance because in this way + //the VI will be desynchronized. So, We are waiting until the FIFO finish and + //while we process only the events required by the FIFO. + while (CPluginManager::GetInstance().GetVideo()->Video_IsFifoBusy()) + { + ProcessFifoWaitEvents(); + Common::YieldCPU(); + } + idledCycles += downcount; downcount = 0; diff --git a/Source/Core/Core/Src/CoreTiming.h b/Source/Core/Core/Src/CoreTiming.h index 2665d39f43..1b40749882 100644 --- a/Source/Core/Core/Src/CoreTiming.h +++ b/Source/Core/Core/Src/CoreTiming.h @@ -57,13 +57,15 @@ void UnregisterAllEvents(); // userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, // when we implement state saves. void ScheduleEvent(int cyclesIntoFuture, int event_type, u64 userdata=0); -void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata=0); +void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata=0, bool fifoWait=false); void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata=0); // We only permit one event of each type in the queue at a time. void RemoveEvent(int event_type); bool IsScheduled(int event_type); void Advance(); +void MoveEvents(); +void ProcessFifoWaitEvents(); // Pretend that the main CPU has executed enough cycles to reach the next event. void Idle(); diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index c59f9b7b40..21c9919393 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -110,6 +110,8 @@ static u32 fake_GPWatchdogLastToken = 0; static Common::EventEx s_fifoIdleEvent; static Common::CriticalSection sFifoCritical; +volatile bool isFifoBusy = false; //This state is changed when the FIFO is processing data. + void FifoCriticalEnter() { sFifoCritical.Enter(); @@ -597,8 +599,8 @@ void STACKALIGN GatherPipeBursted() if (g_VideoInitialize.bOnThread) { // A little trick to prevent FIFO from overflown in dual core mode (n < 100 to avoid dead lock) - for (int cnt = 0; fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase && cnt < 100; cnt++) - Common::SwitchCurrentThread(); + //for (int cnt = 0; fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase && cnt < 100; cnt++) + // Common::SwitchCurrentThread(); } else { @@ -683,7 +685,7 @@ void UpdateInterrupts() void UpdateInterruptsFromVideoPlugin() { - g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0); + g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0, true); } void SetFifoIdleFromVideoPlugin() diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 40771ecb54..4c29d46ca6 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -25,11 +25,12 @@ class PointerWrap; extern bool MT; + namespace CommandProcessor { -extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread - +extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. +extern volatile bool isFifoBusy; //This one is used for sync gfx thread and emulator thread. // internal hardware addresses enum { diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index ab8bf897c2..166d7a027f 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -147,9 +147,13 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) VideoFifo_CheckEFBAccess(); VideoFifo_CheckSwapRequest(); - // check if we are able to run this buffer + // check if we are able to run this buffer + while (_fifo.bFF_GPReadEnable && _fifo.CPReadWriteDistance) { + // while the FIFO is processing data we activate this for sync with emulator thread. + CommandProcessor::isFifoBusy = true; + if (!fifoStateRun) break; @@ -170,6 +174,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) if (_fifo.bFF_BPInt) CommandProcessor::UpdateInterruptsFromVideoPlugin(); CommandProcessor::FifoCriticalLeave(); + CommandProcessor::isFifoBusy = false; break; } @@ -205,15 +210,19 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) // Those two are pretty important and must be called in the FIFO Loop. // If we don't, s_swapRequested (OGL only) or s_efbAccessRequested won't be set to false // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down. + VideoFifo_CheckEFBAccess(); VideoFifo_CheckSwapRequest(); + CommandProcessor::isFifoBusy = false; } - + + if (!_fifo.CPReadIdle && _fifo.CPReadWriteDistance < _fifo.CPLoWatermark) { Common::AtomicStore(_fifo.CPReadIdle, true); CommandProcessor::UpdateInterruptsFromVideoPlugin(); } + _fifo.CPCmdIdle = true; CommandProcessor::SetFifoIdleFromVideoPlugin(); if (EmuRunning) diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 920041912b..8bfe6a314e 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -354,7 +354,7 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge) // This seems smelly... CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack since PEToken seems to be a frame-finish too g_VideoInitialize.pScheduleEvent_Threadsafe( - 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16), true); } else // set token value { @@ -373,7 +373,7 @@ void SetFinish() { CommandProcessor::IncrementGPWDToken(); // for DC watchdog hack g_VideoInitialize.pScheduleEvent_Threadsafe( - 0, et_SetFinishOnMainThread, 0); + 0, et_SetFinishOnMainThread, 0, true); INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); } diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index 1b5e3bbff5..2821ace9fe 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -14,7 +14,7 @@ typedef void (*TimedCallback)(u64 userdata, int cyclesLate); typedef void (*TSetInterrupt)(u32 _causemask, bool _bSet); typedef int (*TRegisterEvent)(const char *name, TimedCallback callback); -typedef void (*TScheduleEvent_Threadsafe)(int cyclesIntoFuture, int event_type, u64 userdata); +typedef void (*TScheduleEvent_Threadsafe)(int cyclesIntoFuture, int event_type, u64 userdata, bool fifoWait); typedef unsigned char* (*TGetMemoryPointer)(const unsigned int _iAddress); typedef void (*TVideoLog)(const char* _pMessage, int _bBreak); typedef void (*TSysMessage)(const char *fmt, ...); @@ -182,5 +182,14 @@ EXPORT void CALL Video_PixelEngineWrite32(const u32 _Data, const u32 _Address); EXPORT void CALL Video_GatherPipeBursted(void); EXPORT void CALL Video_WaitForFrameFinish(void); +// __________________________________________________________________________________________________ +// Function: Video_IsFifoBusy +// Purpose: Return if the FIFO is proecessing data, that is used for sync gfx thread and emulator +// thread in CoreTiming +// input: none +// output: bool +// +EXPORT bool CALL Video_IsFifoBusy(void); + #include "ExportEpilog.h" #endif diff --git a/Source/Plugins/Plugin_VideoDX11/Src/main.cpp b/Source/Plugins/Plugin_VideoDX11/Src/main.cpp index 9c934ae1e2..1dc010d577 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/main.cpp @@ -461,3 +461,8 @@ void Video_WaitForFrameFinish(void) { CommandProcessor::WaitForFrameFinish(); } + +bool Video_IsFifoBusy(void) +{ + return CommandProcessor::isFifoBusy; +} diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index c9d6c4d68f..160afdd22f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -506,3 +506,8 @@ void Video_WaitForFrameFinish(void) { CommandProcessor::WaitForFrameFinish(); } + +bool Video_IsFifoBusy(void) +{ + return CommandProcessor::isFifoBusy; +} diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 89c1381cd6..db51766be4 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -508,3 +508,7 @@ void Video_WaitForFrameFinish(void) CommandProcessor::WaitForFrameFinish(); } +bool Video_IsFifoBusy(void) +{ + return CommandProcessor::isFifoBusy; +} diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/CommandProcessor.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/CommandProcessor.cpp index 6b2d0733b4..200d1200e3 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/CommandProcessor.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/CommandProcessor.cpp @@ -322,7 +322,7 @@ void UpdateInterrupts(u64 userdata) void UpdateInterruptsFromVideoPlugin(u64 userdata) { - g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata); + g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, userdata, true); } void ReadFifo() diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/PixelEngine.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/PixelEngine.cpp index 119a3b5417..255c195d84 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/PixelEngine.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/PixelEngine.cpp @@ -155,7 +155,7 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge) if (_bSetTokenAcknowledge) // set token INT { g_VideoInitialize.pScheduleEvent_Threadsafe( - 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16)); + 0, et_SetTokenOnMainThread, _token | (_bSetTokenAcknowledge << 16), true); } } @@ -164,7 +164,7 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge) void SetFinish() { g_VideoInitialize.pScheduleEvent_Threadsafe( - 0, et_SetFinishOnMainThread, 0); + 0, et_SetFinishOnMainThread, 0, true); INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); } diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/main.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/main.cpp index 29d6084306..fe77401ebd 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/main.cpp @@ -209,3 +209,8 @@ void Video_GatherPipeBursted(void) void Video_WaitForFrameFinish(void) { } + +bool Video_IsFifoBusy(void) +{ + return false; +}