Architecture de l'application¶
Ce document décrit l'architecture modulaire de l'application après le refactoring de app.c.
Vue d'ensemble du refactoring¶
Le fichier monolithique app.c a été décomposé en modules cohérents. Chaque module a une responsabilité claire et des interfaces bien définies.
Modules¶
app_ui — Interface utilisateur¶
Gère l'affichage de la superposition d'informations, du clavier interactif et des métriques de performance.
Responsabilités : - Rendu des textes et des indicateurs visuels - Gestion de la disposition du clavier - Affichage de la Timeline GPU
app_input — Gestion des entrées¶
Traite les événements clavier et souris via les callbacks GLFW. Utilise AppInputContext (bundle de pointeurs ciblés) pour se découpler de l'objet God App, suivant le même pattern que PostProcessInputContext.
Responsabilités : - Dispatch des commandes depuis les frappes clavier - Gestion des modes modificateurs (Shift, Alt) - Mode Dry-Run pour l'exploration des raccourcis
app_env — Environnement HDR¶
Coordonne le chargement des cartes d'environnement et la transition entre elles.
Responsabilités : - Chargement asynchrone des HDR - Génération des cartes IBL (irradiance, spéculaire préfiltrée) - Transitions (fondu enchaîné, écran noir)
app_scene — Scène et primitives¶
Gère les objets de la scène, leur tri et leur rendu.
Responsabilités : - Gestion des sphères (création, mise à jour, tri) - Appel des passes de rendu (géométrie, skybox, post-traitement) - Coordination du profiler GPU
Propriété des données¶
La structure App reste le point d'entrée central. Elle possède tous les sous-systèmes et leur passe des pointeurs selon le besoin.
App
├── AppUI (rendu de l'interface)
├── AppInput (événements et raccourcis)
├── AppEnv (environnement HDR)
├── AppScene (scène 3D)
├── GPUProfiler (métriques temporelles GPU)
├── AsyncLoader (chargement asynchrone)
└── PostProcess (effets de post-traitement)
└── EffectContext (seam vers les effets individuels)
Décomposition de Scene¶
La structure Scene est entièrement décomposée en six sous-structs par domaine, chacune dans son propre header :
SceneGPUResources(include/scene_gpu_resources.h) : tous les handles de ressources GPU — 28 GLuint pour textures, buffers, VAOs, programmes compute, plus le billboard UBO et les caches de binding IBL/SH. Accès viascene->gpu.hdr_texture,scene->gpu.icosphere_vbo, etc.SceneShaders(include/scene_shaders.h) : tous les pointeurs de shaders —pbr_instanced,pbr_billboard,debug,debug_line,skybox(+ conditionnelpbr_ssbo). Accès viascene->shaders.pbr_instanced, etc.SceneConfig(include/scene_config.h) : configuration runtime —wireframe,billboard_mode,sorting_mode,pbr_debug_mode,show_envmap,env_lod,subdivisions,gi_mode,show_probe_grid,specular_aa_enabled,aa_mode. Définit aussi les enumsSortingMode,GIMode,AAMode. Accès viascene->config.wireframe, etc.SceneVisuals(include/scene_visuals.h) : effets visuels —Skybox,TrailRenderer,ShockwaveRenderer. Accès viascene->visuals.skybox, etc.SceneSimulation(include/scene_simulation.h) : état N-body —NBodySim,nbody_mode. Accès viascene->simulation.nbody_sim, etc.SceneLighting(include/scene_lighting.h) : IBL, probes et matériaux —IBLCoordinator,LightProbeGrid,MaterialLib*. Accès viascene->lighting.ibl_coord, etc.
Cela réduit le nombre de champs directs de Scene de ~50 à ~19 et déplace les définitions de types par domaine hors du monolithique scene.h.
Décomposition de App (AppProfiling, AppInput, AppWindow)¶
La structure App est décomposée en sous-structs par domaine :
AppProfiling(include/app_profiling.h) : regroupe le profiling et les métriques —GPUProfiler,GPUProfilerUI,FpsCounter,TracyManager,GPUUsageMonitor,PerfModeContext,perf_mode_active,log_gpu_metrics. Accès viaapp->profiling->gpu_profiler, etc. Init/cleanup délégués àapp_profiling_init()/app_profiling_cleanup()danssrc/app_profiling.c.AppInput(include/app_input_state.h) : regroupe la caméra, le gamepad, les raccourcis clavier et le lissage d'entrée —Camera,GamepadState,AppBindingRegistry,AdaptiveSampler,camera_enabled. Accès viaapp->input->camera, etc. Init/cleanup délégués àapp_input_state_init()/app_input_state_cleanup()danssrc/app_input_state.c.AppWindow(include/app_window.h) : regroupe le handle de fenêtre GLFW et tout l'état fenêtre/resize —GLFWwindow* handle,is_fullscreen,saved_x/y,saved_width/height,resize_pending,pending_width/height. Accès viaapp->win.handle,app->win.is_fullscreen, etc. Init/cleanup délégués àapp_window_subsys_init()/app_window_subsys_cleanup()danssrc/app_window.c. Le descripteur fenêtre est premier dans la table des sous-systèmes — il crée le contexte OpenGL nécessaire à tous les autres sous-systèmes, et est nettoyé en dernier (ordre inverse) pour garantir que le contexte GL survit à toutes les libérations de ressources GPU.
Note de nommage :
app_input_state.hhéberge la définition de la sous-structAppInput, tandis que le fichier existantapp_input.hhéberge le seamAppInputContext(bundle de pointeurs ciblés pour les handlers d'entrée, issue #204).
Cela réduit le nombre de champs directs de App de 24 à ~17. Chaque header de sous-struct possède ses dépendances de type et ses fonctions de délégation, gardant app.c focalisé sur l'orchestration.
Pattern SubsystemDescriptor¶
L'initialisation et le nettoyage des sous-structs de App sont pilotés par une table de descripteurs terminée par sentinelle au lieu de séquences calloc/init/cleanup écrites à la main dans app_init() / app_cleanup().
Types fondamentaux (include/app_subsystem.h) :
typedef struct SubsystemDescriptor {
const char* name;
int (*init)(struct App* app);
void (*cleanup)(struct App* app);
} SubsystemDescriptor;
Déclaration de la table (src/app.c) :
static const SubsystemDescriptor APP_SUBSYSTEM_TABLE[] = {
APP_WINDOW_DESCRIPTOR, // Crée le contexte GL — doit être premier
APP_INPUT_DESCRIPTOR, // Pas de dépendance GL
APP_PROFILING_DESCRIPTOR, // GPU profiler + Tracy (nécessite GL)
APP_ASYNC_COORD_DESCRIPTOR, // Allocation PBO (nécessite GL)
APP_LUM_HISTOGRAM_DESCRIPTOR, // malloc uniquement
APP_ASYNC_LOADER_DESCRIPTOR, // Nécessite profiling->tracy_mgr
APP_SCENE_DESCRIPTOR, // Shaders, textures (nécessite GL)
APP_ENV_MGR_DESCRIPTOR, // État de transition uniquement
APP_POSTPROCESS_DESCRIPTOR, // Nécessite profiling + ressources GPU scène
{0}, /* sentinelle */
};
Chaque module possède sa macro descripteur (ex. APP_WINDOW_DESCRIPTOR dans app_window.h), gardant la définition co-localisée avec les fonctions init/cleanup.
Contrainte d'ordre : APP_WINDOW_DESCRIPTOR doit être la première entrée car il crée le contexte OpenGL. Le cleanup s'exécutant en ordre inverse, la fenêtre est détruite en dernier, garantissant que le contexte GL reste valide pendant la libération de tous les sous-systèmes dépendants du GPU (requêtes profiler, FBOs, VAOs, shaders, etc.).
Sémantique :
app_subsystems_init()parcourt la table en avant jusqu'à la sentinelle{0}. Sur le premier échec à l'index N, il appellecleanup()en ordre inverse pour les entrées [N-1 .. 0] (rollback automatique).app_subsystems_cleanup()compte les entrées, puis parcourt la table en ordre inverse — garantissant que le démontage est le miroir de l'initialisation.- Pas de paramètre count explicite : la sentinelle élimine une source de désynchronisation.
DAG de dépendances des sous-systèmes¶
L'ordre de la table des descripteurs satisfait ces dépendances d'initialisation :
graph LR
classDef first fill:#1a1b26,stroke:#e0af68,color:#e0af68,stroke-width:2
classDef gl fill:#1a1b26,stroke:#7aa2f7,color:#7aa2f7
classDef nogl fill:#1a1b26,stroke:#9ece6a,color:#9ece6a
WIN[WINDOW]:::first
INP[INPUT]:::nogl
PROF[PROFILING]:::gl
AC[ASYNC_COORD]:::gl
LH[LUM_HISTOGRAM]:::nogl
AL[ASYNC_LOADER]:::gl
SC[SCENE]:::gl
ENV[ENV_MGR]:::nogl
PP[POSTPROCESS]:::gl
WIN -->|"contexte GL"| PROF
WIN -->|"contexte GL"| AC
WIN -->|"contexte GL"| SC
WIN -->|"contexte GL"| PP
PROF -->|"tracy_mgr"| AL
PROF -->|"gpu_profiler"| PP
SC -->|"ressources GPU"| PP
Légende : 🟡 doit être premier (crée le contexte GL), 🔵 nécessite GL, 🟢 pas de dépendance GL.
Table d'ordre d'appel des descripteurs¶
Le tableau ci-dessous liste chaque sous-système dans l'ordre d'initialisation (le cleanup s'exécute en ordre inverse) :
| # | Macro descripteur | Fonction init | Fonction cleanup | Fichier source |
|---|---|---|---|---|
| 0 | APP_WINDOW_DESCRIPTOR |
app_window_subsys_init |
app_window_subsys_cleanup |
src/app_window.c |
| 1 | APP_INPUT_DESCRIPTOR |
app_input_subsys_init |
app_input_subsys_cleanup |
src/app_input_state.c |
| 2 | APP_PROFILING_DESCRIPTOR |
app_profiling_subsys_init |
app_profiling_subsys_cleanup |
src/app_profiling.c |
| 3 | APP_ASYNC_COORD_DESCRIPTOR |
async_coord_subsys_init |
async_coord_subsys_cleanup |
src/async_coordinator.c |
| 4 | APP_LUM_HISTOGRAM_DESCRIPTOR |
lum_histogram_subsys_init |
lum_histogram_subsys_cleanup |
src/lum_histogram.c |
| 5 | APP_ASYNC_LOADER_DESCRIPTOR |
async_loader_subsys_init |
async_loader_subsys_cleanup |
src/async_loader.c |
| 6 | APP_SCENE_DESCRIPTOR |
scene_subsys_init |
scene_subsys_cleanup |
src/scene_init.c |
| 7 | APP_ENV_MGR_DESCRIPTOR |
env_mgr_subsys_init |
env_mgr_subsys_cleanup |
src/env_manager.c |
| 8 | APP_POSTPROCESS_DESCRIPTOR |
postprocess_subsys_init |
postprocess_subsys_cleanup |
src/postprocess_init.c |
Annotations statiques de traçabilité¶
Les pointeurs de fonctions cassent l'analyse statique du graphe d'appels (clangd « Call Hierarchy », « Find All References »). Pour compenser, chaque définition *_subsys_init / *_subsys_cleanup porte un commentaire de traçabilité :
/* Called via APP_SUBSYSTEM_TABLE in app.c (subsystem descriptor pattern) */
int my_module_subsys_init(App* app)
{
...
}
Convention de nommage : toutes les fonctions de cycle de vie utilisent le suffixe *_subsys_init / *_subsys_cleanup. Cela garantit une découverte fiable par grep :
Comment ajouter un nouveau sous-système¶
-
Créer la paire init/cleanup dans le fichier
.cdu module :int my_module_subsys_init(struct App* app) { app->my_module = calloc(1, sizeof(*app->my_module)); if (!app->my_module) return 0; // ... initialisation complémentaire ... return 1; } void my_module_subsys_cleanup(struct App* app) { // ... libérer les ressources GL, free les buffers ... free(app->my_module); app->my_module = NULL; } -
Déclarer la macro descripteur dans le fichier
.hdu module : -
Ajouter l'entrée dans
APP_SUBSYSTEM_TABLEdanssrc/app.cà la bonne position (en respectant l'ordre des dépendances). -
Ajouter un test roundtrip dans
tests/test_app_subsystem.c(section Phase C).
Couverture de test (système de descripteurs)¶
| Fichier | Lignes | Fonctions | Branches |
|---|---|---|---|
app_subsystem.c |
100 % | 100 % | 100 % |
lum_histogram.c |
100 % | 100 % | 100 % |
app_profiling.c |
90 % | 100 % | 50 % |
app_window.c |
89 % | 100 % | 50 % |
async_coordinator.c |
88 % | 100 % | 66 % |
env_manager.c |
77 % | 92 % | 56 % |
scene_init.c |
82 % | 100 % | 56 % |
postprocess_init.c |
88 % | 100 % | 52 % |
Lacunes documentées :
- Chemin d'échec de
app_init()(ligne 73) : nécessite un échec deAPP_SUBSYSTEM_TABLEimpossible à injecter en tests unitaires — exercé uniquement en intégration avectest_failure_sweeputilisant des tables factices. - Garde
app_cleanup(NULL)(ligne 116) : vérification défensive triviale. - Branches des sous-systèmes dépendants GL : nécessitent un display virtuel (
llvmpipe) ; couvertes en CI mais pas en exécution headless locale.
Tests (tests/test_app_subsystem.c, 17 tests) :
- Phase A (framework) : chemin de succès, rollback sur échec, sweep, ordre inverse, gestion des pointeurs de fonction NULL (6 + 3 tests).
- Phase B (sous-systèmes réels) : roundtrips input + profiling (2 tests).
- Phase C (descripteurs GL) : roundtrips postprocess, scene, env_mgr, async_coord, init+cleanup table complète, sweep d'échec (6 tests).
Décomposition du header PostProcess¶
Les définitions de types de PostProcess sont décomposées en cinq sous-headers, suivant le même pattern que la décomposition de Scene. postprocess.h (648 → 330 lignes) ne contient plus que la struct agrégat PostProcess, l'enum PostProcessEffect, PostProcessPreset et les signatures de fonctions.
pp_params.h: les 10 structs de paramètres des effets uber-shader (VignetteParams,GrainParams,ExposureParams,ChromAbberationParams,WhiteBalanceParams,ColorGradingParams,TonemapParams,FXAAParams,BandingParams,FogParams) plus l'enumBandingModeet les valeursDEFAULT_*. Les effets avec leur propre pipeline multi-pass (BloomParams,DoFParams,AutoExposureParams,MotionBlurParams,LUT3DParams) vivent dans leurs headersfx_*.hrespectifs.pp_ubo.h: layout GPUPostProcessUBO(std140) — correspond au UBO du uber-shader GLSL.pp_gpu_resources.h: structPPGPUResources— FBOs, textures, handle UBO, quad écran.pp_shader_state.h:PPShaderState+ShaderCacheEntry— état de compilation et cache de shaders.pp_exposure_readback.h: structPPExposureReadback— readback PBO asynchrone pour l'auto-exposition et l'histogramme.
Découpage des unités de traduction PostProcess¶
Le monolithique postprocess.c (1634 lignes) est découpé en six unités de traduction ciblées par domaine, chacune sous 360 lignes :
| UT | Lignes | Responsabilité |
|---|---|---|
postprocess_init.c |
358 | Initialisation, création des framebuffers, redimensionnement, textures factices |
postprocess_apply.c |
360 | Passes de rendu begin/end, synchronisation UBO, passes bloom/DoF/AE/MB/composite |
postprocess_setters.c |
268 | Enable/disable/toggle, setters de paramètres, application de presets |
postprocess_shader.c |
223 | Recherche dans le cache de shaders, compilation optimisée, switching dynamique |
postprocess_readback.c |
199 | Readback PBO, calcul d'histogramme, luminance, mise à jour des matrices |
postprocess_cleanup.c |
97 | Libération des ressources (FBOs, quad, buffers de readback, cache de shaders) |
graph TD
PP_H[postprocess.h<br/><i>API publique</i>]
PP_INT[postprocess_internal.h<br/><i>enums partagés + déclarations pp_</i>]
PP_INT --> PP_H
INIT[postprocess_init.c] --> PP_INT
APPLY[postprocess_apply.c] --> PP_INT
SHADER[postprocess_shader.c] --> PP_INT
CLEANUP[postprocess_cleanup.c] --> PP_INT
SETTERS[postprocess_setters.c] --> PP_H
READBACK[postprocess_readback.c] --> PP_H
Header interne postprocess_internal.h fournit :
- Les enums d'unités de texture (
POSTPROCESS_TEX_UNIT_SCENE,_BLOOM,_DOF, etc.) - Les déclarations de fonctions internes préfixées
pp_partagées entre les UT (ex.pp_create_framebuffer,pp_destroy_framebuffer,pp_setup_sampler_uniforms,pp_update_current_shader,pp_is_shader_in_cache) - Inclus uniquement par les UT nécessitant l'état interne partagé ;
postprocess_setters.cetpostprocess_readback.cn'ont besoin que dupostprocess.hpublic
Extraction du cache d'uniformes Scene¶
Les structs de cache d'uniformes shader (InstancedUniforms, DebugUniforms, BillboardUBO, BillboardUniforms, MAT4_FLOAT_COUNT) sont extraites de scene.h (194 → 120 lignes) vers scene_uniforms.h. Ce sont des détails d'implémentation GPU accessibles uniquement par scene_render.c et scene_init.c. La struct Scene conserve ses champs d'uniformes par valeur ; les définitions de types sont simplement déplacées vers un sous-header ciblé.
Privatisation des données de layout UI¶
Les données de layout statiques (tableau KEY_LAYOUT_QWERTY[] de 66 entrées, tableau GAMEPAD_LAYOUT[] de 16 entrées, ~60 constantes visuelles, définitions des structs KeyPos/GamepadControlPos) sont déplacées de app_ui.h (387 → 128 lignes) vers app_ui.c. Le header public n'expose plus que HelpMode, AppUIOverlay et 8 signatures de fonctions. Cela élimine la duplication des tableaux static const entre les unités de traduction et rend les modifications de layout locales à la recompilation.
Seam GamepadContext¶
Le GamepadContext (include/gamepad_context.h) découple gamepad_input.c de camera.h :
- Contient uniquement la tranche minimale d'état caméra nécessaire pour l'entrée gamepad :
move_input[3],yaw_target,pitch_target,fixed_timestep, limites de pitch. gamepad_write_input()prendGamepadContext*au lieu deCamera*.- Pattern bridge :
Camera ↔ GamepadContextau site d'appel dansapp.c.
Découplage des effets (EffectContext)¶
Les effets de post-traitement (bloom, DoF, auto-exposition, flou de mouvement, LUT, LUT viz) sont entièrement découplés de l'objet God PostProcess via un seam EffectContext :
EffectContext(include/effects/effect_context.h) : snapshot read-only de l'état partagé du pipeline (texture source, dimensions viewport, textures profondeur/vélocité, exposition).- Les effets reçoivent
(FX*, Params*, const EffectContext*)au lieu dePostProcess*. - Cela élimine la dépendance bidirectionnelle :
postprocess.h→fx_*.h(pour l'embedding des structs) reste, maisfx_*.c→postprocess.hest supprimé. - Tous les effets sont désormais entièrement migrés : bloom, DoF, auto-exposition, flou de mouvement, LUT 3D et LUT viz. Plus aucun fichier source d'effet n'inclut
postprocess.h.
Nettoyage des dépendances d'en-têtes (env_manager.h, renderer.h)¶
Deux en-têtes de modules transportaient des includes transitifs inutiles, augmentant le couplage et le coût de recompilation :
env_manager.h: incluaitpostprocess.halors qu'il n'utilise quePostProcess*dans les signatures de fonctions. Remplacé par une déclaration anticipéetypedef struct PostProcess PostProcess;. L'include concret reste dansenv_manager.cqui appellepostprocess_set_exposure_target().renderer.h: incluait 9 en-têtes projet (action_notifier.h,camera.h,effect_benchmark.h,env_manager.h,gpu_profiler.h,gpu_profiler_ui.h,postprocess.h,scene.h,ui.h) alors queRenderContextne contient que des pointeurs. Tous remplacés par des déclarations anticipées. Seuls<stdbool.h>et<stdint.h>restent comme includes concrets. Le fichier.cinclut les en-têtes complets nécessaires.
Extension des déclarations anticipées (Phase 10)¶
Passe systématique remplaçant #include "shader.h" (et autres includes pointeur-only) par typedef struct X X; dans 13 en-têtes supplémentaires. Les structs Shader, NBodySim et SphereInstance ont reçu des tags de struct explicites (auparavant anonymes) pour permettre la déclaration anticipée.
| En-tête | Types déclarés | Notes |
|---|---|---|
effect_benchmark.h |
PostProcess*, GPUProfiler* |
Supprime 2 includes lourds |
trail_renderer.h |
Shader* |
Conserve nbody.h pour la constante NBODY_MAX_BODIES |
light_probes.h |
Shader*, SphereInstance* |
Supprime 2 includes |
skybox.h |
Shader* |
|
shockwave.h |
Shader* |
|
ui.h |
Shader* |
Ajoute gl_common.h pour GLuint |
pp_shader_state.h |
Shader* |
|
fx_bloom.h |
Shader* |
|
fx_dof.h |
Shader* |
|
fx_lut3d.h |
Shader* |
|
fx_lut_viz.h |
Shader* |
Ajoute <stdbool.h> pour bool |
fx_auto_exposure.h |
Shader* |
|
fx_motion_blur.h |
Shader* |
Résultat : 24 en-têtes utilisent désormais des déclarations anticipées (contre 6 avant cette passe). Chaque fichier .c correspondant ajoute l'#include complet nécessaire pour la définition concrète du type.
Réduction du fan-out d'includes (app_input.c, app_ui.c)¶
Les deux fichiers sources avec le plus haut fan-out d'includes ont été allégés en déplaçant la fonction pont app_input_ctx_from_app() vers app.c et en supprimant les includes inutilisés ou transitivement redondants :
app_input.c: 25 → 17 includes. La fonction pont était la seule raison d'inclureapp.h,app_profiling.hetapp_input_state.h. Son déplacement versapp.c(qui inclut déjà ces trois en-têtes) élimine le couplage. Suppressions additionnelles :window.h(jamais utilisé),action_notifier.h,app_settings.h,nbody.h,glad/glad.h,GLFW/glfw3.h(tous disponibles transitivement).app_ui.c: 23 → 16 includes. Suppression destb_image.h(aucun appelstbi_*),<stdio.h>et<stdlib.h>(aucune utilisation directe), plus 4 en-têtes transitivement redondants (action_notifier.h,adaptive_sampler.h,app_binding.h,app_settings.h).
Principe : un en-tête qui n'utilise un type qu'à travers un pointeur ou une référence doit faire une déclaration anticipée de ce type, pas inclure sa définition complète. Cela réduit la propagation des includes et accélère les builds incrémentaux.
Configuration CMake¶
Les modules sont compilés séparément et liés à l'exécutable principal :
Chaque module expose son interface via un en-tête dans include/ avec le préfixe correspondant (app_ui.h, app_input.h, etc.).
Métriques & Santé¶
Dernière mise à jour : mai 2026 (SubsystemDescriptor MVP — Issue #285)
Taille du codebase¶
| Catégorie | Fichiers | LOC total |
|---|---|---|
Sources (src/*.c) |
67 | 20 556 |
En-têtes (include/*.h) |
88 | 7 839 |
Tests (tests/test_*.c) |
70 | 12 666 |
Shaders (shaders/) |
60 | — |
LOC par module (top 15)¶
| Module | LOC | Notes |
|---|---|---|
postprocess.c |
1 634 | Monolithe historique — découpé en 6 UT (voir Découpage PostProcess) |
app_ui.c |
1 317 | Rendu UI + données de layout (privatisées) |
app_input.c |
925 | Dispatch entrées clavier/souris |
ui.c |
879 | Intégration Dear ImGui |
shader.c |
870 | Compilation & édition de liens shaders |
light_probes.c |
752 | Grille de sondes lumineuses |
postprocess_presets.c |
525 | Définitions de presets |
scene_render.c |
494 | Appels de rendu de la scène |
postprocess_input.c |
486 | Contrôles clavier post-process |
nbody.c |
486 | Simulation N-body (CPU + compute) |
scene_init.c |
476 | Création des ressources scène |
app.c |
474 | Orchestrateur (boucle principale) |
billboard_sorter.c |
472 | Tri en profondeur des billboards |
ibl_coordinator.c |
443 | Machine d'état IBL |
async_loader.c |
422 | Chargement HDR asynchrone |
Règle : les modules > 500 LOC sont candidats à une décomposition ultérieure.
Fan-out d'includes des en-têtes¶
| En-tête | #includes | Statut |
|---|---|---|
scene.h |
14 | Agrégat — attendu |
app.h |
13 | Réduit de 22 (Phase 3) |
postprocess.h |
11 | Agrégat — attendu |
app_profiling.h |
7 | Sous-struct — acceptable |
gpu_profiler.h |
7 | En-tête de domaine |
utils.h |
7 | Utilitaires divers |
renderer.h |
0 | Déclarations anticipées uniquement ✅ |
effect_benchmark.h |
1 | Était 3 — décl. anticipées ✅ |
light_probes.h |
2 | Était 4 — décl. anticipées ✅ |
fx_*.h (effets) |
0–1 | Tous utilisent des décl. anticipées pour Shader* ✅ |
Principe : les en-têtes agrégats (app.h, scene.h, postprocess.h) ont naturellement un fan-out élevé. Les en-têtes de modules feuilles doivent rester ≤ 5. 24 en-têtes utilisent désormais des déclarations anticipées.
Couverture de test (LLVM-Cov, juin 2025)¶
| Métrique | Valeur | Cible |
|---|---|---|
| Lignes | 71,4 % | ≥ 78 % |
| Fonctions | 83,6 % | ≥ 85 % |
| Branches | 53,7 % | ≥ 50 % ✅ |
71 tests passent (unitaires + intégration, CTest).
Graphe de dépendances include¶
Dépendances des modules principaux (en-têtes projet uniquement, hors système et vendeur) :
graph TD
classDef aggregate fill:#1a1b26,stroke:#e0af68,color:#e0af68,stroke-width:2
classDef substruct fill:#1a1b26,stroke:#7aa2f7,color:#7aa2f7
classDef leaf fill:#1a1b26,stroke:#9ece6a,color:#9ece6a
classDef effect fill:#1a1b26,stroke:#bb9af7,color:#bb9af7
APP[app.h]:::aggregate
SCENE[scene.h]:::aggregate
PP[postprocess.h]:::aggregate
REND[renderer.h]:::leaf
%% Sous-structs App
APP_PROF[app_profiling.h]:::substruct
APP_INP[app_input_state.h]:::substruct
APP_WIN[app_window.h]:::substruct
APP_UI[app_ui.h]:::substruct
%% Sous-structs Scene
SC_GPU[scene_gpu_resources.h]:::substruct
SC_SH[scene_shaders.h]:::substruct
SC_CFG[scene_config.h]:::substruct
SC_VIS[scene_visuals.h]:::substruct
SC_SIM[scene_simulation.h]:::substruct
SC_LIT[scene_lighting.h]:::substruct
%% Sous-headers PostProcess
PP_PAR[pp_params.h]:::substruct
PP_GPU[pp_gpu_resources.h]:::substruct
PP_SHD[pp_shader_state.h]:::substruct
PP_RDB[pp_exposure_readback.h]:::substruct
%% Effets
FX_BL[fx_bloom.h]:::effect
FX_DOF[fx_dof.h]:::effect
FX_AE[fx_auto_exposure.h]:::effect
FX_MB[fx_motion_blur.h]:::effect
FX_LUT[fx_lut3d.h]:::effect
EC[effect_context.h]:::effect
%% App → dépendances directes
APP --> SCENE
APP --> PP
APP --> APP_UI
APP --> APP_WIN
%% Sous-structs App (possédées, pas incluses par app.h)
APP -.->|"possédée"| APP_PROF
APP -.->|"possédée"| APP_INP
%% Scene → sous-structs
SCENE --> SC_GPU
SCENE --> SC_SH
SCENE --> SC_CFG
SCENE --> SC_VIS
SCENE --> SC_SIM
SCENE --> SC_LIT
%% PostProcess → sous-headers + effets
PP --> PP_PAR
PP --> PP_GPU
PP --> PP_SHD
PP --> PP_RDB
PP --> FX_BL
PP --> FX_DOF
PP --> FX_AE
PP --> FX_MB
PP --> FX_LUT
%% Découplage des effets
FX_BL -.->|"runtime"| EC
FX_DOF -.->|"runtime"| EC
FX_AE -.->|"runtime"| EC
FX_MB -.->|"runtime"| EC
FX_LUT -.->|"runtime"| EC
%% Renderer utilise uniquement des déclarations anticipées
REND -.->|"décl. anticipée"| APP
REND -.->|"décl. anticipée"| SCENE
REND -.->|"décl. anticipée"| PP
Légende : Flèches pleines = dépendance #include. Flèches pointillées = déclaration anticipée ou dépendance runtime. Couleurs : 🟡 agrégat, 🔵 sous-struct, 🟢 feuille, 🟣 effet.