Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,5 @@ out.png
**/target/
**/*.rs.bk
**/*.profraw
/.claude
/DoNotCommitToGit
2 changes: 2 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ exports_files(
[
"LICENSE.md",
"scripts/style-spec-reference/v8.json",
"src/mbgl/plugin/plugin_manager.hpp",
"src/mbgl/plugin/plugin.cpp",
],
visibility = ["//visibility:public"],
)
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,10 @@ list(APPEND SRC_FILES
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_properties.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_impl.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_layer_factory.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_manager.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_map_layer.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/plugin/plugin_style_preprocessor.cpp
)

include(${PROJECT_SOURCE_DIR}/cmake/opengl.cmake)
Expand Down
10 changes: 10 additions & 0 deletions bazel/core.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ MLN_LAYER_PLUGIN_HEADERS = [
"src/mbgl/plugin/plugin_layer_impl.hpp",
"src/mbgl/plugin/plugin_layer_render.hpp",
"src/mbgl/plugin/plugin_layer_properties.hpp",
"src/mbgl/plugin/plugin_style_filter.hpp",
"src/mbgl/plugin/plugin.hpp",
"src/mbgl/plugin/plugin_style_preprocessor.hpp",
"src/mbgl/plugin/plugin_manager.hpp",
"src/mbgl/plugin/plugin_map_layer.hpp",
]

