From 8e7c52b9b997f021566ced5ef4f76e342cb37ff0 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 28 Jul 2025 23:24:21 +0200 Subject: [PATCH] Add MLN_CREATE_AUTORELEASEPOOL flag to create autoreleasepool in render loop (#3655) --- CMakeLists.txt | 20 +++++++++++++++++++- src/mbgl/renderer/renderer_impl.cpp | 4 ++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f24a62dc..5e042ba95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,7 @@ option(MLN_USE_UNORDERED_DENSE "Use ankerl dense containers for performance" ON) option(MLN_USE_TRACY "Enable Tracy instrumentation" OFF) option(MLN_USE_RUST "Use components in Rust" OFF) option(MLN_CORE_INCLUDE_DEPS "Include depdendencies in static build of core" OFF) +option(MLN_CREATE_AUTORELEASEPOOL "Create autoreleasepool in render loop" OFF) if (MLN_LEGACY_RENDERER) message(FATAL "The legacy renderer is no longer supported") @@ -26,7 +27,6 @@ if (MLN_DRAWABLE_RENDERER) message(FATAL "Do not pass MLN_DRAWABLE_RENDERER, the drawable renderer is now the default") endif() - if (MLN_WITH_CLANG_TIDY) find_program(CLANG_TIDY_COMMAND NAMES clang-tidy) if(NOT CLANG_TIDY_COMMAND) @@ -1505,6 +1505,24 @@ set_target_properties( INTERFACE_MAPLIBRE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE.md ) +if(MLN_WITH_METAL AND MLN_CREATE_AUTORELEASEPOOL) + # When using the Metal backend, if there is is no AutoreleasePool, it will result + # in memory leaks when autoreleased objects are created. + + # Platforms such as iOS and GLFW use ARC with @autoreleasepool blocks, for these platforms + # creating an AutoreleasePool is not neccesary (and in fact will not work). + # When using MapLibre Native with Metal on other platforms such as Node.js, you can pass + # this variable to ensure an AutoReleasePool is created in the render loop. + # See also: + # https://developer.apple.com/documentation/foundation/nsautoreleasepool + # https://github.com/maplibre/maplibre-native/issues/2928 + # vendor/metal-cpp/README.md 'AutoreleasePools and Objects' + target_compile_definitions( + mbgl-core + PRIVATE MLN_CREATE_AUTORELEASEPOOL=1 + ) +endif() + set_property(TARGET mbgl-core PROPERTY FOLDER MapLibre) add_library( diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 50dc45910..e20789009 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -93,6 +93,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< assert(updateParameters); #if MLN_RENDER_BACKEND_METAL +#if MLN_CREATE_AUTORELEASEPOOL + NS::SharedPtr pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init()); +#endif + if constexpr (EnableMetalCapture) { const auto& mtlBackend = static_cast(backend);