From 893da94fb3f3fc280b4dcc75c315d170bdb37746 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 2 Aug 2021 19:09:23 +0200 Subject: [PATCH] [util] Introduce CallbackFence --- src/util/sync/sync_signal.h | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/util/sync/sync_signal.h b/src/util/sync/sync_signal.h index aad7227ed..cdbcae821 100644 --- a/src/util/sync/sync_signal.h +++ b/src/util/sync/sync_signal.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include "../rc/util_rc.h" @@ -89,5 +91,70 @@ namespace dxvk::sync { dxvk::condition_variable m_cond; }; + + + /** + * \brief Callback signal + * + * CPU-side fence with the ability to call a + * function when signaled to a given value. + */ + class CallbackFence final : public Signal { + + public: + + CallbackFence() + : m_value(0ull) { } + + explicit CallbackFence(uint64_t value) + : m_value(value) { } + + uint64_t value() const { + return m_value.load(std::memory_order_acquire); + } + + void signal(uint64_t value) { + std::unique_lock lock(m_mutex); + m_value.store(value, std::memory_order_release); + m_cond.notify_all(); + + for (auto i = m_callbacks.begin(); i != m_callbacks.end(); ) { + if (value >= i->first) { + i->second(); + i = m_callbacks.erase(i); + } else { + i++; + } + } + } + + void wait(uint64_t value) { + std::unique_lock lock(m_mutex); + m_cond.wait(lock, [this, value] { + return value <= m_value.load(std::memory_order_acquire); + }); + } + + template + void setCallback(uint64_t value, Fn&& proc) { + std::unique_lock lock(m_mutex); + + if (value > this->value()) + m_callbacks.emplace_back(std::piecewise_construct, + std::make_tuple(value), + std::make_tuple(proc)); + else + proc(); + } + + private: + + std::atomic m_value; + dxvk::mutex m_mutex; + dxvk::condition_variable m_cond; + + std::list>> m_callbacks; + + }; }