1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-21 04:54:15 +01:00

[dxvk] Introduce DxvkTrackingRef and new tracking functions

The intention here is to clean up the code significantly while also
paving a way to perform more complex operations on resource release.
This commit is contained in:
Philip Rebohle 2024-10-17 16:04:49 +02:00 committed by Philip Rebohle
parent 56e8d55830
commit 4a00623c40
8 changed files with 221 additions and 1 deletions

40
src/dxvk/dxvk_access.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "dxvk_access.h"
namespace dxvk {
DxvkObjectTracker::DxvkObjectTracker() {
m_head = std::make_unique<List>();
m_next = m_head.get();
}
DxvkObjectTracker::~DxvkObjectTracker() {
// List should be empty unless something bad has already happened
clear();
}
void DxvkObjectTracker::clear() {
List* list = nullptr;
for (size_t i = 0; i < m_size; i++) {
if (!(i & ListMask))
list = list ? list->next.get() : m_head.get();
auto* ref = std::launder(reinterpret_cast<DxvkTrackingRef*>(list->storage[i & ListMask].data));
ref->~DxvkTrackingRef();
}
m_next = m_head.get();
m_size = 0u;
}
void DxvkObjectTracker::advanceList() {
if (!m_next->next)
m_next->next = std::make_unique<List>();
m_next = m_next->next.get();
}
}

View File

@ -1,7 +1,14 @@
#pragma once
#include <array>
#include <cstdint>
#include <memory>
#include <utility>
#include "../util/util_flags.h"
#include "../util/rc/util_rc_ptr.h"
namespace dxvk {
/**
@ -15,4 +22,99 @@ namespace dxvk {
using DxvkAccessFlags = Flags<DxvkAccess>;
/**
* \brief Tracking reference
*
* Virtual base class for tracking references. The destructor
* of each subclass is responsible for releasing the tracked
* object in an implementation-defined manner.
*/
class DxvkTrackingRef {
public:
/**
* \brief Releases tracked object and destroys reference
*
* This is essentially a destructor with a parameter, and
* subclasses \e must invoke their own destructor here.
* \param [in] submission Last completed GPU submission
*/
virtual ~DxvkTrackingRef() { }
};
/**
* \brief Tracking reference storage
*
* Provides storage for the bae object and an additional pointer.
* All tracking references must be compatible with this layout.
*/
struct DxvkTrackingRefStorage {
alignas(DxvkTrackingRef)
char data[sizeof(DxvkTrackingRef) + sizeof(void*)];
};
/**
* \brief Typed tracking reference for normal ref-counted object
*/
template<typename T>
class DxvkObjectRef : public DxvkTrackingRef {
public:
explicit DxvkObjectRef(Rc<T>&& object)
: m_object(std::move(object)) { }
private:
Rc<T> m_object;
};
/**
* \brief Object tracker
*
* Stores tracking references which keep objects alive until the GPU
* is done using them. Uses a list of arrays in order to avoid having
* to move or copy the stored references at any time.
*/
class DxvkObjectTracker {
constexpr static size_t ListCapacity = 1024;
constexpr static size_t ListMask = ListCapacity - 1u;
public:
DxvkObjectTracker();
~DxvkObjectTracker();
template<typename T, typename... Args>
force_inline void track(Args&&... args) {
new (m_next->storage[(m_size++) & ListMask].data) T(std::forward<Args>(args)...);
if (unlikely(!(m_size & ListMask)))
advanceList();
}
void clear();
private:
struct List {
std::array<DxvkTrackingRefStorage, ListCapacity> storage = { };
std::unique_ptr<List> next;
};
std::unique_ptr<List> m_head;
List* m_next = nullptr;
size_t m_size = 0u;
void advanceList();
};
}

View File

@ -367,6 +367,7 @@ namespace dxvk {
// Free resources and other objects
// that are no longer in use
m_resources.reset();
m_objectTracker.clear();
// Less important stuff
m_signalTracker.reset();

View File

@ -290,6 +290,42 @@ namespace dxvk {
m_resources.trackQuery(std::move(query));
}
/**
* \brief Tracks an object
*
* Keeps the object alive until the command list finishes
* execution on the GPU.
* \param [in] object Object to track
*/
template<typename T>
void track(Rc<T> object) {
m_objectTracker.track<DxvkObjectRef<T>>(std::move(object));
}
/**
* \brief Tracks a resource with access mode
*
* Keeps the object alive and tracks resource access for
* the purpoe of CPU access synchronization. The different
* overloads try to reduce atomic operations.
* \param [in] object Object to track
* \param [in] access Resource access mode
*/
template<typename T>
void track(Rc<T>&& object, DxvkAccess access) {
m_objectTracker.track<DxvkResourceRef>(std::move(object), access);
}
template<typename T>
void track(const Rc<T>& object, DxvkAccess access) {
m_objectTracker.track<DxvkResourceRef>(object.ptr(), access);
}
template<typename T>
void track(T* object, DxvkAccess access) {
m_objectTracker.track<DxvkResourceRef>(object, access);
}
/**
* \brief Tracks a graphics pipeline
* \param [in] pipeline Pipeline
@ -316,6 +352,7 @@ namespace dxvk {
*/
void notifyObjects() {
m_resources.reset();
m_objectTracker.clear();
m_signalTracker.notify();
}
@ -1064,6 +1101,8 @@ namespace dxvk {
PresenterSync m_wsiSemaphores = { };
DxvkObjectTracker m_objectTracker;
DxvkLifetimeTracker m_resources;
DxvkSignalTracker m_signalTracker;
DxvkStatCounters m_statCounters;

View File

@ -126,4 +126,4 @@ namespace dxvk {
};
}
}

View File

@ -7,6 +7,12 @@
namespace dxvk {
DxvkResourceRef::~DxvkResourceRef() {
auto resource = reinterpret_cast<DxvkPagedResource*>(m_ptr & ~AccessMask);
resource->release(DxvkAccess(m_ptr & AccessMask));
}
DxvkSparseMapping::DxvkSparseMapping()
: m_pool(nullptr),
m_page(nullptr) {

View File

@ -446,6 +446,37 @@ namespace dxvk {
};
/**
* \brief Typed tracking reference for resources
*
* Does not provide any access information.
*/
class DxvkResourceRef : public DxvkTrackingRef {
constexpr static uintptr_t AccessMask = 0x3u;
static_assert(alignof(DxvkPagedResource) > AccessMask);
public:
template<typename T>
explicit DxvkResourceRef(Rc<T>&& object, DxvkAccess access)
: m_ptr(reinterpret_cast<uintptr_t>(static_cast<DxvkPagedResource*>(object.ptr())) | uintptr_t(access)) {
object.unsafeExtract()->convertRef(DxvkAccess::None, access);
}
explicit DxvkResourceRef(DxvkPagedResource* object, DxvkAccess access)
: m_ptr(reinterpret_cast<uintptr_t>(object) | uintptr_t(access)) {
object->acquire(access);
}
~DxvkResourceRef();
private:
uintptr_t m_ptr = 0u;
};
/**
* \brief Key for sparse buffer binding entry
*

View File

@ -66,6 +66,7 @@ dxvk_shaders = files([
])
dxvk_src = [
'dxvk_access.cpp',
'dxvk_adapter.cpp',
'dxvk_allocator.cpp',
'dxvk_barrier.cpp',