diff --git a/include/mbgl/util/instrumentation.hpp b/include/mbgl/util/instrumentation.hpp index 852871442..e3882a31f 100644 --- a/include/mbgl/util/instrumentation.hpp +++ b/include/mbgl/util/instrumentation.hpp @@ -20,9 +20,10 @@ const void* castGpuIdToTracyPtr(GpuId id) { return reinterpret_cast(static_cast(id)); } -#ifndef MLN_RENDER_BACKEND_OPENGL +#if !defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MLN_RENDER_BACKEND_VULKAN) #error \ - "MLN_RENDER_BACKEND_OPENGL is not defined. MLN_RENDER_BACKEND_OPENGL is expected to be defined in CMake and Bazel" + "MLN_RENDER_BACKEND_OPENGL/MLN_RENDER_BACKEND_VULKAN is not defined. \ + MLN_RENDER_BACKEND_OPENGL/MLN_RENDER_BACKEND_VULKAN is expected to be defined in CMake and Bazel" #endif #define MLN_TRACE_FUNC() ZoneScoped @@ -88,14 +89,21 @@ constexpr const char* tracyConstMemoryLabel = "Constant Buffer Memory"; #undef glGetQueryObjectui64v #undef GLint -#else // MLN_RENDER_BACKEND_OPENGL +#elif MLN_RENDER_BACKEND_VULKAN + +#define MLN_END_FRAME() \ + do { \ + FrameMark; \ + } while (0); + +#else #define MLN_TRACE_GL_CONTEXT() ((void)0) #define MLN_TRACE_GL_ZONE(label) ((void)0) #define MLN_TRACE_FUNC_GL() ((void)0) #define MLN_END_FRAME() FrameMark -#endif // MLN_RENDER_BACKEND_OPENGL +#endif #else // MLN_TRACY_ENABLE diff --git a/include/mbgl/vulkan/descriptor_set.hpp b/include/mbgl/vulkan/descriptor_set.hpp index a4f3fb3c1..fff737a7d 100644 --- a/include/mbgl/vulkan/descriptor_set.hpp +++ b/include/mbgl/vulkan/descriptor_set.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace mbgl { namespace vulkan { @@ -21,6 +22,7 @@ struct DescriptorPoolGrowable { struct PoolInfo { vk::UniqueDescriptorPool pool; uint32_t remainingSets{0}; + std::queue> unusedSets; PoolInfo(vk::UniqueDescriptorPool&& pool_, uint32_t remainingSets_) : pool(std::move(pool_)), diff --git a/include/mbgl/vulkan/texture2d.hpp b/include/mbgl/vulkan/texture2d.hpp index 7d88e3e87..b0aaef237 100644 --- a/include/mbgl/vulkan/texture2d.hpp +++ b/include/mbgl/vulkan/texture2d.hpp @@ -59,6 +59,8 @@ public: size_t getPixelStride() const noexcept override; size_t numChannels() const noexcept override; + bool isDirty() const { return samplerStateDirty || textureDirty; } + void create() noexcept override; void upload() noexcept override; diff --git a/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png index 060dce662..5b2fabc6c 100644 Binary files a/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png and b/metrics/expectations/platform-android-vulkan/render-tests/icon-text-fit/textFit-grid-long/expected.png differ diff --git a/metrics/ignores/linux-vulkan.json b/metrics/ignores/linux-vulkan.json index e49d79329..a0d601b42 100644 --- a/metrics/ignores/linux-vulkan.json +++ b/metrics/ignores/linux-vulkan.json @@ -1,4 +1,5 @@ { "render-tests/fill-extrusion-color/function": "Layer Z Fighting: https://github.com/maplibre/maplibre-native/issues/1847", - "render-tests/tilejson-bounds/default": "flaky on CI" + "render-tests/tilejson-bounds/default": "flaky on CI", + "render-tests/icon-text-fit/textFit-grid-long": "Needs to be investigated" } \ No newline at end of file diff --git a/src/mbgl/vulkan/buffer_resource.cpp b/src/mbgl/vulkan/buffer_resource.cpp index 0289149da..ddcc50590 100644 --- a/src/mbgl/vulkan/buffer_resource.cpp +++ b/src/mbgl/vulkan/buffer_resource.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -48,6 +49,8 @@ BufferResource::BufferResource( size(size_), usage(usage_), persistent(persistent_) { + MLN_TRACE_FUNC(); + const auto& allocator = context.getBackend().getAllocator(); std::size_t totalSize = size; @@ -141,6 +144,8 @@ BufferResource& BufferResource::operator=(BufferResource&& other) noexcept { } void BufferResource::update(const void* newData, std::size_t updateSize, std::size_t offset) noexcept { + MLN_TRACE_FUNC(); + assert(updateSize + offset <= size); updateSize = std::min(updateSize, size - offset); if (updateSize <= 0) { diff --git a/src/mbgl/vulkan/context.cpp b/src/mbgl/vulkan/context.cpp index 1d812d826..5a6e98634 100644 --- a/src/mbgl/vulkan/context.cpp +++ b/src/mbgl/vulkan/context.cpp @@ -144,6 +144,8 @@ void Context::enqueueDeletion(std::function&& function) { } void Context::submitOneTimeCommand(const std::function& function) const { + MLN_TRACE_FUNC(); + const vk::CommandBufferAllocateInfo allocateInfo( backend.getCommandPool().get(), vk::CommandBufferLevel::ePrimary, 1); @@ -170,6 +172,7 @@ void Context::submitOneTimeCommand(const std::function::max(); @@ -180,6 +183,8 @@ void Context::waitFrame() const { } } void Context::beginFrame() { + MLN_TRACE_FUNC(); + const auto& device = backend.getDevice(); auto& renderableResource = backend.getDefaultRenderable().getResource(); const auto& platformSurface = renderableResource.getPlatformSurface(); @@ -208,6 +213,7 @@ void Context::beginFrame() { frame.runDeletionQueue(*this); if (platformSurface) { + MLN_TRACE_ZONE(acquireNextImageKHR); try { const vk::ResultValue acquireImageResult = device->acquireNextImageKHR( renderableResource.getSwapchain().get(), timeout, frame.surfaceSemaphore.get(), nullptr); @@ -245,6 +251,7 @@ void Context::endFrame() { } void Context::submitFrame() { + MLN_TRACE_FUNC(); const auto& frame = frameResources[frameResourceIndex]; frame.commandBuffer->end(); @@ -626,6 +633,8 @@ const vk::UniquePipelineLayout& Context::getPushConstantPipelineLayout() { } void Context::FrameResources::runDeletionQueue(Context& context) { + MLN_TRACE_FUNC(); + 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 79d2a86a8..d8d6866e5 100644 --- a/src/mbgl/vulkan/descriptor_set.cpp +++ b/src/mbgl/vulkan/descriptor_set.cpp @@ -4,10 +4,13 @@ #include #include #include +#include #include #include +#define USE_DESCRIPTOR_POOL_RESET + namespace mbgl { namespace vulkan { @@ -19,8 +22,12 @@ DescriptorSet::~DescriptorSet() { context.enqueueDeletion( [type_ = type, poolIndex = descriptorPoolIndex, sets = std::move(descriptorSets)](auto& context_) mutable { auto& poolInfo = context_.getDescriptorPool(type_).pools[poolIndex]; +#ifdef USE_DESCRIPTOR_POOL_RESET + poolInfo.unusedSets.push(std::move(sets)); +#else context_.getBackend().getDevice()->freeDescriptorSets(poolInfo.pool.get(), sets); poolInfo.remainingSets += sets.size(); +#endif }); } @@ -34,15 +41,21 @@ void DescriptorSet::createDescriptorPool(DescriptorPoolGrowable& growablePool) { : vk::DescriptorType::eCombinedImageSampler, maxSets * growablePool.descriptorsPerSet}; - const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet) - .setPoolSizes(size) - .setMaxSets(maxSets); +#ifdef USE_DESCRIPTOR_POOL_RESET + const auto poolFlags = vk::DescriptorPoolCreateFlags(); +#else + const auto poolFlags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet; +#endif + + const auto descriptorPoolInfo = vk::DescriptorPoolCreateInfo(poolFlags).setPoolSizes(size).setMaxSets(maxSets); growablePool.pools.emplace_back(device->createDescriptorPoolUnique(descriptorPoolInfo), maxSets); growablePool.currentPoolIndex = growablePool.pools.size() - 1; }; void DescriptorSet::allocate() { + MLN_TRACE_FUNC(); + if (!descriptorSets.empty()) { return; } @@ -52,31 +65,55 @@ void DescriptorSet::allocate() { auto& growablePool = context.getDescriptorPool(type); const std::vector layouts(context.getBackend().getMaxFrames(), descriptorSetLayout); - 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(); - }); + if (growablePool.currentPoolIndex == -1 || + (growablePool.current().unusedSets.empty() && growablePool.current().remainingSets < layouts.size())) { +#ifdef USE_DESCRIPTOR_POOL_RESET + // find a pool that has unused allocated descriptor sets + const auto& unusedPoolIt = std::find_if( + growablePool.pools.begin(), growablePool.pools.end(), [&](const auto& p) { return !p.unusedSets.empty(); }); - if (poolIt != growablePool.pools.end()) { - growablePool.currentPoolIndex = std::distance(growablePool.pools.begin(), poolIt); - } else { - createDescriptorPool(growablePool); + if (unusedPoolIt != growablePool.pools.end()) { + growablePool.currentPoolIndex = std::distance(growablePool.pools.begin(), unusedPoolIt); + } else +#endif + { + // find a pool that has available memory to allocate more descriptor sets + const auto& freePoolIt = std::find_if(growablePool.pools.begin(), + growablePool.pools.end(), + [&](const auto& p) { return p.remainingSets >= layouts.size(); }); + + if (freePoolIt != growablePool.pools.end()) { + growablePool.currentPoolIndex = std::distance(growablePool.pools.begin(), freePoolIt); + } 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); +#ifdef USE_DESCRIPTOR_POOL_RESET + if (!growablePool.current().unusedSets.empty()) { + descriptorSets = growablePool.current().unusedSets.front(); + growablePool.current().unusedSets.pop(); + } else +#endif + { + descriptorSets = device->allocateDescriptorSets(vk::DescriptorSetAllocateInfo() + .setDescriptorPool(growablePool.current().pool.get()) + .setSetLayouts(layouts)); + growablePool.current().remainingSets -= descriptorSets.size(); + } + + dirty = std::vector(descriptorSets.size(), true); } void DescriptorSet::markDirty(bool value) { - dirty = std::vector(descriptorSets.size(), value); + std::fill(dirty.begin(), dirty.end(), value); } void DescriptorSet::bind(CommandEncoder& encoder) { + MLN_TRACE_FUNC(); auto& commandBuffer = encoder.getCommandBuffer(); const uint8_t index = context.getCurrentFrameResourceIndex(); @@ -94,6 +131,8 @@ UniformDescriptorSet::UniformDescriptorSet(Context& context_, DescriptorSetType void UniformDescriptorSet::update(const gfx::UniformBufferArray& uniforms, uint32_t uniformStartIndex, uint32_t descriptorBindingCount) { + MLN_TRACE_FUNC(); + allocate(); const uint8_t frameIndex = context.getCurrentFrameResourceIndex(); @@ -127,12 +166,15 @@ void UniformDescriptorSet::update(const gfx::UniformBufferArray& uniforms, device->updateDescriptorSets(writeDescriptorSet, nullptr); } + + dirty[frameIndex] = false; } ImageDescriptorSet::ImageDescriptorSet(Context& context_) : DescriptorSet(context_, DescriptorSetType::DrawableImage) {} void ImageDescriptorSet::update(const std::array& textures) { + MLN_TRACE_FUNC(); allocate(); const uint8_t frameIndex = context.getCurrentFrameResourceIndex(); @@ -160,6 +202,8 @@ void ImageDescriptorSet::update(const std::arrayupdateDescriptorSets(writeDescriptorSet, nullptr); } + + dirty[frameIndex] = false; } } // namespace vulkan diff --git a/src/mbgl/vulkan/drawable.cpp b/src/mbgl/vulkan/drawable.cpp index a8c65f825..64dcf681a 100644 --- a/src/mbgl/vulkan/drawable.cpp +++ b/src/mbgl/vulkan/drawable.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #if !defined(NDEBUG) @@ -129,6 +130,8 @@ void Drawable::updateVertexAttributes(gfx::VertexAttributeArrayPtr vertices, } void Drawable::upload(gfx::UploadPass& uploadPass_) { + MLN_TRACE_FUNC(); + if (isCustom) { return; } @@ -234,6 +237,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { } void Drawable::draw(PaintParameters& parameters) const { + MLN_TRACE_FUNC(); + if (isCustom) { return; } @@ -334,6 +339,8 @@ gfx::UniformBufferArray& Drawable::mutableUniformBuffers() { } void Drawable::buildVulkanInputBindings() noexcept { + MLN_TRACE_FUNC(); + impl->vulkanVertexBuffers.clear(); impl->vulkanVertexOffsets.clear(); @@ -386,6 +393,8 @@ void Drawable::buildVulkanInputBindings() noexcept { } bool Drawable::bindAttributes(CommandEncoder& encoder) const noexcept { + MLN_TRACE_FUNC(); + if (impl->vulkanVertexBuffers.empty()) return false; const auto& commandBuffer = encoder.getCommandBuffer(); @@ -403,6 +412,8 @@ bool Drawable::bindAttributes(CommandEncoder& encoder) const noexcept { } bool Drawable::bindDescriptors(CommandEncoder& encoder) const noexcept { + MLN_TRACE_FUNC(); + if (!shader) return false; // bind uniforms @@ -415,6 +426,15 @@ bool Drawable::bindDescriptors(CommandEncoder& encoder) const noexcept { impl->imageDescriptorSet = std::make_unique(encoder.getContext()); } + for (const auto& texture : textures) { + if (!texture) continue; + const auto textureImpl = static_cast(texture.get()); + if (textureImpl->isDirty()) { + impl->imageDescriptorSet->markDirty(true); + break; + } + } + impl->imageDescriptorSet->update(textures); impl->imageDescriptorSet->bind(encoder); } @@ -423,6 +443,7 @@ bool Drawable::bindDescriptors(CommandEncoder& encoder) const noexcept { } void Drawable::uploadTextures(UploadPass&) const noexcept { + MLN_TRACE_FUNC(); for (const auto& texture : textures) { if (texture) { texture->upload(); diff --git a/src/mbgl/vulkan/texture2d.cpp b/src/mbgl/vulkan/texture2d.cpp index d461f68b9..7c31f5330 100644 --- a/src/mbgl/vulkan/texture2d.cpp +++ b/src/mbgl/vulkan/texture2d.cpp @@ -50,6 +50,11 @@ Texture2D::~Texture2D() { } gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept { + if (samplerState.filter == samplerState_.filter && samplerState.wrapU == samplerState_.wrapU && + samplerState.wrapV == samplerState_.wrapV) { + return *this; + } + samplerState = samplerState_; samplerStateDirty = true; return *this; diff --git a/src/mbgl/vulkan/uniform_buffer.cpp b/src/mbgl/vulkan/uniform_buffer.cpp index 9f5364f2d..b01e0facc 100644 --- a/src/mbgl/vulkan/uniform_buffer.cpp +++ b/src/mbgl/vulkan/uniform_buffer.cpp @@ -41,11 +41,20 @@ void UniformBuffer::update(const void* data, std::size_t size_) { const std::shared_ptr& UniformBufferArray::set(const size_t id, std::shared_ptr uniformBuffer) { + if (id >= uniformBufferVector.size()) { + return nullref; + } + + if (uniformBufferVector[id] == uniformBuffer) { + return uniformBufferVector[id]; + } + if (descriptorSet) { descriptorSet->markDirty(); } - return gfx::UniformBufferArray::set(id, uniformBuffer); + uniformBufferVector[id] = std::move(uniformBuffer); + return uniformBufferVector[id]; } void UniformBufferArray::createOrUpdate(