From 9358428bebd7d3b0166af8cf447d58d7caf37f72 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Sun, 25 Jul 2021 22:39:22 -0700 Subject: [PATCH] Added object release queue notification to the RHI Device and ObjectCollector. Signed-off-by: dmcdiar --- Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h | 4 ++ .../Code/Include/Atom/RHI/ObjectCollector.h | 60 +++++++++++++++++++ Gems/Atom/RHI/Code/Tests/Device.h | 2 + Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp | 5 ++ Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h | 1 + .../Atom/RHI/Metal/Code/Source/RHI/Device.cpp | 7 ++- Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h | 3 +- Gems/Atom/RHI/Null/Code/Source/RHI/Device.cpp | 5 ++ Gems/Atom/RHI/Null/Code/Source/RHI/Device.h | 1 + .../RHI/Vulkan/Code/Source/RHI/Device.cpp | 5 ++ Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h | 1 + Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h | 1 + 12 files changed, 93 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h index 3f79392403..4232658980 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -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; diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h index cb66225286..d79a86afea 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ObjectCollector.h @@ -34,6 +34,8 @@ namespace AZ using MutexType = NullMutex; }; + using ObjectCollectorNotifyFunction = AZStd::function; + /** * 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 m_objects; uint64_t m_collectIteration; + AZStd::vector m_notifies; }; inline bool IsGarbageReady(size_t collectIteration) @@ -106,6 +112,7 @@ namespace AZ mutable typename Traits::MutexType m_mutex; AZStd::vector m_pendingObjects; AZStd::vector m_pendingGarbage; + AZStd::vector m_pendingNotifies; }; template @@ -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 + void ObjectCollector::Notify(ObjectCollectorNotifyFunction notifyFunction) + { + m_mutex.lock(); + m_pendingNotifies.push_back(notifyFunction); + m_mutex.unlock(); + } } } diff --git a/Gems/Atom/RHI/Code/Tests/Device.h b/Gems/Atom/RHI/Code/Tests/Device.h index 3a7c513c8b..e11bd75983 100644 --- a/Gems/Atom/RHI/Code/Tests/Device.h +++ b/Gems/Atom/RHI/Code/Tests/Device.h @@ -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 MakeTestDevice(); diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp index 88c9098952..9d23dfa43d 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.cpp @@ -292,6 +292,11 @@ namespace AZ return memoryRequirements; } + void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) + { + m_releaseQueue.Notify(notifyFunction); + } + //AZStd::vector Device::GetValidSwapChainImageFormats(const RHI::WindowHandle& windowHandle) const //{ // AZStd::vector formatsList; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h index 149508307a..9119545342 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/Device.h @@ -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); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp index f0771d7c45..dbd2204e93 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.cpp @@ -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() { diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h index d8c3092c59..9cdeee7eae 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/Device.h @@ -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; diff --git a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.cpp index 7b94efb69f..08a2c4f411 100644 --- a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.cpp @@ -20,5 +20,10 @@ namespace AZ { formatsCapabilities.fill(static_cast(~0)); } + + void Device::ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) + { + notifyFunction(); + } } } diff --git a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h index 3aa045212b..cd44135e62 100644 --- a/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Null/Code/Source/RHI/Device.h @@ -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; ////////////////////////////////////////////////////////////////////////// }; } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp index 6d3080dce8..05ff8bb2a6 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp @@ -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); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h index d5f055f4cd..28e56d1fa9 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.h @@ -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); diff --git a/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h b/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h index 1de06802b1..be362c60d6 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RHI/Stubs.h @@ -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