diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 15226ab485..02233d46f4 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1307,11 +1307,11 @@ void GLGSRender::do_local_task(rsx::FIFO::state state) { std::lock_guard lock(queue_guard); - work_queue.remove_if([](auto &q) { return q.received; }); + work_queue.remove_if([](auto &q) { return q.received.load(); }); for (auto& q : work_queue) { - if (q.processed) continue; + if (q.processed.load()) continue; gl::command_context cmd{ gl_state }; q.result = m_gl_texture_cache.flush_all(cmd, q.section_data); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 330838f804..530da541c7 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -6,6 +6,7 @@ #include "GLOverlays.h" #include "GLShaderInterpreter.h" #include "Emu/RSX/rsx_cache.h" +#include "util/asm.hpp" #include #include @@ -45,16 +46,16 @@ namespace gl u32 address_to_flush = 0; gl::texture_cache::thrashed_set section_data; - volatile bool processed = false; + atomic_t processed = false; volatile bool result = false; - volatile bool received = false; + atomic_t received = false; void producer_wait() { - while (!processed) + utils::spin_wait(processed, [](auto v) { - std::this_thread::yield(); - } + return v; + }); received = true; } diff --git a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp index 0a400c68d9..0b80a5d4e6 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp +++ b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp @@ -254,18 +254,18 @@ namespace vk void consumer_wait() const { - while (num_waiters.load() != 0) + utils::spin_wait(num_waiters, [](auto v) { - utils::pause(); - } + return v == 0; + }); } void producer_wait() const { - while (pending_state.load()) + utils::spin_wait(pending_state, [](auto v) { - std::this_thread::yield(); - } + return !v; + }); } }; diff --git a/rpcs3/util/asm.hpp b/rpcs3/util/asm.hpp index 0aea4c10c2..b65e722639 100644 --- a/rpcs3/util/asm.hpp +++ b/rpcs3/util/asm.hpp @@ -3,11 +3,13 @@ #include "util/types.hpp" #include "util/tsc.hpp" #include "util/atomic.hpp" +#include "util/sysinfo.hpp" #include #ifdef ARCH_X64 #ifdef _MSC_VER #include +#include #else #include #include @@ -216,6 +218,84 @@ namespace utils while (get_tsc() < stop); } + template +#if defined(ARCH_X64) && !defined(_MSC_VER) + __attribute__((target("waitpkg,mwaitx"))) +#endif + inline void spin_wait(const atomic_t& var, Pred predicate) + { +#ifdef ARCH_X64 + static const bool use_umwait = has_waitpkg(); + static const bool use_waitx = has_waitx(); +#endif + + const auto read_mem = [&]() + { + return var.load(); + }; + + const void* addr = &var.raw(); + + while (true) + { + if (predicate(read_mem())) + { + return; + } + +#if defined(ARCH_ARM64) + using value_type = decltype(read_mem()); + using wait_type = std::remove_cvref_t; + + wait_type value{}; + const auto* wait_addr = static_cast(addr); + + if constexpr (sizeof(wait_type) == 1) __asm__ volatile("ldaxrb %w0, %1" : "=r"(value) : "Q"(*wait_addr) : "memory"); + else if constexpr (sizeof(wait_type) == 2) __asm__ volatile("ldaxrh %w0, %1" : "=r"(value) : "Q"(*wait_addr) : "memory"); + else if constexpr (sizeof(wait_type) == 4) __asm__ volatile("ldaxr %w0, %1" : "=r"(value) : "Q"(*wait_addr) : "memory"); + else if constexpr (sizeof(wait_type) == 8) __asm__ volatile("ldaxr %x0, %1" : "=r"(value) : "Q"(*wait_addr) : "memory"); + else static_assert(sizeof(wait_type) <= 8, "Unsupported atomic size for spin_wait"); + + if (predicate(static_cast(value))) + { + __asm__ volatile("clrex" ::: "memory"); + return; + } + + __asm__ volatile("wfe" ::: "memory"); + __asm__ volatile("clrex" ::: "memory"); + +#elif defined(ARCH_X64) + if (use_umwait) + { + _umonitor(const_cast(addr)); + if (predicate(read_mem())) + { + return; + } + + _umwait(0, ~0ULL); + } + else if (use_waitx) + { + _mm_monitorx(const_cast(addr), 0, 0); + if (predicate(read_mem())) + { + return; + } + + _mm_mwaitx(0, 0, 0); + } + else + { + pause(); + } +#else + pause(); +#endif + } + } + // Align to power of 2 template requires std::is_unsigned_v diff --git a/rpcs3/util/atomic.hpp b/rpcs3/util/atomic.hpp index f77aad7825..49d9663dec 100644 --- a/rpcs3/util/atomic.hpp +++ b/rpcs3/util/atomic.hpp @@ -1742,6 +1742,11 @@ public: return base::load() != 0; } + const uchar& raw() const + { + return base::raw(); + } + // Override implicit conversion from the parent type explicit operator uchar() const = delete;