From a97e04ae3d565f2163485a9acd1f9f07df066f90 Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 27 Jul 2026 18:30:40 +0200 Subject: [PATCH] docs(render): record the Campaign V4a revert rules Three rules binding on every remaining slice: an RHI pass must restore GL capability state while raw-GL renderers coexist; a failing gate blocks the commit rather than being explained away; and slices stay inside their file list. Also pre-approves the external-texture bridge for the paperdoll viewport so a slice does not invent one mid-implementation. Co-Authored-By: Claude Fable 5 --- docs/plans/2026-07-27-vulkan-campaign.md | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/plans/2026-07-27-vulkan-campaign.md b/docs/plans/2026-07-27-vulkan-campaign.md index 507a4414..d728c5fc 100644 --- a/docs/plans/2026-07-27-vulkan-campaign.md +++ b/docs/plans/2026-07-27-vulkan-campaign.md @@ -575,3 +575,50 @@ work alongside V8. While V4c runs, nothing else touches `Rendering/Wb`. - Connected gates need the live ACE server and the user's machine. The visual sign-off at V10 is a required user stop; there are no others besides gate failures. + +### 7.1 Rules learned from the V4a revert (2026-07-27) + +The first V4a attempt (`ceec3bc4`) was reverted at `9aaf97e7`. Three rules come +out of it, binding on every remaining slice. + +**1. During the transition, an RHI pass must not leak GL capability state.** +Every world renderer is still raw GL until V4c/V4d, so they inherit whatever +capability state the previous pass left enabled. V4a deleted +`TextRenderGlStateScope` — which saved `GL_MULTISAMPLE` and +`GL_SAMPLE_ALPHA_TO_COVERAGE`, disabled them for the text pass, and **restored +them on exit** — and baked that state into a pipeline instead, with nothing +restoring it. The world then drew without multisampling from the first UI frame +on, changing the silhouette edge of every object in the scene. + +So: **`GlGpuPassEncoder.Dispose` saves and restores the capability state its +pipelines change**, for as long as raw-GL renderers coexist. This is not a +workaround; it is what keeps the GL backend's stated behaviour-preserving +property true at a seam where two worlds meet. It is deleted at V4h once nothing +raw-GL remains. For the same reason, the GL render-state cache must be reset at +**`BeginPass`**, not merely per frame — a raw-GL renderer running between two +RHI passes in the same frame desynchronises it just as effectively. + +This is the third time the project has hit this exact class: see the memory notes +on self-contained render state and on issue #52, where an earlier migration lost +cull state the same way. Audit per-pass GL state before declaring a port done. + +**2. A failing gate blocks the commit.** The pixel gate failed at 0.318% against +a 0.001 threshold and the slice committed anyway, attributing the difference to +ambient animation. The control refuted it: same-commit captures differ by 8–19 +pixels at both commits, versus 1,791 across the change. If a gate fails, either +find the root cause or stop and report — never rationalise past it, and never +relax the threshold. + +**3. Stay inside the slice's file list.** The brief was ~10 files; the commit +touched 334, including 323 public-to-internal conversions and 55 test files, and +retired two conformance tests. Out-of-scope churn makes a diff unreviewable and +forces revert of good work along with bad. Do not change type visibility, do not +delete or weaken tests, and do not refactor adjacent code. If the slice genuinely +cannot land without one of those, stop and report instead. + +**Pre-approved transitional seam.** The retained UI draws the paperdoll and +appraisal viewport textures, which are produced by renderers that stay raw GL +until V4g. The GL backend may therefore expose a documented way to register an +externally-owned GL texture as a table slot, used only by that path, removed at +V4g. Approved here so a slice does not have to invent it mid-implementation — +which is what turned it into an undocumented escape hatch the first time.