mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-07 16:54:14 +01:00
[dxvk] Add DxvkFence
Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
This commit is contained in:
parent
a40724aaf8
commit
446ec07f3b
@ -127,8 +127,14 @@ namespace dxvk {
|
|||||||
uint32_t index) {
|
uint32_t index) {
|
||||||
return new DxvkGpuQuery(m_vkd, type, flags, index);
|
return new DxvkGpuQuery(m_vkd, type, flags, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rc<DxvkFence> DxvkDevice::createFence(
|
||||||
|
const DxvkFenceCreateInfo& fenceInfo) {
|
||||||
|
return new DxvkFence(this, fenceInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Rc<DxvkBuffer> DxvkDevice::createBuffer(
|
Rc<DxvkBuffer> DxvkDevice::createBuffer(
|
||||||
const DxvkBufferCreateInfo& createInfo,
|
const DxvkBufferCreateInfo& createInfo,
|
||||||
VkMemoryPropertyFlags memoryType) {
|
VkMemoryPropertyFlags memoryType) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "dxvk_constant_state.h"
|
#include "dxvk_constant_state.h"
|
||||||
#include "dxvk_context.h"
|
#include "dxvk_context.h"
|
||||||
#include "dxvk_extensions.h"
|
#include "dxvk_extensions.h"
|
||||||
|
#include "dxvk_fence.h"
|
||||||
#include "dxvk_framebuffer.h"
|
#include "dxvk_framebuffer.h"
|
||||||
#include "dxvk_image.h"
|
#include "dxvk_image.h"
|
||||||
#include "dxvk_instance.h"
|
#include "dxvk_instance.h"
|
||||||
@ -269,6 +270,15 @@ namespace dxvk {
|
|||||||
VkQueryControlFlags flags,
|
VkQueryControlFlags flags,
|
||||||
uint32_t index);
|
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
|
* \brief Creates a buffer object
|
||||||
*
|
*
|
||||||
@ -495,4 +505,4 @@ namespace dxvk {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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.cpp',
|
||||||
'dxvk_device_filter.cpp',
|
'dxvk_device_filter.cpp',
|
||||||
'dxvk_extensions.cpp',
|
'dxvk_extensions.cpp',
|
||||||
|
'dxvk_fence.cpp',
|
||||||
'dxvk_format.cpp',
|
'dxvk_format.cpp',
|
||||||
'dxvk_framebuffer.cpp',
|
'dxvk_framebuffer.cpp',
|
||||||
'dxvk_gpu_event.cpp',
|
'dxvk_gpu_event.cpp',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user