From 32eed7a806e4fc0720a89b2f3457e7e7d88a349f Mon Sep 17 00:00:00 2001 From: Adrian Cojocaru Date: Thu, 8 Jan 2026 12:54:58 +0200 Subject: [PATCH] Fix Vulkan headless backend resize (#4030) --- include/mbgl/mtl/texture2d.hpp | 1 + .../src/mbgl/vulkan/headless_backend.cpp | 7 +++++- src/mbgl/mtl/texture2d.cpp | 24 +++++++++++++++---- src/mbgl/vulkan/texture2d.cpp | 8 +++++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/include/mbgl/mtl/texture2d.hpp b/include/mbgl/mtl/texture2d.hpp index 0d8706a89..e2024c996 100644 --- a/include/mbgl/mtl/texture2d.hpp +++ b/include/mbgl/mtl/texture2d.hpp @@ -66,6 +66,7 @@ public: private: MTL::PixelFormat getMetalPixelFormat() const noexcept; void createMetalTexture() noexcept; + void destroyMetalTexture() noexcept; Context& context; MTLTexturePtr metalTexture; diff --git a/platform/default/src/mbgl/vulkan/headless_backend.cpp b/platform/default/src/mbgl/vulkan/headless_backend.cpp index f862acf91..307add68f 100644 --- a/platform/default/src/mbgl/vulkan/headless_backend.cpp +++ b/platform/default/src/mbgl/vulkan/headless_backend.cpp @@ -75,16 +75,21 @@ gfx::Renderable& HeadlessBackend::getDefaultRenderable() { } PremultipliedImage HeadlessBackend::readStillImage() { + if (!resource) { + 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->setSize(size); texture->setUsage(Texture2DUsage::Read); } + texture->setSize(size); + contextImpl.waitFrame(); texture->copyImage(resourceImpl.getAcquiredImage()); diff --git a/src/mbgl/mtl/texture2d.cpp b/src/mbgl/mtl/texture2d.cpp index e55cd2272..935598ec0 100644 --- a/src/mbgl/mtl/texture2d.cpp +++ b/src/mbgl/mtl/texture2d.cpp @@ -14,10 +14,7 @@ Texture2D::Texture2D(Context& context_) : context(context_) {} Texture2D::~Texture2D() { - if (metalTexture) { - context.renderingStats().numActiveTextures--; - context.renderingStats().memTextures -= getDataSize(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall) - } + destroyMetalTexture(); } gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept { @@ -36,6 +33,9 @@ gfx::Texture2D& Texture2D::setFormat(gfx::TexturePixelType pixelFormat_, if (pixelFormat_ == pixelFormat && channelType_ == channelType) { return *this; } + + destroyMetalTexture(); + pixelFormat = pixelFormat_; channelType = channelType_; textureDirty = true; @@ -46,6 +46,9 @@ gfx::Texture2D& Texture2D::setSize(mbgl::Size size_) noexcept { if (size_ == size) { return *this; } + + destroyMetalTexture(); + size = size_; textureDirty = true; return *this; @@ -146,7 +149,8 @@ void Texture2D::createMetalTexture() noexcept { if (size == Size{0, 0}) { return; } - metalTexture.reset(); + + destroyMetalTexture(); const auto format = getMetalPixelFormat(); if (format == MTL::PixelFormat::PixelFormatInvalid) { @@ -195,6 +199,16 @@ void Texture2D::create() noexcept { } } +void Texture2D::destroyMetalTexture() noexcept { + if (!metalTexture) { + return; + } + + metalTexture.reset(); + context.renderingStats().numActiveTextures--; + context.renderingStats().memTextures -= getDataSize(); +} + gfx::Texture2D& Texture2D::setUsage(MTL::TextureUsage usage_) noexcept { usage = usage_; textureDirty = true; diff --git a/src/mbgl/vulkan/texture2d.cpp b/src/mbgl/vulkan/texture2d.cpp index 48a43c077..e812ba368 100644 --- a/src/mbgl/vulkan/texture2d.cpp +++ b/src/mbgl/vulkan/texture2d.cpp @@ -62,6 +62,9 @@ gfx::Texture2D& Texture2D::setFormat(gfx::TexturePixelType pixelFormat_, if (pixelFormat_ == pixelFormat && channelType_ == channelType) { return *this; } + + destroyTexture(); + pixelFormat = pixelFormat_; channelType = channelType_; textureDirty = true; @@ -72,6 +75,9 @@ gfx::Texture2D& Texture2D::setSize(mbgl::Size size_) noexcept { if (size_ == size) { return *this; } + + destroyTexture(); + size = size_; textureDirty = true; return *this; @@ -267,6 +273,8 @@ vk::SamplerAddressMode Texture2D::vulkanAddressMode(const gfx::TextureWrapType t void Texture2D::createTexture() { if (size.width == 0 || size.height == 0) return; + destroyTexture(); + const auto& backend = context.getBackend(); const auto format = vulkanFormat(pixelFormat, channelType);