feat(scripting): frame generational collector for wasm scripts (#13869) 0613f5b262
* add rive --bench for headless frame timing and a rasc runtime env override

* map the guest sampler compare sentinel to none instead of casting it raw

* stage tier ladder wamrc input before the in-place module load corrupts it

* compile ladder artifacts with sw bounds checks so non guard page runtimes can run them

* carry the execution tier through the shared module cache and let bench wait for the o3 swap

* add an allocation churn kernel to the wamr bench

* recurring leak warnings with a time-to-trap estimate, arena modules watched too

* allocation-free Mat4 Into builders and multiply, reusable render pass wrapper, cached canvas view

* deliver decode completions at the frame boundary and re-take the mark around them and resize

* build the canvas view wrapper eagerly so it cannot land above a frame arena mark

* rive.yaml wasmRuntime choice and finalizer-based handle release under the collecting runtime

* pregrow aot memory to the declared ceiling and cap ladder artifacts at opt level 1

* let tlsf claim pregrown memory before growing so aot pregrow does not read as oom

* per runtime leak wording via a collected marker export and trap context after warnings

* hw bounds artifact species on the tier ladder for guard page builds

* cap hw artifacts at opt level 0, the miscompile bites earlier without inline checks

* bind ASC_RUNTIME so runtime-gated std branches stop compiling as stub

* register the handle finalizer through the runtime, pin its closure, zero renew slack

* finalizer, soak and aot differential coverage plus a no-ceiling aot notice

* frame collector milestone 0: checked arena runtime, design doc and per-visitor generation fix

* frame collector milestone 1: cheney scavenger, moving visitors, remembered set, exact handle reap

* record frame collector m1 status in the design doc

* pass multivalue through bake postOptimize so value struct modules survive wasm-opt

* add RIVE_RASC_UNSAFE bake hatch and inert arena hooks on collecting runtimes

* record box2d and fields comparison results in the frame gc design doc

* frame collector milestone 2: copying major, large objects born old, pin list, debug heap verifier

* spill start function managed locals to the shadow stack so mid-init itcms steps see them

* count majors for telemetry and pin the threshold trigger with a fixture

* design doc: record milestone 2 and the copying major decision

* android armv7 wamr lane and a headless on-device gc bench tool

* calibrate the major threshold at the first boundary instead of collecting init retention

* declare THUMBV7 to the aot loader and print fault addresses in the device bench

* design doc: console validation results and the arm32 aot lane status

* fix wamrc strict fp miscompile: strictfp on generated functions, codegen cap below ir opt, ladder lifts sw to optimized ir

* frame collector milestone 3: sliced major marks and sweeps across boundaries for big heaps

* design doc: record milestone 3

* address review: reentrant decode cancel, bump-based leak watch under pregrow, pin chunk refcounts, stale view wrapper on resize, windows bench build

* check in the churn soak project used for on-device collector validation

* address review round two: carve capacity includes the block gap, unpin marks during majors, gate the bench target, hw species in the ladder test

* address review round three: reject bad bench counts, version the artifact cache, cover late visitor stubs, clear remembered bits at the copying major

* pin the leak warning firing, unpin-during-sweep, and stale remembered bit with tests

* match the pin contract: trap on double pin and foreign unpin

* twin the function env visitor and cover closure survival under the frame collector

* export the major tuning knobs from frame bakes and stop callModule folding traps and missing exports into zero

* consolidate on the frame collector: delete tcms and the arena lane, deprecate incremental, default wasmRuntime to frame

* remove the incremental runtime: itcms, tlsf, and the shadow stack live on archive/rasc-gc-experiments with tcms and the arena

* sweep retained chunks in sliced majors, relocate DataView dataStart, atomic ladder cache writes, review fixes

* gc bench covers every module vm and the tier bench fails when the O3 swap never lands

* objects born in the old region during a sweep only carry a mark while the sweep still covers their chunk

* switch the sweep to the retained list even when the budget dies on the last old chunk

* reject non-positive --bench frame counts

* renumber our wamrc patches past master's 0013 windows patch

Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
11 files changed
tree: 0877a4128a4cacf44e74c30e5e4b4d63cfe556a9
  1. .github/
  2. .vscode/
  3. build/
  4. cg_renderer/
  5. decoders/
  6. dependencies/
  7. dev/
  8. include/
  9. renderer/
  10. rivinfo/
  11. scripting/
  12. skia/
  13. src/
  14. tests/
  15. utils/
  16. .dockerignore
  17. .gitattributes
  18. .gitignore
  19. .lua-format
  20. .rive_head
  21. .version
  22. Dockerfile
  23. Doxyfile
  24. dummy.cpp
  25. LICENSE
  26. premake5_v2.lua
  27. README.md
  28. runtime.natvis
README.md

Build Status Discord badge Twitter handle

rive-runtime

Rive hero image

Rive's C++ runtime — the lowest-level Rive runtime. Loads .riv files, advances state machines and animations, and draws via the abstract Renderer interface. The built-in GPU renderer (RiveRenderer) has RenderContextImpl backends for Metal, Vulkan, D3D11, D3D12, and OpenGL/WebGL.

Rive's Apple, Android, Flutter, Unity, Unreal, and web runtimes all wrap this library.

Features:

  • Loading artboards and their contents from .riv files.
  • Querying state machines from artboards.
  • Mutating the artboard hierarchy (the same mechanism used by state machines) and efficiently solving those changes via Artboard::advance.
  • A state-of-the-art vector renderer for Metal, Vulkan, D3D12, D3D11, and OpenGL/WebGL.
  • An abstract Renderer interface for hooking up an external vector renderer.

Prerequisites

  • A C++17 toolchain:
    • macOS: clang from Xcode Command Line Tools (xcode-select --install).
    • Linux: clang from your distro (e.g. apt install clang).
    • Windows: Visual Studio 2022 with the C++ Clang Compiler for Windows and MSBuild support for LLVM (clang-cl) toolset individual components.
  • git — the build script clones a pinned premake5 on first run. On Windows, install Git for Windows and during setup pick “Use Git and optional Unix tools from the Command Prompt” so that sh.exe ends up on PATH.
  • Platform SDK for the renderer you're targeting:
    • macOS / iOS: Xcode.
    • Windows: Windows SDK (for D3D).
    • Linux: a Vulkan or OpenGL development environment.
    • Vulkan: the Vulkan SDK.

Build

The build is driven by premake5 wrapped by a helper script:

  • build/build_rive.sh — macOS / Linux (bash) / Windows (MinGW).
  • build/build_rive.ps1 — a PowerShell convenience wrapper for Windows; it shells out to the bash script, so a bash environment (Git for Windows / MinGW, see Prerequisites) must still be on PATH.

The helper self-installs the pinned premake version on first run and dispatches to the right build system for your platform (gmake2 on macOS/Linux, MSBuild on Windows). It must be run from a directory that contains a premake5.lua — typically tests/, which builds the core library, the GPU renderer, and the player sample app.

macOS / Linux

git clone https://github.com/rive-app/rive-runtime.git
cd rive-runtime/tests
../build/build_rive.sh release

Windows

git clone https://github.com/rive-app/rive-runtime.git
cd rive-runtime\tests
..\build\build_rive.ps1 release

Common variants

(On Windows, substitute build_rive.ps1 for build_rive.sh.)

  • build_rive.sh (no args) — debug build for the host.
  • build_rive.sh release clean — clean then build release.
  • build_rive.sh ninja release — use Ninja instead of make/MSBuild.
  • build_rive.sh ios release — cross-compile for iOS.
  • build_rive.sh android release — cross-compile for Android (defaults to arm64).
  • build_rive.sh ninja release wasm — cross-compile for WebAssembly.
  • build_rive.sh --toolset=msc release (Windows) — build with MSVC's cl.exe instead of clang-cl. The build supports both toolchains; the lua warning suppressions cover MSVC too.

See the comment header at the top of build/build_rive.sh for the complete flag reference.

Build outputs

Artifacts land in out/<config>/ relative to the directory you built from (typically tests/). The config directory encodes any OS/arch flags you passed:

  • out/release, out/debug — host build.
  • out/ios_release, out/android_arm64_release, out/wasm_release — cross-compile builds.
ArtifactDescription
librive.a / rive.libCore runtime library.
librive_pls_renderer.a / rive_pls_renderer.libGPU renderer.
player / player.exeSample app — loads and renders a .riv file.
out/<config>/goldens, out/<config>/gms, out/<config>/benchTest harness binaries (regression, golden-image, benchmarking).
librive_decoders.a, librive_harfbuzz.a, …Supporting libraries.

Testing

The runtime's primary form of testing is golden testing — rendering known scenes and diffing the output against checked-in reference images via the goldens and gms test harness binaries (built into out/<config>/goldens and out/<config>/gms). See tests/ for how to run and rebaseline goldens.

Unit tests are secondary and use the Catch2 framework. From the repo root:

cd tests/unit_tests
./test.sh

Unit tests live in tests/unit_tests/runtime/ (core runtime) and tests/unit_tests/renderer/ (renderer). To add a test, create an xxx_test.cpp file in the appropriate directory — the harness picks it up automatically.

Code formatting

rive-runtime uses clang-format.

  • macOS: brew install clang-format.
  • Windows: already installed if you have the prerequisites — VS 2022's C++ Clang Compiler component ships clang-format.exe alongside clang-cl.exe at C:\Program Files\Microsoft Visual Studio\2022\<edition>\VC\Tools\Llvm\x64\bin\. You can also install LLVM standalone from llvm.org or via winget install LLVM.LLVM.
  • Linux: install via your distro's package manager (e.g. apt install clang-format).

Memory checks (macOS only)

To run the tests under macOS's built-in leaks tool:

cd tests/unit_tests
./test.sh memory

This wraps the test binary with leaks --atExit, which ships with macOS — no install required. The memory flag is ignored on Linux and Windows.

Disassembly explorer (macOS / Linux)

To inspect generated assembly per cpp file, install the Disassembly Explorer VSCode extension. A disassemble task is provided in .vscode/tasks.json. The underlying gen assembly task invokes clang++ directly, so it needs clang++ on PATH — works out of the box on macOS (Xcode CLI tools) and most Linux distros, but not on a default Windows + VS install (which provides clang-cl.exe, not clang++.exe).

Reach the task from Tasks: Run Task, or bind a key in keybindings.json:

[
    {
        "key": "cmd+d",
        "command": "workbench.action.tasks.runTask",
        "args": "disassemble"
    }
]