diff --git a/include/mbgl/vulkan/context.hpp b/include/mbgl/vulkan/context.hpp index a2bdcc075..87a458116 100644 --- a/include/mbgl/vulkan/context.hpp +++ b/include/mbgl/vulkan/context.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -135,21 +136,14 @@ public: const std::unique_ptr& getDummyVertexBuffer(); const std::unique_ptr& getDummyUniformBuffer(); const std::unique_ptr& getDummyTexture(); - const vk::UniqueDescriptorSetLayout& getImageDescriptorSetLayout(); - const vk::UniqueDescriptorSetLayout& buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout, - size_t uniformCount, - const std::string& name); - const std::vector& getDescriptorSetLayouts(); const vk::DescriptorSetLayout& getDescriptorSetLayout(DescriptorSetType type); + DescriptorPoolGrowable& getDescriptorPool(DescriptorSetType type); const vk::UniquePipelineLayout& getGeneralPipelineLayout(); const vk::UniquePipelineLayout& getPushConstantPipelineLayout(); - void bindDescriptorSet(DescriptorSetType type, const vk::DescriptorSet& descriptorSet); - uint8_t getCurrentFrameResourceIndex() const { return frameResourceIndex; } - const vk::UniqueDescriptorPool& getGlobalDescriptorPool() const; - void enqueueDeletion(std::function&& function); + void enqueueDeletion(std::function&& function); void submitOneTimeCommand(const std::function& function) const; void requestSurfaceUpdate() { surfaceUpdateRequested = true; } @@ -162,7 +156,7 @@ private: vk::UniqueSemaphore frameSemaphore; vk::UniqueFence flightFrameFence; - std::vector> deletionQueue; + std::vector> deletionQueue; FrameResources(vk::UniqueCommandBuffer& cb, vk::UniqueSemaphore&& surf, @@ -173,17 +167,22 @@ private: frameSemaphore(std::move(frame)), flightFrameFence(std::move(flight)) {} - void runDeletionQueue(const Context&); + void runDeletionQueue(Context&); }; void initFrameResources(); void destroyResources(); + void buildImageDescriptorSetLayout(); + void buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout, + size_t uniformCount, + const std::string& name); + private: RendererBackend& backend; vulkan::UniformBufferArray globalUniformBuffers; - vk::UniqueDescriptorPool globalDescriptorPool; + std::unordered_map descriptorPoolMap; std::unique_ptr dummyVertexBuffer; std::unique_ptr dummyUniformBuffer; @@ -191,8 +190,7 @@ private: vk::UniqueDescriptorSetLayout globalUniformDescriptorSetLayout; vk::UniqueDescriptorSetLayout layerUniformDescriptorSetLayout; vk::UniqueDescriptorSetLayout drawableUniformDescriptorSetLayout; - vk::UniqueDescriptorSetLayout imageDescriptorSetLayout; - std::vector descriptorSetLayouts; + vk::UniqueDescriptorSetLayout drawableImageDescriptorSetLayout; vk::UniquePipelineLayout generalPipelineLayout; vk::UniquePipelineLayout pushConstantPipelineLayout; diff --git a/include/mbgl/vulkan/descriptor_set.hpp b/include/mbgl/vulkan/descriptor_set.hpp index db0a25293..a4f3fb3c1 100644 --- a/include/mbgl/vulkan/descriptor_set.hpp +++ b/include/mbgl/vulkan/descriptor_set.hpp @@ -17,6 +17,32 @@ enum class DescriptorSetType : uint8_t { Count, }; +struct DescriptorPoolGrowable { + struct PoolInfo { + vk::UniqueDescriptorPool pool; + uint32_t remainingSets{0}; + + PoolInfo(vk::UniqueDescriptorPool&& pool_, uint32_t remainingSets_) + : pool(std::move(pool_)), + remainingSets(remainingSets_) {} + }; + + const uint32_t maxSets{0}; + const uint32_t descriptorsPerSet{0}; + const float growFactor{1.5f}; + + std::vector pools; + int32_t currentPoolIndex{-1}; + + PoolInfo& current() { return pools[currentPoolIndex]; } + + DescriptorPoolGrowable() = default; + DescriptorPoolGrowable(uint32_t maxSets_, uint32_t descriptorsPerSet_, float growFactor_ = 1.5f) + : maxSets(maxSets_), + descriptorsPerSet(descriptorsPerSet_), + growFactor(growFactor_) {} +}; + class DescriptorSet { public: DescriptorSet(Context& context_, DescriptorSetType type_); @@ -27,12 +53,16 @@ public: void markDirty(bool value = true); void bind(CommandEncoder& encoder); +protected: + void createDescriptorPool(DescriptorPoolGrowable& growablePool); + protected: Context& context; DescriptorSetType type; std::vector dirty; std::vector descriptorSets; + int32_t descriptorPoolIndex{-1}; }; class UniformDescriptorSet : public DescriptorSet { diff --git a/src/mbgl/vulkan/buffer_resource.cpp b/src/mbgl/vulkan/buffer_resource.cpp index adf392fda..0289149da 100644 --- a/src/mbgl/vulkan/buffer_resource.cpp +++ b/src/mbgl/vulkan/buffer_resource.cpp @@ -118,7 +118,7 @@ BufferResource::~BufferResource() noexcept { if (!bufferAllocation) return; - context.enqueueDeletion([allocation = std::move(bufferAllocation)](const auto&) mutable { allocation.reset(); }); + context.enqueueDeletion([allocation = std::move(bufferAllocation)](auto&) mutable { allocation.reset(); }); } BufferResource BufferResource::clone() const { diff --git a/src/mbgl/vulkan/context.cpp b/src/mbgl/vulkan/context.cpp index 1aa75617a..1d812d826 100644 --- a/src/mbgl/vulkan/context.cpp +++ b/src/mbgl/vulkan/context.cpp @@ -27,10 +27,6 @@ #include #include -#ifndef MLN_VULKAN_DESCRIPTOR_POOL_SIZE -#define MLN_VULKAN_DESCRIPTOR_POOL_SIZE 30000 -#endif - namespace mbgl { namespace vulkan { @@ -39,6 +35,12 @@ namespace vulkan { // per https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxVertexInputBindings // this can be queried at runtime (VkPhysicalDeviceLimits.maxVertexInputBindings) constexpr uint32_t maximumVertexBindingCount = 16; + +constexpr uint32_t globalDescriptorPoolSize = 3 * 4; +constexpr uint32_t layerDescriptorPoolSize = 3 * 256; +constexpr uint32_t drawableUniformDescriptorPoolSize = 3 * 1024; +constexpr uint32_t drawableImageDescriptorPoolSize = drawableUniformDescriptorPoolSize / 2; + static uint32_t glslangRefCount = 0; class RenderbufferResource : public gfx::RenderbufferResource { @@ -71,17 +73,19 @@ void Context::initFrameResources() { const auto& device = backend.getDevice(); const auto frameCount = backend.getMaxFrames(); - // descriptor pool info - const std::vector poolSizes = { - {vk::DescriptorType::eUniformBuffer, MLN_VULKAN_DESCRIPTOR_POOL_SIZE}, - {vk::DescriptorType::eCombinedImageSampler, MLN_VULKAN_DESCRIPTOR_POOL_SIZE}, - }; + descriptorPoolMap.emplace(DescriptorSetType::Global, + DescriptorPoolGrowable(globalDescriptorPoolSize, shaders::globalUBOCount)); - const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet) - .setPoolSizes(poolSizes) - .setMaxSets(MLN_VULKAN_DESCRIPTOR_POOL_SIZE); + descriptorPoolMap.emplace(DescriptorSetType::Layer, + DescriptorPoolGrowable(layerDescriptorPoolSize, shaders::maxUBOCountPerLayer)); - globalDescriptorPool = device->createDescriptorPoolUnique(descriptorPoolInfo); + descriptorPoolMap.emplace( + DescriptorSetType::DrawableUniform, + DescriptorPoolGrowable(drawableUniformDescriptorPoolSize, shaders::maxUBOCountPerDrawable)); + + descriptorPoolMap.emplace( + DescriptorSetType::DrawableImage, + DescriptorPoolGrowable(drawableImageDescriptorPoolSize, shaders::maxTextureCountPerShader)); // command buffers const vk::CommandBufferAllocateInfo allocateInfo( @@ -107,6 +111,14 @@ void Context::initFrameResources() { // force placeholder texture upload before any descriptor sets (void)getDummyTexture(); + + buildUniformDescriptorSetLayout( + globalUniformDescriptorSetLayout, shaders::globalUBOCount, "GlobalUniformDescriptorSetLayout"); + buildUniformDescriptorSetLayout( + layerUniformDescriptorSetLayout, shaders::maxUBOCountPerLayer, "LayerUniformDescriptorSetLayout"); + buildUniformDescriptorSetLayout( + drawableUniformDescriptorSetLayout, shaders::maxUBOCountPerDrawable, "DrawableUniformDescriptorSetLayout"); + buildImageDescriptorSetLayout(); } void Context::destroyResources() { @@ -122,11 +134,7 @@ void Context::destroyResources() { frameResources.clear(); } -const vk::UniqueDescriptorPool& Context::getGlobalDescriptorPool() const { - return globalDescriptorPool; -} - -void Context::enqueueDeletion(std::function&& function) { +void Context::enqueueDeletion(std::function&& function) { if (frameResources.empty()) { function(*this); return; @@ -522,13 +530,9 @@ const std::unique_ptr& Context::getDummyTexture() { return dummyTexture2D; } -const vk::UniqueDescriptorSetLayout& Context::buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout, - size_t uniformCount, - const std::string& name) { - if (layout) { - return layout; - } - +void Context::buildUniformDescriptorSetLayout(vk::UniqueDescriptorSetLayout& layout, + size_t uniformCount, + const std::string& name) { std::vector bindings; const auto stageFlags = vk::ShaderStageFlags() | vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment; @@ -544,62 +548,63 @@ const vk::UniqueDescriptorSetLayout& Context::buildUniformDescriptorSetLayout(vk const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings); layout = backend.getDevice()->createDescriptorSetLayoutUnique(descriptorSetLayoutCreateInfo); backend.setDebugName(layout.get(), name); - - return layout; } -const vk::UniqueDescriptorSetLayout& Context::getImageDescriptorSetLayout() { - if (!imageDescriptorSetLayout) { - std::vector bindings; +void Context::buildImageDescriptorSetLayout() { + std::vector bindings; - for (size_t i = 0; i < shaders::maxTextureCountPerShader; ++i) { - bindings.push_back(vk::DescriptorSetLayoutBinding() - .setBinding(static_cast(i)) - .setStageFlags(vk::ShaderStageFlagBits::eFragment) - .setDescriptorType(vk::DescriptorType::eCombinedImageSampler) - .setDescriptorCount(1)); - } - - const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings); - imageDescriptorSetLayout = backend.getDevice()->createDescriptorSetLayoutUnique(descriptorSetLayoutCreateInfo); - backend.setDebugName(imageDescriptorSetLayout.get(), "ImageDescriptorSetLayout"); + for (size_t i = 0; i < shaders::maxTextureCountPerShader; ++i) { + bindings.push_back(vk::DescriptorSetLayoutBinding() + .setBinding(static_cast(i)) + .setStageFlags(vk::ShaderStageFlagBits::eFragment) + .setDescriptorType(vk::DescriptorType::eCombinedImageSampler) + .setDescriptorCount(1)); } - return imageDescriptorSetLayout; -} - -const std::vector& Context::getDescriptorSetLayouts() { - if (descriptorSetLayouts.empty()) { - descriptorSetLayouts = { - buildUniformDescriptorSetLayout( - globalUniformDescriptorSetLayout, shaders::globalUBOCount, "GlobalUniformDescriptorSetLayout") - .get(), - buildUniformDescriptorSetLayout( - layerUniformDescriptorSetLayout, shaders::maxUBOCountPerLayer, "LayerUniformDescriptorSetLayout") - .get(), - buildUniformDescriptorSetLayout(drawableUniformDescriptorSetLayout, - shaders::maxUBOCountPerDrawable, - "DrawableUniformDescriptorSetLayout") - .get(), - getImageDescriptorSetLayout().get()}; - } - - return descriptorSetLayouts; + const auto descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo().setBindings(bindings); + drawableImageDescriptorSetLayout = backend.getDevice()->createDescriptorSetLayoutUnique( + descriptorSetLayoutCreateInfo); + backend.setDebugName(drawableImageDescriptorSetLayout.get(), "ImageDescriptorSetLayout"); } const vk::DescriptorSetLayout& Context::getDescriptorSetLayout(DescriptorSetType type) { - uint32_t index = static_cast(type); - assert(index < static_cast(DescriptorSetType::Count)); - return getDescriptorSetLayouts()[index]; + switch (type) { + case DescriptorSetType::Global: + return globalUniformDescriptorSetLayout.get(); + + case DescriptorSetType::Layer: + return layerUniformDescriptorSetLayout.get(); + + case DescriptorSetType::DrawableUniform: + return drawableUniformDescriptorSetLayout.get(); + + case DescriptorSetType::DrawableImage: + return drawableImageDescriptorSetLayout.get(); + + default: + assert(static_cast(type) < static_cast(DescriptorSetType::Count)); + return globalUniformDescriptorSetLayout.get(); + break; + } +} + +DescriptorPoolGrowable& Context::getDescriptorPool(DescriptorSetType type) { + assert(static_cast(type) < static_cast(DescriptorSetType::Count)); + return descriptorPoolMap[type]; } const vk::UniquePipelineLayout& Context::getGeneralPipelineLayout() { if (generalPipelineLayout) return generalPipelineLayout; - const auto& descriptorLayouts = getDescriptorSetLayouts(); + const std::vector layouts = { + globalUniformDescriptorSetLayout.get(), + layerUniformDescriptorSetLayout.get(), + drawableUniformDescriptorSetLayout.get(), + drawableImageDescriptorSetLayout.get(), + }; generalPipelineLayout = backend.getDevice()->createPipelineLayoutUnique( - vk::PipelineLayoutCreateInfo().setSetLayouts(descriptorLayouts)); + vk::PipelineLayoutCreateInfo().setSetLayouts(layouts)); backend.setDebugName(generalPipelineLayout.get(), "PipelineLayout_general"); @@ -620,7 +625,7 @@ const vk::UniquePipelineLayout& Context::getPushConstantPipelineLayout() { return pushConstantPipelineLayout; } -void Context::FrameResources::runDeletionQueue(const Context& context) { +void Context::FrameResources::runDeletionQueue(Context& context) { for (const auto& function : deletionQueue) function(context); deletionQueue.clear(); diff --git a/src/mbgl/vulkan/descriptor_set.cpp b/src/mbgl/vulkan/descriptor_set.cpp index 10f041002..79d2a86a8 100644 --- a/src/mbgl/vulkan/descriptor_set.cpp +++ b/src/mbgl/vulkan/descriptor_set.cpp @@ -3,8 +3,10 @@ #include #include #include +#include #include +#include namespace mbgl { namespace vulkan { @@ -14,25 +16,58 @@ DescriptorSet::DescriptorSet(Context& context_, DescriptorSetType type_) type(type_) {} DescriptorSet::~DescriptorSet() { - context.enqueueDeletion([sets = std::move(descriptorSets)](const auto& context_) mutable { - context_.getBackend().getDevice()->freeDescriptorSets(context_.getGlobalDescriptorPool().get(), sets); - }); + context.enqueueDeletion( + [type_ = type, poolIndex = descriptorPoolIndex, sets = std::move(descriptorSets)](auto& context_) mutable { + auto& poolInfo = context_.getDescriptorPool(type_).pools[poolIndex]; + context_.getBackend().getDevice()->freeDescriptorSets(poolInfo.pool.get(), sets); + poolInfo.remainingSets += sets.size(); + }); } +void DescriptorSet::createDescriptorPool(DescriptorPoolGrowable& growablePool) { + const auto& device = context.getBackend().getDevice(); + + const uint32_t maxSets = static_cast(growablePool.maxSets * + std::pow(growablePool.growFactor, growablePool.pools.size())); + const vk::DescriptorPoolSize size = {type != DescriptorSetType::DrawableImage + ? vk::DescriptorType::eUniformBuffer + : vk::DescriptorType::eCombinedImageSampler, + maxSets * growablePool.descriptorsPerSet}; + + const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet) + .setPoolSizes(size) + .setMaxSets(maxSets); + + growablePool.pools.emplace_back(device->createDescriptorPoolUnique(descriptorPoolInfo), maxSets); + growablePool.currentPoolIndex = growablePool.pools.size() - 1; +}; + void DescriptorSet::allocate() { if (!descriptorSets.empty()) { return; } const auto& device = context.getBackend().getDevice(); - const auto& descriptorPool = context.getGlobalDescriptorPool(); const auto& descriptorSetLayout = context.getDescriptorSetLayout(type); + auto& growablePool = context.getDescriptorPool(type); const std::vector layouts(context.getBackend().getMaxFrames(), descriptorSetLayout); - const auto descriptorAllocInfo = - vk::DescriptorSetAllocateInfo().setDescriptorPool(*descriptorPool).setSetLayouts(layouts); + if (growablePool.currentPoolIndex == -1 || growablePool.current().remainingSets < layouts.size()) { + const auto& poolIt = std::find_if(growablePool.pools.begin(), growablePool.pools.end(), [&](const auto& p) { + return p.remainingSets >= layouts.size(); + }); - descriptorSets = device->allocateDescriptorSets(descriptorAllocInfo); + if (poolIt != growablePool.pools.end()) { + growablePool.currentPoolIndex = std::distance(growablePool.pools.begin(), poolIt); + } else { + createDescriptorPool(growablePool); + } + } + + descriptorPoolIndex = growablePool.currentPoolIndex; + descriptorSets = device->allocateDescriptorSets( + vk::DescriptorSetAllocateInfo().setDescriptorPool(growablePool.current().pool.get()).setSetLayouts(layouts)); + growablePool.current().remainingSets -= descriptorSets.size(); markDirty(true); } diff --git a/src/mbgl/vulkan/texture2d.cpp b/src/mbgl/vulkan/texture2d.cpp index bd554e6f5..d461f68b9 100644 --- a/src/mbgl/vulkan/texture2d.cpp +++ b/src/mbgl/vulkan/texture2d.cpp @@ -201,7 +201,7 @@ void Texture2D::uploadSubRegion(const void* pixelData, enqueueCommands(commandBuffer); - context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](const auto&) mutable { buffAlloc.reset(); }); + context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](auto&) mutable { buffAlloc.reset(); }); context.renderingStats().numTextureUpdates++; } @@ -391,7 +391,7 @@ void Texture2D::createSampler() { void Texture2D::destroyTexture() { if (imageAllocation) { - context.enqueueDeletion([allocation = std::move(imageAllocation)](const auto&) mutable { allocation.reset(); }); + context.enqueueDeletion([allocation = std::move(imageAllocation)](auto&) mutable { allocation.reset(); }); imageLayout = vk::ImageLayout::eUndefined; } @@ -399,7 +399,7 @@ void Texture2D::destroyTexture() { void Texture2D::destroySampler() { if (sampler) { - context.enqueueDeletion([sampler_ = std::move(sampler)](const auto& context_) mutable { + context.enqueueDeletion([sampler_ = std::move(sampler)](auto& context_) mutable { context_.getBackend().getDevice()->destroySampler(sampler_); });