mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-21 22:54:16 +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
|
// Return query and event handles
|
||||||
m_gpuQueryTracker.reset();
|
m_gpuQueryTracker.reset();
|
||||||
m_gpuEventTracker.reset();
|
|
||||||
|
|
||||||
// Less important stuff
|
// Less important stuff
|
||||||
m_signalTracker.reset();
|
m_signalTracker.reset();
|
||||||
|
@ -284,17 +284,10 @@ namespace dxvk {
|
|||||||
m_resources.trackSampler(sampler);
|
m_resources.trackSampler(sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void trackEvent(Rc<DxvkGpuEvent>&& event) {
|
||||||
* \brief Tracks a GPU event
|
m_resources.trackEvent(std::move(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Tracks a GPU query
|
* \brief Tracks a GPU query
|
||||||
*
|
*
|
||||||
@ -1082,7 +1075,6 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkLifetimeTracker m_resources;
|
DxvkLifetimeTracker m_resources;
|
||||||
DxvkSignalTracker m_signalTracker;
|
DxvkSignalTracker m_signalTracker;
|
||||||
DxvkGpuEventTracker m_gpuEventTracker;
|
|
||||||
DxvkGpuQueryTracker m_gpuQueryTracker;
|
DxvkGpuQueryTracker m_gpuQueryTracker;
|
||||||
DxvkStatCounters m_statCounters;
|
DxvkStatCounters m_statCounters;
|
||||||
|
|
||||||
|
@ -2470,22 +2470,21 @@ namespace dxvk {
|
|||||||
void DxvkContext::signalGpuEvent(const Rc<DxvkEvent>& event) {
|
void DxvkContext::signalGpuEvent(const Rc<DxvkEvent>& event) {
|
||||||
this->spillRenderPass(true);
|
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
|
// Supported client APIs can't access device memory in a defined manner
|
||||||
// without triggering a queue submission first, so we really only need
|
// without triggering a queue submission first, so we really only need
|
||||||
// to wait for prior commands, especially queries, to complete.
|
// to wait for prior commands, especially queries, to complete.
|
||||||
VkMemoryBarrier2 barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 };
|
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 };
|
VkDependencyInfo depInfo = { VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
|
||||||
depInfo.memoryBarrierCount = 1;
|
depInfo.memoryBarrierCount = 1;
|
||||||
depInfo.pMemoryBarriers = &barrier;
|
depInfo.pMemoryBarriers = &barrier;
|
||||||
|
|
||||||
m_cmd->cmdSetEvent(handle.event, &depInfo);
|
m_cmd->cmdSetEvent(gpuEvent->handle(), &depInfo);
|
||||||
|
m_cmd->trackEvent(std::move(gpuEvent));
|
||||||
m_cmd->trackGpuEvent(event->reset(handle));
|
|
||||||
m_cmd->trackResource<DxvkAccess::None>(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
Rc<DxvkEvent> DxvkDevice::createGpuEvent() {
|
Rc<DxvkEvent> DxvkDevice::createGpuEvent() {
|
||||||
return new DxvkEvent(m_vkd);
|
return new DxvkEvent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,34 +3,76 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkEvent::DxvkEvent(const Rc<vk::DeviceFn>& vkd)
|
DxvkGpuEvent::DxvkGpuEvent(
|
||||||
: m_vkd(vkd) { }
|
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 (vr != VK_SUCCESS)
|
||||||
if (m_handle.pool && m_handle.event)
|
throw DxvkError(str::format("Failed to create event: ", vr));
|
||||||
m_handle.pool->freeEvent(m_handle.event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkGpuEventStatus DxvkEvent::test() const {
|
DxvkGpuEvent::~DxvkGpuEvent() {
|
||||||
if (!m_handle.event)
|
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;
|
return DxvkGpuEventStatus::Invalid;
|
||||||
|
|
||||||
VkResult status = m_vkd->vkGetEventStatus(
|
// Query current event status and recycle
|
||||||
m_vkd->device(), m_handle.event);
|
// it as soon as a signal is observed.
|
||||||
|
auto vk = m_device->vkd();
|
||||||
switch (status) {
|
|
||||||
case VK_EVENT_SET: return DxvkGpuEventStatus::Signaled;
|
m_status = vk->vkGetEventStatus(
|
||||||
case VK_EVENT_RESET: return DxvkGpuEventStatus::Pending;
|
vk->device(), m_gpuEvent->handle());
|
||||||
default: return DxvkGpuEventStatus::Invalid;
|
|
||||||
|
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) {
|
void DxvkEvent::assignGpuEvent(
|
||||||
m_vkd->vkResetEvent(m_vkd->device(), handle.event);
|
Rc<DxvkGpuEvent> event) {
|
||||||
return std::exchange(m_handle, handle);
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
|
m_gpuEvent = std::move(event);
|
||||||
|
m_status = VK_NOT_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -41,61 +83,31 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
DxvkGpuEventPool::~DxvkGpuEventPool() {
|
DxvkGpuEventPool::~DxvkGpuEventPool() {
|
||||||
for (VkEvent ev : m_events)
|
for (auto e : m_freeEvents)
|
||||||
m_vkd->vkDestroyEvent(m_vkd->device(), ev, nullptr);
|
delete e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkGpuEventHandle DxvkGpuEventPool::allocEvent() {
|
Rc<DxvkGpuEvent> DxvkGpuEventPool::allocEvent() {
|
||||||
VkEvent event = VK_NULL_HANDLE;
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
{ std::lock_guard<dxvk::mutex> lock(m_mutex);
|
Rc<DxvkGpuEvent> event;
|
||||||
|
|
||||||
if (m_events.size() > 0) {
|
if (m_freeEvents.empty()) {
|
||||||
event = m_events.back();
|
event = new DxvkGpuEvent(this);
|
||||||
m_events.pop_back();
|
} else {
|
||||||
}
|
event = m_freeEvents.back();
|
||||||
|
m_freeEvents.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event) {
|
m_vkd->vkResetEvent(m_vkd->device(), event->handle());
|
||||||
VkEventCreateInfo info = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO };
|
return event;
|
||||||
|
|
||||||
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 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkGpuEventPool::freeEvent(VkEvent event) {
|
void DxvkGpuEventPool::freeEvent(DxvkGpuEvent* event) {
|
||||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
m_events.push_back(event);
|
m_freeEvents.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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dxvk_resource.h"
|
#include "dxvk_resource.h"
|
||||||
@ -29,9 +30,50 @@ namespace dxvk {
|
|||||||
* as a pointer to the pool that the event
|
* as a pointer to the pool that the event
|
||||||
* was allocated from.
|
* was allocated from.
|
||||||
*/
|
*/
|
||||||
struct DxvkGpuEventHandle {
|
class DxvkGpuEvent {
|
||||||
DxvkGpuEventPool* pool = nullptr;
|
|
||||||
VkEvent event = VK_NULL_HANDLE;
|
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
|
* the application to check whether a specific
|
||||||
* command has completed execution.
|
* command has completed execution.
|
||||||
*/
|
*/
|
||||||
class DxvkEvent : public DxvkResource {
|
class DxvkEvent {
|
||||||
|
friend class DxvkContext;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkEvent(const Rc<vk::DeviceFn>& vkd);
|
DxvkEvent(const Rc<DxvkDevice>& device);
|
||||||
~DxvkEvent();
|
~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
|
* \brief Retrieves event status
|
||||||
*
|
*
|
||||||
@ -56,24 +114,20 @@ namespace dxvk {
|
|||||||
* recorded intro a command buffer.
|
* recorded intro a command buffer.
|
||||||
* \returns Event status
|
* \returns Event status
|
||||||
*/
|
*/
|
||||||
DxvkGpuEventStatus test() const;
|
DxvkGpuEventStatus test();
|
||||||
|
|
||||||
/**
|
|
||||||
* \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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Rc<vk::DeviceFn> m_vkd;
|
std::atomic<uint32_t> m_refCount = { 0u };
|
||||||
DxvkGpuEventHandle m_handle;
|
|
||||||
|
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.
|
* a way to create and recycle Vulkan events.
|
||||||
*/
|
*/
|
||||||
class DxvkGpuEventPool {
|
class DxvkGpuEventPool {
|
||||||
|
friend class DxvkGpuEvent;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkGpuEventPool(const DxvkDevice* device);
|
DxvkGpuEventPool(const DxvkDevice* device);
|
||||||
@ -99,56 +153,22 @@ namespace dxvk {
|
|||||||
* state of the event is undefined.
|
* state of the event is undefined.
|
||||||
* \returns An event handle
|
* \returns An event handle
|
||||||
*/
|
*/
|
||||||
DxvkGpuEventHandle allocEvent();
|
Rc<DxvkGpuEvent> allocEvent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Recycles an event
|
* \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:
|
private:
|
||||||
|
|
||||||
Rc<vk::DeviceFn> m_vkd;
|
Rc<vk::DeviceFn> m_vkd;
|
||||||
dxvk::mutex m_mutex;
|
|
||||||
std::vector<VkEvent> m_events;
|
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_resources.clear();
|
||||||
m_allocations.clear();
|
m_allocations.clear();
|
||||||
m_samplers.clear();
|
m_samplers.clear();
|
||||||
|
m_events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dxvk_gpu_event.h"
|
||||||
#include "dxvk_resource.h"
|
#include "dxvk_resource.h"
|
||||||
#include "dxvk_sampler.h"
|
#include "dxvk_sampler.h"
|
||||||
|
|
||||||
@ -115,6 +116,14 @@ namespace dxvk {
|
|||||||
m_samplers.push_back(res);
|
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
|
* \brief Adds a resource to track
|
||||||
* \param [in] res The resource to track
|
* \param [in] res The resource to track
|
||||||
@ -142,6 +151,7 @@ namespace dxvk {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
std::vector<Rc<DxvkSampler>> m_samplers;
|
std::vector<Rc<DxvkSampler>> m_samplers;
|
||||||
|
std::vector<Rc<DxvkGpuEvent>> m_events;
|
||||||
|
|
||||||
std::vector<DxvkLifetime<DxvkResource>> m_resources;
|
std::vector<DxvkLifetime<DxvkResource>> m_resources;
|
||||||
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
|
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user