{
struct CommandBuffer::Impl
{
- Impl( CommandPool& commandPool, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
- : mGraphics( commandPool.GetGraphics() ),
+ Impl( CommandBuffer& owner, CommandPool& commandPool, uint32_t poolIndex, const vk::CommandBufferAllocateInfo& allocateInfo, vk::CommandBuffer commandBuffer )
+ : mOwner( owner ),
+ mGraphics( commandPool.GetGraphics() ),
mOwnerCommandPool( commandPool ),
+ mPoolAllocationIndex( poolIndex ),
mAllocateInfo( allocateInfo ),
mCommandBuffer( commandBuffer )
{
~Impl()
{
- mResources.clear();
mGraphics.GetDevice().freeCommandBuffers( mOwnerCommandPool.GetPool(),
1, &mCommandBuffer );
}
+ void ReleaseCommandBuffer()
+ {
+ mResources.clear();
+
+ // tell pool the buffer is not in use anymore
+ mOwnerCommandPool.ReleaseCommandBuffer(mOwner, false);
+ }
+
bool Initialise()
{
return true;
.setSubresourceRange( vk::ImageSubresourceRange{ aspectMask, 0, image->GetLevelCount(), 0, image->GetLayerCount() } );
}
-
+ CommandBuffer& mOwner;
Graphics& mGraphics;
CommandPool& mOwnerCommandPool;
+ uint32_t mPoolAllocationIndex;
vk::CommandBufferAllocateInfo mAllocateInfo{};
vk::CommandBuffer mCommandBuffer{};
*/
CommandBuffer::CommandBuffer( CommandPool& commandPool,
+ uint32_t poolIndex,
const vk::CommandBufferAllocateInfo& allocateInfo,
vk::CommandBuffer vkCommandBuffer )
{
- mImpl = MakeUnique<Impl>( commandPool, allocateInfo, vkCommandBuffer );
+ mImpl = MakeUnique<Impl>( *this, commandPool, poolIndex, allocateInfo, vkCommandBuffer );
}
CommandBuffer::~CommandBuffer()
mImpl->Free();
}
-void CommandBuffer::OnRelease( uint32_t refcount )
-{
- VkManaged::OnRelease( refcount );
-}
-
/** Push wait semaphores */
void CommandBuffer::PushWaitSemaphores( const std::vector<vk::Semaphore>& semaphores,
const std::vector<vk::PipelineStageFlags>& stages )
aspectMask );
}
+uint32_t CommandBuffer::GetPoolAllocationIndex() const
+{
+ return mImpl->mPoolAllocationIndex;
+}
+
+bool CommandBuffer::OnDestroy()
+{
+ mImpl->ReleaseCommandBuffer();
+ return true;
+}
+
} // namespace Vulkan
} // namespace Graphics
} // namespace Dali
{
/**
+ * CommandBufferPool contains preallocated command buffers that are
+ * reusable.
+ */
+struct CommandBufferPool
+{
+ static constexpr uint32_t INVALID_NODE_INDEX{ 0xffffffffu };
+ struct Node
+ {
+ Node( uint32_t _nextFreeIndex, CommandBuffer* _commandBuffer ) :
+ nextFreeIndex( _nextFreeIndex ), commandBuffer( _commandBuffer )
+ {
+
+ }
+ uint32_t nextFreeIndex;
+ CommandBuffer* commandBuffer;
+ };
+
+ CommandBufferPool( CommandPool& owner, Graphics& graphics, uint32_t initialCapacity, uint32_t defaultIncrease, bool isPrimary )
+ : mOwner( owner ),
+ mGraphics( graphics ),
+ mPoolData{},
+ mFirstFree(INVALID_NODE_INDEX),
+ mCapacity( initialCapacity ),
+ mAllocationCount( 0u ),
+ mDefaultIncrease( defaultIncrease ),
+ mIsPrimary( isPrimary )
+ {
+ // don't allocate anything if initial capacity is 0
+ if(initialCapacity)
+ {
+ Resize(initialCapacity);
+ }
+ }
+
+ ~CommandBufferPool()
+ {
+ // free all buffers here
+ for( auto&& cmd : mPoolData )
+ {
+ delete cmd.commandBuffer;
+ }
+ }
+
+ /**
+ * Creates new batch of command buffers
+ * @param allocateInfo
+ * @return
+ */
+ std::vector<vk::CommandBuffer> AllocateVkCommandBuffers( vk::CommandBufferAllocateInfo allocateInfo )
+ {
+ return VkAssert( mGraphics.GetDevice().allocateCommandBuffers( allocateInfo ) );
+ }
+
+ /**
+ * Resizes command pool to the new capacity. Pool may only grow
+ * @param newCapacity
+ */
+ void Resize( uint32_t newCapacity )
+ {
+ if( newCapacity <= mPoolData.size() )
+ {
+ return;
+ }
+
+ auto diff = newCapacity - mPoolData.size();
+
+ auto allocateInfo = vk::CommandBufferAllocateInfo{}
+ .setCommandBufferCount( U32(diff) )
+ .setCommandPool( mOwner.GetPool() )
+ .setLevel( mIsPrimary ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary );
+ auto newBuffers = AllocateVkCommandBuffers( allocateInfo );
+
+ uint32_t i = U32(mPoolData.size() + 1);
+
+ mFirstFree = U32(mPoolData.size());
+ if(!mPoolData.empty())
+ {
+ mPoolData.back()
+ .nextFreeIndex = U32(mPoolData.size());
+ }
+ for( auto&& cmdbuf : newBuffers )
+ {
+ auto commandBuffer = new CommandBuffer( mOwner, i-1, allocateInfo, cmdbuf);
+ mPoolData.emplace_back( i, commandBuffer );
+ ++i;
+ }
+ mPoolData.back().nextFreeIndex = INVALID_NODE_INDEX;
+ mCapacity = U32(mPoolData.size());
+ }
+
+ /**
+ * Allocates new command buffer
+ * @return
+ */
+ CommandBufferRef AllocateCommandBuffer( bool reset )
+ {
+ // resize if no more nodes
+ if( mFirstFree == INVALID_NODE_INDEX )
+ {
+ Resize( U32(mPoolData.size() + mDefaultIncrease) );
+ }
+
+ auto& node = mPoolData[mFirstFree];
+ mFirstFree = node.nextFreeIndex;
+
+ if( reset )
+ {
+ node.commandBuffer->Reset();
+ }
+
+ ++mAllocationCount;
+ return CommandBufferRef(node.commandBuffer);
+ }
+
+ /**
+ * Releases command buffer back to the pool
+ * @param reset if true, Resets command buffer
+ * @param ref
+ */
+ void ReleaseCommandBuffer( CommandBuffer& buffer, bool reset = false )
+ {
+ auto indexInPool = buffer.GetPoolAllocationIndex();
+ mPoolData[indexInPool].nextFreeIndex = mFirstFree;
+ mFirstFree = indexInPool;
+
+ if( reset )
+ {
+ buffer.Reset();
+ }
+ --mAllocationCount;
+ }
+
+ uint32_t GetCapacity() const
+ {
+ return mCapacity;
+ }
+
+ uint32_t GetAllocationCount() const
+ {
+ return mAllocationCount;
+ }
+
+ CommandPool& mOwner;
+ Graphics& mGraphics;
+ std::vector<Node> mPoolData;
+ uint32_t mFirstFree;
+ uint32_t mCapacity;
+ uint32_t mAllocationCount;
+ uint32_t mDefaultIncrease;
+ bool mIsPrimary;
+};
+
+/**
*
* Class: CommandPool::Impl
*/
-
struct CommandPool::Impl
{
Impl( Graphics& graphics, CommandPool& interface, const vk::CommandPoolCreateInfo& createInfo )
bool Initialise()
{
mCommandPool = VkAssert(mGraphics.GetDevice().createCommandPool(mCreateInfo, mGraphics.GetAllocator()));
+ mInternalPoolPrimary = std::make_unique<CommandBufferPool>( mInterface, mGraphics, 0, 32, true );
+ mInternalPoolSecondary = std::make_unique<CommandBufferPool>( mInterface, mGraphics, 0, 32, false );
return true;
}
-
void Reset( bool releaseResources )
{
mGraphics.GetDevice().resetCommandPool( mCommandPool, releaseResources ? vk::CommandPoolResetFlagBits::eReleaseResources : vk::CommandPoolResetFlags{} );
- mAllocatedCommandBuffers.clear();
}
CommandBufferRef NewCommandBuffer( const vk::CommandBufferAllocateInfo& allocateInfo )
{
vk::CommandBufferAllocateInfo info( allocateInfo );
- info.setCommandPool( mCommandPool );
- info.setCommandBufferCount(1);
- auto retval = VkAssert( mGraphics.GetDevice().allocateCommandBuffers( info ) );
- mAllocatedCommandBuffers.emplace_back( new CommandBuffer( mInterface, info, retval[0]) );
- return mAllocatedCommandBuffers.back();
+ auto& usedPool = allocateInfo.level == vk::CommandBufferLevel::ePrimary ? *mInternalPoolPrimary.get() : *mInternalPoolSecondary.get();
+ auto retval = usedPool.AllocateCommandBuffer( false );
+ return retval;
}
- bool ReleaseCommandBuffer( const CommandBufferRef& buffer, bool forceRelease )
+ bool ReleaseCommandBuffer( CommandBuffer& buffer, bool forceRelease )
{
- if( buffer.GetRefCount() == 2 )
+ if(buffer.IsPrimary())
+ {
+ mInternalPoolPrimary->ReleaseCommandBuffer( buffer );
+ }
+ else
{
- for(auto&& cmdBuf : mAllocatedCommandBuffers )
- {
- if(cmdBuf == buffer )
- {
- // fixme: should remove from list but in future the cache of command buffer will work
- // different
- cmdBuf.Reset();
- return true;
- }
- }
+ mInternalPoolSecondary->ReleaseCommandBuffer( buffer );
}
return false;
}
vk::CommandPoolCreateInfo mCreateInfo;
vk::CommandPool mCommandPool;
- std::vector<CommandBufferRef> mAllocatedCommandBuffers;
+ // Pools are lazily allocated, depends on the requested command buffers
+ std::unique_ptr<CommandBufferPool> mInternalPoolPrimary;
+ std::unique_ptr<CommandBufferPool> mInternalPoolSecondary;
};
/**
mImpl->Reset( releaseResources );
}
-bool CommandPool::ReleaseCommandBuffer( CommandBufferRef buffer, bool forceRelease )
+bool CommandPool::ReleaseCommandBuffer( CommandBuffer& buffer, bool forceRelease )
{
return mImpl->ReleaseCommandBuffer( buffer, forceRelease );
}
+uint32_t CommandPool::GetCapacity() const
+{
+ return mImpl->mInternalPoolPrimary->GetCapacity()+
+ mImpl->mInternalPoolSecondary->GetCapacity();
+}
+
+uint32_t CommandPool::GetAllocationCount() const
+{
+ return mImpl->mInternalPoolPrimary->GetAllocationCount()+
+ mImpl->mInternalPoolSecondary->GetAllocationCount();
+}
+
+uint32_t CommandPool::GetAllocationCount( vk::CommandBufferLevel level ) const
+{
+ return level == vk::CommandBufferLevel::ePrimary ?
+ mImpl->mInternalPoolPrimary->GetAllocationCount() :
+ mImpl->mInternalPoolSecondary->GetAllocationCount();
+}
+
} // namespace Vulkan
} // namespace Graphics
} // namespace Dali