Added object release queue notification to the RHI Device and ObjectCollector.

Signed-off-by: dmcdiar <dmcdiar@amazon.com>
This commit is contained in:
dmcdiar
2021-07-25 22:39:22 -07:00
parent f3a5e9d948
commit 9358428beb
12 changed files with 93 additions and 2 deletions
@@ -8,6 +8,7 @@
#pragma once
#include <Atom/RHI/ObjectCollector.h>
#include <Atom/RHI.Reflect/DeviceDescriptor.h>
#include <Atom/RHI.Reflect/DeviceFeatures.h>
#include <Atom/RHI.Reflect/DeviceLimits.h>
@@ -140,6 +141,9 @@ namespace AZ
//! Get the memory requirements for allocating a buffer resource.
virtual ResourceMemoryRequirements GetResourceMemoryRequirements(const BufferDescriptor& descriptor) = 0;
//! Notifies after all objects currently in the platform release queue are released
virtual void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) = 0;
protected:
DeviceFeatures m_features;
DeviceLimits m_limits;
@@ -34,6 +34,8 @@ namespace AZ
using MutexType = NullMutex;
};
using ObjectCollectorNotifyFunction = AZStd::function<void()>;
/**
* Deferred-releases reference-counted objects at a specific latency. Example: Use to batch-release
* objects that exist on the GPU timeline at the end of the frame after syncing the oldest GPU frame.
@@ -85,6 +87,9 @@ namespace AZ
/// Must not be called at collection time.
size_t GetObjectCount() const;
/// Notifies after the current set of pending objects is released.
void Notify(ObjectCollectorNotifyFunction notifyFunction);
private:
void QueueForCollectInternal(ObjectPtrType object);
@@ -92,6 +97,7 @@ namespace AZ
{
AZStd::vector<ObjectPtrType> m_objects;
uint64_t m_collectIteration;
AZStd::vector<ObjectCollectorNotifyFunction> m_notifies;
};
inline bool IsGarbageReady(size_t collectIteration)
@@ -106,6 +112,7 @@ namespace AZ
mutable typename Traits::MutexType m_mutex;
AZStd::vector<ObjectPtrType> m_pendingObjects;
AZStd::vector<Garbage> m_pendingGarbage;
AZStd::vector<ObjectCollectorNotifyFunction> m_pendingNotifies;
};
template <typename Traits>
@@ -174,6 +181,45 @@ namespace AZ
}
m_mutex.unlock();
if (m_pendingNotifies.size())
{
if (m_pendingGarbage.size())
{
// find the newest garbage entry and add any pending notifies
Garbage& latestGarbage = m_pendingGarbage.front();
size_t latestGarbageAge = m_currentIteration - latestGarbage.m_collectIteration;
size_t i = 1;
while (i < m_pendingGarbage.size())
{
size_t age = m_currentIteration - m_pendingGarbage[i].m_collectIteration;
if (age < latestGarbageAge)
{
latestGarbage = m_pendingGarbage[i];
latestGarbageAge = age;
}
}
latestGarbage.m_notifies.insert(latestGarbage.m_notifies.end(), m_pendingNotifies.begin(), m_pendingNotifies.end());
m_mutex.lock();
m_pendingNotifies.clear();
m_mutex.unlock();
}
else
{
// garbage queue is empty, notify now
m_mutex.lock();
for (auto& notifyFunction : m_pendingNotifies)
{
notifyFunction();
}
m_pendingNotifies.clear();
m_mutex.unlock();
}
}
size_t objectCount = 0;
size_t i = 0;
while (i < m_pendingGarbage.size())
@@ -189,6 +235,12 @@ namespace AZ
}
}
objectCount += garbage.m_objects.size();
for (auto& notifyFunction : garbage.m_notifies)
{
notifyFunction();
}
garbage = AZStd::move(m_pendingGarbage.back());
m_pendingGarbage.pop_back();
}
@@ -215,5 +267,13 @@ namespace AZ
return objectCount;
}
template <typename Traits>
void ObjectCollector<Traits>::Notify(ObjectCollectorNotifyFunction notifyFunction)
{
m_mutex.lock();
m_pendingNotifies.push_back(notifyFunction);
m_mutex.unlock();
}
}
}
+2
View File
@@ -60,6 +60,8 @@ namespace UnitTest
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::ImageDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::BufferDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
void ObjectCollectionNotify(AZ::RHI::ObjectCollectorNotifyFunction notifyFunction) override {}
};
AZ::RHI::Ptr<AZ::RHI::Device> MakeTestDevice();
@@ -292,6 +292,11 @@ namespace AZ
return memoryRequirements;
}
void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction)
{
m_releaseQueue.Notify(notifyFunction);
}
//AZStd::vector<RHI::Format> Device::GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const
//{
// AZStd::vector<RHI::Format> formatsList;
@@ -162,6 +162,7 @@ namespace AZ
void PreShutdown() override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::ImageDescriptor & descriptor) override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::BufferDescriptor & descriptor) override;
void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override;
//////////////////////////////////////////////////////////////////////////
RHI::ResultCode InitSubPlatform(RHI::PhysicalDevice& physicalDevice);
@@ -315,7 +315,12 @@ namespace AZ
memoryRequirements.m_sizeInBytes = bufferSizeAndAlign.size;
return memoryRequirements;
}
void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction)
{
m_releaseQueue.Notify(notifyFunction);
}
void Device::InitFeatures()
{
+2 -1
View File
@@ -151,7 +151,8 @@ namespace AZ
NullDescriptorManager& GetNullDescriptorManager();
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::ImageDescriptor & descriptor) override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::BufferDescriptor & descriptor) override;
void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override;
private:
Device() = default;
@@ -20,5 +20,10 @@ namespace AZ
{
formatsCapabilities.fill(static_cast<RHI::FormatCapabilities>(~0));
}
void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction)
{
notifyFunction();
}
}
}
@@ -42,6 +42,7 @@ namespace AZ
void PreShutdown() override {}
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const RHI::ImageDescriptor& descriptor) override { return RHI::ResourceMemoryRequirements();}
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const RHI::BufferDescriptor& descriptor) override { return RHI::ResourceMemoryRequirements();}
void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override;
//////////////////////////////////////////////////////////////////////////
};
}
@@ -652,6 +652,11 @@ namespace AZ
return RHI::ResourceMemoryRequirements{ vkRequirements.alignment, vkRequirements.size };
}
void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction)
{
m_releaseQueue.Notify(notifyFunction);
}
void Device::InitFeaturesAndLimits(const PhysicalDevice& physicalDevice)
{
m_features.m_tessellationShader = (m_enabledDeviceFeatures.tessellationShader == VK_TRUE);
@@ -134,6 +134,7 @@ namespace AZ
void PreShutdown() override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::ImageDescriptor& descriptor) override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::BufferDescriptor& descriptor) override;
void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override;
//////////////////////////////////////////////////////////////////////////
void InitFeaturesAndLimits(const PhysicalDevice& physicalDevice);
@@ -70,6 +70,7 @@ namespace UnitTest
void PreShutdown() override {}
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::ImageDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
AZ::RHI::ResourceMemoryRequirements GetResourceMemoryRequirements([[maybe_unused]] const AZ::RHI::BufferDescriptor& descriptor) { return AZ::RHI::ResourceMemoryRequirements{}; };
void ObjectCollectionNotify(AZ::RHI::ObjectCollectorNotifyFunction notifyFunction) override {}
};
class ImageView