diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp new file mode 100644 index 0000000000..dce56c0d7b --- /dev/null +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -0,0 +1,88 @@ +#include "VideoCommon/AsyncRequests.h" +#include "VideoCommon/RenderBase.h" + +AsyncRequests AsyncRequests::s_singleton; + +AsyncRequests::AsyncRequests() +: m_enable(false) +{ +} + +void AsyncRequests::PullEventsInternal() +{ + std::unique_lock lock(m_mutex); + m_empty.store(true); + + while (!m_queue.empty()) + { + const Event& e = m_queue.front(); + + lock.unlock(); + HandleEvent(e); + lock.lock(); + + m_queue.pop(); + } + + if (m_wake_me_up_again) + { + m_wake_me_up_again = false; + m_cond.notify_all(); + } +} + +void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking) +{ + std::unique_lock lock(m_mutex); + m_empty.store(false); + m_wake_me_up_again |= blocking; + + if (!m_enable) + return; + + m_queue.push(event); + + if (blocking) + { + m_cond.wait(lock, [this]{return m_queue.empty();}); + } +} + +void AsyncRequests::SetEnable(bool enable) +{ + std::unique_lock lock(m_mutex); + m_enable = enable; + + if (!enable) + { + // flush the queue on disabling + while (!m_queue.empty()) + m_queue.pop(); + if (m_wake_me_up_again) + m_cond.notify_all(); + } +} + +void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) +{ + switch (e.type) + { + case Event::EFB_POKE_COLOR: + g_renderer->AccessEFB(POKE_COLOR, e.efb_poke.x, e.efb_poke.y, e.efb_poke.data); + break; + + case Event::EFB_POKE_Z: + g_renderer->AccessEFB(POKE_Z, e.efb_poke.x, e.efb_poke.y, e.efb_poke.data); + break; + + case Event::EFB_PEEK_COLOR: + *e.efb_peek.data = g_renderer->AccessEFB(PEEK_COLOR, e.efb_peek.x, e.efb_peek.y, 0); + break; + + case Event::EFB_PEEK_Z: + *e.efb_peek.data = g_renderer->AccessEFB(PEEK_Z, e.efb_peek.x, e.efb_peek.y, 0); + break; + + } +} + diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h new file mode 100644 index 0000000000..d3cfece7eb --- /dev/null +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -0,0 +1,71 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/CommonTypes.h" + +class AsyncRequests +{ +public: + struct Event + { + enum Type + { + EFB_POKE_COLOR, + EFB_POKE_Z, + EFB_PEEK_COLOR, + EFB_PEEK_Z, + } type; + u64 time; + + union + { + struct + { + u16 x; + u16 y; + u32 data; + } efb_poke; + + struct + { + u16 x; + u16 y; + u32* data; + } efb_peek; + }; + }; + + AsyncRequests(); + + void PullEvents() + { + if (!m_empty.load()) + PullEventsInternal(); + } + void PushEvent(const Event& event, bool blocking = false); + void SetEnable(bool enable); + + static AsyncRequests* GetInstance() { return &s_singleton; } + +private: + void PullEventsInternal(); + void HandleEvent(const Event& e); + + static AsyncRequests s_singleton; + + std::atomic m_empty; + std::queue m_queue; + std::mutex m_mutex; + std::condition_variable m_cond; + + bool m_wake_me_up_again; + bool m_enable; +}; diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 4e6dd8a6b6..f3ef98a741 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -1,4 +1,5 @@ -set(SRCS BoundingBox.cpp +set(SRCS AsyncRequests.cpp + BoundingBox.cpp BPFunctions.cpp BPMemory.cpp BPStructs.cpp diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 9da3583a9d..b8f4002d4d 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -15,6 +15,7 @@ #include "Core/NetPlayProto.h" #include "Core/HW/Memmap.h" +#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/CPMemory.h" #include "VideoCommon/DataReader.h" @@ -282,11 +283,14 @@ void RunGpuLoop() // This allows a system that we are maxing out in dual core mode to do other things bool yield_cpu = cpu_info.num_cores <= 2; + AsyncRequests::GetInstance()->SetEnable(true); + while (GpuRunningState) { g_video_backend->PeekMessages(); VideoFifo_CheckAsyncRequest(); + AsyncRequests::GetInstance()->PullEvents(); if (g_use_deterministic_gpu_thread) { // All the fifo/CP stuff is on the CPU. We just need to run the opcode decoder. @@ -349,6 +353,7 @@ void RunGpuLoop() // If we don't, s_swapRequested 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_CheckAsyncRequest(); + AsyncRequests::GetInstance()->PullEvents(); CommandProcessor::isPossibleWaitingSetDrawDone = false; } @@ -377,6 +382,7 @@ void RunGpuLoop() } // wake up SyncGPU if we were interrupted s_video_buffer_cond.notify_all(); + AsyncRequests::GetInstance()->SetEnable(false); } diff --git a/Source/Core/VideoCommon/MainBase.cpp b/Source/Core/VideoCommon/MainBase.cpp index b5c6cdebf9..47eab7d941 100644 --- a/Source/Core/VideoCommon/MainBase.cpp +++ b/Source/Core/VideoCommon/MainBase.cpp @@ -1,6 +1,7 @@ #include "Common/Event.h" #include "Core/ConfigManager.h" +#include "VideoCommon/AsyncRequests.h" #include "VideoCommon/BoundingBox.h" #include "VideoCommon/BPStructs.h" #include "VideoCommon/CommandProcessor.h" @@ -20,8 +21,6 @@ bool s_BackendInitialized = false; Common::Flag s_swapRequested; static Common::Flag s_FifoShuttingDown; -static Common::Flag s_efbAccessRequested; -static Common::Event s_efbAccessReadyEvent; static Common::Flag s_perfQueryRequested; static Common::Event s_perfQueryReadyEvent; @@ -39,16 +38,6 @@ static volatile struct u32 fbHeight; } s_beginFieldArgs; -static struct -{ - EFBAccessType type; - u32 x; - u32 y; - u32 Data; -} s_accessEFBArgs; - -static u32 s_AccessEFBResult = 0; - void VideoBackendHardware::EmuStateChange(EMUSTATE_CHANGE newState) { EmulatorState((newState == EMUSTATE_CHANGE_PLAY) ? true : false); @@ -64,7 +53,6 @@ void VideoBackendHardware::Video_ExitLoop() { ExitGpuLoop(); s_FifoShuttingDown.Set(); - s_efbAccessReadyEvent.Set(); s_perfQueryReadyEvent.Set(); } @@ -152,44 +140,36 @@ bool VideoBackendHardware::Video_Screenshot(const std::string& filename) return true; } -void VideoFifo_CheckEFBAccess() -{ - if (s_efbAccessRequested.IsSet()) - { - s_AccessEFBResult = g_renderer->AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data); - s_efbAccessRequested.Clear(); - s_efbAccessReadyEvent.Set(); - } -} - u32 VideoBackendHardware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData) { - if (s_BackendInitialized && g_ActiveConfig.bEFBAccessEnable) + if (!g_ActiveConfig.bEFBAccessEnable) { - SyncGPU(SYNC_GPU_EFB_POKE); - - s_accessEFBArgs.type = type; - s_accessEFBArgs.x = x; - s_accessEFBArgs.y = y; - s_accessEFBArgs.Data = InputData; - - s_efbAccessRequested.Set(); - - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread) - { - s_efbAccessReadyEvent.Reset(); - if (s_FifoShuttingDown.IsSet()) - return 0; - s_efbAccessRequested.Set(); - s_efbAccessReadyEvent.Wait(); - } - else - VideoFifo_CheckEFBAccess(); - - return s_AccessEFBResult; + return 0; } - return 0; + if (type == POKE_COLOR || type == POKE_Z) + { + AsyncRequests::Event e; + e.type = type == POKE_COLOR ? AsyncRequests::Event::EFB_POKE_COLOR : AsyncRequests::Event::EFB_POKE_Z; + e.time = 0; + e.efb_poke.data = InputData; + e.efb_poke.x = x; + e.efb_poke.y = y; + AsyncRequests::GetInstance()->PushEvent(e, 0); + return 0; + } + else + { + AsyncRequests::Event e; + u32 result; + e.type = type == PEEK_COLOR ? AsyncRequests::Event::EFB_PEEK_COLOR : AsyncRequests::Event::EFB_PEEK_Z; + e.time = 0; + e.efb_peek.x = x; + e.efb_peek.y = y; + e.efb_peek.data = &result; + AsyncRequests::GetInstance()->PushEvent(e, 1); + return result; + } } static void VideoFifo_CheckPerfQueryRequest() @@ -267,12 +247,9 @@ void VideoBackendHardware::InitializeShared() VideoCommon_Init(); s_swapRequested.Clear(); - s_efbAccessRequested.Clear(); s_perfQueryRequested.Clear(); s_FifoShuttingDown.Clear(); memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); - memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs)); - s_AccessEFBResult = 0; m_invalid = false; } @@ -292,10 +269,7 @@ void VideoBackendHardware::DoState(PointerWrap& p) p.DoMarker("VideoCommon"); p.Do(s_swapRequested); - p.Do(s_efbAccessRequested); p.Do(s_beginFieldArgs); - p.Do(s_accessEFBArgs); - p.Do(s_AccessEFBResult); p.DoMarker("VideoBackendHardware"); // Refresh state. @@ -335,7 +309,6 @@ void VideoBackendHardware::RunLoop(bool enable) void VideoFifo_CheckAsyncRequest() { VideoFifo_CheckSwapRequest(); - VideoFifo_CheckEFBAccess(); VideoFifo_CheckPerfQueryRequest(); VideoFifo_CheckBBoxRequest(); } diff --git a/Source/Core/VideoCommon/MainBase.h b/Source/Core/VideoCommon/MainBase.h index bcef8024ec..b8eebf37a0 100644 --- a/Source/Core/VideoCommon/MainBase.h +++ b/Source/Core/VideoCommon/MainBase.h @@ -6,5 +6,4 @@ extern bool s_BackendInitialized; extern Common::Flag s_swapRequested; -void VideoFifo_CheckEFBAccess(); void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 3e95eca5cc..cb9be880e0 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -116,7 +116,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbWidt if (!fbWidth || !fbHeight) return; - VideoFifo_CheckEFBAccess(); VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight); XFBWrited = true; diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index bf7800cc9a..520654448f 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -166,8 +166,6 @@ void VertexManager::Flush() // loading a state will invalidate BP, so check for it g_video_backend->CheckInvalidState(); - VideoFifo_CheckEFBAccess(); - #if defined(_DEBUG) || defined(DEBUGFAST) PRIM_LOG("frame%d:\n texgen=%d, numchan=%d, dualtex=%d, ztex=%d, cole=%d, alpe=%d, ze=%d", g_ActiveConfig.iSaveTargetId, xfmem.numTexGen.numTexGens, xfmem.numChan.numColorChans, xfmem.dualTexTrans.enabled, bpmem.ztex2.op, diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 649cd5095e..ff56a97703 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -35,6 +35,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index eca9287439..1998fce1cc 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -146,6 +146,9 @@ Decoding + + Util + Util @@ -290,6 +293,9 @@ Vertex Loading + + Util + Util