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 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-08 23:55:50 -04:00
parent 5817102b59
commit 68d52f218a
3 changed files with 25 additions and 5 deletions

View File

@@ -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.
---

View File

@@ -113,6 +113,7 @@ public sealed class GfxState
/// <summary>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.</summary>
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)

View File

@@ -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;