Skip to content

The scene's JSON tree is re-deserialized on every frame (no cache between frames) #159

Description

@LeadcodeDev

Found while verifying a round-4 fix, outside the audit corpus.

The call chain

render_frame_task (per frame)
render_scene_frame_scaled_with_prev_bg
prepare_scene (engine/render/scene.rs:549)
deserialize_children (engine/render/scene.rs:534)
→ for each child: serde_json::from_value::<ChildComponent>(v.clone())

prepare_scene is three lines long and has no cache. Its result depends only on scene, never on frame_in_scene — it is identical for every frame of a scene, and recomputed in full for each one.

The cost

Per frame, per child:

  1. a .clone() of the whole serde_json subtree;
  2. a deserialization into ChildComponent, whose component field is an untagged enum with 57 variants — serde tries them in order, re-parsing the same object on every failed attempt.

On a 1200-frame render with 50 nodes, that is 60,000 clones and 60,000 deserializations of a 57-variant enum, for a strictly constant result.

Unmeasured. I am not quoting a figure because I have not profiled it — but the order of magnitude deserves profiling, especially since the round-3 paint workstream (PR #154) already found a comparable factor on another per-frame path (unbounded save_layer: 42-60s → 0.5s over 60 frames).

Direction

Deserialize once per scene, ahead of the frame loop, and pass the Vec<ChildComponent> to the render functions. The render_frame_v2 / render_frame_v2_scaled entry points already take &[ChildComponent]; it is the render_scene_frame* wrappers that call prepare_scene each time. The fix is mostly hoisting the call one level, not re-architecting.

One detail to watch: deserialize_children emits a stderr warning per unreadable child. Today that fires once per frame; hoisting it naturally reduces it to once per scene, which is also the desirable behaviour.

Suggested verification

A before/after benchmark on a realistic scenario (examples/mega-showcase.json), comparing total render time. Plus a test asserting prepare_scene is no longer called from the per-frame path.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions