feat(core): Étape 11 — resize (surface + depth, Phase 4.4)
This commit is contained in:
@@ -3,6 +3,13 @@
|
||||
> 📅 **2026-09-18** — Plan de l'étape suivante.
|
||||
> **Source de vérité** = code + README.md. Ce document est vidé à la complétion de l'étape.
|
||||
> **Références** : ROADMAP Phase 4.4 · PLAN Phase 4 · décision D3 (2026-09-18).
|
||||
>
|
||||
> ✅ **FAIT (2026-09-18).** `App::resize(w,h)` (`lib/src/app.rs`) reconfigure la surface via
|
||||
> `Context::configure` et recrée la depth texture via `Renderer::resize_depth` (+ `set_format`),
|
||||
> avec re-synchronisation de la Scene si le format change (D4). `AppRunner::window_event`
|
||||
> branche `WindowEvent::Resized` (garde 0×0, D3) et `RedrawRequested` (garde taille nulle, D6).
|
||||
> `cargo build --workspace`, `cargo test --workspace` et la compilation des exemples passent.
|
||||
> La vérification visuelle (redimensionner `cube`) reste à faire au runtime.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+8
-6
@@ -148,15 +148,17 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
||||
- [ ] HDR + Tone Mapping (optionnel)
|
||||
|
||||
### 4.4 Gestion du Resize (cycle de vie Surface + Depth)
|
||||
- [ ] Handler `WindowEvent::Resized` dans `AppRunner::window_event` (`app.rs`)
|
||||
- [x] Handler `WindowEvent::Resized` dans `AppRunner::window_event` (`app.rs`) *(Étape 11, 2026-09-18)*
|
||||
→ recalculer `size`, prévenir de ne pas rendre tant que la taille est invalide (0).
|
||||
- [ ] Reconfigurer la surface (`Context::configure`) à la nouvelle taille.
|
||||
- [ ] Recréer la depth texture à la nouvelle taille (`Renderer::resize_depth(width, height)`)
|
||||
- [x] Reconfigurer la surface (`Context::configure`) à la nouvelle taille.
|
||||
- [x] Recréer la depth texture à la nouvelle taille (`Renderer::resize_depth(width, height)`)
|
||||
— le helper `create_depth_texture` isolé (Étape 9, D3) rend ce recreate trivial.
|
||||
- [ ] Collecte du nouveau format si la configuration change (srgb etc.) → re-valider la compat pipeline.
|
||||
- [x] Collecte du nouveau format si la configuration change (srgb etc.) → re-valider la compat pipeline.
|
||||
*(D4 : `App::resize` compare l'ancien/nouveau format et re-synchronise Renderer (`set_format`) + Scene (`init_gpu`) ; cas pathologique, structuré non exercé couramment)*
|
||||
|
||||
> Reporté hors de l'Étape 9 (depth buffer) : l'app ne gère aujourd'hui aucun resize — la surface
|
||||
> n'est configurée qu'au démarrage (`resumed`). Chantier dédié, acté en D3 (2026-09-18).
|
||||
> Géré en Étape 11 (2026-09-18) : la surface est désormais reconfigurée à chaque `Resized` et la
|
||||
> depth texture recréée en même temps (helper `create_depth_texture` isolé, Étape 9, D3). Le present
|
||||
> mode FIFO reste figé (voir Notes de Décision).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -135,6 +135,29 @@ impl App {
|
||||
let aspect = size.width as f32 / size.height.max(1) as f32;
|
||||
self.renderer().render_scene(view, &self.scene, aspect);
|
||||
}
|
||||
|
||||
/// Resizes the surface and depth texture to a new window size (ROADMAP Phase 4.4).
|
||||
/// Reconfigures the surface via `Context::configure` (which returns the chosen format) and
|
||||
/// recreates the depth texture via `Renderer::resize_depth` so the color and depth attachments
|
||||
/// stay the same size. If the surface format changes (rare, deterministic per window), the
|
||||
/// Scene's GPU context is re-initialized to the new format; otherwise the swap alone suffices.
|
||||
/// Inputs: width/height — the new surface dimensions in pixels.
|
||||
/// Returns Ok(()) on success or a `WsgError` if the surface cannot be reconfigured.
|
||||
pub fn resize(&mut self, width: u32, height: u32) -> Result<(), WsgError> {
|
||||
let context = self.context.as_ref().ok_or(WsgError::SurfaceIncompatible)?;
|
||||
let old_format = self.renderer().format();
|
||||
let new_format = context.configure(&context.adapter, width, height)?;
|
||||
self.renderer_mut().resize_depth(width, height);
|
||||
self.renderer_mut().set_format(new_format);
|
||||
if new_format != old_format {
|
||||
// Surface format changed: re-wire the Scene's GPU context (device + queue + format)
|
||||
// so its PipelineCache/pipelines match the new surface format.
|
||||
let device = std::sync::Arc::new(self.renderer_mut().device().clone());
|
||||
self.scene
|
||||
.init_gpu(device, self.context().queue.clone(), new_format);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for constructing a configured `App` instance with custom title and dimensions.
|
||||
@@ -277,7 +300,25 @@ impl<H: AppHandler> ApplicationHandler for AppRunner<H> {
|
||||
return;
|
||||
};
|
||||
match event {
|
||||
WindowEvent::Resized(size) => {
|
||||
// Garde (D3) : minimiser la fenêtre envoie Resized(0x0) ; ne jamais reconfigurer à 0.
|
||||
let w = size.width as u32;
|
||||
let h = size.height as u32;
|
||||
if w == 0 || h == 0 {
|
||||
return;
|
||||
}
|
||||
// Étape 11 : reconfigurer surface + depth à la nouvelle taille, puis re-rendre.
|
||||
if let Err(e) = app.resize(w, h) {
|
||||
eprintln!("WSG : erreur de resize ({e:?})");
|
||||
}
|
||||
app.window().request_redraw();
|
||||
}
|
||||
WindowEvent::RedrawRequested => {
|
||||
// Garde (D6) : ne pas rendre sur une surface de taille nulle (fenêtre minimisée).
|
||||
let size = app.window().inner_size();
|
||||
if size.width == 0 || size.height == 0 {
|
||||
return;
|
||||
}
|
||||
// Rendering logic
|
||||
let frame = app.context().get_next_frame();
|
||||
|
||||
|
||||
@@ -167,6 +167,23 @@ impl Renderer {
|
||||
self.write_default_frame_uniforms();
|
||||
}
|
||||
|
||||
/// Recreates the depth texture at a new size, used on window resize (ROADMAP Phase 4.4).
|
||||
/// The previous depth texture is dropped when its field is replaced — no leak, no double
|
||||
/// allocation. The helper `create_depth_texture` (Étape 9, D3) is reused so the recreate stays
|
||||
/// trivial. Inputs: width/height — the new surface dimensions in pixels.
|
||||
pub fn resize_depth(&mut self, width: u32, height: u32) {
|
||||
let (depth_texture, depth_view) = create_depth_texture(&self.device, width, height);
|
||||
self._depth_texture = depth_texture;
|
||||
self.depth_view = depth_view;
|
||||
}
|
||||
|
||||
/// Updates the stored surface texture format after a surface reconfigure (ROADMAP Phase 4.4).
|
||||
/// Used when `Context::configure` returns a different format so the Renderer stays in sync
|
||||
/// with the surface. Inputs: format — the new surface texture format.
|
||||
pub fn set_format(&mut self, format: wgpu::TextureFormat) {
|
||||
self.format = format;
|
||||
}
|
||||
|
||||
/// Rewrites the shared per-frame uniform buffer from the scene's active camera and the current
|
||||
/// viewport aspect, then returns the frame bind group wired to that buffer. Called at the start of
|
||||
/// every `render_scene` so the GPU sees the latest camera matrices and camera position (Étape 4.3).
|
||||
|
||||
Reference in New Issue
Block a user