diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index 3eddfd5ed5..72c8cb87b2 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -111,9 +111,8 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) // NOTE: GPFifo::ResetGatherPipe() only affects // CPU state, so we can call it directly - AsyncRequests::Event ev = {}; - ev.type = AsyncRequests::Event::FIFO_RESET; - AsyncRequests::GetInstance()->PushEvent(ev); + AsyncRequests::GetInstance()->PushEvent( + [] { Core::System::GetInstance().GetFifo().ResetVideoBuffer(); }); } })); diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 8af5247aba..a9fd5ede4b 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -47,7 +47,9 @@ #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" -#include "VideoCommon/VideoBackendBase.h" +#include "VideoCommon/AsyncRequests.h" +#include "VideoCommon/EFBInterface.h" +#include "VideoCommon/Statistics.h" namespace PowerPC { @@ -109,12 +111,18 @@ static u32 EFB_Read(const u32 addr) } else if (addr & 0x00400000) { - var = g_video_backend->Video_AccessEFB(EFBAccessType::PeekZ, x, y, 0); + var = AsyncRequests::GetInstance()->PushBlockingEvent([&] { + INCSTAT(g_stats.this_frame.num_efb_peeks); + return g_efb_interface->PeekDepth(x, y); + }); DEBUG_LOG_FMT(MEMMAP, "EFB Z Read @ {}, {}\t= {:#010x}", x, y, var); } else { - var = g_video_backend->Video_AccessEFB(EFBAccessType::PeekColor, x, y, 0); + var = AsyncRequests::GetInstance()->PushBlockingEvent([&] { + INCSTAT(g_stats.this_frame.num_efb_peeks); + return g_efb_interface->PeekColor(x, y); + }); DEBUG_LOG_FMT(MEMMAP, "EFB Color Read @ {}, {}\t= {:#010x}", x, y, var); } @@ -134,12 +142,18 @@ static void EFB_Write(u32 data, u32 addr) } else if (addr & 0x00400000) { - g_video_backend->Video_AccessEFB(EFBAccessType::PokeZ, x, y, data); + AsyncRequests::GetInstance()->PushEvent([x, y, data] { + INCSTAT(g_stats.this_frame.num_efb_pokes); + g_efb_interface->PokeDepth(x, y, data); + }); DEBUG_LOG_FMT(MEMMAP, "EFB Z Write {:08x} @ {}, {}", data, x, y); } else { - g_video_backend->Video_AccessEFB(EFBAccessType::PokeColor, x, y, data); + AsyncRequests::GetInstance()->PushEvent([x, y, data] { + INCSTAT(g_stats.this_frame.num_efb_pokes); + g_efb_interface->PokeColor(x, y, data); + }); DEBUG_LOG_FMT(MEMMAP, "EFB Color Write {:08x} @ {}, {}", data, x, y); } } diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 81b44ca042..0469d3ebb9 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -7,15 +7,10 @@ #include "Core/System.h" -#include "VideoCommon/BoundingBox.h" -#include "VideoCommon/EFBInterface.h" #include "VideoCommon/Fifo.h" -#include "VideoCommon/Present.h" -#include "VideoCommon/Statistics.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoEvents.h" -#include "VideoCommon/VideoState.h" AsyncRequests AsyncRequests::s_singleton; @@ -32,46 +27,28 @@ void AsyncRequests::PullEventsInternal() while (!m_queue.empty()) { - Event e = m_queue.front(); - + Event e = std::move(m_queue.front()); lock.unlock(); - HandleEvent(e); + std::invoke(e); lock.lock(); m_queue.pop(); } - if (m_wake_me_up_again) - { - m_wake_me_up_again = false; - m_cond.notify_all(); - } + m_cond.notify_one(); } -void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking) +void AsyncRequests::QueueEvent(Event&& event) { - std::unique_lock lock(m_mutex); - - if (m_passthrough) - { - HandleEvent(event); - return; - } - m_empty.Clear(); - m_wake_me_up_again |= blocking; if (!m_enable) return; - m_queue.push(event); + m_queue.push(std::move(event)); auto& system = Core::System::GetInstance(); system.GetFifo().RunGpu(); - if (blocking) - { - m_cond.wait(lock, [this] { return m_queue.empty(); }); - } } void AsyncRequests::WaitForEmptyQueue() @@ -90,59 +67,7 @@ void AsyncRequests::SetEnable(bool 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: - { - INCSTAT(g_stats.this_frame.num_efb_pokes); - g_efb_interface->PokeColor(e.efb_poke.x, e.efb_poke.y, e.efb_poke.data); - } - break; - - case Event::EFB_POKE_Z: - { - INCSTAT(g_stats.this_frame.num_efb_pokes); - g_efb_interface->PokeDepth(e.efb_poke.x, e.efb_poke.y, e.efb_poke.data); - } - break; - - case Event::EFB_PEEK_COLOR: - INCSTAT(g_stats.this_frame.num_efb_peeks); - *e.efb_peek.data = g_efb_interface->PeekColor(e.efb_peek.x, e.efb_peek.y); - break; - - case Event::EFB_PEEK_Z: - INCSTAT(g_stats.this_frame.num_efb_peeks); - *e.efb_peek.data = g_efb_interface->PeekDepth(e.efb_peek.x, e.efb_peek.y); - break; - - case Event::SWAP_EVENT: - g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, - e.swap_event.fbHeight, e.time, e.swap_event.presentation_time); - break; - - case Event::BBOX_READ: - *e.bbox.data = g_bounding_box->Get(e.bbox.index); - break; - - case Event::FIFO_RESET: - Core::System::GetInstance().GetFifo().ResetVideoBuffer(); - break; - - case Event::PERF_QUERY: - g_perf_query->FlushResults(); - break; - - case Event::DO_SAVE_STATE: - VideoCommon_DoState(*e.do_save_state.p); - break; + m_cond.notify_one(); } } diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index 74d73c6cca..ad2a120e8b 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -4,10 +4,11 @@ #pragma once #include +#include +#include #include #include -#include "Common/CommonTypes.h" #include "Common/Flag.h" struct EfbPokeData; @@ -16,70 +17,6 @@ class PointerWrap; class AsyncRequests { public: - struct Event - { - Event() {} - - enum Type - { - EFB_POKE_COLOR, - EFB_POKE_Z, - EFB_PEEK_COLOR, - EFB_PEEK_Z, - SWAP_EVENT, - BBOX_READ, - FIFO_RESET, - PERF_QUERY, - DO_SAVE_STATE, - } type; - u64 time; - - union - { - struct - { - u16 x; - u16 y; - u32 data; - } efb_poke; - - struct - { - u16 x; - u16 y; - u32* data; - } efb_peek; - - struct - { - u32 xfbAddr; - u32 fbWidth; - u32 fbStride; - u32 fbHeight; - TimePoint presentation_time; - } swap_event; - - struct - { - int index; - u16* data; - } bbox; - - struct - { - } fifo_reset; - - struct - { - } perf_query; - - struct - { - PointerWrap* p; - } do_save_state; - }; - }; - AsyncRequests(); void PullEvents() @@ -87,16 +24,47 @@ public: if (!m_empty.IsSet()) PullEventsInternal(); } - void PushEvent(const Event& event, bool blocking = false); void WaitForEmptyQueue(); void SetEnable(bool enable); void SetPassthrough(bool enable); + template + void PushEvent(F&& callback) + { + std::unique_lock lock(m_mutex); + + if (m_passthrough) + { + std::invoke(callback); + return; + } + + QueueEvent(Event{std::forward(callback)}); + } + + template + auto PushBlockingEvent(F&& callback) -> std::invoke_result_t + { + std::unique_lock lock(m_mutex); + + if (m_passthrough) + return std::invoke(callback); + + std::packaged_task task{std::forward(callback)}; + QueueEvent(Event{[&] { task(); }}); + + lock.unlock(); + return task.get_future().get(); + } + static AsyncRequests* GetInstance() { return &s_singleton; } private: + using Event = std::function; + + void QueueEvent(Event&& event); + void PullEventsInternal(); - void HandleEvent(const Event& e); static AsyncRequests s_singleton; @@ -105,7 +73,6 @@ private: std::mutex m_mutex; std::condition_variable m_cond; - bool m_wake_me_up_again = false; bool m_enable = false; bool m_passthrough = true; }; diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 8150120610..8436f44443 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -61,7 +61,6 @@ #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexShaderManager.h" -#include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoState.h" #include "VideoCommon/Widescreen.h" @@ -98,50 +97,10 @@ void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride auto& system = Core::System::GetInstance(); system.GetFifo().SyncGPU(Fifo::SyncGPUReason::Swap); - AsyncRequests::Event e; - e.time = ticks; - e.type = AsyncRequests::Event::SWAP_EVENT; - - e.swap_event.xfbAddr = xfb_addr; - e.swap_event.fbWidth = fb_width; - e.swap_event.fbStride = fb_stride; - e.swap_event.fbHeight = fb_height; - e.swap_event.presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks); - AsyncRequests::GetInstance()->PushEvent(e, false); - } -} - -u32 VideoBackendBase::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 data) -{ - if (!g_ActiveConfig.bEFBAccessEnable || x >= EFB_WIDTH || y >= EFB_HEIGHT) - { - return 0; - } - - if (type == EFBAccessType::PokeColor || type == EFBAccessType::PokeZ) - { - AsyncRequests::Event e; - e.type = type == EFBAccessType::PokeColor ? AsyncRequests::Event::EFB_POKE_COLOR : - AsyncRequests::Event::EFB_POKE_Z; - e.time = 0; - e.efb_poke.data = data; - e.efb_poke.x = x; - e.efb_poke.y = y; - AsyncRequests::GetInstance()->PushEvent(e, false); - return 0; - } - else - { - AsyncRequests::Event e; - u32 result; - e.type = type == EFBAccessType::PeekColor ? 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, true); - return result; + const TimePoint presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks); + AsyncRequests::GetInstance()->PushEvent([=] { + g_presenter->ViSwap(xfb_addr, fb_width, fb_stride, fb_height, ticks, presentation_time); + }); } } @@ -155,12 +114,10 @@ u32 VideoBackendBase::Video_GetQueryResult(PerfQueryType type) auto& system = Core::System::GetInstance(); system.GetFifo().SyncGPU(Fifo::SyncGPUReason::PerfQuery); - AsyncRequests::Event e; - e.time = 0; - e.type = AsyncRequests::Event::PERF_QUERY; - if (!g_perf_query->IsFlushed()) - AsyncRequests::GetInstance()->PushEvent(e, true); + { + AsyncRequests::GetInstance()->PushBlockingEvent([] { g_perf_query->FlushResults(); }); + } return g_perf_query->GetQueryResult(type); } @@ -196,15 +153,8 @@ u16 VideoBackendBase::Video_GetBoundingBox(int index) auto& system = Core::System::GetInstance(); system.GetFifo().SyncGPU(Fifo::SyncGPUReason::BBox); - AsyncRequests::Event e; - u16 result; - e.time = 0; - e.type = AsyncRequests::Event::BBOX_READ; - e.bbox.index = index; - e.bbox.data = &result; - AsyncRequests::GetInstance()->PushEvent(e, true); - - return result; + return AsyncRequests::GetInstance()->PushBlockingEvent( + [&] { return g_bounding_box->Get(index); }); } static VideoBackendBase* GetDefaultVideoBackend() @@ -309,10 +259,7 @@ void VideoBackendBase::DoState(PointerWrap& p) return; } - AsyncRequests::Event ev = {}; - ev.do_save_state.p = &p; - ev.type = AsyncRequests::Event::DO_SAVE_STATE; - AsyncRequests::GetInstance()->PushEvent(ev, true); + AsyncRequests::GetInstance()->PushBlockingEvent([&] { VideoCommon_DoState(p); }); // 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. diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 0f594a9793..223e46ad03 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -30,14 +30,6 @@ enum class FieldType Even, }; -enum class EFBAccessType -{ - PeekZ, - PokeZ, - PeekColor, - PokeColor -}; - class VideoBackendBase { public: @@ -58,7 +50,6 @@ public: void Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks); - u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 data); u32 Video_GetQueryResult(PerfQueryType type); u16 Video_GetBoundingBox(int index);