MLN_LAYER_PLUGIN_SOURCE = [
Expand All @@ -12,6 +17,11 @@ MLN_LAYER_PLUGIN_SOURCE = [
"src/mbgl/plugin/plugin_layer_impl.cpp",
"src/mbgl/plugin/plugin_layer_render.cpp",
"src/mbgl/plugin/plugin_layer_properties.cpp",
"src/mbgl/plugin/plugin_style_filter.cpp",
"src/mbgl/plugin/plugin.cpp",
"src/mbgl/plugin/plugin_style_preprocessor.cpp",
"src/mbgl/plugin/plugin_manager.cpp",
"src/mbgl/plugin/plugin_map_layer.cpp",
]

MLN_PUBLIC_GENERATED_STYLE_HEADERS = [
Expand Down
5 changes: 2 additions & 3 deletions bazel/flags.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ WARNING_FLAGS = {

GCC_CLANG_CPP_FLAGS = [
"-fexceptions",
"-fno-rtti",
"-ftemplate-depth=1024",
"-std=c++20",
]
Expand All @@ -99,8 +98,8 @@ MSVC_CPP_FLAGS = [

CPP_FLAGS = select({
"//conditions:default": GCC_CLANG_CPP_FLAGS,
"@platforms//os:ios": GCC_CLANG_CPP_FLAGS + WARNING_FLAGS["ios"] + ["-fvisibility=hidden"],
"@platforms//os:macos": GCC_CLANG_CPP_FLAGS + WARNING_FLAGS["macos"] + ["-fvisibility=hidden"],
"@platforms//os:ios": GCC_CLANG_CPP_FLAGS + WARNING_FLAGS["ios"] + ["-fvisibility=default"], # + ["-fvisibility=hidden"],
"@platforms//os:macos": GCC_CLANG_CPP_FLAGS + WARNING_FLAGS["macos"] + ["-fvisibility=default"], # + ["-fvisibility=hidden"],
"@platforms//os:linux": GCC_CLANG_CPP_FLAGS + WARNING_FLAGS["linux"],
"@platforms//os:windows": MSVC_CPP_FLAGS + WARNING_FLAGS["windows"],
})
Expand Down
49 changes: 49 additions & 0 deletions design-proposals/2026-07-07-cpp-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# C++ Plugins Design Proposal

## Motivation

MapLibre Native currently requires new layer types and style-loading behavior to be implemented inside the core engine or platform SDKs. This makes small rendering experiments, proprietary overlays, and platform-specific extensions expensive to maintain because they need to live in a fork or wait for upstream layer support.

The C++ plugins work adds a narrow extension point for registering plugin-provided layer types and style preprocessors at runtime.

## Proposed Change

The change introduces a core plugin API under `mbgl::plugin`:

* `MapLayerType` describes a custom style layer type, its paint/property metadata, and how to create the runtime layer object.
* `MapLayer` is the plugin-owned runtime layer implementation. It receives drawing state, evaluated properties, memory events, and a platform rendering context.
* `StylePreprocessor` can transform style JSON before the core style parser processes it.
* Platform code provides a `RenderingContext` subtype so plugin layers can render with the active backend, such as Metal on Darwin or OpenGL on Android.

`PluginManager` is the central runtime registry for these plugin extension points. It is a singleton so plugin code can register itself before maps or styles are loaded. For layer plugins, it stores registered `MapLayerType` instances and forwards them into the existing `LayerManager` by creating plugin layer factories. When the style parser later encounters that custom layer type, the factory creates a `PluginLayer`, wires it to the plugin's `MapLayer`, passes evaluated properties to the plugin, and calls the plugin's update and render callbacks during normal map rendering.

For style preprocessors, `PluginManager` stores a list of `StylePreprocessor` instances. During style load, the style implementation runs the loaded style JSON through the registered preprocessors before parsing. This allows plugins to adapt style documents without changing the core parser.

## API Modifications

The feature adds C++ APIs for:

* registering plugin map layer types,
* registering style preprocessors,
* defining plugin layer properties,
* receiving drawing context and platform rendering context callbacks.

Darwin and Android add platform glue and examples showing how SDK/application code can register plugin layers and pass backend-specific rendering objects to plugin code.

## Use Cases

This enables:

* custom rendered overlays that should participate in the map render loop,
* proprietary or experimental layer types outside the core style specification,
* platform-specific rendering integrations using Metal, OpenGL, or future backends,
* style JSON preprocessing for compatibility layers, feature flags, or plugin-specific style syntax,
* plugin example libraries that can be developed and shipped independently from the core SDK.

## Migration Plan and Compatibility

The changes are additive. Existing styles and applications continue to work without registering plugins. Plugin layers are only used when application code registers a plugin layer type and a loaded style references that custom layer type.

## Rejected Alternatives

The main alternative is to keep adding every custom layer type directly to core. That keeps the style parser simpler but forces experimentation and product-specific rendering into the main engine. A runtime plugin registry keeps the core API smaller while still allowing advanced users to extend rendering behavior.
3 changes: 3 additions & 0 deletions include/mbgl/style/style.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace style {
class Light;
class Source;
class Layer;
class PluginStyleFilter;

class Style {
public:
Expand Down Expand Up @@ -71,6 +72,8 @@ class Style {
void addLayer(std::unique_ptr<Layer>, const std::optional<std::string>& beforeLayerID = std::nullopt);
std::unique_ptr<Layer> removeLayer(const std::string& layerID);

void addStyleFilter(std::shared_ptr<mbgl::style::PluginStyleFilter>);

// Private implementation
class Impl;
const std::unique_ptr<Impl> impl;
Expand Down
1 change: 1 addition & 0 deletions include/mbgl/util/vectors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace mbgl {

using vec2 = std::array<double, 2>;
using vec2i = std::array<int, 2>;
using vec3 = std::array<double, 3>;
using vec3f = std::array<float, 3>;
using vec3i = std::array<int, 3>;
Expand Down
18 changes: 18 additions & 0 deletions platform/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ objc_library(
"//platform/darwin:darwin_objcpp_custom_drawable_srcs",
],
}),
hdrs = [
"//platform/darwin:darwin_plugin_hdrs"
],
copts = CPP_FLAGS + MAPLIBRE_FLAGS + [
"-fcxx-modules",
"-fmodules",
Expand Down Expand Up @@ -221,6 +224,16 @@ objc_library(
],
)


cc_library(
name = "hpp_headers",
hdrs = [
"//:src/mbgl/plugin/plugin_manager.hpp",
],
includes = ["."], # public include prefix
visibility = ["//visibility:public"],
)

# sdk for the dynamic target. Lacking the resources bundle since for dynamic
# they are in the main package.
objc_library(
Expand All @@ -239,6 +252,7 @@ objc_library(
deps = [
":objc-sdk",
":objcpp-sdk",
":hpp_headers",
],
)

Expand Down Expand Up @@ -315,6 +329,10 @@ objc_library(
"//platform/darwin:app/ExampleCustomDrawableStyleLayer.h",
"//platform/darwin:app/PluginLayerExample.h",
"//platform/darwin:app/PluginLayerExample.mm",
"//platform/darwin:app/StyleFilterExample.h",
"//platform/darwin:app/StyleFilterExample.mm",
"//platform/darwin:app/PluginLayerExampleMetalRenderingCPP.hpp",
"//platform/darwin:app/PluginLayerExampleMetalRenderingCPP.mm",
"//platform/darwin:app/PluginLayerExampleMetalRendering.h",
"//platform/darwin:app/PluginLayerExampleMetalRendering.mm",
"//platform/ios:ios_app_objcpp_srcs",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "plugin_platform_android.hpp"
#include <mbgl/plugin/plugin_map_layer.hpp>
#include <mbgl/layermanager/layer_manager.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/plugin/plugin_style_preprocessor.hpp>
#include <mbgl/plugin/plugin_manager.hpp>
#include <mbgl/gl/command_encoder.hpp>
#include <mbgl/gl/render_pass.hpp>

using namespace mbgl::plugin;

extern "C" mbgl::plugin::RenderingContext *createPlatformRenderingContext(
[[maybe_unused]] mbgl::PaintParameters &paintParameters) {
RenderingContextAndroidOpenGL *renderingContext = new RenderingContextAndroidOpenGL();

return renderingContext;
}

extern "C" {
__attribute__((used)) __attribute__((visibility("default"))) void _force_link_MapLayerTypeAndroid() {
(void)sizeof(mbgl::plugin::PluginManager);
(void)sizeof(mbgl::plugin::LayerProperty);
(void)sizeof(mbgl::plugin::MapLayerType);
(void)sizeof(mbgl::plugin::DrawingContext);
(void)sizeof(mbgl::plugin::RenderingContext);
(void)sizeof(mbgl::plugin::MapLayer);
(void)sizeof(mbgl::plugin::StylePreprocessor);

auto lp = std::make_shared<mbgl::plugin::LayerProperty>();
auto lt = std::make_shared<mbgl::plugin::MapLayerType>();
auto dc = std::make_shared<mbgl::plugin::DrawingContext>();
auto rc = std::make_shared<mbgl::plugin::RenderingContext>();
auto l = std::make_shared<mbgl::plugin::MapLayer>();
auto sp = std::make_shared<mbgl::plugin::StylePreprocessor>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef MAPLIBREANDROID_PLUGIN_PLATFORM_ANDROID_HPP
#define MAPLIBREANDROID_PLUGIN_PLATFORM_ANDROID_HPP

#include <mbgl/plugin/plugin_map_layer.hpp>

namespace mbgl {

namespace plugin {

class RenderingContextAndroidOpenGL : public RenderingContext {
public:
};

} // namespace plugin

} // namespace mbgl

#endif // MAPLIBREANDROID_PLUGIN_PLATFORM_ANDROID_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void LayerManagerAndroid::registerCoreFactory(mbgl::LayerFactory* factory) {
JavaLayerPeerFactory* LayerManagerAndroid::getPeerFactory(const mbgl::style::LayerTypeInfo* typeInfo) {
assert(typeInfo);
for (const auto& factory : peerFactories) {
if (factory->getLayerFactory()->getTypeInfo() == typeInfo) {
if (layerTypeInfoEquals(factory->getLayerFactory()->getTypeInfo(), typeInfo)) {
return factory.get();
}
}
Expand All @@ -154,7 +154,7 @@ LayerFactory* LayerManagerAndroid::getFactory(const mbgl::style::LayerTypeInfo*
}

for (const auto& factory : coreFactories) {
if (factory->getTypeInfo() == info) {
if (layerTypeInfoEquals(factory->getTypeInfo(), info)) {
return factory.get();
}
}
Expand Down
1 change: 1 addition & 0 deletions platform/android/MapLibreAndroidTestApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ kotlin {

dependencies {
implementation(project(":MapLibreAndroid"))
implementation(project(":MapLibrePluginsExampleLibrary"))

implementation(libs.maplibreNavigation) {
exclude(group = "org.maplibre.gl", module = "android-sdk")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,19 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
android:name=".activity.maplayout.PluginMapActivity"
android:description="@string/description_plugin_map"
android:exported="true"
android:label="@string/activity_plugin_map"
android:launchMode="singleInstance">
<meta-data
android:name="@string/category"
android:value="@string/category_basic" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
android:name=".activity.maplayout.SimpleMapActivity"
android:description="@string/description_simple_map"
Expand Down
Loading
Loading