diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 7c8565fa..5d880d59 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -97,6 +97,57 @@ Copy this block when adding a new issue: --- +## #259 — Win32 Vulkan surface creation fails machine-wide (`ERROR_UNKNOWN`) + +**Status:** OPEN — environment fault, not a product defect; recorded so the next +reader does not bisect the tree for it +**Severity:** HIGH while it lasts (the client cannot start at all) +**Filed:** 2026-07-29 +**Component:** host machine / AMD driver / Win32 WSI + +**Symptom:** every `AcDream.App` launch dies during startup with + +``` +VulkanCallException: vkGetPhysicalDeviceSurfaceCapabilitiesKHR returned ErrorUnknown + at VulkanSwapchain.QuerySurface() + at VulkanGraphicsContext.SelectDeviceAndGate() +``` + +**It is not our code.** Observed first during the V11 gate battery and bisected: +the failure reproduces identically at V11 HEAD, at both V11 implementation +commits, and at `db4426d5` — the **pre-V11** commit whose Vulkan soak had +completed 91 checkpoints three hours earlier on the same machine. +`VulkanSwapchain.cs` and `VulkanGraphicsContext.cs` were not modified by V11. + +**The one-line diagnosis.** Run the Khronos tool, which shares no code with us: + +``` +> vulkaninfo --summary +ERROR while creating surface for extension VK_KHR_win32_surface : failed with ERROR_UNKNOWN +``` + +If `vulkaninfo` fails there too, the fault is the machine's, not acdream's, and +no amount of bisecting the tree will find it. **Check this first** whenever the +client will not open a window. + +**State when observed:** session not locked (`LogonUI` absent), desktop present +at 2560x1440, both adapters (RX 9070 XT driver 32.0.31021.5001, and the +integrated Radeon) reporting `Status = OK` and enumerating with Vulkan 1.4. +Vulkan instance and device creation succeed; only Win32 *surface* creation +fails. It followed several hours of continuous GPU-heavy soak runs. + +**Expected remedy:** restart the display driver or reboot. Not reproduced from a +cold boot. If it recurs *after* a reboot, it stops being an environment note and +becomes a real investigation — capture `vulkaninfo --summary` and the driver +version at that point. + +**Blocked by this:** V11's runtime gate battery (offline pixel gate, both +connected routes, validation run, working-set re-measure). The pre-deletion +pixel baseline is already captured at `artifacts/v11-pre`, so the +self-differential is still available once a window can be created. + +--- + ## #258 — Developer panels have no host after V11 deleted ImGui **Status:** OPEN diff --git a/docs/plans/2026-07-27-vulkan-campaign.md b/docs/plans/2026-07-27-vulkan-campaign.md index 240a36db..1cf5d504 100644 --- a/docs/plans/2026-07-27-vulkan-campaign.md +++ b/docs/plans/2026-07-27-vulkan-campaign.md @@ -624,7 +624,7 @@ tenth pair with no consumer at all; see the V6e report. | **V8** ⏸ **measured; two floors missed; the cutover call is the user's — §5.5.21** | Perf gate on the RX 9070 XT, uncapped, both backends, same scene, same day. **What landed:** `VulkanFrameGpuMeasurement` (`00e1b321`), without which the Vulkan arm emitted no `[frame-prof]` line at all — `NullRenderFrameGpuMeasurement` was the only caller of `FrameProfiler.FrameBoundary`, so no performance vehicle could be pointed at it; the finding that **the R6 soak is NOT the vehicle §2's founding numbers came from and is biased against Vulkan** by the per-frame swapchain copy its own artifact directory arms; a same-day GL-versus-Vulkan profile on the G5 ordinary-production vehicle; a phase-level CPU attribution on both arms; and **the R6 soak run natively on Vulkan** (PASS, 0 failures, graceful exit), which V7 left outstanding. **Result, in three configurations:** on a stationary LIGHT scene at 780-870 FPS Vulkan is 75.4% cheaper on GPU p50 and 85.3% lighter on allocation but **14.8% more expensive on CPU p50 and 8.8% on p99** — two floors missed; on a stationary DENSE scene (21,024 entities, identical on both arms) **Vulkan wins every row**, including CPU p50/p99 and 18.5% less total process CPU by Windows' accounting; and on the nine-stop route against an identical world **Vulkan wins every row** and renders **27.3% more frames**. The Vulkan-specific cost is **fixed per frame** — 0.148 ms of required WSI/sync calls (present 0.070, submit 0.027, timeline wait 0.026, acquire 0.025) against GL's ~0.014 ms of present — so it dominates an almost-empty frame and disappears into a full one. **The campaign's named cost centre is closed as measured-and-not-worth-it:** bindings 4/6/7/8 cost **0.031 ms for all ~216 draws of the frame**, 2.4% of it. No Vulkan code was changed to chase the miss. **Not taken:** the RenderDoc capture — RenderDoc is not installed on this machine; it carries to V10. | §2 acceptance table; parity is the floor | | **V9** ✅ **CI green — §5.5.20, §5.5.22** | Linux + CI: a `linux-vulkan` job on lavapipe (probe accepts on a real 1.3+ software device, a short real render under xvfb, forced-unsupported → exit 4, `.spv` freshness). **What landed:** the eleven-step job; `ACDREAM_VULKAN_PROBE_FRAMES`, without which the harness cannot terminate unattended; `tools/compile-shaders.ps1` made path-portable; and the report's jq contract pinned by App tests so a rename fails locally rather than in CI. lavapipe clears every gate requirement by source inspection, including the `samplerAnisotropy` V7 made load-bearing. **Deferred:** the physical Linux GPU row, post-cutover, as for Slice L; and Wayland, which no runner offers. **Not attempted, with cause:** a GL-versus-Vulkan pixel comparison — the GL job asserts exit 4 and so has no frame, and the probe renders synthetic scenes rather than the DAT world CI cannot have. | CI green including the new job — **met**: run 30393357552, all four jobs green, lavapipe `llvmpipe (Cpu)` at Vulkan 1.4.318 / Mesa 25.2.8, a 1280x720 / 35,594-byte captured frame, and "all committed .spv match a fresh compile" on Linux | | **V10** ◐ **flipped and measured; PENDING THE USER'S SIGNATURE — §5.5.23** | Cutover: Vulkan default, GL reachable by env var for one slice, gate scripts default to VK. **What landed:** `ParseRenderBackend` inverted (unset/typo → Vulkan; only `gl`/`opengl` → OpenGL, the polarity of the typo case flipping with the default because GL is now the backend V11 deletes); `run-offline-pixel-gate.ps1` gained `-Backend` (default `vulkan`) and forces all four determinism levers plus MSAA off instead of inheriting them; the two connected gates **clear** `ACDREAM_RENDER_BACKEND` so they exercise the process default and an ambient override cannot disguise a GL run as one. **Battery:** complete Release suite **9,222 / 5 skipped / 0 failed** (`#250` family also 4/4 singly); repeat connected gate **3/3 on both columns**; connected world-lifecycle route **PASS**, 0 failures, both sessions graceful at exit 0; validation layer proven inserted at instance and device level with **zero errors and zero warnings**; GL escape hatch verified by two offline launches. **Every connected launch reached Vulkan with no environment variable set.** **The pixel gate is NOT met and was not relaxed:** VK against the GL-era capture is **1.099e-03 masked / 3.764e-02 whole-frame**, 97.9% of it in the treeline band, the masked residual entirely on distant alpha-blended scenery silhouettes — `AD-46`, whose register row this slice moves from dormant to live. Below the band the arms are photometrically identical (mean luminance Δ 0.01 of 255). Nothing GL, ImGui or Studio is deleted; that stays V11's. **Rollback: `git revert` of this slice's commit.** | complete Release suite + retail expected PNGs **on VK** (baselines not regenerated) + both connected routes + **user visual sign-off** | -| **V11** | GL deletion and closeout: delete `Gpu/Gl`, `OpenGLGraphicsDevice`, `ManagedGL*`, `GLSLShader`, `GLHelpers`, `GLStateScope`, `RenderStateCache`, `BindlessSupport`, `GraphicalGlFunctionProbe`, the GL branch in `GameWindow`, the ImGui project and Studio; drop the GL and (if the audit is clean) Chorizite packages; file the retained-UI dev-panels follow-up; swap CI assertions to VK; update the divergence register, architecture doc, code-structure doc, and rendering memory crib; re-measure memory. | complete Release suite + both connected routes + working-set re-measure | +| **V11** ◐ **DELETED AND STATICALLY GREEN; RUNTIME GATES BLOCKED BY A MACHINE-LEVEL WSI FAULT — §5.5.24** | GL deletion and closeout. **What landed (5 commits, `844cf092`→`c265b52d`): 204 files, +1,870 / −27,607 lines.** The GL backend, `ManagedGL*`, `GLHelpers`, `GLStateScope`, both render-state caches, `BindlessSupport`, `GraphicalGlFunctionProbe`, the ImGui project, the Studio tree and the `ui-studio` verb are gone; `RenderBackendKind` and the `ACDREAM_RENDER_BACKEND` escape hatch are gone with them. `Silk.NET.OpenGL` and `.Extensions.ARB` dropped — **final reference count zero**. `common.glsl`'s GL-only binding-9 texture table and every `GL_ARB_bindless_texture` pragma removed; 9/9 shader pairs recompile. **Two traps the plan did not anticipate:** `Studio/SampleData.cs` was a live production dependency of the retained-UI composition (moved, not deleted) and `ACDREAM_DEVTOOLS` also gates Vulkan debug-utils (kept, now logs that the UI is gone). **Chorizite stays** — the audit is NOT clean: `TextureFormat` is in surviving texture-array signatures and `BoundingBox` is a serialized pak type. **Static gates PASS:** Release build 0 warnings / 0 errors; complete Release suite **8,999 passed / 5 skipped / 9,004** (−218 against V10's 9,222, every one a GL/Studio/DevTools test that lost its subject). **Runtime gates NOT RUN:** the offline pixel gate, both connected routes, the validation run and the working-set re-measure all need a window, and this machine cannot currently create one — see §5.5.24. **Rollback:** revert `c265b52d`, `5852bdb8`, `7a0227c1`, `8a7a0837`, `844cf092`, newest first. | complete Release suite ✅ + both connected routes ⚠ outstanding + working-set re-measure ⚠ outstanding | ### 5.2 Why V2's handle table is not the device's table @@ -3473,6 +3473,96 @@ notes that the reason it was demoted no longer obviously applies. outstanding: V8 established the cause — RenderDoc is not installed on this machine — and nothing about the cutover changes that. It carries to V11. +#### 5.5.24 V11 (2026-07-29): the deletion lands, and the machine stops making windows + +**The deletion is done and the static gates pass.** Five commits removed 27,607 +lines against 1,870 added. What went is listed in the V11 row; what stayed, and +why, is the part worth keeping. + +**Chorizite could not be dropped, and the reason is not the one the risk +register predicted.** §6 assumed the package survived only because +`ManagedGLUniformBuffer` and `OpenGLGraphicsDevice` implemented `IUniformBuffer` +from it — so deleting them would free it. The audit found otherwise: +`Chorizite.Core.Render.Enums.TextureFormat` sits in the +`IWorldTextureArray.CreateClampedArray` signature that the **Vulkan** path +implements, `AcDream.Core/Rendering/Wb/TextureHelpers.cs` needs it, and +`Chorizite.Core.Lib.BoundingBox` is a **serialized type in the pak format** via +`AcDream.Content`. Dropping it is a separate slice that touches the on-disk +format, not a V11 cleanup. The stale justification comment in the csproj is +corrected in place so the next reader is not misled the same way. + +**Two traps the plan's V11 row did not know about**, both of which would have +broken the build or the client if taken literally: + +1. `Studio/SampleData.cs` is **production code**. + `InteractionRetainedUiComposition` passes `SampleData.SampleCharacter` as the + character sheet's fallback, and three surviving UI-layout test files use it + about ninety times. It was moved to `UI/Layout/`, not deleted. +2. `ACDREAM_DEVTOOLS` is **not only** a devtools switch — it also selects + Vulkan's debug-utils instance extensions in `VulkanGraphicsContext`. The flag + survives; only the ImGui frontend went, and setting it now logs one line + saying so rather than silently doing nothing. + +**One real bug fell out of the deletion.** `WbMeshAdapter.Dispose()` was still +pattern-matching the deleted `GpuFrameFlightController` to decide whether to +wait for submitted GPU work. `VulkanFrameFlightController` replaced that type at +V6a and this site was never updated, so **the wait had been silently dead on +every Vulkan run since V6a**. Deleting the GL type is what made it a compile +error instead of a no-op. + +--- + +**The runtime gates did not run, and the reason is not V11.** + +The offline pixel gate failed with the client dying at startup: + +``` +VulkanCallException: vkGetPhysicalDeviceSurfaceCapabilitiesKHR returned ErrorUnknown + at VulkanSwapchain.QuerySurface() + at VulkanGraphicsContext.SelectDeviceAndGate() +``` + +`VulkanSwapchain.cs` and `VulkanGraphicsContext.cs` are **untouched by V11**, so +the first move was to bisect rather than to theorise. The client fails +identically at V11 commit 2, at V11 commit 1, and at **`db4426d5`, the pre-V11 +commit whose Vulkan churn arm had completed 91 checkpoints three hours earlier +and whose offline capture had succeeded.** + +That put the fault outside the tree, and one command settled it: + +``` +> vulkaninfo --summary +ERROR while creating surface for extension VK_KHR_win32_surface : failed with ERROR_UNKNOWN +GPU0: AMD Radeon RX 9070 XT apiVersion 1.4.349 +GPU1: AMD Radeon(TM) Graphics apiVersion 1.4.315 +``` + +**A Khronos tool containing no acdream code fails at the same call.** Vulkan +itself is healthy — both adapters enumerate and report 1.4 — but *Win32 surface +creation is broken process-wide on this machine*. The session is not locked, +`LogonUI` is not running, the desktop is present at 2560x1440 and both adapters +report `Status = OK`. This is transient driver/compositor state, of the class a +reboot or a display-driver restart clears. + +**So V11 is committed and statically green, and its runtime evidence is +outstanding.** Nothing was relaxed to manufacture a pass and nothing was +declared green on a prediction — §7.1 rule 2 cuts both ways, and a gate that +could not run is not a gate that passed. When the machine can make a window +again, the outstanding list is exactly: + +| Gate | Command | +|---|---| +| Offline pixel gate (VK self-differential) | `tools/run-offline-pixel-gate.ps1 -Out artifacts/v11-post -Baseline artifacts/v11-pre -SkipBuild` — **the pre-deletion baseline was captured before the deletion and is already on disk at `artifacts/v11-pre`** | +| Repeat connected gate | `tools/run-repeat-connected-gate.ps1 -Runs 3` | +| Connected world-lifecycle route | `tools/run-connected-world-lifecycle-gate.ps1` | +| Validation proven-loaded, zero errors | any connected launch with `ACDREAM_DEVTOOLS=1` | +| Working-set re-measure | the offline scene, once it renders | + +The baseline capture being taken *before* the deletion is the one piece of +timing that survived the fault: the left-hand side of the self-differential +exists, so the comparison is still available whenever the right-hand side can be +produced. + ### 5.4 The null-target `BeginPass` divergence (V4c) — ✅ DISCHARGED at V6k > **Closed 2026-07-28 by V6k commit 2 (`eb7e6b4e`); see §5.5.16.** The answer is