diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index cfb4840de..fe3c5f3aa 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -146,9 +146,9 @@ namespace dxvk { * the device can guarantee that the submission has * completed. */ - template - void trackResource(Rc rc) { - m_resources.trackResource(std::move(rc)); + template + void trackResource(const Rc& rc) { + m_resources.trackResource(rc.ptr()); } /** diff --git a/src/dxvk/dxvk_lifetime.cpp b/src/dxvk/dxvk_lifetime.cpp index e9439c55d..c38e78651 100644 --- a/src/dxvk/dxvk_lifetime.cpp +++ b/src/dxvk/dxvk_lifetime.cpp @@ -7,19 +7,11 @@ namespace dxvk { void DxvkLifetimeTracker::notify() { - for (const auto& resource : m_resources) - resource.first->release(resource.second); - - m_notified = true; + m_resources.clear(); } void DxvkLifetimeTracker::reset() { - // If this gets called without ever being submitted then - // we should at least report the resources as unused - if (!m_notified) - this->notify(); - m_resources.clear(); } diff --git a/src/dxvk/dxvk_lifetime.h b/src/dxvk/dxvk_lifetime.h index fb80d05f6..4b0211860 100644 --- a/src/dxvk/dxvk_lifetime.h +++ b/src/dxvk/dxvk_lifetime.h @@ -7,7 +7,81 @@ namespace dxvk { /** - * \brief DXVK lifetime tracker + * \brief Resource pointer + * + * Keeps a resource alive and stores access information. + */ + class DxvkLifetime { + + public: + + DxvkLifetime() + : m_resource(nullptr), m_access(DxvkAccess::None) { } + + DxvkLifetime( + DxvkResource* resource, + DxvkAccess access) + : m_resource(resource), m_access(access) { + acquire(); + } + + DxvkLifetime(DxvkLifetime&& other) + : m_resource(other.m_resource), m_access(other.m_access) { + other.m_resource = nullptr; + other.m_access = DxvkAccess::None; + } + + DxvkLifetime(const DxvkLifetime& other) + : m_resource(other.m_resource), m_access(other.m_access) { + acquire(); + } + + DxvkLifetime& operator = (DxvkLifetime&& other) { + release(); + + m_resource = other.m_resource; + m_access = other.m_access; + + other.m_resource = nullptr; + other.m_access = DxvkAccess::None; + return *this; + } + + DxvkLifetime& operator = (const DxvkLifetime& other) { + other.acquire(); + release(); + + m_resource = other.m_resource; + m_access = other.m_access; + return *this; + } + + ~DxvkLifetime() { + release(); + } + + private: + + DxvkResource* m_resource; + DxvkAccess m_access; + + void acquire() const { + if (m_resource) + m_resource->acquire(m_access); + } + + void release() const { + if (m_resource) { + if (!m_resource->release(m_access)) + delete m_resource; + } + } + + }; + + + /** + * \brief Lifetime tracker * * Maintains references to a set of resources. This is * used to guarantee that resources are not destroyed @@ -26,9 +100,8 @@ namespace dxvk { * \param [in] rc The resource to track */ template - void trackResource(Rc&& rc) { - rc->acquire(Access); - m_resources.emplace_back(std::move(rc), Access); + void trackResource(DxvkResource* rc) { + m_resources.emplace_back(rc, Access); } /** @@ -48,8 +121,7 @@ namespace dxvk { private: - std::vector, DxvkAccess>> m_resources; - bool m_notified = false; + std::vector m_resources; }; diff --git a/src/dxvk/dxvk_resource.h b/src/dxvk/dxvk_resource.h index 9a73ed818..80a935270 100644 --- a/src/dxvk/dxvk_resource.h +++ b/src/dxvk/dxvk_resource.h @@ -4,7 +4,7 @@ namespace dxvk { - enum class DxvkAccess { + enum class DxvkAccess : uint32_t { Read = 0, Write = 1, None = 2, @@ -19,12 +19,59 @@ namespace dxvk { * by the GPU. As soon as a command that uses the resource * is recorded, it will be marked as 'in use'. */ - class DxvkResource : public RcObject { + class DxvkResource { + static constexpr uint64_t RdAccessShift = 24; + static constexpr uint64_t WrAccessShift = 44; + static constexpr uint64_t RefcountMask = (1ull << RdAccessShift) - 1; + static constexpr uint64_t RdAccessMask = ((1ull << (WrAccessShift - RdAccessShift)) - 1) << RdAccessShift; + static constexpr uint64_t WrAccessMask = ((1ull << (64 - WrAccessShift)) - 1) << WrAccessShift; + + static constexpr uint64_t RefcountInc = 1ull; + static constexpr uint64_t RdAccessInc = 1ull << RdAccessShift; + static constexpr uint64_t WrAccessInc = 1ull << WrAccessShift; public: virtual ~DxvkResource(); - + + /** + * \brief Increments reference count + * \returns New reference count + */ + uint32_t incRef() { + return acquire(DxvkAccess::None); + } + + /** + * \brief Decrements reference count + * \returns New reference count + */ + uint32_t decRef() { + return release(DxvkAccess::None); + } + + /** + * \brief Acquires resource with given access + * + * Atomically increments both the reference count + * as well as the use count for the given access. + * \returns New reference count + */ + uint32_t acquire(DxvkAccess access) { + return uint32_t((m_useCount += getIncrement(access)) & RefcountMask); + } + + /** + * \brief Releases resource with given access + * + * Atomically decrements both the reference count + * as well as the use count for the given access. + * \returns New reference count + */ + uint32_t release(DxvkAccess access) { + return uint32_t((m_useCount -= getIncrement(access)) & RefcountMask); + } + /** * \brief Checks whether resource is in use * @@ -36,40 +83,12 @@ namespace dxvk { * \returns \c true if the resource is in use */ bool isInUse(DxvkAccess access = DxvkAccess::Read) const { - bool result = m_useCountW.load() != 0; + uint64_t mask = WrAccessMask; if (access == DxvkAccess::Read) - result |= m_useCountR.load() != 0; - return result; + mask |= RdAccessMask; + return bool(m_useCount.load() & mask); } - /** - * \brief Acquires resource - * - * Increments use count for the given access type. - * \param Access Resource access type - */ - void acquire(DxvkAccess access) { - if (access != DxvkAccess::None) { - (access == DxvkAccess::Read - ? m_useCountR - : m_useCountW) += 1; - } - } - - /** - * \brief Releases resource - * - * Decrements use count for the given access type. - * \param Access Resource access type - */ - void release(DxvkAccess access) { - if (access != DxvkAccess::None) { - (access == DxvkAccess::Read - ? m_useCountR - : m_useCountW) -= 1; - } - } - /** * \brief Waits for resource to become unused * @@ -85,9 +104,19 @@ namespace dxvk { private: - std::atomic m_useCountR = { 0u }; - std::atomic m_useCountW = { 0u }; + std::atomic m_useCount = { 0ull }; + + static constexpr uint64_t getIncrement(DxvkAccess access) { + uint64_t increment = RefcountInc; + + if (access != DxvkAccess::None) { + increment |= (access == DxvkAccess::Read) + ? RdAccessInc : WrAccessInc; + } + + return increment; + } }; - + } \ No newline at end of file