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.
This commit is contained in:
Lynix 2023-11-21 23:58:59 +01:00
parent 1e81b38c0f
commit 4cc8b78f5f
2 changed files with 64 additions and 13 deletions

View File

@ -26,6 +26,8 @@ namespace Nz
{
public:
class Releasable;
class ReleasableCallback;
template<typename T> class ReleasableData;
template<typename T> class ReleasableLambda;
virtual ~RenderResources();
@ -50,10 +52,14 @@ namespace Nz
RenderResources(RenderResources&&) = delete;
private:
template<typename T> 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<UInt8>;
std::vector<ReleasableCallback*> m_callbackQueue;
std::vector<Releasable*> m_releaseQueue;
std::vector<Block> 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<typename T>
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<typename T>
class RenderResources::ReleasableLambda final : public ReleasableCallback
{
public:
template<typename U> ReleasableLambda(U&& lambda);

View File

@ -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<decltype(value)>);
return PushReleaseCallback([v = std::move(value)] {});
using ReleaseData = ReleasableData<std::remove_cv_t<std::remove_reference_t<T>>>;
ReleaseData* releasable = Allocate<ReleaseData>();
PlacementNew(releasable, std::forward<T>(value));
m_releaseQueue.push_back(releasable);
}
template<typename F>
@ -44,9 +52,21 @@ namespace Nz
{
using ReleaseFunctor = ReleasableLambda<std::remove_cv_t<std::remove_reference_t<F>>>;
constexpr std::size_t functorSize = sizeof(ReleaseFunctor);
constexpr std::size_t functorAlignment = alignof(ReleaseFunctor);
ReleaseFunctor* releasable = Allocate<ReleaseFunctor>();
PlacementNew(releasable, std::forward<F>(callback));
m_releaseQueue.push_back(releasable);
m_callbackQueue.push_back(releasable);
}
template<typename T>
T* RenderResources::Allocate()
{
return static_cast<T*>(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<ReleaseFunctor*>(&targetBlock[bestBlock.alignedOffset]);
PlacementNew(releasable, std::forward<F>(callback));
return &targetBlock[bestBlock.alignedOffset];
}
m_releaseQueue.push_back(releasable);
template<typename T>
RenderResources::ReleasableData<T>::ReleasableData(T&& data) :
m_data(std::move(data))
{
}
template<typename T>
@ -108,3 +132,4 @@ namespace Nz
}
#include <Nazara/Renderer/DebugOff.hpp>
#include "RenderResources.hpp"