--- type: Technical Specification title: Rendering Architecture: Update/Render Cycle and Data Management description: Technical specification for the rendering architecture of wsg_lib, defining strategies for mutability and data management to maximize performance and memory safety in Rust tags: [architecture, rendering, rust, performance, memory-safety] actor: person/jerome sources: [] generated: { by: human:jerome, at: 2026-07-31T00:00:00Z } verified: true status: target stale_after: 2027-01-31 --- # Architecture de Rendu : Cycle Update/Render et Gestion des Données Ce document définit la stratégie de gestion de la mutabilité et des données du moteur wsg_lib, conçue pour maximiser la performance et garantir la sécurité mémoire via Rust. > **État du document : ACTUEL pour la dichotomie update/render (implémentée) ; CIBLE pour le batching.** > Le cycle strict est en place : `AppHandler::update` (mutation libre de la scène) tourne avant > `AppHandler::render`, dont l'implémentation par défaut appelle `app.render_scene(frame.view())` — > le moteur itère automatiquement les entités et les dessine en **une passe groupée** par frame > (rendu automatisé livré le 2026-09-16 ; la passe d'ombre est ajoutée en tête quand un caster est > actif). Le workflow **manuel** (`Renderer::render` objet par objet, exemple `manual`) coexiste > pour le contrôle fin. Reste en **cible** : le **tri/batching par matériau** (ROADMAP 4.3) et les > **handles typés** `MeshId`/`MaterialId` (voir [ARCHI_ARENES](ARCHI_ARENES.md)) — l'état actuel > utilise des **String IDs** dans `Scene`. ## 1. La Dichotomie Update / Render Pour éviter les conflits de données et optimiser le pipeline GPU, le moteur sépare strictement le cycle de vie de la frame en deux phases : ### Phase Update (Mutabilité Totale) - L'utilisateur peut modifier librement l'état de la Scene (transformations, propriétés des matériaux, ajout/suppression d'entités). - C'est l'unique zone de mutation autorisée. Le système est en "lecture-écriture". ### Phase Render (Lecture et Orchestration) - La Scene est considérée comme immuable vis-à-vis du rendu. - Le moteur itère automatiquement sur les entités pour soumettre les commandes au GPU. - L'utilisateur dispose d'une "trappe" via `AppHandler::render()` pour injecter du code de rendu personnalisé, mais sans modifier l'état métier des objets. ## 2. Gestion des Données : Indirection par ID (Handle) Pour contourner les limitations du Borrow Checker de Rust lors de l'accès aux ressources, le moteur utilise une approche par **Indirection (Handles/IDs)**. - **HashMaps et Vecs indexés** : Les ressources (`Mesh`, `Material`) ne sont pas stockées sous forme de références directes (`&Mesh`) dans les entités. Elles sont stockées dans des conteneurs centralisés dans la Scene. - **Identifiants (Handles)** : Chaque entité possède un `MeshId` ou `MaterialId`. - **Avantage** : Cela élimine les problèmes de durées de vie (lifetimes) complexes. Vous pouvez passer des IDs partout sans bloquer la mutabilité des conteneurs parents. - **Performance** : Cette approche permet au moteur de trier les entités par `MaterialId` avant le rendu, réduisant drastiquement les changements d'état GPU (**State Change Overhead**). ## 3. Points d'Attention du Borrow Checker Bien que cette architecture facilite la gestion de la mémoire, des règles strictes s'appliquent à `App` : - **Conflit de Mutabilité** : App contient à la fois la Scene et le Renderer. Il est interdit d'emprunter `&mut scene` et `&mut renderer` simultanément. - **Solution** : Dans la boucle de rendu interne (`App::run`), le moteur doit être structuré pour séquencer les accès : `let scene = &app.scene;` suivi de `let renderer = &mut app.renderer;` puis `renderer.render_scene(scene);`. - **Séparation des Responsabilités** : Le RenderLoop doit posséder la main sur l'ordonnancement pour éviter que l'utilisateur ne tente de muter la scène pendant que le renderer est en train de lire les données. ## 4. Synthèse des Avantages - **Performance (Batching)** : Le rendu automatique par le moteur permet d'implémenter des stratégies de rendu optimales invisibles pour l'utilisateur. - **Ergonomie** : L'utilisateur n'écrit pas de boucles de rendu complexes. Il se concentre sur sa logique métier dans `update()`. - **Sécurité** : L'utilisation d'IDs évite les cycles de références et les références pendantes, rendant le code plus sûr et plus facile à maintenir. ## 5. Guide de Développement pour l'Utilisateur > "Si vous devez changer la position d'un objet ou son matériau, faites-le dans `update()`. Si vous avez besoin d'afficher un élément de debug ou un rendu spécial, faites-le dans `render()`, mais traitez les objets de la scène comme des données en lecture seule." Cette structure permet au projet d'être extrêmement scalable. L'ajout des fonctionnalités Lumières, Textures et Caméras (livrées — voir [ROADMAP](../ROADMAP.md)) a effectivement consisté à ajouter des conteneurs dans la Scene (`lights`, `textures`, `camera`) et à les consommer dans `Renderer::render_scene()` (existant — il écrit les uniformes de frame chaque frame). Il restera à y ajouter le **système de tri par matériau** (batching, ROADMAP 4.3) quand il sera justifié. ## Liens - [ARCHI_APP](ARCHI_APP.md) · [FRAME_LOOP](FRAME_LOOP.md) · [ARCHI_CPU_GPU](ARCHI_CPU_GPU.md) · [ARCHI_ARENES](ARCHI_ARENES.md) - Documentation utilisateur : [docs/user](../user/README.md) · [README racine](../../README.md) · [ROADMAP](../ROADMAP.md) - Référence API : `cargo doc -p wsg-lib --no-deps`