mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[dxvk] Rework DxvkResource lifetime tracking
Reduces the number of atomic operations required for lifetime tracking by using a single 64-bit integer for usage tracking and reference counting.
This commit is contained in:
parent
8d1d3d66e0
commit
0e38b11569
@ -146,9 +146,9 @@ namespace dxvk {
|
||||
* the device can guarantee that the submission has
|
||||
* completed.
|
||||
*/
|
||||
template<DxvkAccess Access>
|
||||
void trackResource(Rc<DxvkResource> rc) {
|
||||
m_resources.trackResource<Access>(std::move(rc));
|
||||
template<DxvkAccess Access, typename T>
|
||||
void trackResource(const Rc<T>& rc) {
|
||||
m_resources.trackResource<Access>(rc.ptr());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<DxvkAccess Access>
|
||||
void trackResource(Rc<DxvkResource>&& 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<std::pair<Rc<DxvkResource>, DxvkAccess>> m_resources;
|
||||
bool m_notified = false;
|
||||
std::vector<DxvkLifetime> m_resources;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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<uint32_t> m_useCountR = { 0u };
|
||||
std::atomic<uint32_t> m_useCountW = { 0u };
|
||||
std::atomic<uint64_t> 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user