rive-app / rive-app/rive-flutter

Web (Factory.rive): embedded image assets appear to re-upload to the GPU on every artboard draw

Open
#652 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Dart
Stars
1.5k
Forks
240
PR merge metrics
No merged PRs in 30d

Description

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
  1. Is per-draw upload of embedded image assets expected on the web/Factory.rive path,
    or is the texture cache being missed here?
  2. Is there a supported way to keep an artboard's image textures resident across draws?
  3. 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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at WebRiveArtboard.drawInternal and Module._artboardDrawInternal, tracing the upload_image path into texImage2D and RiveNativeRenderBox.paintTexture. Reproduce the reported profile with an embedded-image artboard and compare it with the vector-only control; done means determining whether uploads occur once per texture or on every draw, and documenting the supported residency or sharing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter, wasm
Domain
frontend, performance, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.