Skip to content
Русский

1. Performance — adaptive quality

  • Model: the engine ships two named quality tiers, Floor and Rich (ADR-0045), carried as a TierConfig of capacity values (particle counts, segment budget, internal-grid caps) resolved at renderer construction and, since ADR-0054, re-resolvable on the live context by an explicit Renderer::set_tier (the standalone’s [ / ] and its settings menu). One of those capacities is no longer a single number. Since ADR-0140 the attractor’s sample budget is a density against the render target — the tier’s attractor_particles is the anchor of clamp(round(anchor * target_px / 230400), anchor, ceiling), resolved per target size rather than once at construction, against a frame-time ceiling in a window and a larger memory-bound one under shot --render. The allocation is still made once, at the ceiling, so a resize moves the drawn count and rebuilds no GPU resource. That law scales a cloud and not a trace. Since ADR-0195 a [particles] density at or below 0.08 takes its fraction of the anchor instead, so a sparse world draws the same number of trajectories at every target size; at or above 0.16 the target-scaled budget is what the fraction is taken of, unchanged; between the two the effective budget blends linearly. The budget itself never moves, so this lowers the drawn count at a large target and never raises it. Floor’s live ceiling is its anchor, which is what keeps this section’s floor commitment true at every target size. The values are capacities read at resource-construction time, so a change rebuilds GPU resources and costs one visible re-accumulation of trails and feedback; nothing branches on the tier per frame. A tier changes how much the engine draws, never what — so the same preset reads the same on both, at different budgets.

  • Selection: unpinned resolves Rich, and a frame-time governor demotes it to Floor on a sustained miss of the display’s refresh budget — once per session, one way, reported in the diagnostics overlay and on stderr, never silently. There is no auto-promotion: a demotion is predictable and testable, where an oscillating or continuously feature-shedding design is neither (ADR-0045 Alternatives A/B).

  • Pinning: --tier floor|rich, RLX_TIER, or config.toml’s [quality] tier, in that precedence. A pin is honoured in both directions and the governor never touches it — which is the escape hatch for a capable machine that a transient stall demoted. An in-app change also pins, and clears the governor’s demotion latch: ADR-0045’s “the latch is never cleared” narrows to “never cleared by the governor” (ADR-0054). It writes [quality] tier, so the launch precedence above is unchanged.

  • Floor: ≥ 60 fps at 1080p on the baseline hardware (below) at the Floor tier, whose values are exactly the pre-tier engine’s. The floor commitment is unchanged by tiering: the governor means a mispredicted rich budget degrades to a known-good state instead of stuttering. As of 2026-09-23 this number has never been read on the hardware it names, which is the honest status of the oldest commitment on this page. The instrument exists now — an advisory per-preset frame cost in shot --report (ADR-0232) — and the walk that would produce the reading is specified in On-device validation, gated on §9’s iGPU box being in hand. Read the bullet as a commitment this project holds itself to, not as a measurement it has taken. The nearest reading, on a newer integrated part than the baseline names (2026-09-26, the reference laptop’s AMD Radeon RADV RENOIR, Mesa 26.2.2, Linux, 1920x1080 windowed, music playing, ten heaviest presets, grid scale 1.0): Floor held a 60 fps median with no one-second sample under 60 on every preset, worst sample 106.1 fps (Leviathan), and held at the panel’s native 2560x1440 too, worst 94.0 fps. A 2020 integrated GPU is not a ~2015 one, so this does not discharge the bullet; it bounds it from above. Files: scripts/bench/results/linux-2026-09-26-live-amd-*.tsv.

  • Rich: calibrated against a midrange discrete GPU (RTX 3060 / RX 6600 class) on device, not asserted from a multiplier — Plan 0044 Phase 4.

  • A tier’s frame-time figure names its grid scale. Since ADR-0245 every internal grid is a fraction of the target, resolved in a window from the tier and the adapter’s class: Rich on an integrated GPU draws its grids at 0.75, and every other combination at 1.0, discrete and software by decision. A headless capture takes 1.0 whatever the adapter unless --grid-scale pins it. The 0.75 is the measured row: on the laptop above, Rich at 1.0 missed at 1080p (41.5–50.1 fps median on Nebula, Leviathan and Clifford), and 0.75 is the largest scale that held — worst sample exactly 60.0 fps, Nebula, none under. At 2560x1440 no Rich scale held (Nebula 58.7 fps at 0.5), so on that machine at that size the governor’s demotion to Floor is the answer. A figure quoted for a tier without its scale predates this bullet and was taken at 1.0.

  • Background cost: when the window is minimized or fully occluded, rendering throttles to near-zero GPU; DSP may keep running so visuals resume in sync.

  • frame_ms_p99 spikes on a GPU resource rebuild, and a governor reading it bare would demote a preset that is running fine. Read this before designing the governor — it qualifies the instrument the design is specified to read. Measured over three minutes at Rich tier, 1080p, with preset switching and a fullscreen toggle (Plan 0046 Phase 5, backlog 0082):

    value
    fps median / min165.0 / 114.3
    rows below this section’s 60 fps floor0 of 158
    frame_ms_avg median / max6.061 / 8.749 ms
    frame_ms_p99 median / max6.866 / 25.037 ms
    frames dropped0 of 28,698

    The budget holds with ~2.7x headroom and nothing is dropped, yet p99 passes 16.67 ms. The spikes coincide with the preset switches and the fullscreen toggle: they are the cost of rebuilding GPU resources, not of running the preset. A demotion fired on one of them would change what the audience sees during the event that is already the most visually disruptive.

    Three candidate responses were named, and choosing between them is the governor’s own design decision — this file deliberately does not choose. Exclude the frames following a switch or surface reconfigure from the governor’s window; require N consecutive bad windows rather than one; or read a separate steady-state statistic and leave p99 the diagnostic it is today. Whichever is taken, the measurement above is the test case.

    The shipped governor does not read p99 at all, and that is worth knowing before anyone “fixes” it (checked against core/src/render/tier.rs at Plan 0085 Phase 4, and it contradicts backlog 0082’s own premise that the governor “is specified to read p99”). sustained_miss counts what fraction of the raw frame-time series exceeds budget × MISS_FACTOR and demotes only when 75 % of at least 180 samples miss. A preset switch contributes a handful of slow frames to a 240-sample ring, which cannot approach that fraction — so the governor as built already landed the second candidate response, in the form of a miss fraction rather than consecutive windows. What is still live is the wording: the roadmap item and the backlog entry both describe a governor that reads p99, and a future revisit starting from that description would reintroduce the hazard this measurement documents.

    Every figure above is an integrated-GPU figure, and here is the discrete one beside it (Plan 0147 Phase 6, 2026-09-06). The table above is not edited — a corrected number and a second number answer different questions, and only the second preserves the comparison. These two rows are a matched pair taken on one build minutes apart, 1920x1080 windowed, Rich tier, rotation on with a 20-40 s dwell so switches land inside the window, ~172 one-second samples each. They are not comparable to the three-minute run above, which is a different build and adds a fullscreen toggle this pair does not perform:

    unflagged--gpu pinned
    adapterAMD Radeon(TM) Graphics (Dx12, IntegratedGpu)NVIDIA GeForce RTX 3080 Laptop GPU (Dx12, DiscreteGpu)
    fps median / min112.8 / 37.8165.0 / 162.2
    frame_ms_avg median / max8.863 / 26.490 ms6.061 / 6.164 ms
    frame_ms_p99 median / max12.889 / 31.619 ms6.276 / 8.936 ms
    frames dropped00
    samples under the 60 fps floor21 of 1710 of 172

    What moves is the spread, not just the level. The discrete part holds the 165 Hz vsync cap through every switch — its worst p99 sample is 8.936 ms, inside one 6.06 ms vblank of the median — while the integrated part spends 21 samples under this section’s own 60 fps floor and reaches 31.619 ms. Neither drops a frame. The unflagged run is what an operator gets by default (ADR-0071: a frame-time figure names the machine that produced it), so the floor commitment is met on the part that is not being measured whenever a published figure carries no adapter.

    Provenance, 2026-09-22. Every unflagged windowed row in this section — the three-minute table and the unflagged column of the pair above — was measured under the previous default, which asked the graphics layer for its plain choice and on a hybrid machine received the integrated part. An unflagged window now prefers the high-performance adapter (ADR-0246), so a fresh unflagged run no longer reproduces the integrated-part rows; the numbers are not edited, because each names its adapter and stays readable as history. What is void is the sentence before this note: an unflagged run is no longer what lands on the integrated part, and reading any figure here as “what you get by default” needs the adapter column, not the flag column.

    The instrument for the third response exists anyway: --soak writes frame_ms_p99_steady beside the raw frame_ms_p99, the same statistic with the frames following a switch or reconfigure left out, alongside a monotone switches counter (Plan 0085 Phase 3, ADR-0099). It is a reading, not a gate — nothing demotes on it today.

  • Captures pin Floor. Headless capture is floor-tier by construction (Renderer::new_headless cannot produce another tier, and set_tier is a no-op on a surface-less context — the guard ADR-0054 adds so the runtime switch cannot reopen this), so every golden baseline stays byte-reproducible on the WARP software adapter and the suite’s cost does not scale with the rich tier. Rich is covered by capture-level spot checks plus the on-device checklist — a real QA gap, named rather than solved (ADR-0045 Consequences). See Headless capture and video.

Built from 13c7582 at version 0.158.0. This site tracks main and is not versioned per release.