fix(ui): wait for private viewport mesh residency

This commit is contained in:
Erik 2026-08-25 19:16:53 +02:00
parent 82e4b4cb6d
commit f160f3fee1
3 changed files with 476 additions and 63 deletions

View file

@ -26,8 +26,7 @@ What does NOT go here:
## #443 — Examination/paperdoll private viewport: doll appears only after a delay on first open (was: "renders nothing")
**Status:** OPEN (narrowed at the gate — intermittent first-open DELAY, not
a hard break; NOT gate-blocking, owner passed the Campaign AS gate with it).
**Status:** FIXED / OWNER-ACCEPTED 2026-08-25.
**Component:** private entity viewports (examination clone, inventory
paperdoll — shared `PrivateEntityViewportRenderer`).
**Filed:** 2026-08-25, AS-GF1 gate-fix session. **Narrowed same day at the
@ -46,6 +45,20 @@ extras rows at small window heights) is the authored scroll-less
clipped-list behavior AS-GF1 ruled retail-correct below, plus the clip
line moving with resize — owner-accepted at the gate.
**Fix:** `PrivateEntityViewportRenderer.EntitySlot` now uses a two-phase
mesh-residency handoff. A replacement first acquires/pins its complete mesh
ownership set, remains pending while each drawable `MeshRef` crosses the
render-thread upload barrier, then atomically replaces the active entity and
texture-owner generation. While a replacement is pending the renderer keeps
the last completed viewport texture; on first open it publishes no texture so
the authored panel art remains visible instead of exposing a black-cleared
render target. The slot also detects GfxObj-id changes made in place by the
animated appraisal/chargen paths and supersedes stale pending owners without
leaking references. Focused paperdoll, appraisal, draw-order, synthetic-owner,
and new residency tests pass 30/30; the App hermetic lane passes 6,358/6,358.
The owner then live-verified repeated inventory and monster/player assessment
opens against the local ACE test server: "Good. works."
Owner report at the Campaign AS connected gate: the animated 3-D paperdoll
in the examination window (LayoutDesc `0x2100006B` element `0x10000148`)
worked correctly at baseline `974fe88a` (praised the same session) and was
@ -107,23 +120,15 @@ Campaign AS diff for either symptom:**
presenter at all) are byte-for-byte UNCHANGED across the whole
`974fe88a..87e98395` window (`git log -p` for both files is empty).
**Conclusion:** the trigger is one of `TryGetVisibleTarget`'s
`CurrentObjectId` check or `TrySynchronize`'s `LiveEntityRuntime.
TryGetWorldEntity`/`MeshRefs.Count` check, in code nothing in Campaign AS
touches — meaning either a pre-existing, previously-latent condition this
gate round happened to trigger, or a live/timing condition a hermetic test
cannot reproduce (no live entity, no live wire exchange).
**Probe added this session** (temporary — delete with the real fix):
`ACDREAM_PROBE_CREATURE_APPRAISAL_VIEWPORT=1`
`CreatureAppraisalViewportDiagnostics` in `CreatureAppraisalPresentation.cs`
logs `[AS-GF1-PROBE] creature-appraisal viewport: <reason>` on every REASON
TRANSITION (not every frame) from both `TryGetVisibleTarget` and
`RetailCreatureAppraisalCloneFactory.TrySynchronize`. Next step: relaunch
with the flag set, examine a player, and read which one of the five
possible reasons (`no ActiveView`, `windowFrame hidden`, `viewport hidden`,
`no CurrentObjectId`, `entity not found`, `no MeshRefs`) fires — that
pinpoints the real fix.
**Conclusion after live recurrence:** the temporary probe ruled out every
higher-level gate: the target, clone, 34 MeshRefs, camera and nonzero texture
handle were all healthy while the pane was visibly empty. The shared slot had
published the clone immediately after `IncrementRefCount`, but that operation
only schedules asynchronous preparation/upload. The private pass then cleared
its target to black while `WbDrawDispatcher` skipped every nonresident mesh.
Residency/backlog timing explains both intermittent first-open delay and the
same symptom across inventory and monster/player examination. The probe was
deleted in `ddbd7e40` per the probe-dies rule; no diagnostic flag remains.
## #442 — Flake: DirectionalShadowCasterFrameTests.WarmDenseChangedFrames_AllocateZeroAndReadNoSceneRecords fails intermittently under full parallel suite load