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:
parent
b601a94750
commit
de920458d7
@ -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) };
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user