diff --git a/src/util/sync/sync_signal_win32.h b/src/util/sync/sync_signal_win32.h new file mode 100644 index 000000000..1b839b556 --- /dev/null +++ b/src/util/sync/sync_signal_win32.h @@ -0,0 +1,96 @@ +#pragma once + +#include + +#include "sync_signal.h" + +namespace dxvk::sync { + + /** + * \brief Win32 fence + * + * CPU-side fence that also has the + * ability to signal Win32 events. + */ + class Win32Fence : public Signal { + + public: + + Win32Fence() + : m_value(0ull) { } + + explicit Win32Fence(uint64_t value) + : m_value(value) { } + + /** + * \brief Last signaled value + * \returns Last signaled value + */ + uint64_t value() const { + return m_value.load(std::memory_order_acquire); + } + + /** + * \brief Notifies signal + * + * In addition to waking up blocked threads, this + * will also signal any queued win32 events with + * a lower or equal value. + * \param [in] value Value to set signal to + */ + 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_events.begin(); i != m_events.end(); ) { + if (value >= i->second) { + SetEvent(i->first); + i = m_events.erase(i); + } else { + i++; + } + } + } + + /** + * \brief Waits for signal + * \param [in] value The value to wait for + */ + 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); + }); + } + + /** + * \brief Sets Win32 event on completion + * + * When the signal gets signaled with a value equal to or + * greater than the given value, the event will be signaled. + * Signals the event immediately if the last signaled value + * is already greater than or equal to the requested value. + * \param [in] event Win32 Event to signal + * \param [in] value Requested signal value + */ + void setEvent(HANDLE event, uint64_t value) { + std::unique_lock lock(m_mutex); + + if (value > this->value()) + m_events.push_back({ event, value }); + else + SetEvent(event); + } + + private: + + std::atomic m_value; + std::mutex m_mutex; + std::condition_variable m_cond; + + std::list> m_events; + + }; + +}