diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 11a37afdfa..67a3441af1 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -154,6 +154,10 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) case Event::PERF_QUERY: g_perf_query->FlushResults(); break; + + case Event::DO_SAVE_STATE: + g_video_backend->DoStateGPUThread(*e.do_save_state.p); + break; } } diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index acd665b3b1..dc81667586 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -13,6 +13,7 @@ #include "Common/Flag.h" struct EfbPokeData; +class PointerWrap; class AsyncRequests { @@ -28,6 +29,7 @@ public: SWAP_EVENT, BBOX_READ, PERF_QUERY, + DO_SAVE_STATE, } type; u64 time; @@ -64,6 +66,11 @@ public: struct { } perf_query; + + struct + { + PointerWrap* p; + } do_save_state; }; }; diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 12fc46b209..fdfca161b9 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -68,9 +68,6 @@ static void BPWritten(const BPCmd& bp) ---------------------------------------------------------------------------------------------------------------- */ - // check for invalid state, else unneeded configuration are built - g_video_backend->CheckInvalidState(); - if (((s32*)&bpmem)[bp.address] == bp.newvalue) { if (!(bp.address == BPMEM_TRIGGER_EFB_COPY || bp.address == BPMEM_CLEARBBOX1 || diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 36a9ee7307..f63aaff805 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -299,14 +299,15 @@ void RunGpuLoop() [] { const SConfig& param = SConfig::GetInstance(); + // Run events from the CPU thread. + AsyncRequests::GetInstance()->PullEvents(); + // Do nothing while paused if (!s_emu_running_state.IsSet()) return; if (s_use_deterministic_gpu_thread) { - AsyncRequests::GetInstance()->PullEvents(); - // All the fifo/CP stuff is on the CPU. We just need to run the opcode decoder. u8* seen_ptr = s_video_buffer_seen_ptr; u8* write_ptr = s_video_buffer_write_ptr; @@ -321,9 +322,6 @@ void RunGpuLoop() else { CommandProcessor::SCPFifoStruct& fifo = CommandProcessor::fifo; - - AsyncRequests::GetInstance()->PullEvents(); - CommandProcessor::SetCPStatusFromGPU(); // check if we are able to run this buffer diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index c9fa12f6bb..527a836d63 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -338,9 +338,6 @@ void VertexManagerBase::Flush() m_is_flushed = true; - // loading a state will invalidate BP, so check for it - g_video_backend->CheckInvalidState(); - #if defined(_DEBUG) || defined(DEBUGFAST) PRIM_LOG("frame%d:\n texgen=%u, numchan=%u, dualtex=%u, ztex=%u, cole=%u, alpe=%u, ze=%u", g_ActiveConfig.iSaveTargetId, xfmem.numTexGen.numTexGens, xfmem.numChan.numColorChans, diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index aa4cd8f6dd..ae628e5ab1 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -40,6 +40,7 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VertexLoaderManager.h" +#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -236,8 +237,25 @@ void VideoBackendBase::PopulateBackendInfo() g_Config.Refresh(); } -// Run from the CPU thread void VideoBackendBase::DoState(PointerWrap& p) +{ + if (!SConfig::GetInstance().bCPUThread) + { + DoStateGPUThread(p); + return; + } + + AsyncRequests::Event ev = {}; + ev.do_save_state.p = &p; + ev.type = AsyncRequests::Event::DO_SAVE_STATE; + AsyncRequests::GetInstance()->PushEvent(ev, true); + + // Let the GPU thread sleep after loading the state, so we're not spinning if paused after loading + // a state. The next GP burst will wake it up again. + Fifo::GpuMaySleep(); +} + +void VideoBackendBase::DoStateGPUThread(PointerWrap& p) { bool software = false; p.Do(software); @@ -254,7 +272,10 @@ void VideoBackendBase::DoState(PointerWrap& p) // Refresh state. if (p.GetMode() == PointerWrap::MODE_READ) { - m_invalid = true; + // Inform backend of new state from registers. + g_vertex_manager->Flush(); + g_texture_cache->Invalidate(); + BPReload(); // Clear all caches that touch RAM // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) @@ -262,17 +283,6 @@ void VideoBackendBase::DoState(PointerWrap& p) } } -void VideoBackendBase::CheckInvalidState() -{ - if (m_invalid) - { - m_invalid = false; - - BPReload(); - g_texture_cache->Invalidate(); - } -} - void VideoBackendBase::InitializeShared() { memset(&g_main_cp_state, 0, sizeof(g_main_cp_state)); @@ -282,8 +292,6 @@ void VideoBackendBase::InitializeShared() // do not initialize again for the config window m_initialized = true; - m_invalid = false; - CommandProcessor::Init(); Fifo::Init(); OpcodeDecoder::Init(); diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index d1dada2247..7e68d93147 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -63,18 +63,17 @@ public: // Called by the UI thread when the graphics config is opened. static void PopulateBackendInfo(); - // the implementation needs not do synchronization logic, because calls to it are surrounded by - // PauseAndLock now + // Wrapper function which pushes the event to the GPU thread. void DoState(PointerWrap& p); - void CheckInvalidState(); + // Function which handles the real state load/save logic. + void DoStateGPUThread(PointerWrap& p); protected: void InitializeShared(); void ShutdownShared(); bool m_initialized = false; - bool m_invalid = false; }; extern std::vector> g_available_video_backends;