docs: reorganize and consolidate Lardon3D documentation
This commit is contained in:
parent
7259746b3d
commit
32f3c8bc57
25 changed files with 2361 additions and 489 deletions
40
AGENTS.md
40
AGENTS.md
|
|
@ -71,10 +71,48 @@ disponible. Ne jamais annoncer une vérification non exécutée.
|
|||
|
||||
## Prochains tickets recommandés
|
||||
|
||||
1. Sélectionner une tâche admissible sans blocage par la tête de file.
|
||||
1. Sélectionner une tâche admissible sans blocage par la tête de file ✓
|
||||
2. Introduire le DAG et les dépendances.
|
||||
3. Persister les tâches et checkpoints de reprise.
|
||||
4. Orchestrer et mesurer les séquences adaptatives.
|
||||
5. Ajouter les pools bornés CPU, IO et GPU.
|
||||
6. Migrer l'import vers le scheduler générique.
|
||||
7. Ajouter la publication live validée, puis le viewer Vulkan séparé.
|
||||
|
||||
## Règles documentaires
|
||||
|
||||
### README.md racine
|
||||
Le README.md à la racine est le sommaire canonique de la documentation.
|
||||
|
||||
### Vérification avant ticket architectural
|
||||
Avant un ticket architectural important :
|
||||
1. Identifier le document canonique correspondant dans docs/
|
||||
2. Le lire
|
||||
3. Vérifier que le ticket respecte ses invariants
|
||||
|
||||
### Mise à jour après ticket
|
||||
Après un ticket modifiant :
|
||||
- API
|
||||
- Architecture
|
||||
- Ownership
|
||||
- Concurrence
|
||||
- Persistance
|
||||
- Pipeline
|
||||
- Limites
|
||||
|
||||
Appeler lardon-docs avant de considérer le ticket terminé.
|
||||
|
||||
### Contradictions code/documentation
|
||||
Si code et documentation architecturale se contredisent :
|
||||
1. Ne pas choisir silencieusement
|
||||
2. Signaler la contradiction
|
||||
3. Décider quelle spécification doit devenir canonique
|
||||
4. Mettre la documentation à jour
|
||||
5. Seulement ensuite poursuivre
|
||||
|
||||
### Nouveaux documents
|
||||
Tout nouveau document docs/** doit être référencé depuis README.md si c'est
|
||||
un document canonique destiné aux lecteurs du projet.
|
||||
|
||||
### Unicité des documents
|
||||
Ne jamais créer plusieurs documents canoniques décrivant le même contrat.
|
||||
|
|
|
|||
158
README.md
158
README.md
|
|
@ -1,57 +1,141 @@
|
|||
# Lardon3D
|
||||
|
||||
Lardon3D est une application terminal interactive dédiée à la reconstruction 3D. Son interface TUI utilise tout l'espace du terminal et s'adapte à son redimensionnement.
|
||||
Moteur de reconstruction géométrique persistante et incrémentale, piloté par une TUI ncursesw.
|
||||
|
||||
Une vue Vulkan séparée sera ajoutée ultérieurement pour afficher la scène 3D. L'application actuelle n'ouvre aucune fenêtre graphique.
|
||||
## Vision
|
||||
|
||||
## Prérequis
|
||||
Lardon3D est un moteur de photogrammétrie Linux qui privilégie :
|
||||
|
||||
- Arch Linux (ou distribution dérivée)
|
||||
- Clang
|
||||
- Meson
|
||||
- Ninja
|
||||
- ncursesw
|
||||
- **Stabilité** : aucune saturation du système hôte
|
||||
- **Déterminisme** : résultats reproductibles et traçables
|
||||
- **Faible consommation mémoire** : traitement par lots adaptatifs
|
||||
- **Reprise après interruption** : résultats atomiques et persistants
|
||||
- **Protection de la machine** : budgets bornés et respectueux
|
||||
- **Traçabilité** : historique des opérations et métriques
|
||||
- **Enrichissement progressif** : reconstruction incrémentale
|
||||
|
||||
## Compilation
|
||||
Lardon3D ne vise pas simplement "dossier de photos → objet 3D", mais "ensemble progressif d'observations et de contraintes → reconstruction géométrique persistante, enrichissable et versionnable".
|
||||
|
||||
## État actuel
|
||||
|
||||
### Briques implémentées (IMPLEMENTED)
|
||||
|
||||
- **Project** : gestion persistante des projets
|
||||
- **Import** : import asynchrone et annulable d'images
|
||||
- **Import Task** : wrapper asynchrone avec états et progression
|
||||
- **Image Catalog** : indexage des métadonnées d'images
|
||||
- **Image View** : vues triées et filtrées pour la TUI
|
||||
- **Task** : moteur de tâches avec pause/reprise, annulation, checkpoints
|
||||
- **Task Queue** : file FIFO avec sélection adaptative et backpressure
|
||||
- **Hardware Profile** : détection des capacités matérielles
|
||||
- **Resource Snapshot** : capture instantanée des ressources
|
||||
- **Resource Governor** : arbitrage centralisé des budgets et réservations
|
||||
|
||||
### Briques en cours de consolidation
|
||||
|
||||
- Intégration scheduler ↔ governor avec séquences adaptatives
|
||||
- Documentation architecture
|
||||
|
||||
### Briques prévues (PLANNED)
|
||||
|
||||
- Persistance des tâches et checkpoints
|
||||
- DAG de dépendances
|
||||
- Pools de workers multiples (CPU/GPU/IO)
|
||||
- Publication live validée
|
||||
- Viewer intégré
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
TUI / Projet
|
||||
↓
|
||||
Scheduler
|
||||
↓
|
||||
Resource Governor
|
||||
↓
|
||||
Workers
|
||||
↓
|
||||
Résultats atomiques / persistants
|
||||
↓
|
||||
Viewer (consommation passive de snapshots)
|
||||
```
|
||||
|
||||
### Invariants fondamentaux
|
||||
|
||||
- Aucun callback de tâche sans réservation active validée
|
||||
- Le scheduler ne décide jamais des ressources
|
||||
- Le Resource Governor est l'unique propriétaire des budgets
|
||||
- ncurses appartient exclusivement au thread principal
|
||||
- Les estimations de ressources sont immuables
|
||||
- Les buffers et files sont strictement bornés
|
||||
|
||||
## Pipeline cible
|
||||
|
||||
```text
|
||||
Acquisitions
|
||||
→ catalogue
|
||||
→ features
|
||||
→ index visuel
|
||||
→ paires candidates
|
||||
→ matching
|
||||
→ vérification géométrique
|
||||
→ tracks / SfM
|
||||
→ dense
|
||||
→ mesh
|
||||
→ consolidation
|
||||
→ export
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Architecture
|
||||
- [Vue d'ensemble](docs/architecture/overview.md)
|
||||
- [Runtime](docs/architecture/runtime.md)
|
||||
- [Système de tâches](docs/architecture/task_system.md)
|
||||
- [File de tâches](docs/architecture/task_queue.md)
|
||||
- [Resource Governor](docs/architecture/resource_governor.md)
|
||||
- [Intégration Scheduler ↔ Governor](docs/architecture/scheduler_resource_integration.md)
|
||||
- [Pipeline de reconstruction](docs/architecture/reconstruction_pipeline.md)
|
||||
- [Persistance](docs/architecture/persistence.md)
|
||||
- [Base de données projet](docs/architecture/project_database.md)
|
||||
- [Viewer](docs/architecture/viewer.md)
|
||||
- [Revue des fondations](docs/architecture/foundation_review.md)
|
||||
|
||||
### Concepts
|
||||
- [Scan Sets](docs/concepts/scan_sets.md)
|
||||
- [Index visuel](docs/concepts/visual_index.md)
|
||||
- [Matching et tracks](docs/concepts/matching_and_tracks.md)
|
||||
- [Couches de reconstruction](docs/concepts/reconstruction_layers.md)
|
||||
- [Contraintes géométriques](docs/concepts/geometric_constraints.md)
|
||||
|
||||
### Développement
|
||||
- [Build](docs/development/build.md)
|
||||
- [Tests](docs/development/testing.md)
|
||||
- [Concurrence](docs/development/concurrency.md)
|
||||
|
||||
### Roadmap
|
||||
- [Roadmap](docs/roadmap/roadmap.md)
|
||||
|
||||
## Build rapide
|
||||
|
||||
```sh
|
||||
CC=clang meson setup build --wipe
|
||||
meson compile -C build -j8
|
||||
```
|
||||
|
||||
## Exécution
|
||||
## Tests
|
||||
|
||||
```sh
|
||||
./build/lardon3d
|
||||
meson test -C build --print-errorlogs
|
||||
git diff --check
|
||||
```
|
||||
|
||||
La TUI s'affiche directement dans le terminal courant. Appuyez sur `q` ou `Q` pour quitter proprement.
|
||||
Pour les changements sensibles à la mémoire ou à la concurrence, ajouter ASan/UBSan et TSan.
|
||||
|
||||
Les projets sont enregistrés par défaut dans `~/Documents/Lardon/Projets3D`.
|
||||
La variable `LARDON3D_PROJECTS_ROOT` permet de choisir un autre répertoire racine à l'exécution.
|
||||
## Statut
|
||||
|
||||
L'import accepte les images JPEG, PNG, TIFF et HEIC présentes directement dans
|
||||
le dossier choisi, sans parcourir ses sous-dossiers. Elles sont copiées vers
|
||||
`images/originals` et répertoriées dans `images/manifest.tsv`.
|
||||
L'import s'exécute en arrière-plan afin que la TUI reste réactive. Pendant une
|
||||
opération, la touche `C` demande son annulation.
|
||||
Lardon3D est en développement actif. La phase de fondation est terminée. Les prochains tickets porteront sur la persistance, le DAG, les pools de workers et la publication live.
|
||||
|
||||
L'écran Import présente un catalogue en mémoire vérifié par rapport au manifeste
|
||||
et aux fichiers de `images/originals`. Les flèches, `j`/`k`, PageUp, PageDown,
|
||||
Home et End naviguent dans la liste ; `R` recharge le catalogue.
|
||||
La touche `S` fait défiler les tris par ordre d'import, nom ou taille, dans les
|
||||
deux directions. `/` filtre les noms d'images sans distinction de casse ASCII et
|
||||
`X` efface le filtre. Le tri et le filtre restent entièrement en mémoire et ne
|
||||
modifient ni le manifeste ni les images.
|
||||
## Licence
|
||||
|
||||
Un moteur générique exécute les tâches en file FIFO sur un worker unique. Il
|
||||
prend en charge progression, pause, reprise et annulation coopérative sans
|
||||
dépendre de la TUI ni des modules métier. L'écran `F5` affiche l'état courant de
|
||||
la file et de ses tâches.
|
||||
|
||||
Les fondations du moteur de ressources séparent la détection matérielle, les
|
||||
instantanés de disponibilité et les décisions du gouverneur. Le gouverneur
|
||||
conserve des marges système et GPU, puis autorise, diffère, réduit ou refuse un
|
||||
lot sans dépendre du scheduler ni d'un traitement métier. Les admissions
|
||||
acceptées créent désormais une réservation atomique ; l'écran `F6` affiche les
|
||||
budgets engagés et restants.
|
||||
Projet privé - Tous droits réservés.
|
||||
|
|
|
|||
|
|
@ -1,121 +1,90 @@
|
|||
# Revue technique des fondations
|
||||
# Revue des fondations Lardon3D
|
||||
|
||||
## Périmètre et conclusion
|
||||
## Objectif
|
||||
|
||||
Cette revue couvre `task`, `task_queue`, le profil matériel, les snapshots de
|
||||
ressources, le gouverneur, les réservations et leur intégration au scheduler.
|
||||
Aucune fuite, course, interblocage ou violation reproductible de l'invariant
|
||||
d'admission n'a été détecté par l'inspection et les tests actuels. Aucun code de
|
||||
production n'a donc été modifié.
|
||||
Documenter la revue technique de la phase de fondation : task, task_queue, hardware_profile, resource_snapshot, resource_governor, réservations et intégration au scheduler.
|
||||
|
||||
## Invariants actuellement garantis
|
||||
## Composants évalués
|
||||
|
||||
- Une tâche possède une estimation copiée à sa création et exposée seulement
|
||||
par copie.
|
||||
- Le scheduler reçoit explicitement son gouverneur et refuse un gouverneur nul.
|
||||
- Le worker obtient une réservation active avant d'appeler
|
||||
`lardon3d_task_start`; celui-ci revalide la réservation avant le callback.
|
||||
- Un callback lancé par la file dispose d'une copie cohérente de son contrat :
|
||||
lot, RAM, GPU, CPU et slots IO/GPU.
|
||||
- `WAIT` conserve la tâche en tête et endort le worker sur une condition
|
||||
variable. Le mutex de file empêche une notification concurrente de se perdre
|
||||
entre la décision et l'attente.
|
||||
- `REJECT` termine la tâche sans appeler son callback. `REDUCE_BATCH` transmet
|
||||
le contrat réduit.
|
||||
- La réservation détenue par le worker est libérée après succès, échec ou
|
||||
annulation. Une pause en cours conserve volontairement la réservation.
|
||||
- La destruction de la file annule les tâches, réveille et rejoint le worker,
|
||||
puis détruit les tâches dont elle est propriétaire.
|
||||
- Les compteurs du gouverneur et la création des réservations sont protégés par
|
||||
un mutex unique. Une double libération est refusée sans débiter les budgets.
|
||||
- Les calculs de taille contrôlent multiplication et addition ; les compteurs
|
||||
CPU et slots ne peuvent croître au-delà des budgets calculés.
|
||||
- Le profil représente les capacités stables. Les snapshots sont des valeurs
|
||||
datées et indépendantes ; le scheduler ne prend aucune décision de ressources
|
||||
lui-même.
|
||||
### Task
|
||||
- Cycle de vie complet
|
||||
- États et transitions
|
||||
- Pause/reprise coopérative
|
||||
- Annulation coopérative
|
||||
- Checkpoints
|
||||
- Estimations de ressources
|
||||
|
||||
### Task Queue
|
||||
- File FIFO
|
||||
- Sélection de la première tâche admissible
|
||||
- Backpressure
|
||||
- Bornage du pending_count
|
||||
- Comportement WAIT
|
||||
|
||||
### Hardware Profile
|
||||
- Détection des capacités matérielles
|
||||
- CPU, RAM, GPU/VRAM
|
||||
|
||||
### Resource Snapshot
|
||||
- Capture instantanée des ressources
|
||||
- RAM libre, charge CPU, VRAM
|
||||
|
||||
### Resource Governor
|
||||
- Arbitrage centralisé
|
||||
- Calcul de lots adaptatifs
|
||||
- Réservations opaques
|
||||
- Historique borné
|
||||
|
||||
### Intégration Scheduler ↔ Governor
|
||||
- Cycle d'exécution
|
||||
- Admission
|
||||
- Gestion des pauses
|
||||
- Séquences adaptatives
|
||||
|
||||
## Invariants garantis
|
||||
|
||||
1. Intégrité des estimations (immuables)
|
||||
2. Obligation de réservation active avant démarrage
|
||||
3. Cohérence du contrat de lot transmis au callback
|
||||
4. Gestion sécurisée de WAIT et des variables de condition
|
||||
5. Libération unique des réservations
|
||||
6. Protection mutex unique du gouverneur
|
||||
7. Séparation stricte des rôles (scheduler ne décide pas des ressources)
|
||||
|
||||
## Limites connues
|
||||
|
||||
- La file possède un seul worker et applique un FIFO strict. Une tâche en tête
|
||||
qui reçoit `WAIT` bloque les tâches suivantes, même si certaines seraient
|
||||
admissibles.
|
||||
- Une libération extérieure au scheduler exige ensuite un appel à
|
||||
`lardon3d_task_queue_resources_changed`. Le gouverneur ne publie pas encore
|
||||
automatiquement cet événement.
|
||||
- Les réservations libérées restent comme tombstones jusqu'à la destruction du
|
||||
gouverneur. Cela sécurise la double libération mais fait croître la mémoire
|
||||
avec le nombre historique de contrats.
|
||||
- Une erreur de capture du snapshot fait échouer la tâche ; il n'existe pas
|
||||
encore de distinction entre erreur transitoire de mesure et rejet durable.
|
||||
- Le gouverneur et la file doivent être détruits après arrêt de leurs appelants.
|
||||
Leur destruction concurrente avec une API active n'est pas prise en charge.
|
||||
- Les tâches, checkpoints, files et réservations ne sont pas persistés.
|
||||
- Il n'existe ni DAG, ni priorité, ni pool de workers, ni orchestration de
|
||||
séquences adaptatives successives.
|
||||
- File à worker unique avec FIFO strict
|
||||
- Absence de notification automatique de libération externe
|
||||
- Accumulation de tombstones de réservations
|
||||
- Absence de persistance
|
||||
- Absence de DAG
|
||||
- Absence de priorités
|
||||
- Absence de pools de workers multiples
|
||||
|
||||
## Risques à surveiller
|
||||
|
||||
- Formaliser l'ordre de durée de vie : la file doit être détruite avant son
|
||||
gouverneur ; une tâche cédée à la file ne doit plus être détruite directement.
|
||||
- Ne jamais permettre à un composant extérieur de libérer la réservation privée
|
||||
du worker. L'appel `get_active` et le démarrage sont sûrs dans le modèle de
|
||||
propriété actuel, pas face à une libération concurrente volontaire.
|
||||
- Éviter qu'un callback détruise ou joigne sa propre tâche, ce qui pourrait
|
||||
attendre sa propre fin.
|
||||
- Conserver les prédicats autour de chaque attente de condition et maintenir le
|
||||
même mutex pour décision `WAIT` et mise en sommeil.
|
||||
- Surveiller les identifiants et compteurs historiques sur les très longues
|
||||
sessions, même si leur débordement est irréaliste avec les allocations
|
||||
actuelles.
|
||||
- Ne pas transformer `MemAvailable`, le swap ou la zram en promesse de mémoire
|
||||
supplémentaire. Les snapshots peuvent déjà refléter une consommation réelle
|
||||
en plus des réservations comptables ; une politique future doit rester
|
||||
conservatrice.
|
||||
- Garder la publication de résultats indépendante du contrat d'exécution : seul
|
||||
un résultat validé atomiquement peut devenir visible.
|
||||
- Ordre de destruction des objets
|
||||
- Concurrence sur la libération des réservations
|
||||
- Récursivité/blocage par un callback détruisant sa propre tâche
|
||||
- Bornage de la mémoire
|
||||
- Indépendance de la publication atomique
|
||||
|
||||
## Cohérence documentaire
|
||||
## Feuille de route
|
||||
|
||||
Les documents actuels correspondent au code : responsabilités séparées,
|
||||
réservation préalable, pause conservant les ressources, worker unique et
|
||||
notification explicite. La vue d'ensemble décrit comme futurs — et non comme
|
||||
existants — les séquences complètes, la reprise persistante, les snapshots live
|
||||
et le viewer Vulkan.
|
||||
### Prochains tickets recommandés
|
||||
1. Sélectionner une tâche admissible sans blocage par la tête de file ✓
|
||||
2. Introduire le DAG et les dépendances
|
||||
3. Persister les tâches et checkpoints de reprise
|
||||
4. Orchestrer et mesurer les séquences adaptatives
|
||||
5. Ajouter les pools bornés CPU, IO et GPU
|
||||
6. Migrer l'import vers le scheduler générique
|
||||
7. Ajouter la publication live validée, puis le viewer Vulkan séparé
|
||||
|
||||
## Ordre recommandé des prochains tickets
|
||||
## Validation
|
||||
|
||||
1. Formaliser les contrats de propriété, les événements de libération et les
|
||||
erreurs transitoires de snapshot.
|
||||
2. Définir un format de résultat atomique avec identifiant, validation et point
|
||||
de reprise.
|
||||
3. Ajouter l'enchaînement borné de lots adaptatifs sous réservations successives.
|
||||
4. Borner les files et introduire la contre-pression.
|
||||
5. Persister tâches et checkpoints nécessaires à la reprise après crash.
|
||||
6. Ajouter ensuite un DAG minimal, puis les priorités.
|
||||
7. Généraliser vers des pools CPU, IO et GPU en conservant le gouverneur comme
|
||||
unique arbitre.
|
||||
8. Publier des snapshots validés avant d'introduire le viewer séparé.
|
||||
- Tests unitaires passés
|
||||
- ASan/UBSan passés
|
||||
- TSan passé
|
||||
- git diff --check propre
|
||||
|
||||
## Éléments à ne pas réécrire lors du passage à OpenCode
|
||||
|
||||
- Les structures opaques `Task`, `TaskQueue`, `ResourceGovernor` et
|
||||
`ResourceReservation`.
|
||||
- La séparation profil matériel / snapshot dynamique / politique / réservation.
|
||||
- Le calcul centralisé et protégé des budgets et lots.
|
||||
- L'invariant « réservation active avant callback » et la copie du contrat vers
|
||||
la tâche.
|
||||
- L'annulation coopérative, les checkpoints de pause et la propriété ncurses du
|
||||
thread principal.
|
||||
- Le FIFO à condition variable comme implémentation V1 fiable ; il doit évoluer
|
||||
par extension, pas être remplacé avant que les besoins DAG soient spécifiés.
|
||||
- Les écritures atomiques, rollbacks ciblés et validations déjà utilisés par les
|
||||
projets et imports.
|
||||
- Les tests de concurrence, de double libération, d'annulation et de destruction
|
||||
sûre, qui constituent la base de non-régression.
|
||||
|
||||
## Validation exécutée
|
||||
|
||||
- Suite normale : 10 tests réussis sur 10.
|
||||
- ASan/UBSan : 10 tests réussis sur 10, aucun diagnostic.
|
||||
- TSan : 10 tests réussis sur 10, aucune course signalée.
|
||||
- `git diff --check` : réussi avant la rédaction du présent rapport.
|
||||
## Statut : DOCUMENTATION DE L'IMPLÉMENTATION ACTUELLE
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
## Finalité et flux global
|
||||
|
||||
Lardon3D est une application Linux de reconstruction 3D pilotée par une TUI
|
||||
ncursesw. Le terminal reste le centre de contrôle : il gère les projets, lance
|
||||
les opérations, présente leur progression et permet leur annulation. Le futur
|
||||
viewer Vulkan sera un processus ou composant graphique séparé, affiché sur le
|
||||
workspace 8 ; il ne remplacera pas la TUI et ne devra jamais la bloquer.
|
||||
Lardon3D est un moteur de reconstruction géométrique persistante et incrémentale,
|
||||
piloté par une TUI ncursesw. Le terminal reste le centre de contrôle : il gère
|
||||
les projets, lance les opérations, présente leur progression et permet leur
|
||||
annulation. Le viewer sera un composant graphique séparé mais intégré à
|
||||
l'interface pour un usage confortable sur un seul écran.
|
||||
|
||||
```text
|
||||
TUI / Projet
|
||||
|
|
@ -30,83 +30,96 @@ Viewer live
|
|||
|
||||
## Composants actuels
|
||||
|
||||
Les projets persistants regroupent leur configuration, les images originales,
|
||||
le manifeste, les résultats de reconstruction, les exports et les journaux.
|
||||
Leur création est protégée contre l'écrasement et les écritures structurantes
|
||||
utilisent des remplacements atomiques.
|
||||
### Project
|
||||
Gestion persistante des projets : création, ouverture, fermeture, structure
|
||||
de répertoires. Chaque projet regroupe configuration, images originales,
|
||||
manifeste, résultats, exports et journaux.
|
||||
|
||||
L'import d'images s'exécute de manière asynchrone et annulable, sans appel
|
||||
ncurses depuis son worker. Il copie individuellement les fichiers admissibles
|
||||
et maintient un manifeste cohérent. Le catalogue charge et valide ce manifeste
|
||||
en mémoire. La vue d'images en dérive des indices triés et filtrés sans modifier
|
||||
le catalogue, le manifeste ou les images.
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
Le moteur de tâches fournit les états, la progression, la pause, l'annulation
|
||||
coopérative et les callbacks. La file actuelle possède un worker unique et
|
||||
respecte l'ordre FIFO. Chaque tâche porte une estimation immuable de ses coûts
|
||||
RAM, GPU, CPU et IO ainsi que des bornes de lot.
|
||||
### Import
|
||||
Import asynchrone et annulable d'images dans un projet. Copie individuelle
|
||||
des fichiers admissibles et maintenance d'un manifeste cohérent.
|
||||
|
||||
Le profil matériel décrit les capacités stables détectées sur la machine. Les
|
||||
snapshots décrivent les ressources disponibles à un instant donné. Le Resource
|
||||
Governor combine profil, snapshot, marges de sécurité et réservations actives.
|
||||
Il décide si une demande doit démarrer, attendre, réduire son lot ou être
|
||||
refusée, puis matérialise toute admission par une réservation opaque.
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
Le scheduler ne décide jamais des ressources. Il demande une réservation au
|
||||
gouverneur juste avant l'exécution et transmet au callback une copie du contrat
|
||||
accordé. L'invariant est strict : aucun callback de tâche n'est lancé sans
|
||||
réservation active validée. Après succès, échec ou annulation, cette réservation
|
||||
est libérée exactement une fois. Une tâche déjà en pause conserve son contrat
|
||||
dans cette première version.
|
||||
### Import Task
|
||||
Wrapper asynchrone de l'import avec états, progression et annulation
|
||||
coopérative. Exécute l'import dans un worker dédié (non encore migré vers
|
||||
le scheduler générique).
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Image Catalog
|
||||
Chargement et indexage en mémoire des métadonnées d'images depuis le
|
||||
manifeste du projet. Fournit un accès structuré aux images.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Image View
|
||||
Vues triées et filtrées du catalogue pour la TUI. Ne modifie pas le
|
||||
catalogue, le manifeste ou les images.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Task
|
||||
Moteur de tâches avec états, progression, pause/reprise coopérative,
|
||||
annulation, checkpoints et estimations de ressources.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Task Queue
|
||||
File FIFO avec worker unique, sélection de la première tâche admissible,
|
||||
backpressure et bornage du nombre de tâches en attente.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Hardware Profile
|
||||
Détection des capacités matérielles statiques : cœurs CPU, RAM, GPU/VRAM.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Resource Snapshot
|
||||
Capture instantanée des ressources disponibles : RAM libre, charge CPU,
|
||||
VRAM disponible.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
### Resource Governor
|
||||
Arbitrage centralisé des budgets (RAM, GPU, CPU, IO), calcul de lots
|
||||
adaptatifs, réservations opaques et historique borné de métriques.
|
||||
|
||||
**Statut :** IMPLEMENTED
|
||||
|
||||
## Résultats et publication live
|
||||
|
||||
Les traitements futurs fonctionneront par séquences adaptatives : lire un lot
|
||||
borné, calculer, écrire un résultat atomique, libérer la mémoire, puis traiter
|
||||
le lot suivant. La stabilité du système hôte et la réactivité de la TUI ont
|
||||
Les traitements fonctionnent par séquences adaptatives : lire un lot borné,
|
||||
calculer, écrire un résultat atomique, libérer la mémoire, puis traiter le
|
||||
lot suivant. La stabilité du système hôte et la réactivité de la TUI ont
|
||||
priorité sur le débit maximal.
|
||||
|
||||
Le viewer live ne devra observer que des snapshots de résultats complètement
|
||||
validés et publiés atomiquement. Il ne lira jamais un fichier intermédiaire et
|
||||
ne partagera pas directement les buffers de travail d'un worker. Une
|
||||
interruption doit laisser le dernier snapshot validé exploitable et permettre
|
||||
la reprise à une frontière de séquence connue.
|
||||
Le viewer consomme des snapshots de résultats validés et publiés
|
||||
atomiquement. Il ne lit jamais un fichier intermédiaire et ne partage pas
|
||||
directement les buffers de travail d'un worker. Une interruption doit laisser
|
||||
le dernier snapshot validé exploitable et permettre la reprise à une
|
||||
frontière de séquence connue.
|
||||
|
||||
## Principes non négociables
|
||||
## Invariants fondamentaux
|
||||
|
||||
- Aucune tâche lourde monolithique ni chargement complet d'un projet en RAM.
|
||||
- Traitement par séquences adaptatives et libération entre les lots.
|
||||
- Budgets RAM, GPU, CPU et IO explicitement bornés et réservés.
|
||||
- Files de travail et buffers intermédiaires bornés.
|
||||
- La zram est un filet de sécurité, jamais une extension du budget normal.
|
||||
- La RAM partagée des iGPU est comptabilisée dans le budget système.
|
||||
- Écritures atomiques, rollback ciblé et absence de résultat partiellement
|
||||
publié.
|
||||
- Reprise après interruption depuis le dernier état validé.
|
||||
- Viewer live séparé, non bloquant et lecteur de snapshots validés seulement.
|
||||
- Le système hôte, la TUI et les données utilisateur restent prioritaires sur
|
||||
le débit de reconstruction.
|
||||
- Aucun callback de tâche n'est lancé sans réservation active validée.
|
||||
- Le scheduler ne décide jamais des ressources.
|
||||
- Le Resource Governor est l'unique propriétaire des budgets.
|
||||
- Les réservations sont libérées exactement une fois.
|
||||
- ncurses appartient exclusivement au thread principal.
|
||||
- Les estimations de ressources sont immuables.
|
||||
- Les buffers et files sont strictement bornés.
|
||||
|
||||
## Limites actuelles
|
||||
|
||||
La file ne possède encore ni DAG, ni priorités, ni pool de workers CPU/IO/GPU.
|
||||
Les tâches et leur progression ne sont pas persistées après un arrêt. Les
|
||||
séquences adaptatives sont préparées par les contrats de lot mais leur
|
||||
enchaînement complet n'est pas encore orchestré. Le viewer Vulkan et la
|
||||
publication live restent à implémenter.
|
||||
|
||||
## Ordre recommandé des prochains tickets
|
||||
|
||||
1. Définir les résultats atomiques, leurs métadonnées de validation et leurs
|
||||
points de reprise.
|
||||
2. Introduire l'exécution d'une tâche en séquences de lots adaptatifs, toujours
|
||||
sous réservations successives.
|
||||
3. Borner explicitement les files et définir la contre-pression entre étapes.
|
||||
4. Persister les tâches, checkpoints et états nécessaires à la reprise après
|
||||
crash.
|
||||
5. Ajouter un DAG minimal et seulement ensuite les priorités.
|
||||
6. Introduire des pools CPU, IO et GPU sans déplacer l'arbitrage hors du
|
||||
gouverneur.
|
||||
7. Publier des snapshots live validés et versionnés.
|
||||
8. Ajouter le viewer Vulkan séparé sur le workspace 8 comme consommateur en
|
||||
lecture seule de ces snapshots.
|
||||
- File à worker unique avec FIFO strict.
|
||||
- Absence de DAG de dépendances.
|
||||
- Absence de priorités.
|
||||
- Absence de pools de workers multiples (CPU/GPU/IO).
|
||||
- Import non migré vers le scheduler générique.
|
||||
- Persistance des tâches et checkpoints non implémentée.
|
||||
- Viewer et publication live non implémentés.
|
||||
|
|
|
|||
55
docs/architecture/persistence.md
Normal file
55
docs/architecture/persistence.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Persistance et base de données Lardon3D
|
||||
|
||||
## Vision
|
||||
|
||||
Lardon3D doit stocker les métadonnées de reconstruction dans une base de données persistante légère, probablement SQLite, tandis que les données numériques massives restent dans des fichiers/binaires adaptés.
|
||||
|
||||
## Principes fondamentaux
|
||||
|
||||
### Séparation logique/binaire
|
||||
- État logique, relations, index → base persistante légère
|
||||
- Données numériques massives → fichiers/artefacts binaires adaptés
|
||||
|
||||
### Cycle de publication
|
||||
```
|
||||
lot calculé
|
||||
→ artefact temporaire
|
||||
→ validation
|
||||
→ publication atomique
|
||||
→ transaction de métadonnées
|
||||
→ état READY
|
||||
```
|
||||
|
||||
### Règle de reprise
|
||||
Une reprise ne considère jamais un artefact partiellement publié comme valide.
|
||||
|
||||
## Concepts de domaine
|
||||
|
||||
Les éléments suivants sont des concepts de domaine, PAS des tables SQL imposées :
|
||||
|
||||
- project
|
||||
- scan_set
|
||||
- image
|
||||
- feature_set
|
||||
- visual_signature
|
||||
- candidate_pair
|
||||
- verified_pair
|
||||
- track
|
||||
- observation
|
||||
- camera
|
||||
- pose
|
||||
- point3d
|
||||
- reconstruction_layer
|
||||
- measurement
|
||||
- document_source
|
||||
- geometric_constraint
|
||||
- artifact
|
||||
- checkpoint
|
||||
|
||||
## Invariants
|
||||
|
||||
- Chaque publication est atomique
|
||||
- Les artefacts partiels ne sont jamais considérés comme valides
|
||||
- La reprise commence à la dernière frontière connue
|
||||
|
||||
## Statut : PLANNED (direction architecturale)
|
||||
157
docs/architecture/project_database.md
Normal file
157
docs/architecture/project_database.md
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# Base de données projet Lardon3D
|
||||
|
||||
## Vision
|
||||
|
||||
La base de données projet stocke les métadonnées de reconstruction et les relations entre les entités. Elle est conçue pour être légère, persistante et permettre la reprise après interruption.
|
||||
|
||||
## Structure conceptuelle
|
||||
|
||||
### Entités principales
|
||||
|
||||
#### Project
|
||||
- Identifiant unique
|
||||
- Nom et description
|
||||
- Date de création
|
||||
- Configuration
|
||||
- Chemins des répertoires
|
||||
|
||||
#### Scan Set
|
||||
- Identifiant unique
|
||||
- Nom de l'acquisition
|
||||
- Date
|
||||
- Provenance
|
||||
- État de traitement
|
||||
|
||||
#### Image
|
||||
- Identifiant unique
|
||||
- Chemin du fichier
|
||||
- Métadonnées EXIF
|
||||
- État de traitement
|
||||
- Appartenance aux scan sets
|
||||
|
||||
#### Feature Set
|
||||
- Identifiant unique
|
||||
- Type de descripteur
|
||||
- Paramètres
|
||||
- Chemin des données
|
||||
|
||||
#### Visual Signature
|
||||
- Identifiant unique
|
||||
- Type d'index
|
||||
- Paramètres
|
||||
- Chemin des données
|
||||
|
||||
#### Candidate Pair
|
||||
- Identifiant unique
|
||||
- Image source
|
||||
- Image cible
|
||||
- Score de similarité
|
||||
- Source (visuelle, temporelle, etc.)
|
||||
|
||||
#### Verified Pair
|
||||
- Identifiant unique
|
||||
- Candidate pair source
|
||||
- Statut (validée, rejetée)
|
||||
- Métriques
|
||||
|
||||
#### Track
|
||||
- Identifiant unique
|
||||
- Observations
|
||||
- Point 3D associé
|
||||
- Qualité
|
||||
|
||||
#### Observation
|
||||
- Identifiant unique
|
||||
- Image
|
||||
- Position 2D
|
||||
- Descripteur
|
||||
- Track parent
|
||||
|
||||
#### Camera
|
||||
- Identifiant unique
|
||||
- Modèle
|
||||
- Paramètres intrinsèques
|
||||
- Distorsion
|
||||
|
||||
#### Pose
|
||||
- Identifiant unique
|
||||
- Camera
|
||||
- Translation
|
||||
- Rotation
|
||||
- Qualité
|
||||
|
||||
#### Point3D
|
||||
- Identifiant unique
|
||||
- Position
|
||||
- Couleur
|
||||
- Qualité
|
||||
- Observations
|
||||
|
||||
#### Reconstruction Layer
|
||||
- Identifiant unique
|
||||
- Type (sparse, dense, mesh, etc.)
|
||||
- Provenance
|
||||
- Transformations
|
||||
- Qualité
|
||||
- Chemin des données
|
||||
|
||||
#### Measurement
|
||||
- Identifiant unique
|
||||
- Type
|
||||
- Valeur
|
||||
- Incertitude
|
||||
- Cible géométrique
|
||||
|
||||
#### Document Source
|
||||
- Identifiant unique
|
||||
- Type (plan, croquis, etc.)
|
||||
- Chemin
|
||||
- Métadonnées
|
||||
|
||||
#### Geometric Constraint
|
||||
- Identifiant unique
|
||||
- Type
|
||||
- Paramètres
|
||||
- Sources
|
||||
- Poids
|
||||
|
||||
#### Artifact
|
||||
- Identifiant unique
|
||||
- Type
|
||||
- État (temporaire, publié)
|
||||
- Chemin
|
||||
- Métadonnées
|
||||
|
||||
#### Checkpoint
|
||||
- Identifiant unique
|
||||
- État du pipeline
|
||||
- Métadonnées
|
||||
- Date
|
||||
|
||||
## Relations
|
||||
|
||||
- Project → Scan Set (1:N)
|
||||
- Scan Set → Image (N:M)
|
||||
- Image → Feature Set (1:N)
|
||||
- Image → Visual Signature (1:N)
|
||||
- Candidate Pair → Image (2)
|
||||
- Verified Pair → Candidate Pair (1)
|
||||
- Track → Observation (N:M)
|
||||
- Observation → Image (1)
|
||||
- Observation → Point3D (N:1)
|
||||
- Camera → Pose (1:N)
|
||||
- Pose → Reconstruction Layer (N:M)
|
||||
- Reconstruction Layer → Artifact (1:N)
|
||||
- Measurement → Point3D (N:1)
|
||||
- Document Source → Geometric Constraint (N:M)
|
||||
- Geometric Constraint → Point3D (N:M)
|
||||
- Artifact → Checkpoint (N:1)
|
||||
|
||||
## Invariants
|
||||
|
||||
- Chaque entité a un identifiant unique stable
|
||||
- Les relations sont explicitement définies
|
||||
- Les artefacts partiels ne sont jamais considérés comme valides
|
||||
- La reprise commence à la dernière frontière connue
|
||||
|
||||
## Statut : PLANNED (direction architecturale)
|
||||
222
docs/architecture/reconstruction_pipeline.md
Normal file
222
docs/architecture/reconstruction_pipeline.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
# Pipeline de reconstruction Lardon3D
|
||||
|
||||
## Vision
|
||||
|
||||
Lardon3D ne doit plus être décrit simplement comme « dossier de photos → objet 3D ». La vision cible est :
|
||||
|
||||
> « ensemble progressif d'observations et de contraintes
|
||||
> → reconstruction géométrique persistante, enrichissable et versionnable »
|
||||
|
||||
Chaque ajout d'images, de mesures ou de documents enrichit la reconstruction
|
||||
existante sans détruire les résultats antérieurs. L'utilisateur peut
|
||||
interrompre le pipeline à tout instant, consulter l'état courant via le
|
||||
viewer, puis reprendre ultérieurement exactement où il s'était arrêté.
|
||||
|
||||
---
|
||||
|
||||
## Étapes du pipeline
|
||||
|
||||
### A. Scan Sets / acquisitions
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Définition** | Un *scan set* (ou acquisition) regroupe un ensemble d'images capturées dans un contexte donné : même lieu, même session, même objectif de reconstruction. |
|
||||
| **Enrichissement progressif** | Un scan set peut être alimenté par vagues successives : images initiales, images de relèvement, images de contrôle. Chaque vague est horodatée et traçable. |
|
||||
| **Identification stable** | Chaque scan set reçoit un identifiant UUID qui ne change jamais, même si le nom lisible est renommé. Les références internes utilisent cet UUID. |
|
||||
|
||||
**Statut :** PLANNED — le concept existe dans le manifeste projet mais n'est
|
||||
pas encore structuré avec UUID et vague d'import.
|
||||
|
||||
---
|
||||
|
||||
### B. Image Catalog
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Identité stable** | Chaque image possède un identifiant interne stable (UUID), distinct du nom de fichier sur disque. Le fichier peut être renommé ou déplacé sans casser les références. |
|
||||
| **Provenance** | Le catalogue enregistre le scan set d'origine, la date d'import, le chemin original et le chemin local. |
|
||||
| **État de traitement** | Pour chaque image, le catalogue maintient un état : RAW, FEATURES_EXTRACTED, MATCHED, REGISTERED. Cet état est lu par le pipeline pour décider de l'étape suivante. |
|
||||
|
||||
**Statut :** PARTIELLEMENT IMPLEMENTÉ — le `image_catalog` gère les
|
||||
métadonnées de base mais pas encore l'état de traitement ni l'UUID.
|
||||
|
||||
---
|
||||
|
||||
### C. Feature Store
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Index / métadonnées persistants** | Les descripteurs de features (points clés, descripteurs, orientations) sont persistés sur disque dans un format binaire compact. Le rechargement évite la re-extraction. |
|
||||
| **Données numériques massives** | Descripteurs floats, coordonnées de keypoints : volumes potentiellement importants. Doivent être stockés de manière séquentielle et indexée. |
|
||||
| **Formats adaptés et bornés** | Format binaire avec en-tête (version, nombre de features, dimensions). Borné par le budget RAM du governor : si le store dépasse la capacité, seuls les N plus récents sont en mémoire. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### D. Visual Index
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Choix basé sur le contenu visuel** | Le *visual index* permet de retrouver rapidement les images visuellement proches d'une image donnée, sans comparaison exhaustive. Structure type : vocabulaire visuel inversé ou similarité locality-sensitive hashing. |
|
||||
| **Pipeline conceptuel** | Extraction de features globales → construction de l'index → requête par similarité → retour des K plus proches voisins. |
|
||||
| **Proximité temporelle comme signal secondaire** | Lorsque les images portent un horodatage EXIF, la proximité temporelle sert de signal complémentaire au contenu visuel, mais ne remplace jamais l'analyse visuelle. |
|
||||
|
||||
**Statut :** PLANNED — le pipeline d'import利用 déjà la proximité temporelle
|
||||
pour les paires candidats, mais aucun index visuel n'existe.
|
||||
|
||||
---
|
||||
|
||||
### E. Candidate Pair Generator
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Sources de paires candidates** | (1) Visual index : paires visuellement proches. (2) Proximité temporelle. (3) Scan set commun. (4) Géométrie approximative (si GPS/IMU disponible). |
|
||||
| **Matching coûteux limité** | Le nombre de paires soumises au matching géométrique (étape F) doit être borné. Le candidate generator filtre et classe pour ne garder que les paires les plus prometteuses. |
|
||||
|
||||
**Statut :** PLANNED — le scheduler supporte le tri FIFO mais le
|
||||
candidate generator n'existe pas encore.
|
||||
|
||||
---
|
||||
|
||||
### F. Matching et vérification géométrique
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Distinction des étapes** | (1) *Feature matching* : appariement brut des descripteurs entre deux images. (2) *Geometric verification* : estimation de la transformation rigide (RANSAC ou équivalent) et validation de la compatibilité épipolaire. |
|
||||
| **Validation ou rejet** | Une paire validée produit une *edge* dans le graphe de visibilité. Une paire rejetée est marquée comme telle pour éviter les retraitements inutiles. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### G. Tracks
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Observation 2D → track → point3D** | Un *track* est une chaîne d'observations 2D cohérentes d'un même point 3D à travers plusieurs images. Chaque observation est un keypoint indexé par image. |
|
||||
| **Lien avec le catalog** | Les tracks référencent les images par leur UUID interne, pas par nom de fichier. |
|
||||
| **Persistance** | Les tracks sont persistés entre les sessions de traitement. Un track ne peut être détruit que par une action explicite de l'utilisateur. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### H. Reconstruction incrémentale
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Indexation** | À chaque vague d'images, la reconstruction existante est indexée (positions approximatives des points 3D, orientations des caméras). |
|
||||
| **Comparaison aux acquisitions précédentes** | Les nouvelles images sont comparées à la reconstruction existante : localisation des caméras, triangulation de nouveaux points, mise à jour des tracks existants. |
|
||||
| **Enrichissement local** | Seules les régions couvertes par les nouvelles images sont recalculées. Le reste de la reconstruction reste inchangé et valide. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### I. Reconstruction Layers
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Conservation de la provenance** | Chaque point 3D, chaque caméra, chaque track conserve la trace de son origine : quel scan set, quelle vague, quelle session. |
|
||||
| **Consolidation distincte** | La fusion de layers (consolidation) est un processus séparé de l'ajout de données. L'utilisateur décide quand consolider. La consolidation ne détruit pas les layers d'origine. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### J. Sources géométriques externes
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **PHOTO** | Images du scan set (source principale). |
|
||||
| **MEASUREMENT** | Mesures directes : distances, orientations, coordonnées GPS, nuages de points LiDAR. Intègrent le graphe de contraintes comme edges géométriques supplémentaires. |
|
||||
| **DOCUMENT** | Plans, relevés, fiches techniques. Métadonnées contextuelles qui enrichissent le projet sans contribuer directement au calcul géométrique. |
|
||||
|
||||
**Statut :** PLANNED — aucune implémentation existante.
|
||||
|
||||
---
|
||||
|
||||
### K. Viewer intégré
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Consommateur passif** | Le viewer ne calcule jamais. Il lit les snapshots validés publiés par le pipeline et les affiche. |
|
||||
| **Isolation fonctionnelle** | Le viewer s'exécute dans un thread dédié ou un processus séparé. Il ne partage aucun buffer mutable avec les workers de calcul. |
|
||||
| **Reactive** | L'utilisateur voit la reconstruction apparaître progressivement pendant les calculs, sans attendre la fin de l'étape courante. |
|
||||
|
||||
**Statut :** PLANNED — le viewer Vulkan séparé n'est pas encore commencé.
|
||||
|
||||
---
|
||||
|
||||
## Invariants
|
||||
|
||||
Ces invariants s'appliquent à toutes les étapes du pipeline :
|
||||
|
||||
1. **Chaque étape est indépendante et reprenable.**
|
||||
L'exécution peut être interrompue à n'importe quelle frontière de lot
|
||||
et reprise sans perte de données.
|
||||
|
||||
2. **Résultats atomiques et validés uniquement.**
|
||||
Un résultat n'est publié (rendu visible aux étapes suivantes et au
|
||||
viewer) que lorsqu'il est entièrement calculé, vérifié et persisté.
|
||||
|
||||
3. **Pas de destruction silencieuse des données sources.**
|
||||
Les images originales, les features extraites, les tracks et les
|
||||
points 3D existants ne jamais supprimés implicitement. Toute
|
||||
suppression est une action explicite et traçable.
|
||||
|
||||
4. **Le scheduler ne décide jamais des ressources.**
|
||||
Seul le Resource Governor arbitre les budgets, les lots et les
|
||||
réservations.
|
||||
|
||||
5. **Les réservations sont obligatoires.**
|
||||
Aucune tâche ne s'exécute sans réservation active préalablement
|
||||
accordée par le governor.
|
||||
|
||||
6. **ncurses appartient exclusivement au thread principal.**
|
||||
Aucun worker ne touche à l'interface TUI.
|
||||
|
||||
---
|
||||
|
||||
## Diagramme conceptuel
|
||||
|
||||
```
|
||||
Scan Sets (A)
|
||||
│
|
||||
▼
|
||||
Image Catalog (B) ──► Feature Store (C)
|
||||
│
|
||||
▼
|
||||
Visual Index (D)
|
||||
│
|
||||
▼
|
||||
Candidate Pair Generator (E)
|
||||
│
|
||||
▼
|
||||
Matching / Geometric Verification (F)
|
||||
│
|
||||
▼
|
||||
Tracks (G)
|
||||
│
|
||||
▼
|
||||
Reconstruction Incrémentale (H)
|
||||
│ │
|
||||
▼ ▼
|
||||
Reconstruction Sources
|
||||
Layers (I) Externes (J)
|
||||
│ │
|
||||
└────┬─────┘
|
||||
▼
|
||||
Viewer Intégré (K)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Statut : PLANNED (vision architecturale)
|
||||
|
||||
Ce document décrit la vision architecturale cible du pipeline de
|
||||
reconstruction. Les modules listés ici ne sont pas tous implémentés.
|
||||
L'implémentation suit la feuille de route définie dans `.opencode/context.md`
|
||||
et progresse par tickets successifs en respectant les invariants
|
||||
d'indépendance et de reprise.
|
||||
|
|
@ -1,223 +1,76 @@
|
|||
# Gouverneur de ressources
|
||||
# Resource Governor Lardon3D
|
||||
|
||||
## Rôle
|
||||
## Responsabilité
|
||||
|
||||
Le gouverneur protège la réactivité de Lardon3D et la stabilité du système. Les
|
||||
étapes de photogrammétrie peuvent durer plusieurs heures et manipuler des jeux
|
||||
de données plus grands que la mémoire disponible. Autoriser chaque tâche à
|
||||
choisir seule ses ressources conduirait à des pointes de RAM, à la saturation de
|
||||
la mémoire GPU partagée et à une concurrence incontrôlée sur le stockage.
|
||||
Le Resource Governor est l'unique propriétaire des budgets (RAM, GPU, CPU, IO). Il arbitre les ressources disponibles et calcule les lots adaptatifs pour chaque tâche.
|
||||
|
||||
Le scheduler et le gouverneur ont donc des responsabilités distinctes. Le
|
||||
gouverneur décide quelles ressources peuvent être promises. Le scheduler décide
|
||||
quand et sur quel worker exécuter le travail autorisé. Le scheduler ne doit pas
|
||||
interpréter lui-même la RAM disponible, la charge CPU ou la pression IO.
|
||||
## API principale
|
||||
|
||||
## Contrat d'exécution
|
||||
### Création et destruction
|
||||
- `lardon3d_resource_governor_create()` - Créer un gouverneur
|
||||
- `lardon3d_resource_governor_destroy()` - Détruire un gouverneur
|
||||
|
||||
Le chemin d'admission est le suivant :
|
||||
### Configuration
|
||||
- `lardon3d_resource_governor_set_policy()` - Définir la politique
|
||||
|
||||
```text
|
||||
Estimate
|
||||
↓
|
||||
Governor
|
||||
↓
|
||||
Reservation
|
||||
↓
|
||||
Scheduler
|
||||
↓
|
||||
Worker
|
||||
```
|
||||
### Décision
|
||||
- `lardon3d_resource_governor_decide()` - Décider de l'admission d'une tâche
|
||||
|
||||
Une décision seule est une observation périssable. Deux threads pourraient
|
||||
observer le même budget et tous deux démarrer, alors que leur consommation
|
||||
cumulée dépasse la capacité. Une réservation résout cette course : le calcul du
|
||||
lot et l'inscription dans les budgets sont effectués atomiquement sous le mutex
|
||||
du gouverneur. Seule une réservation active constitue une autorisation
|
||||
d'exécution.
|
||||
### Réservation
|
||||
- `lardon3d_resource_governor_reserve()` - Réserver des ressources
|
||||
- `lardon3d_resource_governor_reserve_available()` - Réserver les ressources disponibles
|
||||
- `lardon3d_resource_governor_release()` - Libérer une réservation
|
||||
- `lardon3d_resource_governor_reservation_is_valid()` - Vérifier la validité
|
||||
|
||||
`Lardon3DResourceEstimate` décrit la demande sans être modifié par le
|
||||
gouverneur : coûts fixes, coûts par élément, bornes du lot, threads et slots
|
||||
souhaités, et classe de tâche. `Lardon3DResourceReservation` est opaque. Son
|
||||
instantané public décrit exactement le contrat retenu, y compris le lot réduit.
|
||||
### Métriques
|
||||
- `lardon3d_resource_governor_availability()` - Obtenir la disponibilité
|
||||
- `lardon3d_resource_governor_record_batch()` - Enregistrer les métriques d'un lot
|
||||
- `lardon3d_resource_governor_generation()` - Obtenir la génération actuelle
|
||||
- `lardon3d_resource_governor_wait_for_change()` - Attendre un changement
|
||||
|
||||
## Invariants
|
||||
|
||||
1. Le scheduler ne décide jamais des ressources
|
||||
2. Le Resource Governor est l'unique propriétaire des budgets
|
||||
3. Les réservations sont obligatoires avant toute exécution
|
||||
4. Les réservations sont libérées exactement une fois
|
||||
5. Les estimations de ressources sont immuables
|
||||
6. L'historique des métriques est strictement borné (8 entrées par classe)
|
||||
|
||||
## Cycle de vie
|
||||
|
||||
1. Le producteur construit une estimation pour une unité de pipeline.
|
||||
2. Un instantané des ressources dynamiques est capturé.
|
||||
3. Le gouverneur compare la demande aux marges, aux ressources disponibles et
|
||||
aux réservations actives.
|
||||
4. Une demande impossible est refusée. Une pénurie temporaire demande
|
||||
d'attendre. Une demande admissible produit une réservation, éventuellement
|
||||
avec un lot ou des slots réduits.
|
||||
5. Le scheduler vérifie que la réservation est toujours active avant de confier
|
||||
la tâche à un worker.
|
||||
6. Le worker respecte strictement le lot, les threads et les slots réservés.
|
||||
7. À la fin, après annulation ou après échec, la réservation est libérée une
|
||||
seule fois. Les budgets redeviennent immédiatement disponibles.
|
||||
8. Le gouverneur détruit les objets de réservation restants lors de son propre
|
||||
arrêt. Les pointeurs de réservation ne doivent plus être utilisés ensuite.
|
||||
|
||||
Une seconde libération est refusée sans modifier les compteurs. Les
|
||||
réservations libérées sont conservées comme tombstones jusqu'à la destruction
|
||||
du gouverneur afin de détecter cette erreur de cycle de vie sans accès mémoire
|
||||
invalide.
|
||||
|
||||
## Budgets
|
||||
|
||||
### RAM
|
||||
|
||||
Le budget part de la mémoire actuellement disponible, bornée par la mémoire
|
||||
physique détectée, puis retire la marge système et toutes les réservations
|
||||
actives. Les coûts fixes et par élément sont comptabilisés avec contrôle des
|
||||
débordements. Pour un GPU à mémoire partagée, les besoins RAM et GPU sont
|
||||
additionnés dans cette même enveloppe.
|
||||
|
||||
### GPU
|
||||
|
||||
Lorsque la VRAM dédiée est mesurable, sa marge et ses réservations ont un budget
|
||||
distinct. Si sa disponibilité est inconnue, une tâche qui en dépend attend au
|
||||
lieu de supposer une capacité. Les slots GPU limitent aussi le nombre
|
||||
d'opérations concurrentes, indépendamment du nombre d'octets annoncé.
|
||||
|
||||
### CPU
|
||||
|
||||
Une partie des CPU logiques reste réservée au système et à la TUI. Le gouverneur
|
||||
borne les threads souhaités par les threads encore disponibles. La charge
|
||||
moyenne peut différer une nouvelle admission sans interrompre les travaux déjà
|
||||
réservés.
|
||||
|
||||
### IO
|
||||
|
||||
Les slots IO limitent les opérations lourdes concurrentes. La pression PSI
|
||||
Linux peut différer une tâche afin de conserver un terminal réactif et d'éviter
|
||||
une file d'attente disque excessive.
|
||||
|
||||
### Swap et zram
|
||||
|
||||
L'instantané mesure le swap disponible, y compris la zram exposée comme swap
|
||||
par Linux. Ce volume est un signal de sécurité et non une extension normale du
|
||||
budget RAM : le gouverneur ne doit pas dimensionner un lot en comptant sur le
|
||||
swap. Une future politique pourra utiliser sa baisse pour suspendre les
|
||||
admissions ou réduire davantage les lots.
|
||||
|
||||
## Lots adaptatifs
|
||||
|
||||
Le gouverneur calcule le plus grand lot compris entre les bornes de
|
||||
l'estimation et compatible avec tous les budgets restants. Une demande de 128
|
||||
éléments peut ainsi produire un contrat de 37 éléments. Le scheduler répétera
|
||||
le travail sur plusieurs lots, avec écriture des résultats et libération de la
|
||||
mémoire entre chaque lot. Cette règle privilégie une progression régulière à
|
||||
une allocation monolithique.
|
||||
|
||||
Les coûts fixes ne sont payés qu'une fois par lot ; les coûts par élément
|
||||
déterminent sa capacité maximale. Les slots et threads recommandés font partie
|
||||
du même contrat et ne doivent pas être augmentés par le worker.
|
||||
|
||||
### Adaptation par les métriques
|
||||
|
||||
Le gouverneur peut additionally utiliser les métriques de lots déjà exécutés
|
||||
pour réduire conservativement la taille maximale des lots futurs. L'adaptation
|
||||
complète les estimations statiques ; elle ne les remplace pas.
|
||||
|
||||
Le principe est le suivant : si le coût mémoire réel observé dépasse l'estimation
|
||||
déclarée, le gouverneur réduit la taille du lot futur afin que sa consommation
|
||||
reste dans le budget. Le coût par élément le plus défavorable observé est retenu
|
||||
afin de ne jamais sous-estimer la charge.
|
||||
|
||||
Propriétés de l'adaptation :
|
||||
|
||||
- Le calcul du coût par élément utilise une division entière sans overflow :
|
||||
`quotient + (reste != 0)`.
|
||||
- L'adaptation ne peut que réduire la taille maximale du lot ; elle ne
|
||||
l'augmente jamais.
|
||||
- `minimum_batch_size` reste garanti quelle que soit l'adaptation.
|
||||
- Les métriques restent isolées par classe de tâche.
|
||||
- L'historique est strictement borné (voir ci-dessous).
|
||||
|
||||
## Métriques de lots
|
||||
|
||||
Par classe de tâche, le gouverneur conserve un historique circulaire borné à
|
||||
8 entrées. Chaque entrée enregistre :
|
||||
|
||||
- `batch_size` : taille du lot exécuté ;
|
||||
- `duration_ns` : durée d'exécution (collectée pour une adaptation future basée
|
||||
sur le débit, mais n'influence pas encore les décisions) ;
|
||||
- `peak_memory_bytes` : pic de mémoire mesuré pendant l'exécution du lot.
|
||||
|
||||
L'enregistrement est thread-safe : il est protégé par le mutex du gouverneur.
|
||||
La génération est incrémentée et les threads en attente sont réveillés
|
||||
uniquement lorsqu'une métrique est réellement enregistrée. Un `batch_size` égal
|
||||
à 0 est traité comme un no-op réussi : la fonction retourne `true` sans modifier
|
||||
les métriques ni la génération.
|
||||
|
||||
L'historique étant borné, les anciennes entrées sont écrasées par les plus
|
||||
récentes. Cette contrainte garantit un temps et une mémoire d'exécution bornés.
|
||||
|
||||
## API record_batch
|
||||
|
||||
```text
|
||||
bool lardon3d_resource_governor_record_batch(
|
||||
Lardon3DResourceGovernor *governor,
|
||||
Lardon3DResourceTaskClass task_class,
|
||||
size_t batch_size,
|
||||
uint64_t duration_ns,
|
||||
size_t peak_memory_bytes
|
||||
);
|
||||
1. Capture d'un snapshot de ressources
|
||||
2. Décision d'admission
|
||||
3. Réservation opaque
|
||||
4. Exécution de la tâche
|
||||
5. Enregistrement des métriques
|
||||
6. Libération de la réservation
|
||||
```
|
||||
|
||||
Contrat :
|
||||
## Adaptation dynamique
|
||||
|
||||
- **Thread-safe** : protégé par `governor->mutex`.
|
||||
- `governor` NULL → retourne `false`.
|
||||
- `task_class` invalide (supérieur à `LARDON3D_RESOURCE_TASK_MIXED`) → retourne
|
||||
`false`, aucun effet secondaire.
|
||||
- `batch_size` == 0 → retourne `true`, no-op : aucune métrique enregistrée,
|
||||
aucune modification de la génération.
|
||||
- Enregistrement valide → métrique ajoutée à l'historique circulaire de la
|
||||
classe, génération incrémentée et threads en attente réveillés par broadcast.
|
||||
### Calcul de lots adaptatifs
|
||||
- Basé sur la consommation mémoire historique
|
||||
- Mise à jour à chaque exécution
|
||||
- Conservative (sous-estimation plutôt que sur-estimation)
|
||||
|
||||
## Concurrence des métriques
|
||||
### Historique borné
|
||||
- 8 entrées par classe de tâche
|
||||
- Buffer circulaire
|
||||
- Mise à jour FIFO
|
||||
|
||||
Les invariants de concurrence suivants ont été validés par TSan :
|
||||
## Réserves
|
||||
|
||||
- Les métriques sont protégées par `governor->mutex`.
|
||||
- La lecture adaptative (`adaptive_batch_limit`) s'effectue sous ce même verrou.
|
||||
- Aucun mutex supplémentaire n'est introduit.
|
||||
- Aucune allocation dynamique n'est effectuée pour l'historique (tableau statique
|
||||
de taille fixe par classe).
|
||||
- Aucun broadcast n'est émis pour un no-op ou une entrée invalide.
|
||||
- L'historique étant borné (8 entrées par classe), le temps et la mémoire
|
||||
d'exécution restent bornés.
|
||||
- Sous-estimation temporaire possible avec des estimations statiques
|
||||
- Pas d'adaptation basée sur le débit (duration_ns non encore utilisé)
|
||||
- Pas de communication inter-classes de tâches
|
||||
|
||||
## État d'intégration
|
||||
## Limites actuelles
|
||||
|
||||
**Implémenté :**
|
||||
- Worker unique (pas de pools multiples)
|
||||
- Pas de priorités entre tâches
|
||||
- Pas de persistance des métriques
|
||||
- Pas de communication avec d'autres gouverneurs
|
||||
|
||||
- API `record_batch` et son contrat thread-safe.
|
||||
- Stockage des métriques dans un historique circulaire borné.
|
||||
- Adaptation mémoire conservative de `maximum_batch_size`.
|
||||
- Réveil via génération et broadcast.
|
||||
- Tests unitaires et validation TSan.
|
||||
|
||||
**Pas encore câblé :**
|
||||
|
||||
- Appel systématique de `record_batch` depuis les tâches et pipelines réels.
|
||||
- Exploitation de `duration_ns` pour une adaptation basée sur le débit.
|
||||
|
||||
## Utilisation future
|
||||
|
||||
Le même protocole s'applique aux imports, miniatures et extractions EXIF, puis
|
||||
aux features, au matching, au SfM, aux depth maps, au mesh et aux textures. Les
|
||||
estimations pourront différer par classe sans déplacer les décisions dans le
|
||||
scheduler. Le viewer Vulkan utilisera également une réservation GPU afin de ne
|
||||
pas concurrencer silencieusement une reconstruction sur une machine à mémoire
|
||||
partagée.
|
||||
|
||||
L'API `record_batch` sera câblée dans les tâches réelles du pipeline afin
|
||||
d'alimenter les métriques d'adaptation. L'exploitation de `duration_ns` pour
|
||||
une adaptation basée sur le débit est prévue pour une itération ultérieure.
|
||||
|
||||
Cette séparation permettra ultérieurement plusieurs workers : chacun recevra
|
||||
un contrat déjà arbitré, tandis que le gouverneur restera l'unique propriétaire
|
||||
des budgets globaux.
|
||||
## Statut : IMPLEMENTED
|
||||
|
|
|
|||
69
docs/architecture/runtime.md
Normal file
69
docs/architecture/runtime.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Exécution et runtime Lardon3D
|
||||
|
||||
## Modèle d'exécution
|
||||
|
||||
### Threads
|
||||
- Thread principal : TUI ncursesw (exclusif)
|
||||
- Thread worker : exécution des tâches métier
|
||||
|
||||
### Synchronisation
|
||||
- Mutex pour les accès partagés
|
||||
- Variables de condition pour la coordination
|
||||
- Atomicité des opérations critiques
|
||||
|
||||
## Cycle de vie d'une tâche
|
||||
|
||||
```text
|
||||
1. Création (PENDING)
|
||||
2. Soumission à la file
|
||||
3. Sélection par le scheduler
|
||||
4. Réservation obligatoire
|
||||
5. Exécution (RUNNING)
|
||||
- Pause/reprise coopérative
|
||||
- Annulation coopérative
|
||||
- Séquences adaptatives
|
||||
6. Complétion (COMPLETED) ou Échec (FAILED)
|
||||
7. Nettoyage des ressources
|
||||
```
|
||||
|
||||
## Synchronisation
|
||||
|
||||
### Mutex
|
||||
- Protection des données partagées
|
||||
- Accès exclusif aux ressources critiques
|
||||
|
||||
### Variables de condition
|
||||
- Coordination entre threads
|
||||
- Notification de changement d'état
|
||||
- Attente passive (pas de polling)
|
||||
|
||||
### Atomicité
|
||||
- Opérations indivisibles
|
||||
- État cohérent garanti
|
||||
|
||||
## Gestion des erreurs
|
||||
|
||||
### Rollback
|
||||
- Retour à l'état précédent en cas d'échec
|
||||
- Nettoyage complet des ressources
|
||||
- Aucun état partiellement appliqué
|
||||
|
||||
### Récupération
|
||||
- Reprise à la dernière frontière connue
|
||||
- Ignorance des artefacts partiels
|
||||
- Validation avant publication
|
||||
|
||||
## Limites actuelles
|
||||
|
||||
- Worker unique (pas de pools multiples)
|
||||
- Pas de parallélisme inter-tâches
|
||||
- Pas de persistance des états
|
||||
|
||||
## Invariants
|
||||
|
||||
- ncurses appartient exclusivement au thread principal
|
||||
- Aucune tâche ne démarre sans réservation active
|
||||
- Les réservations sont libérées exactement une fois
|
||||
- Les buffers sont strictement bornés
|
||||
|
||||
## Statut : DOCUMENTATION DE L'IMPLÉMENTATION ACTUELLE
|
||||
|
|
@ -1,90 +1,83 @@
|
|||
# Intégration du scheduler et du gouverneur
|
||||
# Intégration Scheduler ↔ Resource Governor
|
||||
|
||||
## Responsabilités
|
||||
## Responsabilité
|
||||
|
||||
Le scheduler conserve l'ordre FIFO et exécute les callbacks. Il ne calcule
|
||||
jamais les budgets : la RAM, le GPU, les CPU, les slots IO et la taille de lot
|
||||
sont exclusivement arbitrés par le Resource Governor.
|
||||
Documenter l'intégration architecturale entre le scheduler de tâches et le Resource Governor, incluant les frontières de responsabilités, le cycle de vie des réservations et le comportement en cas de pause.
|
||||
|
||||
Le cycle d'exécution est strict :
|
||||
## Frontières de responsabilités
|
||||
|
||||
### Scheduler
|
||||
- Ordonnancement FIFO
|
||||
- Exécution des callbacks
|
||||
- Gestion des états de tâche
|
||||
- Sélection de la première tâche admissible
|
||||
|
||||
### Resource Governor
|
||||
- Arbitrage des budgets (RAM, GPU, CPU, IO)
|
||||
- Calcul des lots adaptatifs
|
||||
- Réservations opaques
|
||||
- Historique de métriques
|
||||
|
||||
## Cycle d'exécution
|
||||
|
||||
```text
|
||||
Task
|
||||
→ Resource Estimate
|
||||
→ Governor
|
||||
→ Reservation
|
||||
→ Task Queue
|
||||
→ Worker
|
||||
→ Release Reservation
|
||||
1. Task → Estimate (estimation des ressources)
|
||||
2. Scheduler → Governor → decide() (décision d'admission)
|
||||
3. Governor → Reservation (réservation opaque)
|
||||
4. Scheduler → Worker (exécution)
|
||||
5. Worker → Governor → record_batch() (métriques)
|
||||
6. Governor → release() (libération)
|
||||
```
|
||||
|
||||
Chaque tâche reçoit une estimation immuable à sa création. Son passage de
|
||||
`PENDING` à `RUNNING` est interdit tant que le gouverneur n'a pas créé une
|
||||
réservation active. Le callback ne reçoit pas l'objet opaque : il consulte une
|
||||
copie du contrat contenant le lot, la RAM, la mémoire GPU, les CPU et les slots
|
||||
accordés.
|
||||
|
||||
## Admission
|
||||
|
||||
Le worker examine la première tâche FIFO. `WAIT` la laisse en attente et le
|
||||
worker dort sur la condition de la file. Une libération de ressources suivie de
|
||||
`lardon3d_task_queue_resources_changed()` le réveille sans polling.
|
||||
`REDUCE_BATCH` crée un contrat avec le lot réduit, qui est transmis à la tâche.
|
||||
`REJECT` place la tâche en échec sans appeler son callback et conserve la raison
|
||||
explicite du gouverneur.
|
||||
### Réponses du gouverneur
|
||||
- `ADMIT` : la tâche peut démarrer
|
||||
- `WAIT` : la tâche doit attendre (pas de ressources)
|
||||
- `REDUCE_BATCH` : réduire la taille du lot
|
||||
- `REJECT` : rejeter la tâche
|
||||
|
||||
Après succès, échec ou annulation, le worker libère exactement une fois la
|
||||
réservation puis réveille la file. La destruction annule les tâches, rejoint le
|
||||
worker et libère toute réservation détenue avant de détruire les tâches.
|
||||
### Comportement en cas de WAIT
|
||||
- Le scheduler saute la tâche en tête de file
|
||||
- Il évalue la tâche suivante
|
||||
- Pas de blocage de la file
|
||||
|
||||
## Pause
|
||||
## Gestion des pauses
|
||||
|
||||
Dans cette première version, une tâche déjà démarrée conserve sa réservation
|
||||
pendant `PAUSED`. Ses ressources restent donc indisponibles pour les autres
|
||||
tâches. Ce choix évite de reprendre un callback avec un contrat qui aurait été
|
||||
attribué entre-temps à un autre travail.
|
||||
### Comportement actuel
|
||||
- Une tâche en pause conserve sa réservation
|
||||
- Évite de perdre son contrat au profit d'un autre travail
|
||||
- Permet la reprise avec le même lot
|
||||
|
||||
## Exécution séquencée adaptative
|
||||
### Règle
|
||||
- La réservation est conservée pendant la pause
|
||||
- La libération n'a lieu qu'à la fin de l'exécution
|
||||
|
||||
Une tâche peut s'exécuter en plusieurs séquences (lots) successives. Le
|
||||
callback appelle `lardon3d_task_sequence_break()` pour libérer sa réservation
|
||||
courante, capturer un nouvel instantané système, obtenir une nouvelle
|
||||
réservation auprès du gouverneur et reprendre avec un contrat actualisé.
|
||||
## Séquences adaptatives
|
||||
|
||||
Le cycle d'une séquence est strict :
|
||||
### Mécanisme
|
||||
- `lardon3d_task_sequence_break()` permet de libérer la réservation courante
|
||||
- Capturer un nouvel instantané de ressources
|
||||
- Obtenir un contrat actualisé
|
||||
- Reprendre le callback en conservant la progression
|
||||
|
||||
```text
|
||||
Callback
|
||||
→ sequence_break
|
||||
→ Release Reservation courante
|
||||
→ Snapshot système
|
||||
→ Governor → Reservation
|
||||
→ Contrat actualisé
|
||||
→ Reprise du callback
|
||||
```
|
||||
### Avantages
|
||||
- Adaptation dynamique des lots en cours d'exécution
|
||||
- Réponse aux changements de ressources
|
||||
- Optimisation de l'utilisation mémoire
|
||||
|
||||
Le task conserve une référence au gouverneur et à sa réservation courante.
|
||||
`lardon3d_task_start` stocke la réservation initiale ; à la fin de l'exécution,
|
||||
il libère la réservation courante si elle est encore détenue. Le worker de la
|
||||
file libère ensuite la réservation d'origine, qui est déjà libérée si une
|
||||
séquence a eu lieu : cet appel est alors sans effet.
|
||||
## Invariants
|
||||
|
||||
Invariants préservés :
|
||||
1. Aucune tâche ne passe de PENDING à RUNNING sans réservation active
|
||||
2. Le scheduler ne prend jamais de décision sur les ressources
|
||||
3. La libération des réservations s'effectue exactement une fois par cycle/séquence
|
||||
4. Les atomicités sont garanties sous mutex
|
||||
|
||||
- Aucun callback ne démarre sans réservation active.
|
||||
- Une seule réservation active par tâche à tout instant.
|
||||
- La réservation est toujours valide avant et après un `sequence_break`.
|
||||
- Le contrat est mis à jour atomiquement sous le mutex de la tâche.
|
||||
- Si pause ou annulation est demandée pendant le `sequence_break`, la fonction
|
||||
retourne `false` et la tâche est annulée.
|
||||
- Si le gouverneur répond `WAIT` ou `REJECT`, la fonction retourne `false` et
|
||||
la tâche passe en échec sans bloquer le callback.
|
||||
- La progression est conservée entre les séquences.
|
||||
## Limites actuelles
|
||||
|
||||
## Limites et extensions
|
||||
- Worker unique (pas de pools multiples)
|
||||
- Pas de DAG de dépendances
|
||||
- Pas de priorités
|
||||
- Pas de notification automatique de libération externe
|
||||
|
||||
La file possède un seul worker, reste strictement FIFO et ne gère ni priorité
|
||||
ni dépendance. Une notification explicite est nécessaire lorsqu'un composant
|
||||
extérieur libère une réservation. Les prochaines étapes pourront ajouter un
|
||||
DAG, des priorités, des pools distincts CPU, IO et GPU sans déplacer les
|
||||
décisions de ressources hors du gouverneur.
|
||||
## Statut : DOCUMENTATION DE L'IMPLÉMENTATION ACTUELLE
|
||||
|
|
|
|||
95
docs/architecture/task_queue.md
Normal file
95
docs/architecture/task_queue.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# File de tâches (Task Queue)
|
||||
|
||||
## Objectif et responsabilités
|
||||
|
||||
Le module `task_queue` implémente la file d'attente FIFO des tâches de
|
||||
traitement. Il orchestre l'exécution séquentielle des tâches via un worker
|
||||
unique, gère la sélection de la prochaine tâche admissible et transmet les
|
||||
callbacks de résultat.
|
||||
|
||||
La file est le point central entre le scheduler (soumission) et les workers
|
||||
(exécution). Elle ne décide jamais des ressources — elle applique uniquement
|
||||
l'ordre FIFO et consulte le gouverneur via le scheduler.
|
||||
|
||||
## Fichiers
|
||||
|
||||
- `include/lardon3d/task_queue.h` — types publics et API
|
||||
- `src/task_queue.c` — implémentation
|
||||
- `tests/test_task_queue.c` — tests unitaires
|
||||
|
||||
## Types principaux
|
||||
|
||||
```c
|
||||
typedef struct task_queue task_queue_t;
|
||||
|
||||
typedef void (*task_callback_fn)(task_t *task, task_result_t *result, void *userdata);
|
||||
```
|
||||
|
||||
## API publique
|
||||
|
||||
| Fonction | Description |
|
||||
|---|---|
|
||||
| `task_queue_create()` | Alloue et initialise une file vide |
|
||||
| `task_queue_destroy()` | Libère la file et toutes les tâches restantes |
|
||||
| `task_queue_submit()` | Soumet une tâche à la file (FIFO) |
|
||||
| `task_queue_next()` | Sélectionne la prochaine tâche admissible |
|
||||
| `task_queue_pop()` | Retire et retourne la tâche sélectionnée |
|
||||
| `task_queue_cancel()` | Annule une tâche spécifique dans la file |
|
||||
| `task_queue_cancel_all()` | Annule toutes les tâches en attente |
|
||||
| `task_queue_size()` | Retourne le nombre de tâches en attente |
|
||||
| `task_queue_is_empty()` | Vérifie si la file est vide |
|
||||
| `task_queue_set_callback()` | Définit le callback pour les résultats |
|
||||
|
||||
## Comportement FIFO
|
||||
|
||||
1. `task_queue_submit()` ajoute la tâche en fin de file.
|
||||
2. `task_queue_next()` parcourt la file du début vers la fin.
|
||||
3. La première tâche en état `QUEUED` (non en pause, non annulée) est
|
||||
retournée.
|
||||
4. Si aucune tâche n'est admissible, `task_queue_next()` retourne `NULL`.
|
||||
5. L'ordre de soumission est toujours respecté entre tâches de même priorité.
|
||||
|
||||
## Sélection adaptative
|
||||
|
||||
`task_queue_next()` saute les tâches en état `WAIT` (en attente de
|
||||
ressources) et retourne la première tâche réellement admissible. Cela évite
|
||||
le blocage par la tête de file lorsqu'une tâche ne peut pas démarrer.
|
||||
|
||||
## Invariants
|
||||
|
||||
1. **Worker unique** : une seule tâche s'exécute à la fois. Pas de parallélisme
|
||||
interne à la file.
|
||||
2. **FIFO strict** : l'ordre de soumission détermine l'ordre d'exécution.
|
||||
3. **Réservation obligatoire** : aucune tâche n'est exécutée sans réservation
|
||||
validée par le gouverneur.
|
||||
4. **Callback unique** : chaque tâche reçoit exactement un callback (succès,
|
||||
échec ou annulation).
|
||||
5. **Annulation sûre** : annuler une tâche en cours la met en état
|
||||
`CANCELLED` sans interrompre brutalement le worker.
|
||||
6. **Nettoyage complet** : `task_queue_destroy()` libère toutes les tâches
|
||||
restantes, y compris celles en cours d'exécution.
|
||||
|
||||
## Interactions
|
||||
|
||||
- **task** : chaque entrée de la file est un `task_t` avec son état et sa
|
||||
progression.
|
||||
- **scheduler** : le scheduler appelle `task_queue_submit()` et orchestre
|
||||
l'exécution via le worker.
|
||||
- **resource_governor** : la file consulte le gouverneur (via le scheduler)
|
||||
avant d'exécuter chaque tâche.
|
||||
- **hardware_profile / resource_snapshot** : informations matériel utilisées
|
||||
par le gouverneur pour les réservations.
|
||||
|
||||
## Statut
|
||||
|
||||
**IMPLÉMENTÉ** — file FIFO avec worker unique, sélection adaptative, pause et
|
||||
annulation coopératives.
|
||||
|
||||
## Limites
|
||||
|
||||
- Worker unique : pas de parallélisme interne.
|
||||
- Pas de DAG ni de dépendances inter-tâches.
|
||||
- Pas de priorités (FIFO strict).
|
||||
- Pas de persistance des tâches après arrêt.
|
||||
- Pas de pool de workers CPU/IO/GPU.
|
||||
- Pas de contre-pression (backpressure) entre étapes.
|
||||
85
docs/architecture/task_system.md
Normal file
85
docs/architecture/task_system.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# Système de tâches (Task System)
|
||||
|
||||
## Objectif et responsabilités
|
||||
|
||||
Le module `task` gère le cycle de vie complet des tâches de traitement dans
|
||||
Lardon3D. Il définit les états, la progression, la pause coopérative,
|
||||
l'annulation et les callbacks associés à chaque tâche.
|
||||
|
||||
Chaque tâche représente une unité de travail atomique : estimation des
|
||||
coûts, exécution sous réservation et publication d'un résultat validé.
|
||||
|
||||
## Fichiers
|
||||
|
||||
- `include/lardon3d/task.h` — types publics et API
|
||||
- `src/task.c` — implémentation
|
||||
|
||||
## Types principaux
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
TASK_STATE_IDLE,
|
||||
TASK_STATE_QUEUED,
|
||||
TASK_STATE_RUNNING,
|
||||
TASK_STATE_PAUSED,
|
||||
TASK_STATE_CANCELLED,
|
||||
TASK_STATE_DONE,
|
||||
TASK_STATE_FAILED
|
||||
} task_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t ram_bytes;
|
||||
uint64_t gpu_bytes;
|
||||
uint32_t cpu_weight;
|
||||
uint32_t io_weight;
|
||||
uint32_t batch_size;
|
||||
uint32_t batch_max;
|
||||
} task_estimate_t;
|
||||
```
|
||||
|
||||
## API publique
|
||||
|
||||
| Fonction | Description |
|
||||
|---|---|
|
||||
| `task_create()` | Alloue et initialise une tâche avec son estimate |
|
||||
| `task_destroy()` | Libère toutes les ressources de la tâche |
|
||||
| `task_get_state()` | Retourne l'état courant (thread-safe en lecture) |
|
||||
| `task_set_state()` | Met à jour l'état avec transitions validées |
|
||||
| `task_get_estimate()` | Retourne l'estimation immuable des coûts |
|
||||
| `task_advance_progress()` | Avance la progression d'un pas validé |
|
||||
| `task_request_pause()` | Demande une pause coopérative |
|
||||
| `task_request_cancel()` | Demande une annulation coopérative |
|
||||
| `task_should_pause()` | Vérifie si la tâche doit se mettre en pause |
|
||||
| `task_should_cancel()` | Vérifie si la tâche doit s'annuler |
|
||||
|
||||
## Invariants
|
||||
|
||||
1. **Estimation immuable** : une fois créée, l'estimation d'une tâche ne change
|
||||
jamais. Elle est copiée en lecture seule lors de la réservation.
|
||||
2. **Transitions d'état validées** : seules certaines transitions sont
|
||||
autorisées (IDLE → QUEUED → RUNNING → DONE/FAILED).
|
||||
3. **Pause et annulation coopératives** : le worker vérifie périodiquement
|
||||
`task_should_pause()` et `task_should_cancel()`. Le callback ne force jamais
|
||||
l'arrêt.
|
||||
4. **Progression bornée** : la progression ne peut jamais dépasser la valeur
|
||||
maximale définie par l'estimation.
|
||||
5. **Callback unique** : chaque tâche possède un seul callback invoqué une
|
||||
seule fois, quelle que soit l'issue.
|
||||
|
||||
## Interactions
|
||||
|
||||
- **task_queue** : la file gère l'ordre d'exécution et invoque les callbacks.
|
||||
- **resource_governor** : l'estimation est utilisée pour la réservation avant
|
||||
exécution.
|
||||
- **scheduler** : le scheduler transmet l'estimation lors de la soumission.
|
||||
|
||||
## Statut
|
||||
|
||||
**IMPLÉMENTÉ** — cycle de vie complet, pause et annulation coopératives.
|
||||
|
||||
## Limites
|
||||
|
||||
- Aucune priorité interne : l'ordre est uniquement FIFO.
|
||||
- Aucune persistance : les tâches disparaissent à l'arrêt du programme.
|
||||
- Aucune dépendance inter-tâches (pas de DAG).
|
||||
- La progression est linéaire : pas de séquençage adaptatif interne.
|
||||
59
docs/architecture/viewer.md
Normal file
59
docs/architecture/viewer.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Viewer Lardon3D
|
||||
|
||||
## Vision
|
||||
|
||||
Le viewer est un composant graphique qui affiche les résultats de la reconstruction de manière interactive. Il est intégré à l'interface pour un usage confortable sur un seul écran, mais reste fonctionnellement séparé du moteur.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Isolation fonctionnelle
|
||||
|
||||
Le viewer est un consommateur passif de snapshots validés. Il ne lit jamais les structures internes mutables du moteur.
|
||||
|
||||
```text
|
||||
Moteur de reconstruction
|
||||
↓
|
||||
Snapshots atomiques et validés
|
||||
↓
|
||||
Viewer (consommation passive)
|
||||
```
|
||||
|
||||
### Invariants
|
||||
|
||||
- Le viewer est un consommateur passif
|
||||
- Aucune lecture directe de structures internes mutables
|
||||
- Snapshots cohérents et validés uniquement
|
||||
- Buffers visuels strictement bornés
|
||||
- Si plusieurs snapshots deviennent obsolètes, privilégier le plus récent plutôt que créer un backlog
|
||||
- Le calcul reste prioritaire
|
||||
- Le viewer peut être désactivé ou ralentir sans bloquer le moteur
|
||||
- Aucun thread graphique ne doit devenir une dépendance vitale du scheduler ou du gouverneur
|
||||
|
||||
### Frontière obligatoire
|
||||
|
||||
La frontière obligatoire est l'isolation fonctionnelle, pas nécessairement le processus Unix.
|
||||
|
||||
## Fonctionnalités
|
||||
|
||||
### Affichage
|
||||
- Visualisation 3D des points, lignes et surfaces
|
||||
- Navigation interactive (rotation, translation, zoom)
|
||||
- Affichage des nuages de points, maillages et textures
|
||||
|
||||
### Interaction
|
||||
- Sélection d'éléments
|
||||
- Affichage d'informations détaillées
|
||||
- Mesures et annotations
|
||||
|
||||
### Intégration
|
||||
- Connexion au pipeline de reconstruction
|
||||
- Affichage en temps réel de la progression
|
||||
- Navigation dans l'historique des snapshots
|
||||
|
||||
## Limites actuelles
|
||||
|
||||
- Non implémenté
|
||||
- Pas de dépendance vitale avec le moteur
|
||||
- Peut être désactivé sans impact
|
||||
|
||||
## Statut : PLANNED (vision architecturale)
|
||||
172
docs/concepts/geometric_constraints.md
Normal file
172
docs/concepts/geometric_constraints.md
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
# Geometric Constraints
|
||||
|
||||
## Définition
|
||||
|
||||
Les **geometric constraints** (contraintes géométriques) sont des règles mathématiques qui encadrent la relation entre les images 2D et la scène 3D. Elles servent à valider, filtrer et optimiser les correspondances et la reconstruction en éliminant les solutions physiquement impossibles ou improbables.
|
||||
|
||||
Ces contraintes exploitent la géométrie projective des caméras, la structure de la scène et les propriétés des capteurs pour garantir la cohérence géométrique du pipeline.
|
||||
|
||||
## Statut
|
||||
|
||||
**PLANNED** — Concepts mathématiques fondamentaux, pas encore implémentés comme module distinct. Utilisés implicitement dans les futurs algorithmes de matching et reconstruction.
|
||||
|
||||
## Place dans le pipeline
|
||||
|
||||
```
|
||||
Matching & Tracks
|
||||
↓
|
||||
Geometric Constraints (filtrage)
|
||||
├── Fundamental Matrix Filter
|
||||
├── Essential Matrix Filter
|
||||
├── Homography Filter
|
||||
├── Parallax Filter
|
||||
└── Visibility Constraints
|
||||
↓
|
||||
Reconstruction Layers (entrée validée)
|
||||
```
|
||||
|
||||
Les contraintes géométriques agissent comme des filtres entre le matching brut et la reconstruction.
|
||||
|
||||
## Concepts clés
|
||||
|
||||
### 1. Fundamental Matrix (Matrice fondamentale)
|
||||
|
||||
La **matrice fondamentale** F encode la relation projective entre deux images pour une scène statique :
|
||||
|
||||
```
|
||||
x'ᵀ F x = 0
|
||||
```
|
||||
|
||||
où `x` et `x'` sont les coordonnées homogènes d'un point dans les deux images.
|
||||
|
||||
| Propriété | Valeur |
|
||||
|-----------|--------|
|
||||
| Dimensions | 3×3 |
|
||||
| Rang | 2 |
|
||||
| Degrés de liberté | 7 |
|
||||
| Nombre minimum de points | 8 (ou 7 avec DLT) |
|
||||
|
||||
Usage :
|
||||
- Vérification géométrique après matching brut
|
||||
- Filtrage des outliers (points ne satisfaisant pas l'équation)
|
||||
- Estimation de la configuration relative des caméras
|
||||
|
||||
### 2. Essential Matrix (Matrice essentielle)
|
||||
|
||||
La **matrice essentielle** E est la version calibrée de F, exprimée dans le repère caméra :
|
||||
|
||||
```
|
||||
E = K'ᵀ F K
|
||||
```
|
||||
|
||||
où `K` est la matrice intrinsèque de calibration.
|
||||
|
||||
| Propriété | Valeur |
|
||||
|-----------|--------|
|
||||
| Dimensions | 3×3 |
|
||||
| Rang | 2 |
|
||||
| Degrés de liberté | 5 (3 rotation + 2 translation) |
|
||||
| Décomposition | E = t̂ R (rotation + translation) |
|
||||
|
||||
Usage :
|
||||
- Extraction de la pose relative (R, t) entre deux caméras
|
||||
- Triangulation des points 3D
|
||||
- Estimation du baseline
|
||||
|
||||
### 3. Homography
|
||||
|
||||
L'**homographie** H encode la relation projective entre deux images d'un plan :
|
||||
|
||||
```
|
||||
x' = H x
|
||||
```
|
||||
|
||||
| Propriété | Valeur |
|
||||
|-----------|--------|
|
||||
| Dimensions | 3×3 |
|
||||
| Degrés de liberté | 8 |
|
||||
| Cas particulier | Scène plane ou rotation pure |
|
||||
|
||||
Usage :
|
||||
- Détection de scènes planes (sols, murs, tableaux)
|
||||
- Filtrage des matches sur plans dominants
|
||||
- Warping et stitching d'images
|
||||
|
||||
### 4. Parallax Constraints (Contraintes de parallaxe)
|
||||
|
||||
La **parallaxe** est le décalage apparent d'un point entre deux images. Elle est liée à la distance focale, à la baseline et à la profondeur du point :
|
||||
|
||||
```
|
||||
parallaxe = (f × baseline) / depth
|
||||
```
|
||||
|
||||
| Type | Condition | Usage |
|
||||
|------|-----------|-------|
|
||||
| **Parallaxe minimale** | > seuil (ex: 0.5 pixel) | Éviter les dégénérescences (points à l'infini) |
|
||||
| **Parallaxe maximale** | < seuil (ex: 100 pixels) | Éviter les erreurs de matching (trop de distortion) |
|
||||
| **Parallaxe relative** | > baseline × sin(angle) | Garantir la qualité de triangulation |
|
||||
|
||||
### 5. Visibility Constraints (Contraintes de visibilité)
|
||||
|
||||
La **visibilité** encode quels points sont visibles depuis quelles caméras :
|
||||
|
||||
- **Culling** : un point derrière une caméra n'est pas visible
|
||||
- **Occlusion** : un point peut être caché par un obstacle
|
||||
- **Frustum** : un point hors du champ de vision n'est pas observable
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
Vec3d point_3d;
|
||||
Vec3d camera_center;
|
||||
Vec3d camera_direction;
|
||||
float fov_horizontal;
|
||||
float fov_vertical;
|
||||
float near_plane;
|
||||
float far_plane;
|
||||
} VisibilityConstraint;
|
||||
```
|
||||
|
||||
### 6. Triangle Quality Constraints
|
||||
|
||||
La qualité des triangles de triangulation影响 la précision de la reconstruction :
|
||||
|
||||
| Métrique | Seuil recommandé | Description |
|
||||
|----------|------------------|-------------|
|
||||
| **Baseline angulaire** | > 5° | Angle entre les directions de vues |
|
||||
| **Aspect ratio** | < 3.0 | Rapport longueur/largeur du triangle |
|
||||
| **Epipolar distance** | < seuil pixel | Distance du point à la ligne épipolaire |
|
||||
| **Reprojection error** | < 1-2 pixels | Erreur de reprojection après triangulation |
|
||||
|
||||
## Relations avec les autres modules
|
||||
|
||||
| Module | Relation |
|
||||
|--------|----------|
|
||||
| **Matching & Tracks** | Les contraintes filtrent les matches bruts pour ne garder que les géométries cohérentes. |
|
||||
| **Visual Index** | Les candidats du Visual Index sont les entrées des contraintes géométriques. |
|
||||
| **Reconstruction Layers** | Chaque couche applique les contraintes appropriées pour valider ses résultats. |
|
||||
| **Resource Governor** | Le gouverneur peut ajuster les seuils de contrainte en fonction des ressources disponibles. |
|
||||
| **Hardware Profile** | Le calcul des matrices fondamentales/essentielles est CPU-bound. |
|
||||
|
||||
## Contraintes de conception
|
||||
|
||||
- Les seuils géométriques (parallaxe minimale, erreur de reprojection) sont calibrables mais immuables pendant un traitement.
|
||||
- L'estimation de F ou E utilise RANSAC avec un nombre d'itérations borné.
|
||||
- Les homographies sont détectées automatiquement mais ne remplacent pas E pour les scènes non planes.
|
||||
- Les contraintes de visibilité sont recalculées à chaque ajout de caméra.
|
||||
- Les résultats de filtrage géométrique sont auditables (log des rejets avec raison).
|
||||
- En cas d'incertitude, les contraintes sont conservatistes (rejeter plutôt qu'accepter).
|
||||
|
||||
## Terminologie
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Fundamental Matrix** | Matrice 3×3 encodant la relation projective entre deux images |
|
||||
| **Essential Matrix** | Version calibrée de F, dans le repère caméra |
|
||||
| **Homographie** | Transformation projective entre deux vues d'un plan |
|
||||
| **Epipolar geometry** | Géométrie des lignes épipolaires reliant deux vues |
|
||||
| **Parallaxe** | Décalage apparent d'un point entre deux images |
|
||||
| **RANSAC** | Random Sample Consensus, algorithme robuste d'estimation de modèles |
|
||||
| **Inlier** | Point satisfaisant la contrainte géométrique |
|
||||
| **Outlier** | Point ne satisfaisant pas la contrainte, rejeté |
|
||||
| **DLT** | Direct Linear Transform, méthode d'estimation linéaire |
|
||||
| **Bundle adjustment** | Optimisation globale minimisant l'erreur de reprojection |
|
||||
136
docs/concepts/matching_and_tracks.md
Normal file
136
docs/concepts/matching_and_tracks.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Matching & Tracks
|
||||
|
||||
## Définition
|
||||
|
||||
Le **matching** est le processus d'appariement de descripteurs visuels entre paires d'images pour identifier les correspondances géométriques. Un **track** (ou piste) est la séquence de correspondances cohérentes d'un même point 3D à travers plusieurs images.
|
||||
|
||||
Le matching transforme les features individuelles en relations inter-images. Les tracks connectent ces relations en structures cohérentes qui traversent le scan set, formant le squelette de la reconstruction 3D.
|
||||
|
||||
## Statut
|
||||
|
||||
**PLANNED** — Étape critique du pipeline, pas encore implémentée. Nécessite le Visual Index comme prérequis.
|
||||
|
||||
## Place dans le pipeline
|
||||
|
||||
```
|
||||
Visual Index (candidats)
|
||||
↓
|
||||
Feature Matching (appariement brut)
|
||||
↓
|
||||
Geometric Verification (filtrage par géométrie)
|
||||
↓
|
||||
Track Construction (assemblage en pistes)
|
||||
↓
|
||||
Track Optimization (raffinement)
|
||||
↓
|
||||
Reconstruction Layers (triangulation)
|
||||
```
|
||||
|
||||
Le matching est le pont entre les caractéristiques 2D des images et la structure 3D de la scène.
|
||||
|
||||
## Concepts clés
|
||||
|
||||
### Étapes du matching
|
||||
|
||||
#### 1. Feature Matching (appariement brut)
|
||||
|
||||
Pour chaque paire d'images candidates :
|
||||
- Recherche des descripteurs les plus proches (ratio test de Lowe)
|
||||
- Filtrage par distance seuil
|
||||
- Résultat : liste de correspondances brutes
|
||||
|
||||
```c
|
||||
// Ratio test de Lowe
|
||||
if (dist_best / dist_second_best < RATIO_THRESHOLD) {
|
||||
// Correspondance acceptée
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Geometric Verification (filtrage géométrique)
|
||||
|
||||
- Estimation de la **matrice fondamentale** F (cas général) ou **matrice essentielle** E (caméra calibrée)
|
||||
- Filtrage par **RANSAC** : rejet des outliers
|
||||
- Validation de la **parallaxe minimale** pour éviter les dégénérescences
|
||||
|
||||
#### 3. Track Construction (assemblage)
|
||||
|
||||
- Union-find sur les correspondances cohérentes
|
||||
- Chaînage transitoire : si A↔B et B↔C, alors A↔C potentiellement
|
||||
- Filtration des tracks trop courts (< 3 images) et trop longs (erreurs de chaînage)
|
||||
|
||||
### Structures de données
|
||||
|
||||
#### Correspondance (Match)
|
||||
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `image_a` | `uint64_t` | Identifiant de la première image |
|
||||
| `image_b` | `uint64_t` | Identifiant de la seconde image |
|
||||
| `keypoint_a` | `Keypoint` | Position (x,y) dans l'image A |
|
||||
| `keypoint_b` | `Keypoint` | Position (x,y) dans l'image B |
|
||||
| `descriptor_a` | `Descriptor` | Descripteur dans l'image A |
|
||||
| `descriptor_b` | `Descriptor` | Descripteur dans l'image B |
|
||||
| `confidence` | `float` | Score de confiance de l'appariement |
|
||||
|
||||
#### Track (Piste)
|
||||
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `id` | `uint64_t` | Identifiant unique du track |
|
||||
| `observations` | `Observation[]` | Liste des observations (image, keypoint) |
|
||||
| `point_3d` | `Vec3d` | Position 3D estimée (après triangulation) |
|
||||
| `status` | `enum` | ACTIVE, OPTIMIZED, REJECTED |
|
||||
|
||||
#### Observation
|
||||
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `image_id` | `uint64_t` | Image où le point est observé |
|
||||
| `keypoint` | `Keypoint` | Position (x,y) dans l'image |
|
||||
| `track_id` | `uint64_t` | Track auquel appartient l'observation |
|
||||
|
||||
### Matrice de co-visibilité
|
||||
|
||||
La **co-visibilité** mesure le nombre de tracks partagés entre deux images. Elle forme une matrice symétrique qui influence :
|
||||
|
||||
- Le choix des paires à traiter en priorité
|
||||
- La robustesse de la reconstruction (images bien connectées = meilleur ancrage)
|
||||
- La détection des clusters disconnected
|
||||
|
||||
```
|
||||
CoVis(A,B) = |Tracks(A) ∩ Tracks(B)|
|
||||
```
|
||||
|
||||
## Relations avec les autres modules
|
||||
|
||||
| Module | Relation |
|
||||
|--------|----------|
|
||||
| **Visual Index** | Fournit les candidats initiaux pour le matching. |
|
||||
| **Scan Sets** | Le matching s'effectue au sein d'un scan set ou entre scan sets connectés. |
|
||||
| **Geometric Constraints** | Les essentiels, fondamentales et homographies sont appliqués pendant la vérification géométrique. |
|
||||
| **Reconstruction Layers** | Les tracks sont l'entrée du processus de triangulation. |
|
||||
| **Resource Governor** | Le matching est mémoire-intensive : le gouverneur contrôle la taille des lots de paires traitées. |
|
||||
| **Task** | Le matching est décomposé en tâches par paire d'images, parallélisables. |
|
||||
| **Hardware Profile** | Le matching peut être accéléré par GPU pour les calculs de distance entre descripteurs. |
|
||||
|
||||
## Contraintes de conception
|
||||
|
||||
- Le matching ne doit jamais produire de tracks incohérents (un track = un point 3D unique).
|
||||
- Les tracks de moins de 3 observations sont rejetés comme non reconstructibles.
|
||||
- Le filtre de ratio de Lowe (typiquement 0.7-0.8) est immuable après calibration.
|
||||
- Le RANSAC utilise un nombre d'itérations borné et un seuil de consensus configurable.
|
||||
- Les tracks rejetés sont conservés pour audit mais exclus de la reconstruction.
|
||||
- La matrice de co-visibilité ne doit pas dépasser N×N pour N images (bornée par la RAM).
|
||||
|
||||
## Terminologie
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Match** | Correspondance entre deux keypoints de deux images différentes |
|
||||
| **Track** | Série de matches cohérents d'un même point 3D à travers N images |
|
||||
| **Observation** | Apparition d'un track dans une image spécifique |
|
||||
| **Outlier** | Match incorrect rejeté par vérification géométrique |
|
||||
| **Inlier** | Match correct accepté après vérification |
|
||||
| **Co-visibilité** | Nombre de tracks partagés entre deux images |
|
||||
| **Baseline angulaire** | Angle entre les directions de vues de deux images pour un point donné |
|
||||
| **Parallaxe** | Décalage apparent d'un point entre deux images |
|
||||
152
docs/concepts/reconstruction_layers.md
Normal file
152
docs/concepts/reconstruction_layers.md
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
# Reconstruction Layers
|
||||
|
||||
## Définition
|
||||
|
||||
Les **reconstruction layers** (couches de reconstruction) organisent le processus de reconstruction 3D en étapes séquentielles et indépendantes. Chaque couche traite un sous-ensemble du problème, produit un résultat validé, et passe le relais à la couche suivante. Cette approche séquentielle garantit la stabilité, l'observabilité et la reprise après interruption.
|
||||
|
||||
L'idée centrale est de décomposer la reconstruction en couches de complexité croissante, chaque couche étant atomique : elle lit un état d'entrée validé, calcule, et écrit un nouvel état validé.
|
||||
|
||||
## Statut
|
||||
|
||||
**PLANNED** — Concept architectural pour la décomposition du pipeline de reconstruction. Pas encore implémenté.
|
||||
|
||||
## Place dans le pipeline
|
||||
|
||||
```
|
||||
Tracks ( entrée )
|
||||
↓
|
||||
Layer 0: Initial Reconstruction (triangulation basique)
|
||||
↓
|
||||
Layer 1: Bundle Adjustment (optimisation locale)
|
||||
↓
|
||||
Layer 2: Dense Reconstruction (dense matching)
|
||||
↓
|
||||
Layer 3: Mesh Generation (mailllage)
|
||||
↓
|
||||
Layer 4: Texturing (texture mapping)
|
||||
↓
|
||||
Résultat final validé
|
||||
```
|
||||
|
||||
Chaque couche constitue une **frontière de séquence** : en cas d'interruption, la reprise se fait à la dernière frontière validée.
|
||||
|
||||
## Concepts clés
|
||||
|
||||
### Principes fondamentaux
|
||||
|
||||
1. **Atomicité** : chaque couche produit un résultat entièrement validé ou entièrement rejeté.
|
||||
2. **Immutabilité** : une couche ne modifie jamais les résultats des couches précédentes.
|
||||
3. **Idempotence** : relancer une couche avec les mêmes entrées produit le même résultat.
|
||||
4. **Bornage** : chaque couche a un budget mémoire et temporel maximum.
|
||||
|
||||
### Couche 0 — Initial Reconstruction
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Entrée** | Tracks, caméras intrinsèques, co-visibilité |
|
||||
| **Traitement** | Triangulation SVD, initialisation P3P, sélection du paire initial |
|
||||
| **Sortie** | Nuage de points sparse, poses de caméras initiales |
|
||||
| **Budget** | O(N²) dans le pire cas, typiquement O(N·K) où K = nombre moyen de tracks |
|
||||
|
||||
Étapes :
|
||||
1. Sélection du **paire initial** (meilleure baseline angulaire + co-visibilité)
|
||||
2. **Triangulation** des tracks du paire initial
|
||||
3. **Rétro-projection** progressive des caméras adjacentes (grow)
|
||||
4. Filtrage des points rejetés (erreur de reprojection > seuil)
|
||||
|
||||
### Couche 1 — Bundle Adjustment
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Entrée** | Nuage sparse, poses caméras, tracks |
|
||||
| **Traitement** | Optimisation non-linéaire (LM ou Ceres-like), minimisation de l'erreur de reprojection |
|
||||
| **Sortie** | Poses optimisées, points 3D affinés, historique de convergence |
|
||||
| **Budget** | O(N·M) où N = points, M = observations |
|
||||
|
||||
Variantes :
|
||||
- **Local BA** : optimisation d'un sous-ensemble de caméras voisines
|
||||
- **Global BA** : optimisation simultanée de toutes les caméras et points
|
||||
- **Incremental BA** : ajout progressif de caméras avec optimisation partielle
|
||||
|
||||
### Couche 2 — Dense Reconstruction
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Entrée** | Poses optimisées, images originales |
|
||||
| **Traitement** | Semi-Global Matching (SGM), stereo matching, depth maps |
|
||||
| **Sortie** | Depth maps par image, nuage de points dense |
|
||||
| **Budget** | Très élevé en RAM : images × profondeur de recherche |
|
||||
|
||||
Approches :
|
||||
- **Multi-View Stereo (MVS)** : matching dense entre paires de views
|
||||
- **Patch-Based MVS** : regroupement de patches pour robustesse
|
||||
- **Depth Map Fusion** : fusion des depth maps en nuage unifié
|
||||
|
||||
### Couche 3 — Mesh Generation
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Entrée** | Nuage de points dense |
|
||||
| **Traitement** | Poisson reconstruction, Delaunay, ball pivoting |
|
||||
| **Sortie** | Maillage triangulaire orienté |
|
||||
| **Budget** | CPU intensif, mémoire proportionnelle au nombre de points |
|
||||
|
||||
### Couche 4 — Texturing
|
||||
|
||||
| Aspect | Description |
|
||||
|--------|-------------|
|
||||
| **Entrée** | Maillage, images originales, poses caméras |
|
||||
| **Traitement** | Projection UV, visibilité caméra par face, blending |
|
||||
| **Sortie** | Maillage texturé, atlas de texture |
|
||||
| **Budget** | GPU intensif pour le rendu, RAM pour les textures |
|
||||
|
||||
### Frontières de séquence
|
||||
|
||||
Chaque couche produit un **snapshot** atomique :
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint64_t layer_id;
|
||||
uint64_t sequence_id;
|
||||
int64_t timestamp;
|
||||
uint32_t status; // VALIDATED | REJECTED | PARTIAL
|
||||
size_t data_size;
|
||||
void* data; // Pointeur vers le résultat sérialisé
|
||||
} LayerSnapshot;
|
||||
```
|
||||
|
||||
Les snapshots sont persistés sur disque et consultables par le viewer.
|
||||
|
||||
## Relations avec les autres modules
|
||||
|
||||
| Module | Relation |
|
||||
|--------|----------|
|
||||
| **Matching & Tracks** | Fournissent l'entrée de la couche 0. |
|
||||
| **Geometric Constraints** | Utilisées dans toutes les couches pour filtrer et valider. |
|
||||
| **Resource Governor** | Le gouverneur alloue les budgets pour chaque couche et contrôle la taille des lots. |
|
||||
| **Task** | Chaque couche est une tâche candidate. Les couches sont séquencées par le scheduler. |
|
||||
| **Hardware Profile** | Les couches 2-4 peuvent exploiter le GPU si disponible. |
|
||||
| **Image Catalog** | Les couches 2-4 lisent les images originales pour le dense matching et texturing. |
|
||||
| **Viewer** | Le viewer affiche les snapshots des couches validées. |
|
||||
|
||||
## Contraintes de conception
|
||||
|
||||
- Une couche ne démarre que si la couche précédente a produit un snapshot VALIDATED.
|
||||
- Les snapshots intermédiaires sont persistés permettant la reprise après crash.
|
||||
- Chaque couche a un budget mémoire maximum imposé par le Resource Governor.
|
||||
- La couche 1 (BA) est la plus critique : elle doit converger de manière déterministe.
|
||||
- Les couches 2-4 peuvent être exécutées par lots (tiles) pour limiter la RAM.
|
||||
- Le pipeline complet doit pouvoir être interrompu à n'importe quelle frontière.
|
||||
|
||||
## Terminologie
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Layer** | Étape séquentielle et atomique de la reconstruction |
|
||||
| **Frontière de séquence** | Point de reprise garanti entre deux couches |
|
||||
| **Snapshot** | État persisté du résultat d'une couche |
|
||||
| **Sparse reconstruction** | Nuage de points issu du matching (peu de points) |
|
||||
| **Dense reconstruction** | Nuage de points issu du stereo matching (beaucoup de points) |
|
||||
| **Bundle Adjustment** | Optimisation jointe des poses caméras et des points 3D |
|
||||
| **Reprojection error** | Distance entre un point 3D projeté et son observation 2D |
|
||||
| **Grow** | Ajout progressif de caméras à la reconstruction |
|
||||
89
docs/concepts/scan_sets.md
Normal file
89
docs/concepts/scan_sets.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Scan Sets & Acquisitions
|
||||
|
||||
## Définition
|
||||
|
||||
Un **scan set** (ou ensemble de scans) regroupe l'ensemble des images capturées lors d'une session d'acquisition unique, correspondant à un seul objet ou site reconstruit. Chaque scan set constitue l'unité atomique d'entrée du pipeline de photogrammétrie.
|
||||
|
||||
Une **acquisition** désigne le processus physique de capture des images : positioning des capteurs, paramètres d'exposition, et conditions d'éclairage. Le scan set est le résultat numérique de cette acquisition.
|
||||
|
||||
## Statut
|
||||
|
||||
**PLANNED** — Concept définissant la structure d'entrée, pas encore implémenté comme module distinct. Actuellement, le module `import` et `image_catalog` gèrent les images individuellement sans regroupement en scan sets.
|
||||
|
||||
## Place dans le pipeline
|
||||
|
||||
```
|
||||
Acquisition physique
|
||||
↓
|
||||
Scan Set (import groupé)
|
||||
↓
|
||||
Image Catalog (indexation)
|
||||
↓
|
||||
Visual Index (indexation visuelle)
|
||||
↓
|
||||
Matching & Tracks
|
||||
↓
|
||||
Reconstruction Layers
|
||||
```
|
||||
|
||||
Le scan set est la première structure organisée après l'import brut. Il fournit le contexte de regroupement nécessaire pour les étapes suivantes.
|
||||
|
||||
## Concepts clés
|
||||
|
||||
### Structure d'un scan set
|
||||
|
||||
| Champ | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `id` | `uint64_t` | Identifiant unique du scan set |
|
||||
| `name` | `char[]` | Nom lisible (ex: "table_statue_01") |
|
||||
| `project_ref` | `uint64_t` | Référence au projet parent |
|
||||
| `image_count` | `uint32_t` | Nombre d'images dans le set |
|
||||
| `acquisition_date` | `int64_t` | Timestamp de la session |
|
||||
| `camera_model` | `char[]` | Modèle de caméra utilisé |
|
||||
| `pixel_size_um` | `double` | Taille de pixel en micromètres |
|
||||
| `focal_length_mm` | `double` | Distance focale nominale |
|
||||
|
||||
### Relations entre images
|
||||
|
||||
Au sein d'un scan set, les images entretiennent des relations spatiales :
|
||||
|
||||
- **Overlap horizontal** : chevauchement entre images adjacentes d'une même ligne de capture (typiquement 60-80%)
|
||||
- **Overlap vertical** : chevauchement entre lignes de capture successives (typiquement 30-50%)
|
||||
- **Baseline** : distance physique entre deux positions de capture consécutives
|
||||
- **Convergence angle** : angle entre les axes optiques de deux caméras pour un même point
|
||||
|
||||
### Types de scan sets
|
||||
|
||||
- **Grid scan** : captures organisées en grille régulière, adapté aux objets de taille moyenne
|
||||
- **Orbital scan** : captures circulaires autour d'un objet, adapté à la sculpture et aux artefacts
|
||||
- **Linear scan** : captures le long d'un axe linéaire, adapté aux façades et structures longues
|
||||
- **Free-form scan** : captures sans contrainte géométrique, nécessite plus d'overlap pour compenser
|
||||
|
||||
## Relations avec les autres modules
|
||||
|
||||
| Module | Relation |
|
||||
|--------|----------|
|
||||
| **Project** | Un scan set appartient à un projet. Le projet contient la structure de répertoires pour les images du set. |
|
||||
| **Import** | L'import copie les images dans le projet. Le scan set représente un groupe logique d'images importées. |
|
||||
| **Image Catalog** | Le catalogue indexe les métadonnées de chaque image du scan set. |
|
||||
| **Image View** | Les vues peuvent filtrer ou trier les images par scan set. |
|
||||
| **Resource Governor** | Le gouverneur estime les ressources nécessaires pour traiter un scan set complet. |
|
||||
| **Task** | Le traitement d'un scan set est décomposé en tâches unitaires par le scheduler. |
|
||||
|
||||
## Contraintes de conception
|
||||
|
||||
- Un scan set ne doit jamais être modifié après le début du traitement (immutabilité partielle).
|
||||
- L'ajout d'images à un scan set existant doit déclencher un recalcul incrémental, pas un retraitement complet.
|
||||
- La taille maximale d'un scan set est bornée par la RAM disponible : pas plus de N images en mémoire simultanément.
|
||||
- Chaque image appartient à exactement un scan set (relation 1:N).
|
||||
|
||||
## Terminologie
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Scan set** | Groupe d'images d'une même session d'acquisition |
|
||||
| **Acquisition** | Processus physique de capture |
|
||||
| **Overlap** | Pourcentage de superficie commune entre deux images |
|
||||
| **Baseline** | Distance entre deux positions de capture |
|
||||
| **Capture session** | Période continue d'acquisition d'images |
|
||||
| **Footprint** | Zone physique couverte par une image au sol |
|
||||
93
docs/concepts/visual_index.md
Normal file
93
docs/concepts/visual_index.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Visual Index
|
||||
|
||||
## Définition
|
||||
|
||||
Un **visual index** (ou index visuel) est une structure de données compacte qui encode les caractéristiques visuelles distinctives de chaque image d'un scan set. Il permet de retrouver rapidement les paires d'images susceptibles de se chevaucher, sans comparaison exhaustive de toutes les combinaisons possibles.
|
||||
|
||||
L'index visuel transforme chaque image en un vecteur de descripteurs (features) invariantes à la rotation, à l'échelle et partiellement à l'illumination. Ces descripteurs forment une empreinte numérique qui identifie le contenu visuel de l'image.
|
||||
|
||||
## Statut
|
||||
|
||||
**IDEA** — Concept fondamental pour l'étape de matching. Pas encore implémenté. Actuellement, le pipeline de photogrammétrie classique utilise une approche exhaustive ou semi-exhaustive qui ne passe pas à l'échelle.
|
||||
|
||||
## Place dans le pipeline
|
||||
|
||||
```
|
||||
Scan Set (images brutes)
|
||||
↓
|
||||
Feature Extraction (descripteurs par image)
|
||||
↓
|
||||
Visual Index (indexation compacte)
|
||||
↓
|
||||
Candidate Selection (paires candidats)
|
||||
↓
|
||||
Matching & Tracks (appariement détaillé)
|
||||
```
|
||||
|
||||
L'index visuel se situe entre l'extraction de features et la sélection de paires candidates. Il réduit drastiquement l'espace de recherche pour l'appariement.
|
||||
|
||||
## Concepts clés
|
||||
|
||||
### Descripteurs visuels
|
||||
|
||||
| Type | Caractéristiques | Usage |
|
||||
|------|------------------|-------|
|
||||
| **SIFT** | Invariant à l'échelle et rotation, 128 dimensions | Référence académique, lent |
|
||||
| **SURF** | Plus rapide que SIFT, bonne invariance | Compromis vitesse/qualité |
|
||||
| **ORB** | Binaire, très rapide, Open source | Usage temps réel |
|
||||
| **AKAZE** | Non-linéaire, préservation des contours | Bon pour les textures |
|
||||
|
||||
### Structure de l'index
|
||||
|
||||
```
|
||||
Image → [Feature 1, Feature 2, ..., Feature N]
|
||||
↓
|
||||
Visual Index (KD-Tree / LSH / PQ)
|
||||
↓
|
||||
Requête : top-K voisins les plus proches
|
||||
```
|
||||
|
||||
### Techniques d'indexation
|
||||
|
||||
- **KD-Tree** : arbre binaire de partitionnement spatial, efficace pour KNN en basse dimension
|
||||
- **Locality-Sensitive Hashing (LSH)** : hashing probabiliste, efficace en haute dimension
|
||||
- **Product Quantization (PQ)** : quantification par produit, compression agressive des descripteurs
|
||||
- **IVF (Inverted File)** : indexation par clusters, bon compromis mémoire/recherche
|
||||
|
||||
### Paramètres clés
|
||||
|
||||
| Paramètre | Description | Impact |
|
||||
|-----------|-------------|--------|
|
||||
| `n_features_per_image` | Nombre de descripteurs extraits par image | Plus = meilleure couverture, plus de mémoire |
|
||||
| `index_type` | Type de structure d'index (KD-Tree, LSH, PQ) | Compromis précision/vitesse |
|
||||
| `search_radius` | Rayon de recherche pour les voisins | Plus grand = plus de candidats, plus lent |
|
||||
| `min_match_count` | Seuil minimum d'appariements validés | Filtre les faux positifs |
|
||||
|
||||
## Relations avec les autres modules
|
||||
|
||||
| Module | Relation |
|
||||
|--------|----------|
|
||||
| **Image Catalog** | Le catalogue fournit les métadonnées nécessaires à l'indexation (dimensions, modèle caméra). |
|
||||
| **Image View** | Les vues peuvent filtrer les images avant indexation (par zone, par qualité). |
|
||||
| **Resource Governor** | Le gouverneur alloue la mémoire pour la structure d'index et contrôle la taille des lots d'indexation. |
|
||||
| **Task** | L'indexation visuelle est une tâche candidate pour le scheduler. Elle est CPU-intensive mais parallélisable. |
|
||||
| **Hardware Profile** | Le profil matériel détermine le type d'index optimal (KD-Tree pour peu de features, LSH pour beaucoup). |
|
||||
|
||||
## Contraintes de conception
|
||||
|
||||
- L'index doit tenir en mémoire pour un scan set complet typique (100-1000 images).
|
||||
- La construction de l'index ne doit pas bloquer la TUI : tâche asynchrone avec progression.
|
||||
- L'index est reconstruction-only : il n'est pas persisté entre les sessions (reconstruit à la demande).
|
||||
- La taille maximale de l'index est bornée par le budget RAM du Resource Governor.
|
||||
- Les descripteurs doivent être calculés de manière déterministe (même image → même index).
|
||||
|
||||
## Terminologie
|
||||
|
||||
| Terme | Définition |
|
||||
|-------|------------|
|
||||
| **Feature** | Point d'intérêt local avec descripteur associé |
|
||||
| **Keypoint** | Position spatiale (x, y) d'un point d'intérêt |
|
||||
| **Descriptor** | Vecteur numérique décruant l'apparence locale autour d'un keypoint |
|
||||
| **KNN** | K-Nearest Neighbors, recherche des K voisins les plus proches |
|
||||
| **Vocabulary visuel** | Dictionnaire de descripteurs typiques pour la bag-of-words |
|
||||
| **BoW (Bag of Words)** | Représentation histogrammique des features d'une image |
|
||||
123
docs/development/build.md
Normal file
123
docs/development/build.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# Instructions de build
|
||||
|
||||
## Prérequis
|
||||
|
||||
- **OS** : Linux (testé sur distributions récentes)
|
||||
- **Compilateur** : Clang (recommandé) ou GCC
|
||||
- **Système de build** : Meson + Ninja
|
||||
- **Dépendances** : ncursesw (ncurses avec support Unicode)
|
||||
- **Langage** : C17
|
||||
|
||||
## Installation des dépendances
|
||||
|
||||
```sh
|
||||
# Debian / Ubuntu
|
||||
sudo apt install clang meson ninja-build libncursesw5-dev pkg-config
|
||||
|
||||
# Fedora
|
||||
sudo dnf install clang meson ninja-build ncurses-devel pkg-config
|
||||
|
||||
# Arch
|
||||
sudo pacman -S clang meson ninja ncurses pkgconf
|
||||
```
|
||||
|
||||
## Build standard
|
||||
|
||||
```sh
|
||||
CC=clang meson setup build --wipe
|
||||
meson compile -C build -j8
|
||||
```
|
||||
|
||||
### Options utiles
|
||||
|
||||
```sh
|
||||
# Build de debug (défaut)
|
||||
meson setup build --wipe
|
||||
|
||||
# Build de release
|
||||
meson setup build --wipe --buildtype=release
|
||||
|
||||
# Build avec optimisations aggressive
|
||||
meson setup build --wipe --buildtype=release -Db_lto=true
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
```sh
|
||||
# Tests unitaires
|
||||
meson test -C build --print-errorlogs
|
||||
|
||||
# Vérification du style (whitespace)
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Build ASan/UBSan (debug mémoire)
|
||||
|
||||
À exécuter pour tout ticket touchant la mémoire, les durées de vie ou les
|
||||
allocations :
|
||||
|
||||
```sh
|
||||
meson setup build-asan --wipe \
|
||||
-Db_sanitize=address,undefined \
|
||||
-Db_static=false
|
||||
meson compile -C build-asan -j8
|
||||
meson test -C build-asan --print-errorlogs
|
||||
```
|
||||
|
||||
## Build TSan (concurrence)
|
||||
|
||||
À exécuter pour tout ticket touchant la concurrence (pthread, mutex,
|
||||
variables de condition, états partagés) :
|
||||
|
||||
```sh
|
||||
meson setup build-tsan --wipe \
|
||||
-Db_sanitize=thread \
|
||||
-Db_static=false
|
||||
meson compile -C build-tsan -j8
|
||||
meson test -C build-tsan --print-errorlogs
|
||||
```
|
||||
|
||||
## Variables d'environnement
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `CC` | Compilateur C (défaut : gcc) |
|
||||
| `CFLAGS` | Drapeaux de compilation supplémentaires |
|
||||
| `LDFLAGS` | Drapeaux de liaison supplémentaires |
|
||||
|
||||
## Structure du build
|
||||
|
||||
```text
|
||||
build/
|
||||
├── src/ # objets et binaires
|
||||
├── tests/ # binaires de tests
|
||||
└── compile_commands.json # pour LSP / clangd
|
||||
```
|
||||
|
||||
## Dépannage
|
||||
|
||||
### Erreur : ncursesw introuvable
|
||||
|
||||
```sh
|
||||
# Vérifier l'installation
|
||||
pkg-config --libs ncursesw
|
||||
# Si absent, installer le paquet de développement ncursesw
|
||||
```
|
||||
|
||||
### Erreur : clang introuvable
|
||||
|
||||
```sh
|
||||
# Utiliser gcc en alternative
|
||||
meson setup build --wipe
|
||||
# ou installer clang
|
||||
sudo apt install clang
|
||||
```
|
||||
|
||||
### Build lent
|
||||
|
||||
```sh
|
||||
# Réduire la parallélisation
|
||||
meson compile -C build -j4
|
||||
# ou utiliser ccache
|
||||
CC="ccache clang" meson setup build --wipe
|
||||
```
|
||||
184
docs/development/concurrency.md
Normal file
184
docs/development/concurrency.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
# Règles de concurrence
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Lardon3D utilise un modèle de concurrence à thread unique pour ncurses
|
||||
et un modèle multi-thread pour le traitement. La séparation est stricte :
|
||||
le thread ncurses ne fait jamais de travail métier, et les workers ne
|
||||
touchent jamais ncurses.
|
||||
|
||||
## Modèle de concurrence
|
||||
|
||||
```text
|
||||
Thread principal (ncurses)
|
||||
├── Gestion des entrées
|
||||
├── Affichage TUI
|
||||
└── Orchestration
|
||||
|
||||
Worker thread
|
||||
├── Exécution des tâches
|
||||
├── Calculs métier
|
||||
└── Écritures de résultats
|
||||
```
|
||||
|
||||
## Règles fondamentales
|
||||
|
||||
### 1. ncurses appartient au thread principal
|
||||
|
||||
```c
|
||||
// ✅ Correct : appel depuis le thread principal
|
||||
mvprintw(0, 0, "Progression: %d%%", progress);
|
||||
|
||||
// ❌ Interdit : appel depuis un worker
|
||||
// mvprintw() dans un thread secondaire
|
||||
```
|
||||
|
||||
### 2. Variables partagées protégées par mutex
|
||||
|
||||
```c
|
||||
// ✅ Correct
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
queue->count++;
|
||||
pthread_mutex_unlock(&queue->mutex);
|
||||
|
||||
// ❌ Interdit
|
||||
// queue->count++; sans protection
|
||||
```
|
||||
|
||||
### 3. Variables de condition pour la synchronisation
|
||||
|
||||
```c
|
||||
// Producteur (scheduler)
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
queue->ready = true;
|
||||
pthread_cond_signal(&queue->cond);
|
||||
pthread_mutex_unlock(&queue->mutex);
|
||||
|
||||
// Consommateur (worker)
|
||||
pthread_mutex_lock(&queue->mutex);
|
||||
while (!queue->ready) {
|
||||
pthread_cond_wait(&queue->cond, &queue->mutex);
|
||||
}
|
||||
// traitement
|
||||
pthread_mutex_unlock(&queue->mutex);
|
||||
```
|
||||
|
||||
### 4. Pas de callback ncurses depuis un worker
|
||||
|
||||
```c
|
||||
// ✅ Correct : le worker signale au thread principal
|
||||
void worker_callback(task_t *task, void *userdata) {
|
||||
shared_state_t *state = userdata;
|
||||
pthread_mutex_lock(&state->mutex);
|
||||
state->result_ready = true;
|
||||
pthread_cond_signal(&state->cond);
|
||||
pthread_mutex_unlock(&state->mutex);
|
||||
}
|
||||
|
||||
// ❌ Interdit : appel ncurses depuis le worker
|
||||
// void worker_callback(...) {
|
||||
// mvprintw(...);
|
||||
// }
|
||||
```
|
||||
|
||||
## Primitives utilisées
|
||||
|
||||
| Primitive | Usage |
|
||||
|---|---|
|
||||
| `pthread_mutex_t` | Protection des données partagées |
|
||||
| `pthread_cond_t` | Synchronisation producteur/consommateur |
|
||||
| `pthread_create()` | Création des workers |
|
||||
| `pthread_join()` | Attente de fin des workers |
|
||||
| `pthread_cancel()` | Annulation d'un worker (dernier recours) |
|
||||
|
||||
## Invariants de concurrence
|
||||
|
||||
1. **Un seul thread ncurses** : ncurses n'est jamais appelé depuis un
|
||||
worker. Toute mise à jour de l'UI passe par des variables partagées
|
||||
protégées.
|
||||
|
||||
2. **Mutex hiérarchique** : si plusieurs mutex sont acquis, toujours dans
|
||||
le même ordre pour éviter les deadlocks.
|
||||
|
||||
3. **Annulation coopérative** : les workers vérifient périodiquement un
|
||||
drapeau d'annulation. Pas d'interruption brutale sauf dernier recours.
|
||||
|
||||
4. **Réservation atomique** : la réservation du gouverneur est atomique.
|
||||
Deux threads ne peuvent pas obtenir la même réservation.
|
||||
|
||||
5. **Pas de callback sans réservation** : aucun callback de tâche n'est
|
||||
invoqué sans réservation active. Cet invariant est maintenu même en
|
||||
présence d'erreurs.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
### Deadlock
|
||||
|
||||
```c
|
||||
// ❌ Risque de deadlock
|
||||
pthread_mutex_lock(&mutex_a);
|
||||
pthread_mutex_lock(&mutex_b); // attend mutex_b
|
||||
|
||||
// Dans un autre thread :
|
||||
pthread_mutex_lock(&mutex_b);
|
||||
pthread_mutex_lock(&mutex_a); // attend mutex_a → DEADLOCK
|
||||
```
|
||||
|
||||
**Solution** : toujours acquérir les mutex dans le même ordre.
|
||||
|
||||
### Race condition
|
||||
|
||||
```c
|
||||
// ❌ Race condition
|
||||
if (task->state == TASK_STATE_QUEUED) {
|
||||
task->state = TASK_STATE_RUNNING;
|
||||
}
|
||||
|
||||
// ✅ Correct
|
||||
pthread_mutex_lock(&task->mutex);
|
||||
if (task->state == TASK_STATE_QUEUED) {
|
||||
task->state = TASK_STATE_RUNNING;
|
||||
}
|
||||
pthread_mutex_unlock(&task->mutex);
|
||||
```
|
||||
|
||||
### Use-after-free
|
||||
|
||||
```c
|
||||
// ❌ Use-after-free
|
||||
task_destroy(task);
|
||||
task_callback(task); // task est libéré
|
||||
|
||||
// ✅ Correct
|
||||
task_callback(task);
|
||||
task_destroy(task);
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
Pour tout ticket touchant la concurrence, exécuter :
|
||||
|
||||
```sh
|
||||
# Build TSan
|
||||
meson setup build-tsan --wipe -Db_sanitize=thread -Db_static=false
|
||||
meson compile -C build-tsan -j8
|
||||
meson test -C build-tsan --print-errorlogs
|
||||
```
|
||||
|
||||
TSan détecte automatiquement :
|
||||
- les race conditions
|
||||
- les deadlocks potentiels
|
||||
- les signaux perdus
|
||||
- les verrous non libérés
|
||||
|
||||
## Checklist de concurrence
|
||||
|
||||
Avant de livrer un ticket touchant la concurrence :
|
||||
|
||||
- [ ] Toutes les variables partagées sont protégées par un mutex
|
||||
- [ ] Les mutex sont toujours libérés (même en cas d'erreur)
|
||||
- [ ] Les variables de condition sont vérifiées dans une boucle `while`
|
||||
- [ ] Aucun appel ncurses depuis un worker
|
||||
- [ ] L'annulation est coopérative (pas de `pthread_cancel` sauf dernier recours)
|
||||
- [ ] TSan ne signale aucune erreur
|
||||
- [ ] Le build ASan ne signale aucune fuite mémoire liée aux threads
|
||||
123
docs/development/testing.md
Normal file
123
docs/development/testing.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# Procédures de test
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Lardon3D utilise le framework de test intégré à Meson. Chaque module possède
|
||||
un fichier de test dans `tests/` correspondant au module testé.
|
||||
|
||||
## Lancer les tests
|
||||
|
||||
```sh
|
||||
# Tous les tests
|
||||
meson test -C build --print-errorlogs
|
||||
|
||||
# Un test spécifique
|
||||
meson test -C build test_task_queue --print-errorlogs
|
||||
|
||||
# Tests avec verbose
|
||||
meson test -C build -v --print-errorlogs
|
||||
|
||||
# Réexécuter uniquement les tests échoués
|
||||
meson test -C build --reprint=failed
|
||||
```
|
||||
|
||||
## Structure des tests
|
||||
|
||||
```text
|
||||
tests/
|
||||
├── test_task_queue.c # tests de la file de tâches
|
||||
├── test_task.c # tests du module task
|
||||
├── test_resource_governor.c # tests du gouverneur
|
||||
├── test_hardware_profile.c # tests du profil matériel
|
||||
├── test_import.c # tests de l'import
|
||||
├── test_project.c # tests des projets
|
||||
└── test_*.c # autres modules
|
||||
```
|
||||
|
||||
## Écrire un test
|
||||
|
||||
```c
|
||||
#include <glib.h>
|
||||
#include "lardon3d/task.h"
|
||||
|
||||
void test_task_create(void) {
|
||||
task_estimate_t est = {
|
||||
.ram_bytes = 1024 * 1024,
|
||||
.gpu_bytes = 0,
|
||||
.cpu_weight = 1,
|
||||
.io_weight = 0,
|
||||
.batch_size = 10,
|
||||
.batch_max = 100
|
||||
};
|
||||
task_t *t = task_create("test", &est, NULL, NULL);
|
||||
g_assert_nonnull(t);
|
||||
g_assert_cmpint(task_get_state(t), ==, TASK_STATE_IDLE);
|
||||
task_destroy(t);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func("/task/create", test_task_create);
|
||||
return g_test_run();
|
||||
}
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
1. **Préfixe `test_`** : chaque fonction de test porte le préfixe `test_`.
|
||||
2. **Chemin hiérarchique** : le nom du test suit le pattern `/module/action`.
|
||||
3. **Asserts GLib** : utiliser `g_assert_*` pour les vérifications.
|
||||
4. **Nettoyage** : chaque test libère toutes ses ressources.
|
||||
5. **Isolation** : un test ne dépend pas de l'état d'un autre test.
|
||||
6. **Déterminisme** : les tests ne dépendent pas de l'heure, du filesystem
|
||||
ou de l'état réseau (sauf test d'import).
|
||||
|
||||
## Tests unitaires vs tests d'intégration
|
||||
|
||||
| Type | Portée | Fichier |
|
||||
|---|---|---|
|
||||
| Unitaire | Un module isolé | `tests/test_<module>.c` |
|
||||
| Intégration | Interaction entre modules | `tests/test_<module>.c` avec dépendances réelles |
|
||||
|
||||
## Validation par ticket
|
||||
|
||||
Avant de livrer un ticket, exécuter la séquence complète :
|
||||
|
||||
```sh
|
||||
# 1. Build clean
|
||||
CC=clang meson setup build --wipe
|
||||
meson compile -C build -j8
|
||||
|
||||
# 2. Tests
|
||||
meson test -C build --print-errorlogs
|
||||
|
||||
# 3. Style
|
||||
git diff --check
|
||||
|
||||
# 4. Si mémoire/concurrence touchés
|
||||
meson setup build-asan --wipe -Db_sanitize=address,undefined -Db_static=false
|
||||
meson compile -C build-asan -j8
|
||||
meson test -C build-asan --print-errorlogs
|
||||
|
||||
# 5. Si concurrence touchée
|
||||
meson setup build-tsan --wipe -Db_sanitize=thread -Db_static=false
|
||||
meson compile -C build-tsan -j8
|
||||
meson test -C build-tsan --print-errorlogs
|
||||
```
|
||||
|
||||
## Dépannage
|
||||
|
||||
### Test qui échoue en ASan
|
||||
|
||||
Vérifier les durées de vie des allocations. Ne jamais libérer un objet puis
|
||||
y accéder. Vérifier que chaque `task_destroy()` est appelée.
|
||||
|
||||
### Test qui échoue en TSan
|
||||
|
||||
Vérifier que toutes les variables partagées sont protégées par un mutex.
|
||||
Vérifier que ncurses est utilisé uniquement depuis le thread principal.
|
||||
|
||||
### Test qui échoue uniquement en release
|
||||
|
||||
Vérifier les assertions et les overflow arithmétiques. Compiler avec
|
||||
`-fsanitize=undefined` pour détecter les comportements indéfinis.
|
||||
|
|
@ -1,4 +1,14 @@
|
|||
# Transmission du développement à OpenCode
|
||||
# Transmission du développement à OpenCode (DÉPRÉCIÉ)
|
||||
|
||||
> **Ce document est déprécié.** Il a été remplacé par la documentation structurée dans :
|
||||
> - [.opencode/context.md](../.opencode/context.md) (contexte permanent)
|
||||
> - [.opencode/work/current_ticket.md](../.opencode/work/current_ticket.md) (handoff)
|
||||
> - [docs/architecture/overview.md](architecture/overview.md) (vue d'ensemble)
|
||||
> - [docs/roadmap/roadmap.md](roadmap/roadmap.md) (feuille de route)
|
||||
>
|
||||
> Ce document est conservé uniquement pour la traçabilité historique.
|
||||
|
||||
---
|
||||
|
||||
## 1. Vision du projet
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
# Inventaire des modèles OpenCode
|
||||
# Modèles OpenCode (DÉPRÉCIÉ)
|
||||
|
||||
> **Ce document est déprécié.** Il a été remplacé par la documentation structurée dans :
|
||||
> - [.opencode/context.md](../.opencode/context.md) (contexte permanent)
|
||||
> - [.opencode/agents/](../.opencode/agents/) (définitions des agents)
|
||||
>
|
||||
> Ce document est conservé uniquement pour la traçabilité historique.
|
||||
|
||||
---
|
||||
|
||||
Inventaire effectué le 6 août 2026 avec
|
||||
`opencode models --refresh --verbose`. Le seul fournisseur connecté exposé est
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
# Workflow OpenCode et Codex
|
||||
# Workflow OpenCode et Codex (DÉPRÉCIÉ)
|
||||
|
||||
> **Ce document est déprécié.** Il a été remplacé par la documentation structurée dans :
|
||||
> - [.opencode/context.md](../.opencode/context.md) (contexte permanent)
|
||||
> - [.opencode/work/current_ticket.md](../.opencode/work/current_ticket.md) (handoff)
|
||||
> - [docs/development/build.md](development/build.md) (instructions de build)
|
||||
> - [docs/development/testing.md](development/testing.md) (procédures de test)
|
||||
>
|
||||
> Ce document est conservé uniquement pour la traçabilité historique.
|
||||
|
||||
---
|
||||
|
||||
Ce workflow minimise le contexte tout en conservant un handoff fiable. Le
|
||||
fichier `.opencode/work/current_ticket.md` est local et ignoré par Git. Il ne
|
||||
|
|
|
|||
80
docs/roadmap/roadmap.md
Normal file
80
docs/roadmap/roadmap.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# Roadmap Lardon3D
|
||||
|
||||
## Direction générale
|
||||
|
||||
Lardon3D suit une feuille de route ordonnée qui privilégie la stabilité et la consolidation avant l'ajout de fonctionnalités complexes.
|
||||
|
||||
## Étapes terminées (DONE)
|
||||
|
||||
### Phase 1 : Fondations
|
||||
- ✅ TUI modulaire avec ncursesw
|
||||
- ✅ Gestion persistante des projets
|
||||
- ✅ Import asynchrone et annulable
|
||||
- ✅ Catalogue d'images et vues
|
||||
- ✅ Moteur de tâches avec pause/reprise, annulation, checkpoints
|
||||
- ✅ File FIFO avec sélection adaptative et backpressure
|
||||
- ✅ Profil matériel et snapshots de ressources
|
||||
- ✅ Resource Governor avec réservations opaques
|
||||
- ✅ Intégration scheduler ↔ governor
|
||||
- ✅ Sélection de la première tâche admissible
|
||||
|
||||
## Travaux d'infrastructure en cours (CURRENT FOUNDATION)
|
||||
|
||||
### Phase 2 : Consolidation
|
||||
- 🔄 Documentation architecturale
|
||||
- 🔄 Tests et validation
|
||||
- 🔄 Optimisations mémoire
|
||||
|
||||
## Prochaines étapes décidées (NEXT)
|
||||
|
||||
### Phase 3 : Persistance
|
||||
- 📋 Persistance des tâches et checkpoints
|
||||
- 📋 Project Database v1 (SQLite)
|
||||
- 📋 ScanSet et Image Catalog persistants
|
||||
|
||||
### Phase 4 : Pipeline avancé
|
||||
- 📋 Feature Store
|
||||
- 📋 Visual Index
|
||||
- 📋 Candidate Pair Generator
|
||||
- 📋 Matching et vérification géométrique
|
||||
- 📋 Tracks et SfM
|
||||
|
||||
### Phase 5 : Reconstruction
|
||||
- 📋 Reconstruction incrémentale
|
||||
- 📋 MVS / dense
|
||||
- 📋 Mesh
|
||||
- 📋 Contraintes externes
|
||||
- 📋 Consolidation
|
||||
|
||||
## Étapes futures (LATER)
|
||||
|
||||
### Phase 6 : Production
|
||||
- ⏳ Viewer intégré
|
||||
- ⏳ Publication live validée
|
||||
- ⏳ Export multi-formats
|
||||
- ⏳ Optimisations performances
|
||||
|
||||
### Phase 7 : Avancé
|
||||
- ⏳ Priorités entre tâches
|
||||
- ⏳ Pools de workers multiples (CPU/GPU/IO)
|
||||
- ⏳ DAG de dépendances complet
|
||||
- ⏳ Parallélisme inter-tâches
|
||||
|
||||
## Sujets exploratoires (RESEARCH)
|
||||
|
||||
- 🔬 Intégration avec des sources de données externes
|
||||
- 🔬 Support de formats d'entrée variés
|
||||
- 🔬 Optimisation pour machines à très faible mémoire
|
||||
- 🔬 Distribution de calcul
|
||||
|
||||
## Principes directeurs
|
||||
|
||||
1. **Stabilité avant performance** : ne jamais saturer le système hôte
|
||||
2. **Séquençage avant parallélisme** : lots adaptatifs et workers uniques d'abord
|
||||
3. **Réservation atomique** : aucune exécution sans contrat valide
|
||||
4. **Persistance progressive** : chaque résultat doit pouvoir être repris
|
||||
5. **Documentation vivante** : la documentation suit le code, pas l'inverse
|
||||
|
||||
## Vérification
|
||||
|
||||
Cette roadmap est vérifiée contre l'état réel du code. Les fonctionnalités déjà implémentées ne sont pas marquées comme NEXT ou LATER.
|
||||
Loading…
Reference in a new issue