mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-31 14:52:11 +01:00
[dxvk] Add DxvkFence
Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
This commit is contained in:
parent
a40724aaf8
commit
446ec07f3b
@ -129,6 +129,12 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkFence> DxvkDevice::createFence(
|
||||
const DxvkFenceCreateInfo& fenceInfo) {
|
||||
return new DxvkFence(this, fenceInfo);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> DxvkDevice::createBuffer(
|
||||
const DxvkBufferCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "dxvk_constant_state.h"
|
||||
#include "dxvk_context.h"
|
||||
#include "dxvk_extensions.h"
|
||||
#include "dxvk_fence.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_image.h"
|
||||
#include "dxvk_instance.h"
|
||||
@ -269,6 +270,15 @@ namespace dxvk {
|
||||
VkQueryControlFlags flags,
|
||||
uint32_t index);
|
||||
|
||||
/**
|
||||
* \brief Creates new fence
|
||||
*
|
||||
* \param [in] info Fence create info
|
||||
* \returns The fence
|
||||
*/
|
||||
Rc<DxvkFence> createFence(
|
||||
const DxvkFenceCreateInfo& fenceInfo);
|
||||
|
||||
/**
|
||||
* \brief Creates a buffer object
|
||||
*
|
||||
|
95
src/dxvk/dxvk_fence.cpp
Normal file
95
src/dxvk/dxvk_fence.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "dxvk_device.h"
|
||||
#include "dxvk_fence.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkFence::DxvkFence(
|
||||
DxvkDevice* device,
|
||||
const DxvkFenceCreateInfo& info)
|
||||
: m_vkd(device->vkd()), m_info(info) {
|
||||
VkSemaphoreTypeCreateInfo typeInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO };
|
||||
typeInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
|
||||
typeInfo.initialValue = info.initialValue;
|
||||
|
||||
VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &typeInfo };
|
||||
|
||||
VkResult vr = m_vkd->vkCreateSemaphore(m_vkd->device(),
|
||||
&semaphoreInfo, nullptr, &m_semaphore);
|
||||
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError("Failed to create timeline semaphore");
|
||||
|
||||
m_thread = dxvk::thread([this] { run(); });
|
||||
}
|
||||
|
||||
|
||||
DxvkFence::~DxvkFence() {
|
||||
m_stop.store(true);
|
||||
m_thread.join();
|
||||
|
||||
m_vkd->vkDestroySemaphore(m_vkd->device(), m_semaphore, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void DxvkFence::enqueueWait(uint64_t value, DxvkFenceEvent&& event) {
|
||||
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
if (value > m_lastValue.load())
|
||||
m_queue.emplace(value, std::move(event));
|
||||
else
|
||||
event();
|
||||
}
|
||||
|
||||
|
||||
void DxvkFence::run() {
|
||||
uint64_t value = 0ull;
|
||||
|
||||
VkSemaphoreWaitInfo waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO };
|
||||
waitInfo.semaphoreCount = 1;
|
||||
waitInfo.pSemaphores = &m_semaphore;
|
||||
waitInfo.pValues = &value;
|
||||
|
||||
while (!m_stop.load()) {
|
||||
std::unique_lock<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
// Query actual semaphore value and start from there, so that
|
||||
// we can skip over large increments in the semaphore value
|
||||
VkResult vr = m_vkd->vkGetSemaphoreCounterValue(m_vkd->device(), m_semaphore, &value);
|
||||
|
||||
if (vr != VK_SUCCESS) {
|
||||
Logger::err(str::format("Failed to query semaphore value: ", vr));
|
||||
return;
|
||||
}
|
||||
|
||||
m_lastValue.store(value);
|
||||
|
||||
// Signal all enqueued events whose value is not greater than
|
||||
// the current semaphore value
|
||||
while (!m_queue.empty() && m_queue.top().value <= value) {
|
||||
m_queue.top().event();
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
if (m_stop)
|
||||
return;
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// Wait for the semaphore to be singaled again and update state.
|
||||
// The timeout is unfortunate, but we can't always know when a
|
||||
// signal operation has been recorded, and the alternative would
|
||||
// be to create a teardown semaphore and use WAIT_ANY, which may
|
||||
// be fall back to a busy-wait loop on some drivers.
|
||||
value += 1;
|
||||
|
||||
vr = m_vkd->vkWaitSemaphores(
|
||||
m_vkd->device(), &waitInfo, 10'000'000ull);
|
||||
|
||||
if (vr != VK_SUCCESS && vr != VK_TIMEOUT) {
|
||||
Logger::err(str::format("Failed to wait for semaphore: ", vr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
97
src/dxvk/dxvk_fence.h
Normal file
97
src/dxvk/dxvk_fence.h
Normal file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
#include "../util/thread.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkDevice;
|
||||
|
||||
using DxvkFenceEvent = std::function<void ()>;
|
||||
|
||||
/**
|
||||
* \brief Fence create info
|
||||
*/
|
||||
struct DxvkFenceCreateInfo {
|
||||
uint64_t initialValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Fence
|
||||
*
|
||||
* Wrapper around Vulkan timeline semaphores that
|
||||
* can signal an event when the value changes.
|
||||
*/
|
||||
class DxvkFence : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkFence(
|
||||
DxvkDevice* device,
|
||||
const DxvkFenceCreateInfo& info);
|
||||
|
||||
~DxvkFence();
|
||||
|
||||
/**
|
||||
* \brief Semaphore handle
|
||||
*/
|
||||
VkSemaphore handle() const {
|
||||
return m_semaphore;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves current semaphore value
|
||||
* \returns Current semaphore value
|
||||
*/
|
||||
uint64_t getValue() {
|
||||
return m_lastValue.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enqueues semaphore wait
|
||||
*
|
||||
* Signals the given event when the
|
||||
* semaphore reaches the given value.
|
||||
* \param [in] value Enqueue value
|
||||
* \param [in] event Callback
|
||||
*/
|
||||
void enqueueWait(uint64_t value, DxvkFenceEvent&& event);
|
||||
|
||||
private:
|
||||
|
||||
struct QueueItem {
|
||||
QueueItem() { }
|
||||
QueueItem(uint32_t v, DxvkFenceEvent&& e)
|
||||
: value(v), event(std::move(e)) { }
|
||||
|
||||
uint64_t value;
|
||||
DxvkFenceEvent event;
|
||||
|
||||
bool operator == (const QueueItem& item) const { return value == item.value; }
|
||||
bool operator != (const QueueItem& item) const { return value != item.value; }
|
||||
bool operator < (const QueueItem& item) const { return value < item.value; }
|
||||
bool operator <= (const QueueItem& item) const { return value <= item.value; }
|
||||
bool operator > (const QueueItem& item) const { return value > item.value; }
|
||||
bool operator >= (const QueueItem& item) const { return value >= item.value; }
|
||||
};
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkFenceCreateInfo m_info;
|
||||
VkSemaphore m_semaphore;
|
||||
|
||||
std::priority_queue<QueueItem> m_queue;
|
||||
std::atomic<uint64_t> m_lastValue = { 0ull };
|
||||
std::atomic<bool> m_stop = { false };
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
dxvk::thread m_thread;
|
||||
|
||||
void run();
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -73,6 +73,7 @@ dxvk_src = files([
|
||||
'dxvk_device.cpp',
|
||||
'dxvk_device_filter.cpp',
|
||||
'dxvk_extensions.cpp',
|
||||
'dxvk_fence.cpp',
|
||||
'dxvk_format.cpp',
|
||||
'dxvk_framebuffer.cpp',
|
||||
'dxvk_gpu_event.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user