Trouvé en vérifiant un correctif du round 4, hors corpus d'audit.
La chaîne d'appel
render_frame_task (par frame)
→ render_scene_frame_scaled_with_prev_bg
→ prepare_scene (engine/render/scene.rs:549)
→ deserialize_children (engine/render/scene.rs:534)
→ pour chaque enfant : serde_json::from_value::<ChildComponent>(v.clone())
prepare_scene fait exactement trois lignes et n'a aucun cache. Le résultat ne dépend que de scene, jamais de frame_in_scene — il est donc identique pour toutes les frames d'une même scène, et recalculé intégralement pour chacune.
Le coût
Pour chaque frame et chaque enfant :
- un
.clone() de la valeur serde_json du sous-arbre complet ;
- une désérialisation vers
ChildComponent, dont le champ component est un enum untagged de 57 variants — serde les essaie dans l'ordre jusqu'à ce que l'un réussisse, en re-parsant le même objet à chaque tentative infructueuse.
Sur un rendu de 1200 frames avec 50 nœuds, cela fait 60 000 clones et 60 000 désérialisations d'un enum à 57 variants, pour un résultat rigoureusement constant.
Non mesuré. Je n'avance pas de chiffre parce que je n'ai pas profilé — mais l'ordre de grandeur mérite qu'on le fasse, d'autant que le lot paint du round 3 (PR #154) avait déjà trouvé un facteur comparable sur un autre chemin par frame (couche save_layer non bornée : 42–60 s → 0,5 s sur 60 frames).
Piste
Désérialiser une fois par scène, en amont de la boucle de frames, et passer le Vec<ChildComponent> aux fonctions de rendu. Les points d'entrée render_frame_v2 / render_frame_v2_scaled prennent déjà &[ChildComponent] en paramètre — ce sont les enveloppes render_scene_frame* qui rappellent prepare_scene à chaque fois. La correction consiste donc surtout à hisser l'appel d'un niveau, pas à réarchitecturer.
Attention à un détail : deserialize_children émet un avertissement sur stderr pour chaque enfant illisible. Aujourd'hui il sort une fois par frame ; le hisser le réduira naturellement à une fois par scène, ce qui est aussi le comportement souhaitable.
Vérification suggérée
Un benchmark avant/après sur un scénario réaliste (examples/mega-showcase.json), en comparant le temps de rendu total. Et un test qui affirme que prepare_scene n'est plus appelé depuis le chemin par frame.
Trouvé en vérifiant un correctif du round 4, hors corpus d'audit.
La chaîne d'appel
render_frame_task(par frame)→
render_scene_frame_scaled_with_prev_bg→
prepare_scene(engine/render/scene.rs:549)→
deserialize_children(engine/render/scene.rs:534)→ pour chaque enfant :
serde_json::from_value::<ChildComponent>(v.clone())prepare_scenefait exactement trois lignes et n'a aucun cache. Le résultat ne dépend que descene, jamais deframe_in_scene— il est donc identique pour toutes les frames d'une même scène, et recalculé intégralement pour chacune.Le coût
Pour chaque frame et chaque enfant :
.clone()de la valeurserde_jsondu sous-arbre complet ;ChildComponent, dont le champcomponentest un enumuntaggedde 57 variants — serde les essaie dans l'ordre jusqu'à ce que l'un réussisse, en re-parsant le même objet à chaque tentative infructueuse.Sur un rendu de 1200 frames avec 50 nœuds, cela fait 60 000 clones et 60 000 désérialisations d'un enum à 57 variants, pour un résultat rigoureusement constant.
Non mesuré. Je n'avance pas de chiffre parce que je n'ai pas profilé — mais l'ordre de grandeur mérite qu'on le fasse, d'autant que le lot paint du round 3 (PR #154) avait déjà trouvé un facteur comparable sur un autre chemin par frame (couche
save_layernon bornée : 42–60 s → 0,5 s sur 60 frames).Piste
Désérialiser une fois par scène, en amont de la boucle de frames, et passer le
Vec<ChildComponent>aux fonctions de rendu. Les points d'entréerender_frame_v2/render_frame_v2_scaledprennent déjà&[ChildComponent]en paramètre — ce sont les enveloppesrender_scene_frame*qui rappellentprepare_sceneà chaque fois. La correction consiste donc surtout à hisser l'appel d'un niveau, pas à réarchitecturer.Attention à un détail :
deserialize_childrenémet un avertissement sur stderr pour chaque enfant illisible. Aujourd'hui il sort une fois par frame ; le hisser le réduira naturellement à une fois par scène, ce qui est aussi le comportement souhaitable.Vérification suggérée
Un benchmark avant/après sur un scénario réaliste (
examples/mega-showcase.json), en comparant le temps de rendu total. Et un test qui affirme queprepare_scenen'est plus appelé depuis le chemin par frame.