// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include namespace Nz { CommandBufferPtr VulkanCommandPool::BuildCommandBuffer(const std::function& callback) { std::vector commandBuffers; auto BuildCommandBuffer = [&](std::size_t imageIndex) { Vk::AutoCommandBuffer& commandBuffer = commandBuffers.emplace_back(m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)); if (!commandBuffer->Begin()) throw std::runtime_error("failed to begin command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); VulkanCommandBufferBuilder builder(commandBuffer.Get(), imageIndex); callback(builder); if (!commandBuffer->End()) throw std::runtime_error("failed to build command buffer: " + TranslateVulkanError(commandBuffer->GetLastErrorCode())); return builder.GetMaxFramebufferCount(); }; std::size_t maxFramebufferCount = BuildCommandBuffer(0); for (std::size_t i = 1; i < maxFramebufferCount; ++i) BuildCommandBuffer(i); for (std::size_t i = 0; i < m_commandPools.size(); ++i) { if (m_commandPools[i].freeCommands.TestNone()) continue; return AllocateFromPool(i, std::move(commandBuffers)); } // No allocation could be made, time to allocate a new pool std::size_t newPoolIndex = m_commandPools.size(); AllocatePool(); return AllocateFromPool(newPoolIndex, std::move(commandBuffers)); } auto VulkanCommandPool::AllocatePool() -> CommandPool& { constexpr UInt32 MaxSet = 128; CommandPool pool; pool.freeCommands.Resize(MaxSet, true); pool.storage = std::make_unique(MaxSet); return m_commandPools.emplace_back(std::move(pool)); } void VulkanCommandPool::Release(CommandBuffer& binding) { VulkanCommandBuffer& vulkanBinding = static_cast(binding); std::size_t poolIndex = vulkanBinding.GetPoolIndex(); std::size_t bindingIndex = vulkanBinding.GetBindingIndex(); assert(poolIndex < m_commandPools.size()); auto& pool = m_commandPools[poolIndex]; assert(!pool.freeCommands.Test(bindingIndex)); VulkanCommandBuffer* bindingMemory = reinterpret_cast(&pool.storage[bindingIndex]); PlacementDestroy(bindingMemory); pool.freeCommands.Set(bindingIndex); // Try to free pool if it's one of the last one if (poolIndex >= m_commandPools.size() - 1 && poolIndex <= m_commandPools.size()) TryToShrink(); } }