diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index ee7e1141d7..d8af296679 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -498,6 +498,9 @@ void EmuThread() CBoot::BootUp(); + // This adds the SyncGPU handler to CoreTiming, so now CoreTiming::Advance might block. + Fifo::Prepare(); + // Thread is no longer acting as CPU Thread UndeclareAsCPUThread(); diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 6a1c76b186..59d40727ae 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -446,7 +446,7 @@ void Idle() //the VI will be desynchronized. So, We are waiting until the FIFO finish and //while we process only the events required by the FIFO. ProcessFifoWaitEvents(); - Fifo::Update(0); + Fifo::FlushGpu(); } idledCycles += DowncountToCycles(PowerPC::ppcState.downcount); diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index 82e6962bf2..e900e33762 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -66,7 +66,6 @@ namespace SystemTimers static int et_Dec; static int et_VI; -static int et_CP; static int et_AudioDMA; static int et_DSP; static int et_IPC_HLE; @@ -74,7 +73,6 @@ static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by de static int et_Throttle; static u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!) -static u64 s_last_sync_gpu_tick; // These two are badly educated guesses. // Feel free to experiment. Set them in Init below. @@ -123,16 +121,6 @@ static void VICallback(u64 userdata, int cyclesLate) CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI); } -static void CPCallback(u64 userdata, int cyclesLate) -{ - u64 now = CoreTiming::GetTicks(); - int next = Fifo::Update((int)(now - s_last_sync_gpu_tick)); - s_last_sync_gpu_tick = now; - - if (next > 0) - CoreTiming::ScheduleEvent(next, et_CP); -} - static void DecrementerCallback(u64 userdata, int cyclesLate) { PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF; @@ -238,8 +226,6 @@ void Init() et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); - if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU) - et_CP = CoreTiming::RegisterEvent("CPCallback", CPCallback); et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback); et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback); et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); @@ -250,9 +236,6 @@ void Init() CoreTiming::ScheduleEvent(0, et_DSP); CoreTiming::ScheduleEvent(s_audio_dma_period, et_AudioDMA); CoreTiming::ScheduleEvent(0, et_Throttle, Common::Timer::GetTimeMs()); - if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU) - CoreTiming::ScheduleEvent(0, et_CP); - s_last_sync_gpu_tick = CoreTiming::GetTicks(); CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine); diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 33a7454083..df97809e16 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 50; // Last changed in PR 3457 +static const u32 STATE_VERSION = 51; // Last changed in PR 3530 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 506024c193..e04f3ffcbf 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -15,6 +15,7 @@ #include "Common/MsgHandler.h" #include "Core/ConfigManager.h" +#include "Core/CoreTiming.h" #include "Core/NetPlayProto.h" #include "Core/HW/Memmap.h" @@ -45,6 +46,9 @@ static u8* s_fifo_aux_read_ptr; bool g_use_deterministic_gpu_thread; +static u64 s_last_sync_gpu_tick; +static int s_event_sync_gpu; + // STATE_TO_SAVE static u8* s_video_buffer; static u8* s_video_buffer_read_ptr; @@ -79,6 +83,7 @@ void DoState(PointerWrap &p) s_video_buffer_seen_ptr = s_video_buffer_pp_read_ptr = s_video_buffer_read_ptr; } p.Do(g_bSkipCurrentFrame); + p.Do(s_last_sync_gpu_tick); } void PauseAndLock(bool doLock, bool unpauseOnUnlock) @@ -492,16 +497,15 @@ void UpdateWantDeterminism(bool want) } } -int Update(int ticks) +/* This function checks the emulated CPU - GPU distance and may wake up the GPU, + * or block the CPU if required. It should be called by the CPU thread regulary. + * @ticks The gone emulated CPU time. + * @return A good time to call Update() next. + */ +static int Update(int ticks) { const SConfig& param = SConfig::GetInstance(); - if (ticks == 0) - { - FlushGpu(); - return param.iSyncGpuMaxDistance; - } - // GPU is sleeping, so no need for synchronization if (s_gpu_mainloop.IsDone() || g_use_deterministic_gpu_thread) { @@ -514,10 +518,12 @@ int Update(int ticks) return param.iSyncGpuMaxDistance; } + // Wakeup GPU int old = s_sync_ticks.fetch_add(ticks); if (old < param.iSyncGpuMinDistance && old + ticks >= param.iSyncGpuMinDistance) RunGpu(); + // Wait for GPU if (s_sync_ticks.load() >= param.iSyncGpuMaxDistance) { while (s_sync_ticks.load() > 0) @@ -529,4 +535,25 @@ int Update(int ticks) return param.iSyncGpuMaxDistance - s_sync_ticks.load(); } +static void SyncGPUCallback(u64 userdata, int cyclesLate) +{ + u64 now = CoreTiming::GetTicks(); + int next = Fifo::Update((int)(now - s_last_sync_gpu_tick)); + s_last_sync_gpu_tick = now; + + if (next > 0) + CoreTiming::ScheduleEvent(next, s_event_sync_gpu); +} + +// Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread. +void Prepare() +{ + if (SConfig::GetInstance().bCPUThread && SConfig::GetInstance().bSyncGPU) + { + s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback); + CoreTiming::ScheduleEvent(0, s_event_sync_gpu); + s_last_sync_gpu_tick = CoreTiming::GetTicks(); + } +} + } diff --git a/Source/Core/VideoCommon/Fifo.h b/Source/Core/VideoCommon/Fifo.h index d342b535df..b30d41069e 100644 --- a/Source/Core/VideoCommon/Fifo.h +++ b/Source/Core/VideoCommon/Fifo.h @@ -22,6 +22,7 @@ extern std::atomic g_video_buffer_write_ptr_xthread; void Init(); void Shutdown(); +void Prepare(); // Must be called from the CPU thread. void DoState(PointerWrap &f); void PauseAndLock(bool doLock, bool unpauseOnUnlock); void UpdateWantDeterminism(bool want); @@ -52,6 +53,5 @@ void EmulatorState(bool running); bool AtBreakpoint(); void ResetVideoBuffer(); void SetRendering(bool bEnabled); -int Update(int ticks); };