From 4cc8b78f5ff686aa808f3b12f1ccdf3a96af27f4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 21 Nov 2023 23:58:59 +0100 Subject: [PATCH] Renderer/RenderResource: Half the number of virtual calls required on cleanup Since most of the time objects are directly pushed for release instead of callbacks, it makes sense to optimize this case by not storing the object in a callback and removing the call to the virtual Release method. The virtual destructor does the job here. --- include/Nazara/Renderer/RenderResources.hpp | 28 +++++++++++- include/Nazara/Renderer/RenderResources.inl | 49 ++++++++++++++++----- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/include/Nazara/Renderer/RenderResources.hpp b/include/Nazara/Renderer/RenderResources.hpp index b1791d2aa..851ffaf6d 100644 --- a/include/Nazara/Renderer/RenderResources.hpp +++ b/include/Nazara/Renderer/RenderResources.hpp @@ -26,6 +26,8 @@ namespace Nz { public: class Releasable; + class ReleasableCallback; + template class ReleasableData; template class ReleasableLambda; virtual ~RenderResources(); @@ -50,10 +52,14 @@ namespace Nz RenderResources(RenderResources&&) = delete; private: + template T* Allocate(); + inline void* Allocate(std::size_t size, std::size_t alignment); + static constexpr std::size_t BlockSize = 4 * 1024 * 1024; using Block = std::vector; + std::vector m_callbackQueue; std::vector m_releaseQueue; std::vector m_releaseMemoryPool; RenderDevice& m_renderDevice; @@ -63,12 +69,32 @@ namespace Nz { public: virtual ~Releasable(); + }; + class RenderResources::ReleasableCallback : public Releasable + { + public: virtual void Release() = 0; }; template - class RenderResources::ReleasableLambda : public Releasable + class RenderResources::ReleasableData : public Releasable + { + public: + ReleasableData(T&& data); + ReleasableData(const ReleasableData&) = delete; + ReleasableData(ReleasableData&&) = delete; + ~ReleasableData() = default; + + ReleasableData& operator=(const ReleasableData&) = delete; + ReleasableData& operator=(ReleasableData&&) = delete; + + private: + T m_data; + }; + + template + class RenderResources::ReleasableLambda final : public ReleasableCallback { public: template ReleasableLambda(U&& lambda); diff --git a/include/Nazara/Renderer/RenderResources.inl b/include/Nazara/Renderer/RenderResources.inl index 892dd9503..13a0698c2 100644 --- a/include/Nazara/Renderer/RenderResources.inl +++ b/include/Nazara/Renderer/RenderResources.inl @@ -15,11 +15,14 @@ namespace Nz inline void RenderResources::FlushReleaseQueue() { + for (ReleasableCallback* callback : m_callbackQueue) + callback->Release(); + + m_callbackQueue.clear(); + for (Releasable* releasable : m_releaseQueue) - { - releasable->Release(); PlacementDestroy(releasable); - } + m_releaseQueue.clear(); for (auto& memoryblock : m_releaseMemoryPool) @@ -36,7 +39,12 @@ namespace Nz { static_assert(std::is_rvalue_reference_v); - return PushReleaseCallback([v = std::move(value)] {}); + using ReleaseData = ReleasableData>>; + + ReleaseData* releasable = Allocate(); + PlacementNew(releasable, std::forward(value)); + + m_releaseQueue.push_back(releasable); } template @@ -44,9 +52,21 @@ namespace Nz { using ReleaseFunctor = ReleasableLambda>>; - constexpr std::size_t functorSize = sizeof(ReleaseFunctor); - constexpr std::size_t functorAlignment = alignof(ReleaseFunctor); + ReleaseFunctor* releasable = Allocate(); + PlacementNew(releasable, std::forward(callback)); + m_releaseQueue.push_back(releasable); + m_callbackQueue.push_back(releasable); + } + + template + T* RenderResources::Allocate() + { + return static_cast(Allocate(sizeof(T), alignof(T))); + } + + void* RenderResources::Allocate(std::size_t size, std::size_t alignment) + { // Try to minimize lost space struct { @@ -59,8 +79,8 @@ namespace Nz { std::size_t freeOffset = block.size(); - UInt64 alignedOffset = Align(freeOffset, functorAlignment); - if (alignedOffset + functorSize > block.capacity()) + UInt64 alignedOffset = Align(freeOffset, alignment); + if (alignedOffset + size > block.capacity()) continue; //< Not enough space UInt64 lostSpace = alignedOffset - freeOffset; @@ -85,12 +105,16 @@ namespace Nz } Block& targetBlock = *bestBlock.block; - targetBlock.resize(bestBlock.alignedOffset + functorSize); + targetBlock.resize(bestBlock.alignedOffset + size); - ReleaseFunctor* releasable = reinterpret_cast(&targetBlock[bestBlock.alignedOffset]); - PlacementNew(releasable, std::forward(callback)); + return &targetBlock[bestBlock.alignedOffset]; + } - m_releaseQueue.push_back(releasable); + + template + RenderResources::ReleasableData::ReleasableData(T&& data) : + m_data(std::move(data)) + { } template @@ -108,3 +132,4 @@ namespace Nz } #include +#include "RenderResources.hpp"