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:
parent
56e8d55830
commit
4a00623c40
40
src/dxvk/dxvk_access.cpp
Normal file
40
src/dxvk/dxvk_access.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -126,4 +126,4 @@ namespace dxvk {
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -66,6 +66,7 @@ dxvk_shaders = files([
|
||||
])
|
||||
|
||||
dxvk_src = [
|
||||
'dxvk_access.cpp',
|
||||
'dxvk_adapter.cpp',
|
||||
'dxvk_allocator.cpp',
|
||||
'dxvk_barrier.cpp',
|
||||
|
Loading…
x
Reference in New Issue
Block a user