1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-13 19:29:14 +01:00

[dxvk] Add GPU event class

GPU events allow for finer-grained CPU<>GPU synchronization than
the current approach, so we should change our implementation.
This commit is contained in:
Philip Rebohle 2018-11-16 23:40:24 +01:00
parent 7fa2fb5188
commit 4da89ccc48
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 257 additions and 0 deletions

103
src/dxvk/dxvk_gpu_event.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "dxvk_gpu_event.h"
namespace dxvk {
DxvkGpuEvent::DxvkGpuEvent(const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) { }
DxvkGpuEvent::~DxvkGpuEvent() {
if (m_handle.pool && m_handle.event)
m_handle.pool->freeEvent(m_handle.event);
}
DxvkGpuEventStatus DxvkGpuEvent::test() const {
if (!m_handle.event)
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;
}
}
DxvkGpuEventHandle DxvkGpuEvent::reset(DxvkGpuEventHandle handle) {
m_vkd->vkResetEvent(m_vkd->device(), handle.event);
return std::exchange(m_handle, handle);
}
DxvkGpuEventPool::DxvkGpuEventPool(const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) { }
DxvkGpuEventPool::~DxvkGpuEventPool() {
for (VkEvent ev : m_events)
m_vkd->vkDestroyEvent(m_vkd->device(), ev, nullptr);
}
DxvkGpuEventHandle DxvkGpuEventPool::allocEvent() {
VkEvent event = VK_NULL_HANDLE;
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
if (m_events.size() > 0) {
event = m_events.back();
m_events.pop_back();
}
}
if (!event) {
VkEventCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
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) {
std::lock_guard<sync::Spinlock> 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();
}
}

153
src/dxvk/dxvk_gpu_event.h Normal file
View File

@ -0,0 +1,153 @@
#pragma once
#include <vector>
#include "dxvk_resource.h"
namespace dxvk {
class DxvkGpuEventPool;
/**
* \brief Event status
*
* Reports whether the event is in
* a signaled or unsignaled state.
*/
enum class DxvkGpuEventStatus : uint32_t {
Invalid = 0,
Pending = 1,
Signaled = 2,
};
/**
* \brief Event handle
*
* Stores the event handle itself as well
* as a pointer to the pool that the event
* was allocated from.
*/
struct DxvkGpuEventHandle {
DxvkGpuEventPool* pool = nullptr;
VkEvent event = VK_NULL_HANDLE;
};
/**
* \brief GPU event
*
* An event managed by the GPU which allows
* the application to check whether a specific
* command has completed execution.
*/
class DxvkGpuEvent : public DxvkResource {
public:
DxvkGpuEvent(const Rc<vk::DeviceFn>& vkd);
~DxvkGpuEvent();
/**
* \brief Retrieves event status
*
* Only valid after the event has been
* 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);
private:
Rc<vk::DeviceFn> m_vkd;
DxvkGpuEventHandle m_handle;
};
/**
* \brief Event pool
*
* Thread-safe event allocator that provides
* a way to create and recycle Vulkan events.
*/
class DxvkGpuEventPool : public RcObject {
public:
DxvkGpuEventPool(const Rc<vk::DeviceFn>& vkd);
~DxvkGpuEventPool();
/**
* \brief Allocates an event
*
* Either returns a recycled event, or
* creates a new one if necessary. The
* state of the event is undefined.
* \returns An event handle
*/
DxvkGpuEventHandle allocEvent();
/**
* \brief Recycles an event
*
* \param [in] handle Event to free
*/
void freeEvent(VkEvent event);
private:
Rc<vk::DeviceFn> m_vkd;
sync::Spinlock m_mutex;
std::vector<VkEvent> m_events;
};
/**
* \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;
};
}

View File

@ -55,6 +55,7 @@ dxvk_src = files([
'dxvk_event.cpp',
'dxvk_format.cpp',
'dxvk_framebuffer.cpp',
'dxvk_gpu_event.cpp',
'dxvk_graphics.cpp',
'dxvk_image.cpp',
'dxvk_instance.cpp',