From 764accc8f5be4fca165ed10224c1fb97bae77834 Mon Sep 17 00:00:00 2001 From: Taku Fukada Date: Tue, 14 Jul 2026 02:04:18 +0900 Subject: [PATCH] core: Fix Vulkan snapshot timing for headless too (#4397) Co-authored-by: Adrian Cojocaru --- .../include/mbgl/vulkan/headless_backend.hpp | 2 - .../src/mbgl/vulkan/headless_backend.cpp | 20 ++------ src/mbgl/vulkan/renderable_resource.cpp | 48 +++++++++---------- 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/platform/default/include/mbgl/vulkan/headless_backend.hpp b/platform/default/include/mbgl/vulkan/headless_backend.hpp index 97319c32a..e4f035d6a 100644 --- a/platform/default/include/mbgl/vulkan/headless_backend.hpp +++ b/platform/default/include/mbgl/vulkan/headless_backend.hpp @@ -38,8 +38,6 @@ private: private: std::unique_ptr impl; bool active = false; - - std::unique_ptr texture; }; } // namespace vulkan diff --git a/platform/default/src/mbgl/vulkan/headless_backend.cpp b/platform/default/src/mbgl/vulkan/headless_backend.cpp index 5083d1ec2..2e55df35f 100644 --- a/platform/default/src/mbgl/vulkan/headless_backend.cpp +++ b/platform/default/src/mbgl/vulkan/headless_backend.cpp @@ -26,8 +26,8 @@ public: void bind() override {} void swap() override { + queueSurfaceRead(); SurfaceRenderableResource::swap(); - static_cast(backend.getContext()).waitFrame(); } }; @@ -42,8 +42,6 @@ HeadlessBackend::HeadlessBackend(const Size size_, HeadlessBackend::~HeadlessBackend() { gfx::BackendScope guard{*this, gfx::BackendScope::ScopeType::Implicit}; - texture.reset(); - // Explicitly reset the renderable resource resource.reset(); // Explicitly reset the context so that it is destructed and cleaned up @@ -79,21 +77,11 @@ PremultipliedImage HeadlessBackend::readStillImage() { resource = std::make_unique(*this); } - auto& contextImpl = static_cast(*context); auto& resourceImpl = static_cast(*resource); - if (!texture) { - texture = std::make_unique(contextImpl); - texture->setFormat(gfx::TexturePixelType::RGBA, gfx::TextureChannelDataType::UnsignedByte); - texture->setUsage(Texture2DUsage::Read); - } - - texture->setSize(size); - - contextImpl.waitFrame(); - texture->copyImage(resourceImpl.getAcquiredImage(), size); - - return std::move(*texture->readImage()); + auto image = resourceImpl.readImage(); + assert(image); + return std::move(*image); } RendererBackend* HeadlessBackend::getRendererBackend() { diff --git a/src/mbgl/vulkan/renderable_resource.cpp b/src/mbgl/vulkan/renderable_resource.cpp index c219a64b9..c114b69e2 100644 --- a/src/mbgl/vulkan/renderable_resource.cpp +++ b/src/mbgl/vulkan/renderable_resource.cpp @@ -483,7 +483,9 @@ void SurfaceRenderableResource::queueSurfaceRead() { } surfaceRead = true; - backend.getContext().requestSurfaceUpdate(false); + if (surface) { + backend.getContext().requestSurfaceUpdate(false); + } } void SurfaceRenderableResource::copySurfaceToReadTexture() { @@ -502,25 +504,23 @@ void SurfaceRenderableResource::copySurfaceToReadTexture() { const auto swapchainImage = getAcquiredImage(); auto& commandBuffer = contextImpl.getCommandBuffer(); - if (surface) { - const auto barrier = vk::ImageMemoryBarrier() + const auto oldLayout = surface ? vk::ImageLayout::ePresentSrcKHR : vk::ImageLayout::eTransferSrcOptimal; + const auto srcStage = vk::PipelineStageFlagBits::eColorAttachmentOutput; + const vk::AccessFlags srcAccess = vk::AccessFlagBits::eColorAttachmentWrite; + const vk::AccessFlags dstAccess = vk::AccessFlagBits::eTransferRead; + + const auto readBarrier = vk::ImageMemoryBarrier() .setImage(swapchainImage) - .setOldLayout(vk::ImageLayout::ePresentSrcKHR) + .setOldLayout(oldLayout) .setNewLayout(vk::ImageLayout::eTransferSrcOptimal) - .setSrcAccessMask({}) - .setDstAccessMask(vk::AccessFlagBits::eTransferWrite) + .setSrcAccessMask(srcAccess) + .setDstAccessMask(dstAccess) .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); - commandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, - vk::PipelineStageFlagBits::eTransfer, - {}, - nullptr, - nullptr, - barrier, - dispatcher); - } + commandBuffer->pipelineBarrier( + srcStage, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, readBarrier, dispatcher); bool useBlit = surface && @@ -536,22 +536,22 @@ void SurfaceRenderableResource::copySurfaceToReadTexture() { } if (surface) { - const auto barrier = vk::ImageMemoryBarrier() - .setImage(swapchainImage) - .setOldLayout(vk::ImageLayout::eTransferSrcOptimal) - .setNewLayout(vk::ImageLayout::ePresentSrcKHR) - .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead) - .setDstAccessMask(vk::AccessFlagBits::eTransferWrite) - .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); + const auto presentBarrier = vk::ImageMemoryBarrier() + .setImage(swapchainImage) + .setOldLayout(vk::ImageLayout::eTransferSrcOptimal) + .setNewLayout(vk::ImageLayout::ePresentSrcKHR) + .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead) + .setDstAccessMask(vk::AccessFlagBits::eTransferWrite) + .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); commandBuffer->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, - barrier, + presentBarrier, dispatcher); } }