fix #424: a zero-area viewport skips the frame before any GPU work (alt-tab out of exclusive fullscreen crashed the pack-on client)

GLFW auto-iconifies an exclusive-fullscreen window on focus loss; for one
frame the window size reads 0x0 while the swapchain is still created, so
GameWindow.OnRender's PrepareFrame guard let a zero-area RenderFrameInput
through. The retail path tolerated it silently; the render-pack controller
correctly rejects a zero activation extent, which surfaced the latent frame
as an unhandled ArgumentOutOfRangeException during the owner's VM6/VM3 gate.

RenderFrameOrchestrator.Render now returns RenderFrameOutcome.ZeroArea
before BeginFrame when either dimension is <= 0 (no GPU frame, phase,
measurement, diagnostics or recovery runs) and GameWindow skips
NoteFrameClosed for it. Test: ZeroAreaViewport_SkipsTheFrameBeforeAnyGpuWork.

Verify: App hermetic lane 6,059/0 (Release).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-23 09:49:56 +02:00
parent b017391b98
commit 38def07edb
4 changed files with 84 additions and 3 deletions

View file

@ -24,6 +24,36 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## #424 — Client crashed on alt-tab out of exclusive fullscreen: zero-area frame reached `RenderPackActivationExtent.Validate`
**Status:** ✅ FIXED 2026-08-23 (same session it was found — the owner's VM6/VM3 gate launch).
**Component:** rendering / frame orchestration (host minimised-window guard)
**Symptom:** exclusive fullscreen 2560×1440, High pack, alt-tab to the desktop →
`Unhandled exception. System.ArgumentOutOfRangeException: Activation extent must be
positive. (Parameter 'Width')` at `RenderPackController.ApplyAtFrameBoundary`
`VulkanWorldScenePhase.Render``GameWindow.OnRender`. Log:
`artifacts/owner-gate/launch.err`.
**Root cause:** GLFW auto-iconifies an exclusive-fullscreen window on focus
loss. `GameWindow.OnRender` guards minimised windows through
`VulkanGraphicsContext.PrepareFrame()`, but that only consults a *pending*
recreate / swapchain existence — for the one frame between iconify and the
present that reports OUT_OF_DATE, `_window.Size` already reads 0×0 while
the swapchain is still "created", so a zero-area `RenderFrameInput` went
down the full pipeline. Pre-campaign the retail path tolerated a 0×0
viewport silently; Campaign AR's pack controller (correctly) refuses a
zero activation extent, turning the latent zero-area frame into a crash.
**Fix:** `RenderFrameOrchestrator.Render` returns
`RenderFrameOutcome.ZeroArea` (flag `SkippedZeroArea`) BEFORE
`BeginFrame` when either viewport dimension is ≤ 0 — no GPU frame, phase,
measurement, diagnostics or recovery runs — and `GameWindow.OnRender` skips
`NoteFrameClosed` for such a frame. Test:
`RenderFrameOrchestratorTests.ZeroAreaViewport_SkipsTheFrameBeforeAnyGpuWork`
(four extents). Not a workaround: a window with no area has nothing to
render, and the rule now lives at the one seam every frame passes through.
## #423 — Atmospheric ray/shadow/volumetric day-group policy keys on the raw day-group index, not the DAT-classified WeatherKind
**Status:** OPEN — filed 2026-08-23 at Campaign VM VM6 (spot-check); pre-existing from Campaign AR.