1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-13 19:29:14 +01:00

[dxvk] Make DxvkEvent lock-free

Reduces locking overhead and potential stuttering
issues when an app is spinning on the event.
This commit is contained in:
Philip Rebohle 2018-07-20 15:48:09 +02:00
parent b601a94750
commit de920458d7
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 46 additions and 20 deletions

View File

@ -2,35 +2,55 @@
namespace dxvk {
DxvkEvent:: DxvkEvent() { }
DxvkEvent::~DxvkEvent() { }
DxvkEvent::DxvkEvent()
: m_packed(pack({ DxvkEventStatus::Signaled, 0u })) { }
DxvkEvent::~DxvkEvent() {
}
uint32_t DxvkEvent::reset() {
std::unique_lock<std::mutex> lock(m_mutex);
m_status = DxvkEventStatus::Reset;
return ++m_revision;
Status info;
uint64_t packed = m_packed.load();
do {
info.status = DxvkEventStatus::Reset;
info.revision = unpack(packed).revision + 1;
} while (!m_packed.compare_exchange_strong(packed, pack(info)));
return info.revision;
}
void DxvkEvent::signal(uint32_t revision) {
std::unique_lock<std::mutex> lock(m_mutex);
if (m_revision == revision)
m_status = DxvkEventStatus::Signaled;
uint64_t expected = pack({ DxvkEventStatus::Reset, revision });
uint64_t desired = pack({ DxvkEventStatus::Signaled, revision });
m_packed.compare_exchange_strong(expected, desired);
}
DxvkEventStatus DxvkEvent::getStatus() {
std::unique_lock<std::mutex> lock(m_mutex);
return m_status;
DxvkEventStatus DxvkEvent::getStatus() const {
return unpack(m_packed.load()).status;
}
void DxvkEvent::wait() {
void DxvkEvent::wait() const {
while (this->getStatus() != DxvkEventStatus::Signaled)
dxvk::this_thread::yield();
}
uint64_t DxvkEvent::pack(Status info) {
return (uint64_t(info.revision))
| (uint64_t(info.status) << 32);
}
DxvkEvent::Status DxvkEvent::unpack(uint64_t packed) {
return { DxvkEventStatus(packed >> 32), uint32_t(packed) };
}
}

View File

@ -44,7 +44,7 @@ namespace dxvk {
* \brief Queries event status
* \returns Current event status
*/
DxvkEventStatus getStatus();
DxvkEventStatus getStatus() const;
/**
* \brief Waits for event to get signaled
@ -53,14 +53,20 @@ namespace dxvk {
* thread calls \ref signal for the current
* revision of the event.
*/
void wait();
void wait() const;
private:
std::mutex m_mutex;
DxvkEventStatus m_status = DxvkEventStatus::Signaled;
uint32_t m_revision = 0;
struct Status {
DxvkEventStatus status = DxvkEventStatus::Signaled;
uint32_t revision = 0;
};
// Packed status and revision
std::atomic<uint64_t> m_packed;
static uint64_t pack(Status info);
static Status unpack(uint64_t packed);
};