From ac481b4002ae0ef57df3c58ed012223effbf07d6 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Wed, 8 Jul 2026 23:55:50 -0400 Subject: [PATCH] diag+docs: confirm grey-BG root cause = unfilled slot-table (label_125bd via stubbed coroutine op 0x140) Traced end-to-end (AGE_DIAG_SETTEX): set-texture slot=G[0x62452] <- query-gfx-object? (-1 for unregistered CG handles) -> fallback lookup-array-2d(rec[s3]=G[0x3239])=0 because the slot table is never filled: label_125bd (SC0000 0x50f, slots 4..13) is gated behind the scene-coroutine framework (0x140 coroutine-yield, stubbed). Adds env-gated VM set-texture/query slot diagnostics + GfxState.IsRegistered. Co-Authored-By: Claude Opus 4.8 --- docs/engine-re.md | 19 ++++++++++++++----- engine/Age.Engine/Model/GfxState.cs | 1 + engine/Age.Engine/Vm/VirtualMachine.cs | 10 ++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/engine-re.md b/docs/engine-re.md index 40c12c9..819175d 100644 --- a/docs/engine-re.md +++ b/docs/engine-re.md @@ -637,11 +637,20 @@ Diagnosed with the new `--gfx-log` compositor/op trace (docs/tools-reference.md) the effect spritesheet (`AE001H`, an 800×400 4×2 grid of blob frames) **all set-texture into slot 0**. Objects live-reference their slot, so loading the effect **evicts** the BG → grey; and the effect is drawn full-screen from slot 0 (its object `src=(0,0 800x600)`) → the whole sheet (blob grid) covers the - screen. ⇒ The layering failure is a **slot-assignment** problem: the slot-selecting globals aren't - populated (unseeded boot/gfx state, or a stubbed op the display subroutine relies on), collapsing the - scene into one slot. **Open (next):** trace an effect-display subroutine to find which global holds the - slot and why it's 0 (`--boot`/INIT2 gap vs a stubbed slot-compute op). Same class as the known - `G[0x624xx]` gfx boot-state gap. NOT a compositor/z-order/blend bug. + screen. ⇒ The layering failure is a **slot-assignment** problem. **CONFIRMED CAUSE (2026-07-08, live + `AGE_DIAG_SETTEX` trace):** every `set-texture` slot = `G[0x62452]`, written by `query-gfx-object?` + (`0x215`) which returns **-1** for the (correctly-unregistered) CG/effect handles → the fallback at + SC0000 `label_12649` does `G[0x62452] = lookup-array-2d(rec[s3]=G[0x3239], G[0x62450], 3, 0)` = **0** + because the slot table `rec[s3]`/`G[0x3239]` is **empty**. That table is filled by `call label_125bd` + (SC0000 `0x50f`, slots 4..13), which is reached **only through the scene-coroutine framework** — the + `G[0xaba5c]` gate (`0x450`) + op `0x140` (`u0041F9C0`, coroutine LABEL/yield `"LABEL" "J"` @ `0x46d`). + **Op `0x140` is stubbed** (SC0000 GAP list) → the coroutine re-entry never routes through `label_125bd` + → slot table stays 0 → all layers collapse into slot 0. This is exactly the "second still-latent gap" + flagged above (§"the render drift's second half"), now confirmed as the cause of the visible grey BG on + multi-object pages. **Fix = implement the scene-coroutine framework (`0x7b`/`0x7c`/`0x140` + `G[0xaba5c]` + gate) so `label_125bd` runs** (or, as a targeted unblock, run `label_125bd`/seed `G[0x3239]` directly). + NOT a compositor/z-order/blend bug. Diagnostics: `AGE_DIAG_SETTEX=1` env → VM logs each `set-texture` + slot operand + `query-gfx-object?` result. --- diff --git a/engine/Age.Engine/Model/GfxState.cs b/engine/Age.Engine/Model/GfxState.cs index b3988ee..52b3d42 100644 --- a/engine/Age.Engine/Model/GfxState.cs +++ b/engine/Age.Engine/Model/GfxState.cs @@ -113,6 +113,7 @@ public sealed class GfxState /// Op 0x215 (query-gfx-object): native returns std::map::find(handle) — the registered value (=handle), /// or 0xffffffff (=-1) when the handle was never 0x1a2-registered. NOT a fabricated slot allocator. public int QuerySlot(long handle) => _registry.Contains(handle) ? (int)handle : -1; + public bool IsRegistered(long handle) { lock (_lock) { return _registry.Contains(handle); } } public long QueryField(long idx) => _fieldTable.TryGetValue(idx, out var v) ? v : 0; public void Release(long handle) diff --git a/engine/Age.Engine/Vm/VirtualMachine.cs b/engine/Age.Engine/Vm/VirtualMachine.cs index 8d24278..992ae98 100644 --- a/engine/Age.Engine/Vm/VirtualMachine.cs +++ b/engine/Age.Engine/Vm/VirtualMachine.cs @@ -16,6 +16,7 @@ public sealed class VirtualMachine private readonly IHost _host; private readonly VmOptions _o; private readonly IScriptProvider? _provider; + private static readonly bool _diagSetTexture = System.Environment.GetEnvironmentVariable("AGE_DIAG_SETTEX") == "1"; private ExecFrame _cur = null!; private int _depth; private readonly ITraceSink _sink; @@ -221,6 +222,9 @@ public sealed class VirtualMachine Gfx.ClearSurface((int)Read(a[0])); _host.CreateTexture((int)Read(a[0]), (int)Read(a[1]), (int)Read(a[2])); return pc + 1; case "set-texture": // 0x1f9 (resId)(slot)(colorkey) — load a file into the slot's surface + if (_diagSetTexture) // AGE_DIAG_SETTEX: log the SLOT operand source (literal vs which global) — grey-BG slot dig + System.Console.Error.WriteLine($"[settex] resId=0x{Read(a[0]):x} slot={(int)Read(a[1])} " + + $"slotOp=(type={a[1].Type} val=0x{a[1].Value:x}){(a[1].Type == 3 ? $" G[0x{a[1].Value:x}]" : "")}"); Gfx.SetSurface((int)Read(a[1]), Read(a[0]), a.Count > 2 ? Read(a[2]) : 0); _host.SetTexture(Read(a[0]), (int)Read(a[1])); return pc + 1; // host still tracks dims for get-texture-size case "draw-texture": // 0x1fb (handle)(slot)(srcX)(srcY)(w)(h)(dstX)(dstY) — bind object -> surface + rect + pos @@ -238,6 +242,12 @@ public sealed class VirtualMachine case "play-voice": _host.PlayVoice(Read(a[0])); return pc + 1; // ---- gfx command-buffer ops (VM-internal GfxState; docs/engine-re.md op-contract table) ---- case "query-gfx-object?": // 0x215 (out)(handle) -> slot | -1 + if (_diagSetTexture) // reuse the flag: show what the slot query returns (grey-BG slot dig) + { + long h = Read(a[1]); + System.Console.Error.WriteLine($"[query] handle=0x{h:x} handleOp=(type={a[1].Type} val=0x{a[1].Value:x}) " + + $"-> QuerySlot={Gfx.QuerySlot(h)} registered={Gfx.IsRegistered(h)}"); + } Write(a[0], Gfx.QuerySlot(Read(a[1]))); return pc + 1; case "query-gfx-field?": // 0x216 (out)(idx) Write(a[0], Gfx.QueryField(Read(a[1]))); return pc + 1;