This directory hosts the C++ version of the MapLibre Native + Slint example. It mirrors the Rust implementation under rust/ but uses the C++ MapLibre API and the Slint C++ bindings.
From the repository root:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build./build/maplibre-slint-examplemain.cpp— application entry point and UI wiringmap_window.slint— Slint UI definition that generatesmap_window.hsrc/slint_maplibre_headless.*— MapLibre headless integration and rendering
maplibre-slint-example (above) renders the map with mbgl::HeadlessFrontend
and copies every frame back to the CPU (readStillImage) before handing it to
Slint. maplibre-slint-gl instead renders MapLibre Native directly into an
OpenGL texture inside Slint's own GL context and hands that texture to Slint
as a borrowed texture (slint::Image::create_from_borrowed_gl_2d_rgba_texture).
There is no GPU->CPU readback and no second GL context, which suits
GPU-constrained devices such as the Raspberry Pi.
How it works:
- A custom
mbgl::gl::RendererBackend+mbgl::gfx::Renderable(src/slint_gl_backend.*, modelled on the upstream GLFW backend) renders into an FBO whose colour texture lives in Slint's GL context. GL entry points are loaded viaeglGetProcAddress;activate()/deactivate()are no-ops because Slint's context is already current inside the rendering-notifier callback. main_gl.cppcreates the FBO/texture (+ depth/stencil) duringRenderingState::RenderingSetup, renders the map into it duringBeforeRendering, and publishes the texture withcreate_from_borrowed_gl_2d_rgba_texture(..., BottomLeft).gl_map_window.slintis a small-panel / touch layout (large buttons, a right-edge vertical zoom slider + zoom buttons, no pitch/bearing sliders).
Requires the OpenGL backend (not WebGPU) and Slint's FemtoVG GL renderer. On a Raspberry Pi running on the console over DRM/KMS, also use the libseat linuxkms backend:
cmake -B build -DCMAKE_BUILD_TYPE=Release \
-DMLN_WITH_OPENGL=ON -DMLN_WITH_WEBGPU=OFF -DMLN_WITH_GLFW=OFF \
-DSLINT_FEATURE_RENDERER_FEMTOVG=ON \
-DSLINT_FEATURE_BACKEND_LINUXKMS=ON
cmake --build build --target maplibre-slint-glThe target is compiled with -fno-rtti to match mbgl-core
(MLN_WITH_RTTI=OFF).
SLINT_BACKEND=linuxkms ./build/cpp/maplibre-slint-gl| Variable | Effect |
|---|---|
MAPLIBRE_STYLE_URL |
Initial style URL |
MAPLIBRE_WIDTH / MAPLIBRE_HEIGHT |
Render size (default: the display resolution) |
MAPLIBRE_FLY_MS |
flyTo duration in ms for the city buttons (default 2500) |
Verified on a Raspberry Pi 4 (Debian trixie, aarch64, V3D / vc4-kms-v3d) with a
480x320 HDMI touch panel (Quimat MPI3508) on the console over DRM/KMS:
- DRM master: install/enable
seatd, add the user to thevideogroup, and build Slint withSLINT_FEATURE_BACKEND_LINUXKMS=ON(libseat). seatd grants DRM master without an X11/Wayland session or an active VT. - Display mode: the MPI3508 only advertises standard HDMI modes (it scales
internally to 480x320); a raw 480x320 CVT signal is rejected. For less
downscaling, force e.g.
video=HDMI-A-1:720x576@50incmdline.txt. - Touch: the XPT2046/ADS7846 resistive controller is single-touch (no
pinch). Enable
dtparam=spi=onanddtoverlay=ads7846,cs=1,penirq=25,..., then set a libinput calibration matrix via udev, e.g.ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 -1 0 1"for this panel/orientation. Resistive panels have a dead zone at the very edges, so keep interactive controls inset with a margin (the Pi layout does this). Double-tap zooms in (detected inhandle_mouse_press); zoom out with the on-screen zoom buttons/slider. - maplibre-native renders on the Pi's V3D GPU, composited zero-copy by Slint;
the
flyTocamera animation stays smooth.
A few integration details matter when extending the zero-copy GL example on V3D:
- Re-render every frame. V3D is a tiled GPU and treats the FBO colour
attachment as transient: skipping
frontend->render()on idle frames discards the borrowed texture and the map turns white or black. Drive a repaint every frame rather than only on map invalidation. - Save and restore GL state around the render. Slint's FemtoVG renderer
shares the GL context, so the
BeforeRenderingcallback snapshots and restores the framebuffer binding, viewport, current program, array/element buffer bindings, active texture, and theBLEND/DEPTH_TEST/SCISSOR_TEST/CULL_FACEenables aroundfrontend->render(). Without that, Slint's own drawing is corrupted. - Borrowed-texture size. A borrowed GL texture is composited at its native
size (it is not scaled to the element via
image-fit), so create the FBO at the display resolution.