Skip to main content

How the renderer works

What the render path does, how it is implemented, how it compares to tangram-ng, and why it differs where it does.

Split so a reader — human or agent — can open one page and get a whole subsystem. Every page states its scope at the top and links out rather than repeating.

Pick your page

You are working onRead
anything at all, first timeFrame & threads
frame order, threads, what runs where, redraw requestsFrame & threads
which tiles are chosen, LOD, fetching, decoding (MVT and MLT), cachesTiles & LOD
the GL draw path, style layers, draw counts, shadersGL vector-tile renderer
3D terrain: elevation data, surfaces, the ground pass3D terrain
bridges and tunnels: chords, decks, the opt-in switch, what is still wrong3D bridges
z-fighting, see-through, content sinking into the groundDepth model
labels: placement, flicker, glyph sharpness, anchoring onto terrainLabels
hillshade, contour lines, contour labels, hypsometric tintHillshade & contours
sun, shadows, sky, fogLighting, sky & fog
CompositeVectorTileLayer, style-driven slotsComposite layer
markers, popups, app-drawn lines/polygons, pickingVector elements
navigation maneuver arrows on a routeManeuver arrows
sun/moon/stars/aircraft placed in the skyCelestial objects
full-screen effects, the relief look, layers drawn above themPost-processing
making it faster, or measuring anythingPerformance
"why don't we just do what tangram does?"vs tangram-ng
which graphics API we target, ES 3.0, Metal, ANGLE, new platformsGraphics API migration

The dated measurement history is a separate lab notebook: Performance log. These pages are the current design; that one is what was tried.

One frame

Detail in Frame & threads. The PROF sections of a -PprofileRender build map onto these boxes one-for-one.

Two rules that shaped the render code

1. tangram-ng is the reference implementation, and we copy it. Where it does something differently, we adopt its way rather than designing an alternative. Its constants are copied, not derived — every constant this project derived instead turned out wrong (failure catalogue in Depth model). Each mechanism is ported whole: half of their depth model was measurably worse than none of it, three times over. When comparing, read their scene files (res/scenes/*.yaml), not only their shaders — the shader defaults are overridden there.

2. The RTT drape is being deleted and is deliberately not documented. The old path baked flat 2D content into per-tile render-target textures and textured the terrain with them. It still exists behind TerrainOptions.DrapeFillsEnabled and --es drape true in the demo, but the shared ground (3D terrain) replaced it. Do not build on it, and do not extend these pages to cover it.

Where the render code lives

PathWhat
all/native/renderers/frame orchestration (MapRenderer), per-kind renderers, TileRenderer (the bridge into vt)
all/native/renderers/workers/CullWorker, VTLabelPlacementWorker, BillboardPlacementWorker
all/native/layers/TileLayer, VectorTileLayer, RasterTileLayer, HillshadeRasterTileLayer, CompositeVectorTileLayer
all/native/terrain/ElevationManager, ElevationTileGrid, TerrainTileTransformer
all/native/datasources/tile sources, including the on-the-fly ContourTileDataSource
libs-massif/vt/the GL renderer: GLTileRenderer, TileSurfaceBuilder, Label, LabelCuller, shaders
libs-massif/mapnikvt, cartocsstile decoding and style evaluation

vt has no logger — probe it with __android_log_print(4, "massif", …), and throttle a probe shared by several renderer instances with a prime modulus.