Environment
|
|
rive |
0.14.11 |
rive_native |
0.1.11 |
| Flutter |
3.44.7 |
| Build |
flutter build web --wasm --profile (dart2wasm, skwasm renderer) |
| Browser |
Chrome 151, macOS |
| Factory |
Factory.rive |
Summary
On web, an artboard that contains embedded raster assets appears to re-upload those
rasters to the GPU on every draw pass, rather than uploading once per render
texture and reusing the resident texture. The uploads are synchronous on the renderer
main thread, so each one costs a dropped frame.
Evidence
Chrome performance trace with disabled-by-default-v8.cpu_profiler enabled. All CPU
samples inside the affected main-thread slices resolve to a single stack:
RiveNativeRenderBox.paintTexture
ArtboardWidgetPainter.paint
BasicArtboardPainter.paint
WebRiveArtboard.drawInternal
Module._artboardDrawInternal
upload_image
texImage2D
upload_image sitting inside _artboardDrawInternal is the part that looks wrong —
it puts the upload in the draw path rather than in texture setup.
The uploads are not front-loaded. If this were a one-time residency cost they would
cluster at the start of the artboard's life. Bucketing texImage2D samples at 100 ms
against Rive paint samples over one artboard's ~915 ms of activity:
bucket (ms) texImage2D rive-paint
0-100 390 523
100-200 468 541
200-300 0 748
300-400 0 729
400-500 530 578
500-600 369 454
600-700 507 578
700-800 525 625
800-900 555 653
900-1000 93 93
first half: 1388 uploads second half: 2049
Uploads track the paint count bucket for bucket, and the second half has more than
the first — consistent with per-draw re-upload, not per-mount.
Control case. A vector-only artboard (no embedded rasters), same build and browser,
drawing continuously for 10.5 s under sustained pointer input: 1105 Rive paint samples
and zero texImage2D samples. So the uploads are specific to artboards carrying
image assets, not to drawing in general.
Asset shape
The affected artboards are ~1425x1487 and contain a background raster at artboard size
plus 6-14 smaller object rasters (webp), 3-5 MP in total, i.e. roughly 12-19 MB once
expanded to RGBA. The images are static for the life of the artboard — nothing swaps
them at runtime, and no assetLoader replaces them (our loader only intercepts
FontAsset and returns false for everything else).
Impact
Roughly 400 ms of main-thread upload spread over ~25 slices of ~16 ms each while such
an artboard animates. Since each slice exceeds a frame budget, each one is a visible
hitch. A screen showing two RiveWidgets built from the same .riv pays it twice.
Questions
- Is per-draw upload of embedded image assets expected on the web/
Factory.rive path,
or is the texture cache being missed here?
- Is there a supported way to keep an artboard's image textures resident across draws?
- Does drawing into a shared texture (
RivePanel / useSharedTexture) let two
artboards from the same file share one upload, or does each artboard upload
independently regardless?
Happy to supply the raw trace or a reduced repro if useful.
Environment
riverive_nativeflutter build web --wasm --profile(dart2wasm, skwasm renderer)Factory.riveSummary
On web, an artboard that contains embedded raster assets appears to re-upload those
rasters to the GPU on every draw pass, rather than uploading once per render
texture and reusing the resident texture. The uploads are synchronous on the renderer
main thread, so each one costs a dropped frame.
Evidence
Chrome performance trace with
disabled-by-default-v8.cpu_profilerenabled. All CPUsamples inside the affected main-thread slices resolve to a single stack:
upload_imagesitting inside_artboardDrawInternalis the part that looks wrong —it puts the upload in the draw path rather than in texture setup.
The uploads are not front-loaded. If this were a one-time residency cost they would
cluster at the start of the artboard's life. Bucketing
texImage2Dsamples at 100 msagainst Rive paint samples over one artboard's ~915 ms of activity:
Uploads track the paint count bucket for bucket, and the second half has more than
the first — consistent with per-draw re-upload, not per-mount.
Control case. A vector-only artboard (no embedded rasters), same build and browser,
drawing continuously for 10.5 s under sustained pointer input: 1105 Rive paint samples
and zero
texImage2Dsamples. So the uploads are specific to artboards carryingimage assets, not to drawing in general.
Asset shape
The affected artboards are ~1425x1487 and contain a background raster at artboard size
plus 6-14 smaller object rasters (webp), 3-5 MP in total, i.e. roughly 12-19 MB once
expanded to RGBA. The images are static for the life of the artboard — nothing swaps
them at runtime, and no
assetLoaderreplaces them (our loader only interceptsFontAssetand returnsfalsefor everything else).Impact
Roughly 400 ms of main-thread upload spread over ~25 slices of ~16 ms each while such
an artboard animates. Since each slice exceeds a frame budget, each one is a visible
hitch. A screen showing two
RiveWidgets built from the same.rivpays it twice.Questions
Factory.rivepath,or is the texture cache being missed here?
RivePanel/useSharedTexture) let twoartboards from the same file share one upload, or does each artboard upload
independently regardless?
Happy to supply the raw trace or a reduced repro if useful.