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

[dxvk] Improve lifetime tracking logic

Reduces ref counting overhead on the CS thread a bit.
This commit is contained in:
Philip Rebohle 2024-09-25 16:34:50 +02:00 committed by Philip Rebohle
parent 7ac9918b39
commit 5263307c4a
6 changed files with 79 additions and 28 deletions

View File

@ -256,17 +256,31 @@ namespace dxvk {
* the device can guarantee that the submission has * the device can guarantee that the submission has
* completed. * completed.
*/ */
template<DxvkAccess Access>
void trackResource(Rc<DxvkResourceAllocation>&& rc) {
m_resources.trackResource(DxvkLifetime<DxvkResourceAllocation>(std::move(rc), Access));
}
template<DxvkAccess Access>
void trackResource(const Rc<DxvkResourceAllocation>& rc) {
m_resources.trackResource(DxvkLifetime<DxvkResourceAllocation>(rc.ptr(), Access));
}
template<DxvkAccess Access, typename T>
void trackResource(Rc<T>&& rc) {
m_resources.trackResource(DxvkLifetime<DxvkResource>(std::move(rc), Access));
}
template<DxvkAccess Access, typename T> template<DxvkAccess Access, typename T>
void trackResource(const Rc<T>& rc) { void trackResource(const Rc<T>& rc) {
m_resources.trackResource<Access>(rc.ptr()); m_resources.trackResource(DxvkLifetime<DxvkResource>(rc.ptr(), Access));
} }
template<DxvkAccess Access, typename T> template<DxvkAccess Access, typename T>
void trackResource(T* rc) { void trackResource(T* rc) {
// TODO remove this jank once things are refactored m_resources.trackResource(DxvkLifetime<DxvkResource>(rc, Access));
m_resources.trackResource<Access>(rc);
} }
/** /**
* \brief Tracks a GPU event * \brief Tracks a GPU event
* *

View File

@ -1821,7 +1821,7 @@ namespace dxvk {
Rc<DxvkResourceAllocation>&& slice) { Rc<DxvkResourceAllocation>&& slice) {
// Allocate new backing resource // Allocate new backing resource
Rc<DxvkResourceAllocation> prevAllocation = buffer->assignSlice(std::move(slice)); Rc<DxvkResourceAllocation> prevAllocation = buffer->assignSlice(std::move(slice));
m_cmd->trackResource<DxvkAccess::None>(prevAllocation); m_cmd->trackResource<DxvkAccess::None>(std::move(prevAllocation));
// We also need to update all bindings that the buffer // We also need to update all bindings that the buffer
// may be bound to either directly or through views. // may be bound to either directly or through views.

View File

@ -21,8 +21,16 @@ namespace dxvk {
DxvkLifetime() = default; DxvkLifetime() = default;
template<typename Tx>
DxvkLifetime( DxvkLifetime(
T* resource, Rc<Tx>&& resource,
DxvkAccess access)
: m_ptr(reinterpret_cast<uintptr_t>(resource.ptr()) | uintptr_t(access)) {
resource.unsafeExtract()->convertRef(DxvkAccess::None, access);
}
DxvkLifetime(
const T* resource,
DxvkAccess access) DxvkAccess access)
: m_ptr(reinterpret_cast<uintptr_t>(resource) | uintptr_t(access)) { : m_ptr(reinterpret_cast<uintptr_t>(resource) | uintptr_t(access)) {
acquire(); acquire();
@ -92,37 +100,28 @@ namespace dxvk {
* device has finished using them. * device has finished using them.
*/ */
class DxvkLifetimeTracker { class DxvkLifetimeTracker {
public: public:
DxvkLifetimeTracker(); DxvkLifetimeTracker();
~DxvkLifetimeTracker(); ~DxvkLifetimeTracker();
/** /**
* \brief Adds a resource to track * \brief Adds a resource to track
* \param [in] rc The resource to track * \param [in] res The resource to track
*/ */
template<DxvkAccess Access> void trackResource(DxvkLifetime<DxvkResource>&& res) {
void trackResource(DxvkResource* rc) { m_resources.push_back(std::move(res));
m_resources.emplace_back(rc, Access);
} }
/** /**
* \brief Adds a resource allocation to track * \brief Adds a resource allocation to track
* \param [in] rc The allocation to track * \param [in] res The allocation to track
*/ */
template<DxvkAccess Access> void trackResource(DxvkLifetime<DxvkResourceAllocation>&& res) {
void trackResource(DxvkResourceAllocation* rc) { m_allocations.push_back(std::move(res));
m_allocations.emplace_back(rc, Access);
} }
/**
* \brief Releases resources
*
* Marks all tracked resources as unused.
*/
void notify();
/** /**
* \brief Resets the command list * \brief Resets the command list
* *
@ -130,12 +129,12 @@ namespace dxvk {
* the command list has completed execution. * the command list has completed execution.
*/ */
void reset(); void reset();
private: private:
std::vector<DxvkLifetime<DxvkResource>> m_resources; std::vector<DxvkLifetime<DxvkResource>> m_resources;
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations; std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
}; };
} }

View File

@ -477,6 +477,21 @@ namespace dxvk {
free(); free();
} }
/**
* \brief Converts reference
*
* Decrements and increments the use counter according
* to the given access types in a single operation.
* \param [in] from Previous access type
* \param [in] to New access type
*/
force_inline void convertRef(DxvkAccess from, DxvkAccess to) {
uint64_t increment = getIncrement(to) - getIncrement(from);
if (increment)
m_useCount.fetch_add(increment, std::memory_order_acq_rel);
}
/** /**
* \brief Checks whether the resource is in use * \brief Checks whether the resource is in use
* *

View File

@ -76,6 +76,19 @@ namespace dxvk {
delete this; delete this;
} }
/**
* \brief Converts reference type
*
* \param [in] from Old access type
* \param [in] to New access type
*/
void convertRef(DxvkAccess from, DxvkAccess to) {
uint64_t increment = getIncrement(to) - getIncrement(from);
if (increment)
m_useCount += increment;
}
/** /**
* \brief Checks whether resource is in use * \brief Checks whether resource is in use
* *

View File

@ -2,6 +2,7 @@
#include <functional> #include <functional>
#include <ostream> #include <ostream>
#include <utility>
namespace dxvk { namespace dxvk {
@ -106,6 +107,15 @@ namespace dxvk {
return m_object != nullptr; return m_object != nullptr;
} }
void unsafeInsert(T* object) {
this->decRef();
m_object = object;
}
T* unsafeExtract() {
return std::exchange(m_object, nullptr);
}
private: private:
T* m_object = nullptr; T* m_object = nullptr;