diff --git a/docs/research/2026-09-01-overhaul/476-capture-lifetime-diagnosis.md b/docs/research/2026-09-01-overhaul/476-capture-lifetime-diagnosis.md index dc91ce20b..e67e90960 100644 --- a/docs/research/2026-09-01-overhaul/476-capture-lifetime-diagnosis.md +++ b/docs/research/2026-09-01-overhaul/476-capture-lifetime-diagnosis.md @@ -88,3 +88,51 @@ No #476 implementation is authorized by this diagnostic note. The lead will commit a bounded contract and dispatch one implementer after #475, with both review lenses and the campaign's normal gate/ledger rules. C1c, the geometry witness, full lanes, C2 and owner G4 remain outstanding; never merge main. + +## Additional lead static checks while #475 tests are corrected + +No #476 implementation was started. The lead read the complete real outer +frame transaction, private renderer, capture controller and GPU frame adapter. +The existing `IPrivateFrameScreenshot` is already a narrow capture seam; +moving its invocation does not require a second GPU-frame owner. Preserve +GPU measurement closure before GPU submission, and exactly one attempted +frame close on every successful Begin, including render/recovery/close errors. +The actual adapter clears CurrentFrame before calling its End. + +Post-screenshot consumers inspected: RenderFrameDiagnosticsController is +CPU diagnostics; WorldLifecycleAutomationController reads borrowed world/ +reveal/resource snapshots and writes checkpoint JSON; the shadow comparison +reads the completed CPU render oracle and clears its own dirty markers. +None of these bodies requires an open GPU command frame. Their mutual order +(capture, diagnostics, shadow comparison, lifecycle checkpoint) still matters. +Do not move world/private draw phases or introduce another frame tick. + +Vulkan retention is explicitly opt-in. ConfigureBackbufferCapture creates +the buffer only when `_retainBackbufferCapture` is true; retain that default- +off cost. RecordBackbufferCapture records the copy while the swapchain image +is acquired, then QueueSubmit2 submits it. A validity marker must reflect an +actually submitted copy, not merely allocation or command recording; resize, +failed submission and skipped/zero-area frames must not label old/uninitialized +bytes as the newly requested complete frame. The bring-up caller already +reads after ending its frame. + +Named retail's screenshot boundary was also checked statically against the +same paired executable SHA256006FFEADC5D679C871497112A5BD1F87714D0E273E2166BAE5052DDE369297B1: + +| Function/window | Length | SHA256 | +|---|---:|---| +| Device::GetScreenshotSurface00439160, complete body |298|7717277646A9283ECBD10594177A5EC70213194E19B8F61BBC587C20BC3A7907| +| Device::SaveScreenshot0043A540, initial call window |32|00C51A0CD7CCA7D4C8075352BDA05683B196516604719243D01C349B4C408B4A| +| RenderDeviceD3D::GenerateSurfaceFromFrontBuffer005A0210, complete body |105|BA36CC608770994E60F9566C36D269160AE4936765CAD103DAF9DE061B7A4653| + +Lead PE-section mapping gives raw offsets00039160/0003A540/001A0210. +The call at0043A553 is E808ECFFFF, resolving to00439160; the initial +GetScreenshotSurface vcall is offset3C (GenerateSurfaceFromFrontBuffer). +The D3D function's005A0256 call is FF9384000000, the named +IDirect3DDevice9 GetFrontBufferData vtable slot. The named body and bytes +agree on allocating a front-buffer-sized surface, then calling that capture. +GetScreenshotSurface crops to the client rectangle in windowed mode. +This is evidence for capturing completed front-buffer contents, NOT a claim +that Vulkan's acquired-image retained-copy technique is literal D3D retail. +The current PNG/location conventions and typed RHI lifetime remain modern +adaptations; no screenshot numbering, format or orientation change is proposed.