refactor renderer responsable + docs + schema

This commit is contained in:
Jérôme Bousquié
2026-07-06 17:37:13 +02:00
parent 47851b8f61
commit 8e57dc783b
11 changed files with 256 additions and 136 deletions
+18 -39
View File
@@ -1,62 +1,41 @@
# ARCHI_MESH_MATERIAL.md (Version corrigée)
# ARCHI_MESH_MATERIAL.md
## La nouvelle vision architecturale : L'Atelier de Rendu
Pour comprendre notre structure, imagine que tu veux peindre 10 tableaux différents.
**Avant :** Chaque tableau possédait sa propre cuisine, son propre chef (le pipeline), et son propre matériel. C'était inefficace et lourd.
**Avant :** Chaque tableau possédait sa propre cuisine et ses propres outils. C'était inefficace.
**Après :** Tu as un Atelier (Renderer) qui orchestre le dessin. Il utilise des Recettes (Material + PipelineCache) pour définir l'apparence et traite des Toiles (Mesh) pour la géométrie. Tu peux utiliser la même recette pour 50 toiles différentes sans effort.
**Après :** Tu as un Atelier (`Renderer`) qui orchestre le dessin et possède les outils de base (`Device`, `Queue`, `Format`). Il utilise des Recettes (`Material` + `PipelineCache`) pour définir l'apparence et traite des Toiles (`Mesh`) pour la géométrie.
---
## 1. Le Mesh (La Géométrie)
Il est purement passif. Il ne sait pas comment il est affiché, il sait seulement ce qu'il est.
- **Contenu :** `vertexBuffer`, optionnellement `indexBuffer`, et les compteurs associés (`num_vertices`, `num_indices`).
- **Contenu :** `vertex_buffer`, optionnellement `index_buffer`, et les compteurs (`num_vertices`, `num_indices`).
- **Rôle :** Fournir les données brutes au GPU.
---
## 2. Le Material & PipelineCache (Le Look & La Recette)
Le look est découplé de la géométrie via une gestion centralisée.
Le look est désormais découplé de la géométrie via une gestion centralisée.
**PipelineCache :** C'est la bibliothèque de recettes. Il charge les shaders (WGSL), compile les RenderPipeline, et les met en cache (via `HashMap` + `Arc`) pour éviter de dupliquer les ressources GPU.
**Material :** C'est une instance légère qui pointe vers une recette compilée. Il contient un `shader_id` et une référence partagée (`Arc`) vers le RenderPipeline.
- **Rôle :** Garantir la réutilisation. Si 100 objets partagent le même shader, ils pointent tous vers la même instance compilée en mémoire.
- **PipelineCache :** Bibliothèque de recettes. Il charge les shaders (WGSL), compile les `RenderPipeline`, et les met en cache (via `HashMap` + `Arc`) pour éviter de dupliquer les ressources GPU.
- **Material :** Instance légère qui pointe vers une recette compilée. Il contient un `shader_id` et une référence partagée (`Arc`) vers le `RenderPipeline`.
- **Rôle :** Garantir la réutilisation. Si 100 objets partagent le même shader, ils pointent tous vers la même instance compilée.
---
## 3. Le Renderer (L'Orchestrateur)
## 3. Le Renderer (L'Orchestrateur propriétaire)
Le `Renderer` a été promu au rang de propriétaire des ressources matérielles.
Il est devenu ultra-léger et généraliste. Il ne possède plus aucun buffer ni pipeline en dur.
- **Contenu :** Aucun état lourd.
- **Rôle :** Il fait la liaison au moment de l'appel :
- **Contenu :** `device`, `queue`, `format`.
- **Rôle :**
1. **Initialisation :** Reçoit le `Context` au démarrage et s'approprie ses ressources.
2. **Exécution :** Orchestre les appels GPU en utilisant ses ressources internes. Il expose une API simplifiée qui ne demande plus à l'utilisateur de manipuler le `device` ou la `queue`.
3. **Présentation :** Possède la méthode `present(frame)` qui utilise sa `queue` interne pour afficher l'image.
```rust
// Schématiquement
render_pass.set_pipeline(&material.pipeline); // On change de recette
render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); // On pose la toile
// Puis dessin indexé ou simple...
```
---
## Pourquoi cette structure est-elle meilleure ?
1. **Performance :** Les shaders sont compilés une seule fois. La mémoire GPU est optimisée grâce au partage des RenderPipeline via `Arc`.
2. **Modularité :** Tu peux combiner n'importe quel Mesh avec n'importe quel Material.
3. **Propreté :** Ton Renderer est désormais un orchestrateur pur. Il ne connaît plus le détail des shaders ou des layouts de sommets : il se contente d'exécuter la commande de dessin.
---
## Quelques notes techniques pour ta doc
- **Découplage :** Le Material demande au PipelineCache de lui fournir un pipeline au moment de sa création.
- **Sécurité :** Le PipelineCache utilise un `HashMap` pour retrouver instantanément un pipeline existant par son `shader_id`, évitant les compilations inutiles.
- **Flexibilité :** Le Mesh gère lui-même ses indices, permettant de passer facilement du rendu simple au rendu indexé optimisé.
// Exemple d'orchestration simplifiée dans main.rs
renderer.render(frame.view(), &mesh, &material);
renderer.present(frame); // Plus besoin de passer la queue !
+11 -11
View File
@@ -2,17 +2,17 @@
## Manager Layer (Context)
**Responsabilité :** Propriétaire du cycle de vie des ressources matérielles (`Device`, `Queue`, `Surface`).
**Responsabilité :** Propriétaire initial du cycle de vie des ressources matérielles (`Device`, `Queue`, `Surface`).
**Rôle :** Encapsule la complexité du système de fenêtrage et du swapchain. Orchestre les transactions GPU via `begin_frame()` et `end_frame()`.
**Rôle :** Encapsule la complexité du système de fenêtrage et du swapchain. Il fournit les capacités brutes au `Renderer` lors de son initialisation.
---
## Specialist Layer (Renderer & PipelineCache)
**PipelineCache (La Bibliothèque) :** Propriétaire de la compilation et du stockage des RenderPipeline. Garantit qu'un shader n'est compilé qu'une seule fois.
**PipelineCache (La Bibliothèque) :** Propriétaire de la compilation et du stockage des `RenderPipeline`. Garantit qu'un shader n'est compilé qu'une seule fois.
**Renderer (L'Exécuteur) :** Orchestre l'appel au dessin. Il est désormais agnostique : il ne possède plus les pipelines en dur, mais reçoit dynamiquement les Mesh et les Material à dessiner.
**Renderer (L'Exécuteur propriétaire) :** Il est devenu le propriétaire des ressources matérielles (`Device`, `Queue`, `Format`). Il est agnostique du contenu graphique : il orchestre dynamiquement le rendu des `Mesh` via les `Material` et gère seul la présentation des `Frame`.
---
@@ -20,7 +20,7 @@
**Responsabilité :** Logique métier et boucle d'exécution.
**Rôle :** Coordonne le Context, le PipelineCache pour créer les Material, et enfin passe le tout au Renderer pour produire l'image.
**Rôle :** Coordonne le `Context` (pour l'init matérielle), le `PipelineCache` (pour les shaders), et délègue l'exécution au `Renderer`. Il ne manipule plus directement le `Device` ou la `Queue` après la création du `Renderer`.
---
@@ -28,22 +28,22 @@
## Modularité Totale (Decoupling)
Le Renderer est totalement découplé du contenu graphique. Il ne connaît pas les shaders, il sait juste "lier" un Material à un Mesh. Cela permet un rendu multi-objets très simple.
Le `Renderer` est totalement découplé du contenu graphique. Il sait "lier" un `Material` à un `Mesh` en utilisant ses propres ressources internes.
## Efficacité Mémoire (Resource Sharing)
Grâce au PipelineCache et à l'utilisation de `Arc<wgpu::RenderPipeline>`, plusieurs Material partagent la même recette compilée sur le GPU. On évite la duplication coûteuse de ressources.
Grâce au `PipelineCache` et à l'utilisation de `Arc<wgpu::RenderPipeline>`, plusieurs `Material` partagent la même recette compilée sur le GPU. On évite la duplication coûteuse de ressources.
## Performance de Rendu
## Encapsulation & Robustesse
En séparant la "préparation des recettes" (PipelineCache) de "l'exécution du dessin" (Renderer), on élimine tout risque de compilation/allocation lourde pendant la boucle de rendu (60 FPS).
En transférant la propriété de `Device` et `Queue` au `Renderer`, on élimine les erreurs de transmission de références. Le `main.rs` devient plus léger et le `Renderer` devient un point d'entrée unique et sécurisé pour toutes les commandes GPU.
## Flexibilité
Le passage à un modèle (Mesh + Material) permet de combiner n'importe quelle géométrie avec n'importe quel effet visuel à la volée.
Le passage à un modèle (`Mesh` + `Material`) permet de combiner n'importe quelle géométrie avec n'importe quel effet visuel, tout en laissant le `Renderer` gérer la boucle de présentation de manière autonome (ex: `renderer.present(frame)`).
---
# Summary
Cette structure transforme une architecture rigide en un atelier de rendu dynamique. Le Context prépare le terrain, le PipelineCache fournit les outils (shaders), le Material définit le style, le Mesh apporte la forme, et le Renderer orchestre l'assemblage final. Le système est désormais prêt à gérer des scènes complexes avec de multiples objets et des effets variés.
Cette structure transforme une architecture rigide en un atelier de rendu dynamique. Le `Context` prépare le terrain, le `Renderer` devient le propriétaire des ressources et l'orchestrateur de dessin, le `PipelineCache` fournit les outils, le `Material` définit le style et le `Mesh` apporte la forme. Le système est désormais prêt à gérer des scènes complexes avec une API propre et sécurisée.
+19
View File
@@ -0,0 +1,19 @@
graph TD
%% Entités persistantes
Context --> Renderer
Context --> Mesh
PipelineCache --> Material
Renderer --> Material
%% Interactions lors de la boucle de rendu
subgraph Boucle_de_Rendu [Cycle de vie Frame]
Frame -->|view| Renderer
Material -->|pipeline| Renderer
Mesh -->|buffers| Renderer
Renderer -->|draw| CommandEncoder
CommandEncoder -->|submit| Context
end
style Context fill:#f9f,stroke:#333
style Renderer fill:#bbf,stroke:#333
style Frame fill:#dfd,stroke:#333