From 5263307c4a06a3339238cd6bfc34c57deff6be61 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 25 Sep 2024 16:34:50 +0200 Subject: [PATCH] [dxvk] Improve lifetime tracking logic Reduces ref counting overhead on the CS thread a bit. --- src/dxvk/dxvk_cmdlist.h | 24 +++++++++++++++++----- src/dxvk/dxvk_context.cpp | 2 +- src/dxvk/dxvk_lifetime.h | 43 +++++++++++++++++++-------------------- src/dxvk/dxvk_memory.h | 15 ++++++++++++++ src/dxvk/dxvk_resource.h | 13 ++++++++++++ src/util/rc/util_rc_ptr.h | 10 +++++++++ 6 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 6ff1fe5c5..0cd2163ee 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -256,17 +256,31 @@ namespace dxvk { * the device can guarantee that the submission has * completed. */ + template + void trackResource(Rc&& rc) { + m_resources.trackResource(DxvkLifetime(std::move(rc), Access)); + } + + template + void trackResource(const Rc& rc) { + m_resources.trackResource(DxvkLifetime(rc.ptr(), Access)); + } + + template + void trackResource(Rc&& rc) { + m_resources.trackResource(DxvkLifetime(std::move(rc), Access)); + } + template void trackResource(const Rc& rc) { - m_resources.trackResource(rc.ptr()); + m_resources.trackResource(DxvkLifetime(rc.ptr(), Access)); } - + template void trackResource(T* rc) { - // TODO remove this jank once things are refactored - m_resources.trackResource(rc); + m_resources.trackResource(DxvkLifetime(rc, Access)); } - + /** * \brief Tracks a GPU event * diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9d1492c00..39117b966 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1821,7 +1821,7 @@ namespace dxvk { Rc&& slice) { // Allocate new backing resource Rc prevAllocation = buffer->assignSlice(std::move(slice)); - m_cmd->trackResource(prevAllocation); + m_cmd->trackResource(std::move(prevAllocation)); // We also need to update all bindings that the buffer // may be bound to either directly or through views. diff --git a/src/dxvk/dxvk_lifetime.h b/src/dxvk/dxvk_lifetime.h index cb48dc518..5aa903ffc 100644 --- a/src/dxvk/dxvk_lifetime.h +++ b/src/dxvk/dxvk_lifetime.h @@ -21,8 +21,16 @@ namespace dxvk { DxvkLifetime() = default; + template DxvkLifetime( - T* resource, + Rc&& resource, + DxvkAccess access) + : m_ptr(reinterpret_cast(resource.ptr()) | uintptr_t(access)) { + resource.unsafeExtract()->convertRef(DxvkAccess::None, access); + } + + DxvkLifetime( + const T* resource, DxvkAccess access) : m_ptr(reinterpret_cast(resource) | uintptr_t(access)) { acquire(); @@ -92,37 +100,28 @@ namespace dxvk { * device has finished using them. */ class DxvkLifetimeTracker { - + public: - + DxvkLifetimeTracker(); ~DxvkLifetimeTracker(); - + /** * \brief Adds a resource to track - * \param [in] rc The resource to track + * \param [in] res The resource to track */ - template - void trackResource(DxvkResource* rc) { - m_resources.emplace_back(rc, Access); + void trackResource(DxvkLifetime&& res) { + m_resources.push_back(std::move(res)); } /** * \brief Adds a resource allocation to track - * \param [in] rc The allocation to track + * \param [in] res The allocation to track */ - template - void trackResource(DxvkResourceAllocation* rc) { - m_allocations.emplace_back(rc, Access); + void trackResource(DxvkLifetime&& res) { + m_allocations.push_back(std::move(res)); } - /** - * \brief Releases resources - * - * Marks all tracked resources as unused. - */ - void notify(); - /** * \brief Resets the command list * @@ -130,12 +129,12 @@ namespace dxvk { * the command list has completed execution. */ void reset(); - + private: - + std::vector> m_resources; std::vector> m_allocations; - + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index d39717ab4..a4e8e9258 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -477,6 +477,21 @@ namespace dxvk { 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 * diff --git a/src/dxvk/dxvk_resource.h b/src/dxvk/dxvk_resource.h index 03ae6c6d2..9e317c119 100644 --- a/src/dxvk/dxvk_resource.h +++ b/src/dxvk/dxvk_resource.h @@ -76,6 +76,19 @@ namespace dxvk { 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 * diff --git a/src/util/rc/util_rc_ptr.h b/src/util/rc/util_rc_ptr.h index c528120bc..f475c8f89 100644 --- a/src/util/rc/util_rc_ptr.h +++ b/src/util/rc/util_rc_ptr.h @@ -2,6 +2,7 @@ #include #include +#include namespace dxvk { @@ -106,6 +107,15 @@ namespace dxvk { return m_object != nullptr; } + void unsafeInsert(T* object) { + this->decRef(); + m_object = object; + } + + T* unsafeExtract() { + return std::exchange(m_object, nullptr); + } + private: T* m_object = nullptr;