fix #387: window resize never recreated the Vulkan swapchain (stretch)

User report: resolution picks (and window drags) stretched the image
instead of changing the pixel count. Root cause: Campaign V slice V11
deleted the GL viewport target and left a null target, assuming the
driver's OUT_OF_DATE/SUBOPTIMAL acquire/present results would drive
swapchain recreation on resize. That is driver-dependent and
spec-insufficient — this machine's Windows AMD driver keeps presenting
the stale-extent swapchain scaled to the new window indefinitely, so
OnFramebufferResize only ever updated the camera aspect while every
pass (UI included) kept rendering at the old extent.

Fix: SwapchainRecreateViewportTarget implements the existing
IFramebufferViewportTarget seam for Vulkan and arms
VulkanGraphicsContext.RequestRecreate() on every resize event; the next
PrepareFrame rebuilds the swapchain at the live FramebufferSize (bursts
collapse to one recreation, stale events cannot install a stale extent,
minimised sizes stay gated by FramebufferResizeController).

Tests: SwapchainRecreateViewportTargetTests (target contract, size-
agnostic arming, null hook, controller-to-target end-to-end with the
minimised gate). Full Debug App suite 4,941/3 skips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-13 09:05:13 +02:00
parent 2fd99c4265
commit a7ae756b44
4 changed files with 147 additions and 22 deletions

View file

@ -9,10 +9,15 @@ internal interface IFramebufferViewportTarget
}
// Campaign V slice V11 deleted SilkFramebufferViewportTarget, the GL
// implementation of IFramebufferViewportTarget: VulkanHostInputCameraComposition
// Factory's NullFramebufferViewportTarget is the sole surviving implementation
// (Vulkan's swapchain recreation owns the actual viewport-equivalent resize,
// which this seam never drove).
// implementation of IFramebufferViewportTarget, and left a null target on the
// assumption that the driver's OUT_OF_DATE/SUBOPTIMAL results would drive
// swapchain recreation on resize. That assumption is driver-dependent — a
// conformant driver may present a stale-extent swapchain scaled to the new
// window indefinitely (observed on Windows AMD; #387, the 2026-08-13
// "resolution pick just stretches" user gate report). The sole implementation
// is now VulkanHostInputCameraCompositionFactory.SwapchainRecreateViewportTarget,
// which arms the context's frame-boundary swapchain recreation on every
// resize event.
internal interface IFramebufferCameraTarget
{