[Tracking] Graphics Modernization (GM)

Author: birkskyumCreated May 15, 2026Updated Sep 16, 2026
Labelsenhancementperformancemeta

After sunsetting WebGL1 as part of GL JS v6 ( #3947 ) we are positioned to move the graphics pipeline forward towards a modern WebGL2 and WebGPU dual renderer. This is a tracking ticket for that modernization.

Phase 1 - Complete - WebGL2 Pre-Architectural Improvements - WebGL2 improvements that don't depend on the Drawable architecture from Phase 3. Texture allocation, shader attribute declaration, vertex attribute binding, and modern GLSL ES 3.00 features.

  • #7641
  • #7643
  • #7644
  • #7661
  • #8130
  • #8143
  • #8145

Phase 2 - Complete - Shared rendering state - Move projection, terrain and per-frame shader values into shared std140 UBOs. Bring shared rendering inputs together so they’re clearer to use and don’t need to be set up separately for each draw.

  • #8290
  • #8304
  • #8306
  • #8313
  • #8318
  • #8455
  • #8462

Checkpoint - Fix the horizong sky/atmosphere

  • #8299
  • #8464
  • #8466

Phase 3 - In Progress - Drawable Rendering Architecture - Each draw call becomes a persistent Drawable that carries its geometry, settings and uniform data, following maplibre-native's drawable / tweaker / uniform buffer design. Per-layer and per-drawable uniform data lives in one arena buffer and is re-uploaded only when it changes. Layers migrate one at a time; each layer's legacy draw path is deleted one release after its drawable path ships.

  • GM3.1 Keep background draw setup between frames using drawables
  • GM3.2 Move background shader values into shared GPU buffers
  • GM3.3 Move fill to drawables, with tile clipping, data-driven paint blocks, outlines and layer opacity
  • GM3.4 Move circle to drawables
  • GM3.5 Move line and its variants to drawables
  • GM3.6 Move raster, color relief and the hillshade render pass to drawables
  • GM3.7 Add render targets and move the offscreen passes to drawables
  • GM3.8 Move symbol and collision debug to drawables
  • GM3.9 Move sky, atmosphere, terrain, debug and clipping masks to drawables
  • GM3.10 Remove the legacy draw path
  • Closes #4511

Checkpoint - Fix the horizon fog

  • #4985
  • #4986
  • #4337

Phase 4 - Instanced Rendering - Draws repetitive features in bulk with WebGL2 instancing. Circles first, symbols if measurements justify it.

  • GM4.1 Add instancing to the Drawable contract
  • GM4.2 Instance circles
  • GM4.3 Instance symbols

Phase 5 - WebGPU Backend - A second executor (WebGPUDrawable) over the same drawables and block layouts, shipped as a lazily loaded chunk so the main bundle keeps one renderer.

  • GM5.1 Add the async renderer lifecycle seam and WebGPU device initialization, based on ibgreen's staged work
  • GM5.2 Add the WebGPU render pass and stencil clipping
  • GM5.3 Add backend-owned buffers
  • GM5.4 Render background end to end on WebGPU
  • GM5.x Move the remaining layers to WebGPU
  • Closes #2606
  • Supersedes #7411

Phase 6 - Evaluate luma.gl for shared WebGPU/WebGL2 code - There are PoC's that show a luma.gl backend is feasible on the current code. luma.gl v10 develops in parallel with Phases 3 to 5; once both GL JS backends exist, the question is whether luma.gl can replace the shared implementation layer, be offered as an optional backend next to it, or not be adopted.

  • GM6.1 Rebase the luma.gl evaluation onto the finished drawable architecture and luma.gl v10, and measure code, bundle chunk size, performance and feature coverage
  • GM6.2 Decide between adopting luma.gl, offering it as an optional backend, or staying direct
  • GM6.x Implement the decision
  • Closes #6206