diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index d2fdf30bb6..4cd975fae8 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -148,6 +148,10 @@ void Host_ShowVideoConfig(void*, const std::string&) { } +void Host_YieldToUI() +{ +} + static bool MsgAlert(const char* caption, const char* text, bool yes_no, int /*Style*/) { __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "%s:%s", caption, text); diff --git a/Source/Core/Common/BlockingLoop.h b/Source/Core/Common/BlockingLoop.h index da148fccd4..a1ebe7d708 100644 --- a/Source/Core/Common/BlockingLoop.h +++ b/Source/Core/Common/BlockingLoop.h @@ -66,6 +66,33 @@ public: m_may_sleep.Set(); } + // Wait for a complete payload run after the last Wakeup() call. + // This version will call a yield function every 100ms. + // If stopped, this returns immediately. + template + void WaitYield(const std::chrono::duration& rel_time, Functor yield_func) + { + // already done + if (IsDone()) + return; + + // notifying this event will only wake up one thread, so use a mutex here to + // allow only one waiting thread. And in this way, we get an event free wakeup + // but for the first thread for free + std::lock_guard lk(m_wait_lock); + + // Wait for the worker thread to finish. + while (!IsDone()) + { + if (!m_done_event.WaitFor(rel_time)) + yield_func(); + } + + // As we wanted to wait for the other thread, there is likely no work remaining. + // So there is no need for a busy loop any more. + m_may_sleep.Set(); + } + // Half start the worker. // So this object is in a running state and Wait() will block until the worker calls Run(). // This may be called from any thread and is supposed to be called at least once before Wait() is diff --git a/Source/Core/Core/Host.h b/Source/Core/Core/Host.h index c739f0dca1..2f517c4c8e 100644 --- a/Source/Core/Core/Host.h +++ b/Source/Core/Core/Host.h @@ -38,6 +38,7 @@ void Host_UpdateDisasmDialog(); void Host_UpdateMainFrame(); void Host_UpdateTitle(const std::string& title); void Host_ShowVideoConfig(void* parent, const std::string& backend_name); +void Host_YieldToUI(); // TODO (neobrain): Remove this from host! void* Host_GetRenderHandle(); diff --git a/Source/Core/DolphinQt2/Host.cpp b/Source/Core/DolphinQt2/Host.cpp index 62af45b489..0652942dfe 100644 --- a/Source/Core/DolphinQt2/Host.cpp +++ b/Source/Core/DolphinQt2/Host.cpp @@ -89,6 +89,9 @@ bool Host_RendererIsFullscreen() { return Host::GetInstance()->GetRenderFullscreen(); } +void Host_YieldToUI() +{ +} // We ignore these, and their purpose should be questioned individually. // In particular, RequestRenderWindowSize, RequestFullscreen, and diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index 871e89ad28..444b270d39 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -547,3 +548,8 @@ void Host_ShowVideoConfig(void* parent, const std::string& backend_name) diag.ShowModal(); } } + +void Host_YieldToUI() +{ + wxGetApp().GetMainLoop()->YieldFor(wxEVT_CATEGORY_UI); +} diff --git a/Source/Core/DolphinWX/MainNoGUI.cpp b/Source/Core/DolphinWX/MainNoGUI.cpp index 216eb5a707..6c8a53b88d 100644 --- a/Source/Core/DolphinWX/MainNoGUI.cpp +++ b/Source/Core/DolphinWX/MainNoGUI.cpp @@ -161,6 +161,10 @@ void Host_ShowVideoConfig(void*, const std::string&) { } +void Host_YieldToUI() +{ +} + #if HAVE_X11 #include #include "DolphinWX/X11Utils.h" diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 374ddb07f3..678dc77687 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -18,6 +18,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/Host.h" #include "Core/NetPlayProto.h" #include "VideoCommon/AsyncRequests.h" @@ -94,7 +95,13 @@ void PauseAndLock(bool doLock, bool unpauseOnUnlock) { SyncGPU(SyncGPUReason::Other); EmulatorState(false); - FlushGpu(); + + const SConfig& param = SConfig::GetInstance(); + + if (!param.bCPUThread || s_use_deterministic_gpu_thread) + return; + + s_gpu_mainloop.WaitYield(std::chrono::milliseconds(100), Host_YieldToUI); } else { diff --git a/Source/UnitTests/TestUtils/StubHost.cpp b/Source/UnitTests/TestUtils/StubHost.cpp index c6d1cbb12e..e32561da90 100644 --- a/Source/UnitTests/TestUtils/StubHost.cpp +++ b/Source/UnitTests/TestUtils/StubHost.cpp @@ -63,6 +63,9 @@ void Host_SetWiiMoteConnectionState(int) void Host_ShowVideoConfig(void*, const std::string&) { } +void Host_YieldToUI() +{ +} std::unique_ptr HostGL_CreateGLInterface() { return nullptr;