Concept
Performance you can measure.
X-GIS treats frame budget as something to measure, not guess. Three mechanisms carry the load: one shared GPU buffer with byte-aware eviction, data-driven paint that can move to an opt-in compute pass, and a real GPU-timestamp profiler that prints a GPU-vs-CPU verdict on screen.
The GPU arena
At zoom 14 over a dense basemap a frame touches on the order of ten thousand tile meshes. Giving each its own GPU buffer means a buffer swap per tile and thousands of tiny allocations. X-GIS instead packs tiles into one large shared buffer and hands out byte offsets.
One shared buffer, not thousands
O(1) allocation with exact-footprint reuse
alloc is a free-list pop or
a bump-pointer bump — constant time. The free-list is keyed by the
exact 4-byte-aligned footprint, so a reused slot always fits the
request and can never overrun its neighbour. Real tiles cluster around
a few stride-aligned sizes, so reuse stays high during pan and zoom.
Byte-aware eviction, compaction, and auto-grow
Compute kernels for paint
Data-driven paint — a colour or width chosen per feature from its properties — can be moved off the fragment shader and evaluated once per frame in a compute pass.
Per-feature paint, evaluated once on the GPU
match,
a conditional (case/ternary), and interpolate
each have their own emitter — for the runtime's
ComputeDispatcher to dispatch,
writing one packed RGBA per feature into a storage buffer the draw pass
reads. Routing is selective: only paint whose value depends on feature
properties is eligible for the compute path; zoom-only paint stays
elsewhere. High-arm match
expressions switch from an if-else chain to a constant lookup table.
This path is opt-in — armed with ?compute=1
(the enableComputePath option); by
default feature-dependent paint still evaluates in the fragment shader,
and no production style turns the compute path on yet.
Real GPU-time measurement
CPU wall-clock around a draw call tells you almost nothing — the GPU runs asynchronously. X-GIS reads the real device time with WebGPU timestamp queries.
WebGPU timestamp queries, not wall-clock guesses
?gpuprof=1), the
GPUTimer plants timestamp queries
around each render pass and resolves them through a small readback ring
— so the number reported is actual GPU execution time, hidden behind a
couple of frames of map latency rather than blocking the frame.
Per-pass GPU and per-phase CPU breakdown
frame.prep,
frame.encode,
frame.submit, and per-pass encode
times, each tracking its mean and its worst single frame. The
marks are off by default — they cost real CPU — and arm with
?perfmarks=1 or
?gpuprof=1.
The on-screen verdict
Mobile testers can't open DevTools. The playground carries an on-screen scoreboard that runs a fixed camera sweep and prints — and one-tap copies — the numbers.
GPU-bound or CPU-bound, decided on screen
?perf=1 for
the scoreboard. Its GPU/CPU button runs a rotate-and-pitch sweep while a
message-channel probe measures how long the main thread is busy: if the
worst stall fills the frame the verdict is
CPU-bound; if the main thread sits idle
waiting on present, GPU-bound. It also
captures the worst frame anywhere in the run and attributes it —
inside-render (naming the pass) versus the tile drain chain — so a
bursty stall a mean would hide gets pinned down.
Quality knobs
X-GIS generally avoids quality settings — the goal is to render correctly and fast, not to ship sliders. There is exactly one opt-in exception, because a GPU-bound scene physically can't hit a high frame rate without trading MSAA or pixel density.
One opt-in trade-off, always explicit
performance,
balanced,
battery) and URL flags
(?quality,
?msaa,
?dpr,
?adaptiveDpr) trade fidelity for
budget. The default keeps full quality. Under balanced
/ battery (or an explicit
?adaptiveDpr=N) the renderer
drops device-pixel-ratio during an active pan or zoom and restores it
when the gesture settles — pan motion hides the lower density. It is
inert otherwise. The engine never adapts quality on its own; the
trade-off is always something a host opted into.
Where it is going
Roadmap · not yet shipped
These are planned, not built. They are on the roadmap, not in the engine today:
- → Automatic quality adaptation — a closed loop that watches measured frame time (or thermal pressure) and lowers DPR / MSAA on its own. Today the trade-off is opt-in only; there is no automatic, FPS- or thermal-driven downgrade.
- → Always-on perf HUD — the GPU/CPU verdict and frame-phase breakdown live in the playground scoreboard behind a URL flag, not as a product-facing overlay in the embedding API.
Tracked in the repo ROADMAP.md ↗.
See it live
Open the
playground
or pick a map from the
examples gallery,
then append ?perf=1&gpuprof=1
to the demo URL. Tap 측정 to run the
sweep, or GPU/CPU 판정 for the
bound-by verdict, then copy the report.
Specifications
See also
- →Compute paint — How feature-dependent paint is routed to a compute kernel instead of the fragment shader.
- →Compile pipeline — Where the WGSL — fragment and compute — is generated from a .xgis source.
- →RTC + DSFUN precision — The f32-precision scheme that keeps the cheap-to-render geometry correct at any zoom.
Problem on this page?