mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[dxvk] Refactor events to be properly ref-counted
Mostly serves as a proof-of-concept for the pending query rework, but also cleans up some silly code.
This commit is contained in:
parent
d00669cb52
commit
1b9c59c964
@ -370,7 +370,6 @@ namespace dxvk {
|
||||
|
||||
// Return query and event handles
|
||||
m_gpuQueryTracker.reset();
|
||||
m_gpuEventTracker.reset();
|
||||
|
||||
// Less important stuff
|
||||
m_signalTracker.reset();
|
||||
|
@ -284,17 +284,10 @@ namespace dxvk {
|
||||
m_resources.trackSampler(sampler);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Tracks a GPU event
|
||||
*
|
||||
* The event will be returned to its event pool
|
||||
* after the command buffer has finished executing.
|
||||
* \param [in] handle Event handle
|
||||
*/
|
||||
void trackGpuEvent(DxvkGpuEventHandle handle) {
|
||||
m_gpuEventTracker.trackEvent(handle);
|
||||
void trackEvent(Rc<DxvkGpuEvent>&& event) {
|
||||
m_resources.trackEvent(std::move(event));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Tracks a GPU query
|
||||
*
|
||||
@ -1082,7 +1075,6 @@ namespace dxvk {
|
||||
|
||||
DxvkLifetimeTracker m_resources;
|
||||
DxvkSignalTracker m_signalTracker;
|
||||
DxvkGpuEventTracker m_gpuEventTracker;
|
||||
DxvkGpuQueryTracker m_gpuQueryTracker;
|
||||
DxvkStatCounters m_statCounters;
|
||||
|
||||
|
@ -2470,22 +2470,21 @@ namespace dxvk {
|
||||
void DxvkContext::signalGpuEvent(const Rc<DxvkEvent>& event) {
|
||||
this->spillRenderPass(true);
|
||||
|
||||
DxvkGpuEventHandle handle = m_common->eventPool().allocEvent();
|
||||
Rc<DxvkGpuEvent> gpuEvent = m_common->eventPool().allocEvent();
|
||||
event->assignGpuEvent(gpuEvent);
|
||||
|
||||
// Supported client APIs can't access device memory in a defined manner
|
||||
// without triggering a queue submission first, so we really only need
|
||||
// to wait for prior commands, especially queries, to complete.
|
||||
VkMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 };
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
||||
|
||||
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||
depInfo.memoryBarrierCount = 1;
|
||||
depInfo.pMemoryBarriers = &barrier;
|
||||
|
||||
m_cmd->cmdSetEvent(handle.event, &depInfo);
|
||||
|
||||
m_cmd->trackGpuEvent(event->reset(handle));
|
||||
m_cmd->trackResource<DxvkAccess::None>(event);
|
||||
m_cmd->cmdSetEvent(gpuEvent->handle(), &depInfo);
|
||||
m_cmd->trackEvent(std::move(gpuEvent));
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
Rc<DxvkEvent> DxvkDevice::createGpuEvent() {
|
||||
return new DxvkEvent(m_vkd);
|
||||
return new DxvkEvent(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,34 +3,76 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkEvent::DxvkEvent(const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) { }
|
||||
DxvkGpuEvent::DxvkGpuEvent(
|
||||
DxvkGpuEventPool* parent)
|
||||
: m_pool(parent) {
|
||||
auto vk = m_pool->m_vkd;
|
||||
|
||||
VkEventCreateInfo info = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO };
|
||||
VkResult vr = vk->vkCreateEvent(vk->device(), &info, nullptr, &m_event);
|
||||
|
||||
DxvkEvent::~DxvkEvent() {
|
||||
if (m_handle.pool && m_handle.event)
|
||||
m_handle.pool->freeEvent(m_handle.event);
|
||||
if (vr != VK_SUCCESS)
|
||||
throw DxvkError(str::format("Failed to create event: ", vr));
|
||||
}
|
||||
|
||||
|
||||
DxvkGpuEventStatus DxvkEvent::test() const {
|
||||
if (!m_handle.event)
|
||||
DxvkGpuEvent::~DxvkGpuEvent() {
|
||||
auto vk = m_pool->m_vkd;
|
||||
vk->vkDestroyEvent(vk->device(), m_event, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void DxvkGpuEvent::free() {
|
||||
m_pool->freeEvent(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DxvkEvent::DxvkEvent(const Rc<DxvkDevice>& device)
|
||||
: m_device(device) { }
|
||||
|
||||
|
||||
DxvkEvent::~DxvkEvent() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkGpuEventStatus DxvkEvent::test() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_status == VK_EVENT_SET)
|
||||
return DxvkGpuEventStatus::Signaled;
|
||||
|
||||
if (!m_gpuEvent)
|
||||
return DxvkGpuEventStatus::Invalid;
|
||||
|
||||
VkResult status = m_vkd->vkGetEventStatus(
|
||||
m_vkd->device(), m_handle.event);
|
||||
|
||||
switch (status) {
|
||||
case VK_EVENT_SET: return DxvkGpuEventStatus::Signaled;
|
||||
case VK_EVENT_RESET: return DxvkGpuEventStatus::Pending;
|
||||
default: return DxvkGpuEventStatus::Invalid;
|
||||
|
||||
// Query current event status and recycle
|
||||
// it as soon as a signal is observed.
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
m_status = vk->vkGetEventStatus(
|
||||
vk->device(), m_gpuEvent->handle());
|
||||
|
||||
switch (m_status) {
|
||||
case VK_EVENT_SET:
|
||||
m_gpuEvent = nullptr;
|
||||
return DxvkGpuEventStatus::Signaled;
|
||||
|
||||
case VK_EVENT_RESET:
|
||||
return DxvkGpuEventStatus::Pending;
|
||||
|
||||
default:
|
||||
return DxvkGpuEventStatus::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxvkGpuEventHandle DxvkEvent::reset(DxvkGpuEventHandle handle) {
|
||||
m_vkd->vkResetEvent(m_vkd->device(), handle.event);
|
||||
return std::exchange(m_handle, handle);
|
||||
void DxvkEvent::assignGpuEvent(
|
||||
Rc<DxvkGpuEvent> event) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
m_gpuEvent = std::move(event);
|
||||
m_status = VK_NOT_READY;
|
||||
}
|
||||
|
||||
|
||||
@ -41,61 +83,31 @@ namespace dxvk {
|
||||
|
||||
|
||||
DxvkGpuEventPool::~DxvkGpuEventPool() {
|
||||
for (VkEvent ev : m_events)
|
||||
m_vkd->vkDestroyEvent(m_vkd->device(), ev, nullptr);
|
||||
for (auto e : m_freeEvents)
|
||||
delete e;
|
||||
}
|
||||
|
||||
|
||||
DxvkGpuEventHandle DxvkGpuEventPool::allocEvent() {
|
||||
VkEvent event = VK_NULL_HANDLE;
|
||||
Rc<DxvkGpuEvent> DxvkGpuEventPool::allocEvent() {
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
{ std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
|
||||
if (m_events.size() > 0) {
|
||||
event = m_events.back();
|
||||
m_events.pop_back();
|
||||
}
|
||||
Rc<DxvkGpuEvent> event;
|
||||
|
||||
if (m_freeEvents.empty()) {
|
||||
event = new DxvkGpuEvent(this);
|
||||
} else {
|
||||
event = m_freeEvents.back();
|
||||
m_freeEvents.pop_back();
|
||||
}
|
||||
|
||||
if (!event) {
|
||||
VkEventCreateInfo info = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO };
|
||||
|
||||
VkResult status = m_vkd->vkCreateEvent(
|
||||
m_vkd->device(), &info, nullptr, &event);
|
||||
|
||||
if (status != VK_SUCCESS) {
|
||||
Logger::err("DXVK: Failed to create GPU event");
|
||||
return DxvkGpuEventHandle();
|
||||
}
|
||||
}
|
||||
|
||||
return { this, event };
|
||||
m_vkd->vkResetEvent(m_vkd->device(), event->handle());
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
void DxvkGpuEventPool::freeEvent(VkEvent event) {
|
||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||
m_events.push_back(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DxvkGpuEventTracker::DxvkGpuEventTracker() { }
|
||||
DxvkGpuEventTracker::~DxvkGpuEventTracker() { }
|
||||
|
||||
|
||||
void DxvkGpuEventTracker::trackEvent(DxvkGpuEventHandle handle) {
|
||||
if (handle.pool && handle.event)
|
||||
m_handles.push_back(handle);
|
||||
}
|
||||
|
||||
|
||||
void DxvkGpuEventTracker::reset() {
|
||||
for (const auto& h : m_handles)
|
||||
h.pool->freeEvent(h.event);
|
||||
|
||||
m_handles.clear();
|
||||
void DxvkGpuEventPool::freeEvent(DxvkGpuEvent* event) {
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_freeEvents.push_back(event);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_resource.h"
|
||||
@ -29,9 +30,50 @@ namespace dxvk {
|
||||
* as a pointer to the pool that the event
|
||||
* was allocated from.
|
||||
*/
|
||||
struct DxvkGpuEventHandle {
|
||||
DxvkGpuEventPool* pool = nullptr;
|
||||
VkEvent event = VK_NULL_HANDLE;
|
||||
class DxvkGpuEvent {
|
||||
|
||||
public:
|
||||
|
||||
explicit DxvkGpuEvent(
|
||||
DxvkGpuEventPool* parent);
|
||||
|
||||
~DxvkGpuEvent();
|
||||
|
||||
/**
|
||||
* \brief Increments ref count
|
||||
*/
|
||||
void incRef() {
|
||||
m_refs.fetch_add(1u, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decrements ref count
|
||||
*
|
||||
* Returns event to the pool if no further
|
||||
* references exist for this event.
|
||||
*/
|
||||
void decRef() {
|
||||
if (m_refs.fetch_sub(1u, std::memory_order_release) == 1u)
|
||||
free();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Queries event handle
|
||||
* \returns Event handle
|
||||
*/
|
||||
VkEvent handle() const {
|
||||
return m_event;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxvkGpuEventPool* m_pool = nullptr;
|
||||
VkEvent m_event = VK_NULL_HANDLE;
|
||||
|
||||
std::atomic<uint32_t> m_refs = { 0u };
|
||||
|
||||
void free();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -42,13 +84,29 @@ namespace dxvk {
|
||||
* the application to check whether a specific
|
||||
* command has completed execution.
|
||||
*/
|
||||
class DxvkEvent : public DxvkResource {
|
||||
|
||||
class DxvkEvent {
|
||||
friend class DxvkContext;
|
||||
public:
|
||||
|
||||
DxvkEvent(const Rc<vk::DeviceFn>& vkd);
|
||||
DxvkEvent(const Rc<DxvkDevice>& device);
|
||||
~DxvkEvent();
|
||||
|
||||
/**
|
||||
* \brief Increments reference count
|
||||
*/
|
||||
force_inline void incRef() {
|
||||
m_refCount.fetch_add(1u, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decrements reference count
|
||||
* Frees the event as necessary.
|
||||
*/
|
||||
force_inline void decRef() {
|
||||
if (m_refCount.fetch_sub(1u, std::memory_order_release) == 1u)
|
||||
delete this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves event status
|
||||
*
|
||||
@ -56,24 +114,20 @@ namespace dxvk {
|
||||
* recorded intro a command buffer.
|
||||
* \returns Event status
|
||||
*/
|
||||
DxvkGpuEventStatus test() const;
|
||||
|
||||
/**
|
||||
* \brief Resets event
|
||||
*
|
||||
* Assigns a new Vulkan event to this event
|
||||
* object and replaces the old one. The old
|
||||
* event should be freed as soon as the GPU
|
||||
* stops using it.
|
||||
* \param [in] handle New GPU event handle
|
||||
* \returns Old GPU event handle
|
||||
*/
|
||||
DxvkGpuEventHandle reset(DxvkGpuEventHandle handle);
|
||||
DxvkGpuEventStatus test();
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkGpuEventHandle m_handle;
|
||||
std::atomic<uint32_t> m_refCount = { 0u };
|
||||
|
||||
sync::Spinlock m_mutex;
|
||||
VkResult m_status = VK_NOT_READY;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkGpuEvent> m_gpuEvent;
|
||||
|
||||
void assignGpuEvent(
|
||||
Rc<DxvkGpuEvent> event);
|
||||
|
||||
};
|
||||
|
||||
@ -85,7 +139,7 @@ namespace dxvk {
|
||||
* a way to create and recycle Vulkan events.
|
||||
*/
|
||||
class DxvkGpuEventPool {
|
||||
|
||||
friend class DxvkGpuEvent;
|
||||
public:
|
||||
|
||||
DxvkGpuEventPool(const DxvkDevice* device);
|
||||
@ -99,56 +153,22 @@ namespace dxvk {
|
||||
* state of the event is undefined.
|
||||
* \returns An event handle
|
||||
*/
|
||||
DxvkGpuEventHandle allocEvent();
|
||||
Rc<DxvkGpuEvent> allocEvent();
|
||||
|
||||
/**
|
||||
* \brief Recycles an event
|
||||
*
|
||||
* \param [in] handle Event to free
|
||||
* \param [in] event Event object to free
|
||||
*/
|
||||
void freeEvent(VkEvent event);
|
||||
void freeEvent(DxvkGpuEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
dxvk::mutex m_mutex;
|
||||
std::vector<VkEvent> m_events;
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
dxvk::mutex m_mutex;
|
||||
std::vector<DxvkGpuEvent*> m_freeEvents;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief GPU event tracker
|
||||
*
|
||||
* Stores events currently accessed by the
|
||||
* GPU, and returns them to the event pool
|
||||
* once they are no longer in use.
|
||||
*/
|
||||
class DxvkGpuEventTracker {
|
||||
|
||||
public:
|
||||
|
||||
DxvkGpuEventTracker();
|
||||
~DxvkGpuEventTracker();
|
||||
|
||||
/**
|
||||
* \brief Tracks an event
|
||||
* \param [in] handle Event to track
|
||||
*/
|
||||
void trackEvent(DxvkGpuEventHandle handle);
|
||||
|
||||
/**
|
||||
* \brief Resets event tracker
|
||||
*
|
||||
* Releases all tracked events back
|
||||
* to the respective event pool
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
std::vector<DxvkGpuEventHandle> m_handles;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ namespace dxvk {
|
||||
m_resources.clear();
|
||||
m_allocations.clear();
|
||||
m_samplers.clear();
|
||||
m_events.clear();
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "dxvk_gpu_event.h"
|
||||
#include "dxvk_resource.h"
|
||||
#include "dxvk_sampler.h"
|
||||
|
||||
@ -115,6 +116,14 @@ namespace dxvk {
|
||||
m_samplers.push_back(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds an event to track
|
||||
* \param [in] res The event to track
|
||||
*/
|
||||
void trackEvent(Rc<DxvkGpuEvent>&& event) {
|
||||
m_events.push_back(std::move(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds a resource to track
|
||||
* \param [in] res The resource to track
|
||||
@ -142,6 +151,7 @@ namespace dxvk {
|
||||
private:
|
||||
|
||||
std::vector<Rc<DxvkSampler>> m_samplers;
|
||||
std::vector<Rc<DxvkGpuEvent>> m_events;
|
||||
|
||||
std::vector<DxvkLifetime<DxvkResource>> m_resources;
|
||||
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
|
||||
|
Loading…
x
Reference in New Issue
Block a user