Commit graph

4 commits

Author SHA1 Message Date
Erik
5852bdb877 feat(render): Vulkan campaign V11 step 4 — retire GL from CI and gate scripts
Closes out the GL deletion by fixing the CI workflow and developer gate
scripts that still assumed a GL arm existed to compare against, build,
or select via ACDREAM_RENDER_BACKEND.

.github/workflows/headless-portability.yml: linux-graphical's "Verify
actionable unsupported-driver gate" step is deleted outright — it ran
the deleted `ui-studio` CLI verb (Studio was removed at Commit 1) to
prove the GL capability gate rejects Mesa's llvmpipe driver, and there
is no more GL capability gate for any driver to pass or fail. Its test
filter dropped two dead entries (GraphicalCapabilityRequirementsTests,
deleted at Commit 2; StudioWindowTests, already gone). Its package
contract check dropped the libcimgui.so assertion (ImGui's native
bridge, deleted at Commit 1). linux-vulkan's explanatory comment, which
described GL's rejection as the reason no cross-backend pixel diff runs
in CI, is rewritten to explain there is no GL arm left at all. Two dead
src/AcDream.UI.ImGui/** path triggers (that project no longer exists)
are removed from both the pull_request and push filters.

tools/run-backend-differential-gate.ps1 and its dedicated route file
tools/connected-backend-differential.route.txt are deleted: the whole
script's purpose was comparing a GL launch against a Vulkan launch of
the same route, and there is no second arm left to compare. Single-arm
regression checking already exists via run-offline-pixel-gate.ps1's
-Baseline mechanism.

tools/run-portal-churn-soak.ps1 is simplified rather than deleted: its
repeated-portal-churn methodology (within-arm capture comparison,
memory/entity/GPU trend analysis) has value independent of the
GL-versus-Vulkan question it was built to answer for issues #256/#257
before V11. -Backends now defaults to @('vulkan') alone; the doc
comments are rewritten from "step 0 discriminator, run before V11" to
an ongoing single-arm regression soak.

tools/run-offline-pixel-gate.ps1 drops its now-nonfunctional -Backend
parameter (ACDREAM_RENDER_BACKEND has read zero call sites since
RuntimeOptions.RenderBackend was removed at Commit 2 — passing -Backend
gl silently launched Vulkan anyway) along with its GL-escape-hatch
example and every comment that referenced the now-deleted differential
gate. tools/run-connected-world-lifecycle-gate.ps1,
tools/run-offline-vulkan-capture.ps1, and
tools/run-repeat-connected-gate.ps1 keep their (harmless, already
no-op) ACDREAM_RENDER_BACKEND set/clear lines but have their
now-inaccurate "escape hatch" / "GL run" comments corrected to state
plainly that the variable is unread and the line is kept only for the
historical record.

No .cs files touched; `dotnet build AcDream.slnx -c Release` unaffected
(0 warnings, 0 errors, matching the prior commit's build).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 03:06:45 +02:00
Erik
122fe8a7e2 feat(render): Campaign V slice V10 — Vulkan becomes the default backend
THIS CUTOVER AWAITS THE USER'S VISUAL SIGN-OFF. It is not complete. Section 7
of the campaign plan names the V10 sign-off as the only required user stop
besides gate failures, and it has not been given. This commit flips the default
and runs the battery so that the sign-off has evidence in front of it.

ROLLBACK, one line: `git revert` of this commit. It restores the GL default,
the pre-V10 escape-hatch polarity and the gate scripts' inherited backend
together; nothing else has to move with it.

An unset, empty or unrecognised ACDREAM_RENDER_BACKEND now yields
RenderBackendKind.Vulkan. Only `gl` or `opengl`, case-insensitive, selects
OpenGL. The polarity of the typo case flipped with the default and on purpose:
before V10 an unrecognised token had to land on GL because Vulkan was dark and a
typo must never silently start a backend that cannot draw; after V10 it has to
land on Vulkan for the same reason read the other way, because GL is the backend
V11 deletes. `opengl` is honoured beside `gl` because an escape hatch exists to
be found.

Three gate scripts follow the flip. run-offline-pixel-gate.ps1 gains -Backend
(default vulkan) and now FORCES all four determinism levers — backend, day
group, world day fraction, sky phase — plus ACDREAM_MSAA_SAMPLES=0, instead of
inheriting any of them. run-repeat-connected-gate.ps1 and
run-connected-world-lifecycle-gate.ps1 CLEAR ACDREAM_RENDER_BACKEND rather than
setting it, so what they exercise is the process default and an ambient override
in a caller's shell cannot make a GL run wear the default's report.

TEST PIN UPDATED, flagged as required: RenderBackend_DefaultsToGl becomes
RenderBackend_DefaultsToVulkan, and RenderBackend_AnythingElseStaysOnGl splits
into RenderBackend_SelectsGlOnlyForTheEscapeHatchTokens and
RenderBackend_AnythingElseStaysOnVulkan. Five cases replace two. No other test
is touched, weakened or deleted.

AD-46's divergence-register row moves from "dormant until the V10 cutover" to
live, in this commit, per the same-commit register rule.

Battery, all on the new default:

  complete Release suite    9,222 passed / 5 skipped / 0 failed (9 projects)
                            +5 against the pre-flip 9,217; the +5 are this
                            slice's own escape-hatch cases
  #250 family, singly       4/4 pass (none failed in the whole-suite run)
  repeat connected gate     PASS 3/3 on both columns
  world-lifecycle route     PASS, 0 failures, both sessions graceful at exit 0
  validation layer          inserted at instance AND device level by the loader,
                            zero errors and zero warnings, real frame captured
  GL escape hatch           verified by two offline launches: 4.3.0 Core Profile
                            Context, bindless present, exit 0

Every connected launch in the battery reached Vulkan with no environment
variable set, which is the flip itself under test rather than an assertion
about it.

THE PIXEL GATE IS NOT MET, AND WAS NOT RELAXED. Vulkan against a GL-era capture
taken at this commit through the escape hatch, MSAA off and both clocks pinned:
1.099e-03 masked / 3.764e-02 whole-frame, against a 0.001 threshold. 97.9% of
the difference is in the treeline band, and the masked residual of 619 px — set
against a same-backend control of 10 px — sits entirely on the silhouettes of
distant alpha-blended scenery. That is AD-46's registered population; section
5.5.19 measured the same quantity at 497 px / 8.8e-04. Below the band the two
backends are photometrically identical: mean luminance differs by 0.01 of 255.
No baseline was regenerated and no mask or tolerance was widened.

Two instrument findings are recorded in section 5.5.23. The offline gate's sky
mask is still load-bearing — this slice tried retiring it on the reasoning that
V7's clock pins had made it obsolete, and the control refuted that: two launches
of the same binary still differ by 1,011 px on GL and 482 px on Vulkan, almost
all of it in the band. The default went back to 280 with the measurement written
into the script's help. And the repeat gate's desktop witness needs an
uncontested primary monitor: a first attempt reported 1/3, and the two failing
grabs turn out to be a web browser and Discord composited over the client rect,
not a blank frame — the client's Vulkan capture rendered in all six runs.

Nothing GL, ImGui or Studio is deleted. That is V11's scope and it is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 22:32:25 +02:00
Erik
a475732587 test(render): fail the offline pixel gate on stray camera input
The offline capture window is minimised but still focusable, so a scroll or key press from whoever is at the keyboard can move the camera mid-capture. That yields two screenshots of the same scene from different camera positions and an enormous, entirely spurious pixel difference - which happened during slice V4b and was correctly discarded rather than interpreted. The gate now detects camera-affecting input in the client log and exits 2, so a perturbed run cannot be mistaken for a rendering regression in either direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 20:05:25 +02:00
Erik
86afbe2ecd test(render): add the Campaign V offline pixel gate
Seven of the campaign slices (V2, V4a-V4g) are renderer ports whose entire
acceptance criterion is that no pixel changed, and the existing connected
lifecycle route needs both a live ACE server and the user watching. That would
have made the campaign advance only when someone is at the keyboard.

The client renders the world from the DATs without ACDREAM_LIVE, so the existing
UI automation probe can capture a settled frame with no session created and no
ACE state to disturb. The gate wraps that: capture at the parent commit, capture
at slice HEAD, compare through the existing compare-screenshots CLI at the
project's pinned tolerance 2 / 0.001.

Determinism was measured rather than assumed, and the first measurement failed:
two captures at the same commit differed in 0.29% of pixels. The differences
were confined to the top ~180 rows, which is correct behavior rather than a bug
- the sky animates and the Dereth clock advances with wall time, so two launches
cannot agree there. Below the horizon everything was stable. Masking the top 280
rows brings two independent same-commit pairs to 15 and 17 differing pixels out
of 563,200 compared, a ~33x margin under the threshold. Masking the animated
band keeps the rest a strict identity check; relaxing the tolerance instead
would have hidden real regressions everywhere else.

Covers terrain and blending, scenery, static meshes, water, fog, and the whole
retained UI. Does not cover sky (masked), EnvCell interiors, particles, or the
paperdoll viewports, since the offline scene is a fixed outdoor view - so V4e,
V4f and V4g keep a user visual gate on top of this one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 15:19:43 +02:00