mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-15 07:29:17 +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 {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkEvent:: DxvkEvent() { }
|
DxvkEvent::DxvkEvent()
|
||||||
DxvkEvent::~DxvkEvent() { }
|
: m_packed(pack({ DxvkEventStatus::Signaled, 0u })) { }
|
||||||
|
|
||||||
|
|
||||||
|
DxvkEvent::~DxvkEvent() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t DxvkEvent::reset() {
|
uint32_t DxvkEvent::reset() {
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
Status info;
|
||||||
|
|
||||||
m_status = DxvkEventStatus::Reset;
|
uint64_t packed = m_packed.load();
|
||||||
return ++m_revision;
|
|
||||||
|
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) {
|
void DxvkEvent::signal(uint32_t revision) {
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
uint64_t expected = pack({ DxvkEventStatus::Reset, revision });
|
||||||
|
uint64_t desired = pack({ DxvkEventStatus::Signaled, revision });
|
||||||
if (m_revision == revision)
|
m_packed.compare_exchange_strong(expected, desired);
|
||||||
m_status = DxvkEventStatus::Signaled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkEventStatus DxvkEvent::getStatus() {
|
DxvkEventStatus DxvkEvent::getStatus() const {
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
return unpack(m_packed.load()).status;
|
||||||
return m_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkEvent::wait() {
|
void DxvkEvent::wait() const {
|
||||||
while (this->getStatus() != DxvkEventStatus::Signaled)
|
while (this->getStatus() != DxvkEventStatus::Signaled)
|
||||||
dxvk::this_thread::yield();
|
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
|
* \brief Queries event status
|
||||||
* \returns Current event status
|
* \returns Current event status
|
||||||
*/
|
*/
|
||||||
DxvkEventStatus getStatus();
|
DxvkEventStatus getStatus() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Waits for event to get signaled
|
* \brief Waits for event to get signaled
|
||||||
@ -53,14 +53,20 @@ namespace dxvk {
|
|||||||
* thread calls \ref signal for the current
|
* thread calls \ref signal for the current
|
||||||
* revision of the event.
|
* revision of the event.
|
||||||
*/
|
*/
|
||||||
void wait();
|
void wait() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::mutex m_mutex;
|
struct Status {
|
||||||
|
DxvkEventStatus status = DxvkEventStatus::Signaled;
|
||||||
|
uint32_t revision = 0;
|
||||||
|
};
|
||||||
|
|
||||||
DxvkEventStatus m_status = DxvkEventStatus::Signaled;
|
// Packed status and revision
|
||||||
uint32_t m_revision = 0;
|
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