Files
wsg/docs/tech/ARCHI_RENDU.md
T
Jérôme Bousquié b72c4e43ae docs: align tech/ docs with current vs target state
Clarify for each docs/tech document whether it describes the current
(implemented) or target (planned) architecture, and reconcile with the
readme/roadmap source of truth:

- ARCHI_APP, ARCHI_CPU_GPU, ARCHI_RENDU: mark status=target and add a
  banner stating the GPU-driven two-pass pipeline, persistent VRAM buffers
  and scene auto-render are not implemented (they are ROADMAP Phase 3 /
  README roadmap items 1-3). render() still cannot draw the scene.
- ARCHI_ARENES: status=target/deferred. String IDs are the current design;
  slotmap generational handles are the deferred 'typed handles' step and
  the slotmap dependency is currently absent (supersedes the retired dep).
- FRAME_LOOP: stays status=current; correct the described API flow (Frame
  based via get_next_frame/Renderer::present, plus the low-level
  begin_frame/end_frame variant) and move the single-buffer VRAM note to
  target.
- README: label each tech doc as current or target in the Documentation
  section.
2026-09-14 16:11:42 +02:00

5.0 KiB


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 : CIBLE (modèle de mutabilité pour le futur rendu automatisé). Le cycle update/render strict, l'itération automatique des entités et renderer.render_scene() décrits ici ne sont pas implémentés : c'est l'étape 1 du Roadmap README (scene auto-rendering). Aujourd'hui App::run acquiert/présente la frame mais render() ne peut pas encore dessiner la scène, et le Renderer ne dessine qu'un objet par soumission, à la main (exemple manual). La terminologie MeshId/MaterialId (handles typés) est celle de la cible ; l'état actuel utilise des String IDs dans Scene. La dichotomie update/render reste toutefois le modèle de référence retenu pour la suite.

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 futur de fonctionnalités (Lumières, Textures, Caméras) ne nécessitera que d'ajouter de nouveaux conteneurs dans la Scene et de mettre à jour le système de tri dans Renderer::render_scene() (méthode à créer — cible de l'étape 1 du Roadmap README).