From 63183141bce794ecd377d04f77d0c9498d6fe932 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 19 Sep 2019 19:35:52 +0200 Subject: [PATCH] [dxvk] Implement read/write tracking in lifetime tracker This way we will be able to more accurately determine how a resource is going to be used by the GPU, and we can also cut unnecessary atomic operations for non-resource objects. --- src/dxvk/dxvk_cmdlist.h | 2 +- src/dxvk/dxvk_lifetime.cpp | 2 +- src/dxvk/dxvk_lifetime.h | 7 ++--- src/dxvk/dxvk_resource.h | 54 +++++++++++++++++++++++++++++++++----- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 6b1bdcad..5f790b73 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -147,7 +147,7 @@ namespace dxvk { * completed. */ void trackResource(Rc rc) { - m_resources.trackResource(std::move(rc)); + m_resources.trackResource(std::move(rc)); } /** diff --git a/src/dxvk/dxvk_lifetime.cpp b/src/dxvk/dxvk_lifetime.cpp index 3d03f523..777cf020 100644 --- a/src/dxvk/dxvk_lifetime.cpp +++ b/src/dxvk/dxvk_lifetime.cpp @@ -8,7 +8,7 @@ namespace dxvk { void DxvkLifetimeTracker::reset() { for (const auto& resource : m_resources) - resource->release(); + resource.first->release(resource.second); m_resources.clear(); } diff --git a/src/dxvk/dxvk_lifetime.h b/src/dxvk/dxvk_lifetime.h index 2b141e90..75f3c8df 100644 --- a/src/dxvk/dxvk_lifetime.h +++ b/src/dxvk/dxvk_lifetime.h @@ -25,9 +25,10 @@ namespace dxvk { * \brief Adds a resource to track * \param [in] rc The resource to track */ + template void trackResource(Rc&& rc) { - rc->acquire(); - m_resources.emplace_back(std::move(rc)); + rc->acquire(Access); + m_resources.emplace_back(std::move(rc), Access); } /** @@ -40,7 +41,7 @@ namespace dxvk { private: - std::vector> m_resources; + std::vector, DxvkAccess>> m_resources; }; diff --git a/src/dxvk/dxvk_resource.h b/src/dxvk/dxvk_resource.h index 5e143e8a..8f8342c9 100644 --- a/src/dxvk/dxvk_resource.h +++ b/src/dxvk/dxvk_resource.h @@ -7,6 +7,7 @@ namespace dxvk { enum class DxvkAccess { Read = 0, Write = 1, + None = 2, }; using DxvkAccessFlags = Flags; @@ -19,22 +20,63 @@ namespace dxvk { * is recorded, it will be marked as 'in use'. */ class DxvkResource : public RcObject { - + constexpr static uint32_t UseCountIncrementW = 1 << 18; + constexpr static uint32_t UseCountIncrementR = 1; + constexpr static uint32_t UseCountMaskW = ~(UseCountIncrementW - 1); + constexpr static uint32_t UseCountMaskR = ~(UseCountIncrementR - 1); public: virtual ~DxvkResource(); - bool isInUse() const { - return m_useCount.load() != 0; + /** + * \brief Checks whether resource is in use + * + * Returns \c true if there are pending accesses to + * the resource by the GPU matching the given access + * type. Note that checking for reads will also return + * \c true if the resource is being written to. + * \param [in] access Access type to check for + * \returns \c true if the resource is in use + */ + bool isInUse(DxvkAccess access = DxvkAccess::Read) const { + uint32_t mask = access == DxvkAccess::Write + ? UseCountMaskW + : UseCountMaskR; + return m_useCount.load() & mask; } - void acquire() { m_useCount += 1; } - void release() { m_useCount -= 1; } + /** + * \brief Acquires resource + * + * Increments use count for the given access type. + * \param Access Resource access type + */ + void acquire(DxvkAccess access) { + if (access != DxvkAccess::None) + m_useCount += getIncrement(access); + } + + /** + * \brief Releases resource + * + * Decrements use count for the given access type. + * \param Access Resource access type + */ + void release(DxvkAccess access) { + if (access != DxvkAccess::None) + m_useCount -= getIncrement(access); + } private: std::atomic m_useCount = { 0u }; - + + static constexpr uint32_t getIncrement(DxvkAccess access) { + return access == DxvkAccess::Write + ? UseCountIncrementW + : UseCountIncrementR; + } + }; } \ No newline at end of file