diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index dd14703a..bbcb13a2 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -107,40 +107,21 @@ See [`structures/ui-composable-bundles.md`](structures/ui-composable-bundles.md) title — the one screen with ground truth — it takes mean luminance from **+18 % to −1.3 %** of the capture (76.30 → 63.72 vs 64.58) and mean abs diff 16.07 → 13.08. Off by default because of the item below. -* ❔ **Where a primitive paints. ← next, and it needs the emulator.** A primitive - has no `T8aD` header, so no layer key, and the derived order forces the keyless - last — which wipes **36 of the 125** builds that draw one (`GP_DIALOG`'s - `pzeff00.prm` is a single opaque-black full-screen keyframe). No constant - default works: the splash paints its primitive **first** (a black backdrop), - the title paints one at slot **4** and another **last**, and declaration order - fails the title too. Cheapest first step: a third measured paint order from a - screen carrying exactly one primitive — the `GP_DIALOG` DIFFICULTY box, which - is reachable from the main menu, would say whether its dim is first or last. - This is a runtime child-list read, so it is an emulator item, not a static one. - 🔴 **ATTEMPTED 2026-08-19 and BLOCKED.** The reader - (`tools/re-capture/screen_children.py`) is written and validated — it - reproduces both known permutations character-for-character off the live title. - The screen could not be reached: **Ⓐ does not advance the title screen** at any - hold from 0.10 s to 0.40 s, nor does START, with the pad verified end to end. - Two harness bugs were found and fixed on the way (`--audio` is not a cvar and - broke eight boot scripts; `vgamepad` no longer exists but `skip_intro.sh` - still called it, pressing nothing while exiting 0). Neither unblocks the title. - 🔬 **2026-08-19, second attempt: a root cause found and then refuted.** With - the emulator's stdout kept, the log said it at once — `dialogs=1`, and - **8 388 601** `XamInputGetKeystrokeEx` calls discarded by `IsUIActive()`. The - dialog is a **sign-in UI opened because the requested profile does not exist**: - the script asked for `E0300000EFBEA3D4` and only `B13EBABEBABEBABE` is on disc. - Signing in the real profile takes the swallow count to **0** — and the title - *still* does not advance on a single Ⓐ. Real bug, not the explanation. - Four harness bugs fixed on the way (stdout to `/dev/null`; a title probe using - a 1280×720 pixel against the 1279×675 game surface, which caused a 600 s - timeout with the title on screen; tapping through the movies, which reaches a - title that accepts nothing; a hard-coded XUID). Boots now reach the title - reliably at ~240 s. - **Next probe:** `--log_mask=13` records no kernel *calls*, so it is not known - whether the game polls at the title at all. Add a log on the **successful** - `XamInputGetKeystrokeEx` return, mirroring the one already on the swallow path; - one boot answers it. See +* 🟡 **Where a primitive paints — three measured screens, still no derivation** + (2026-08-19). A primitive has no `T8aD` header and so no layer key. Measured + positions are stable **by role**: `palogo_eff0.prm` (opaque backdrop) **first** + on the splash; `pteff02.prm` (25 % dim) at slot **4** on both the title and the + main menu; `pteff00.prm` (transition fade) **last** on both. Nothing in the + file predicts this — any key must live in the 60-byte declaration entry, of + which four words are still unread. **That is the next first step**, and it is + a *static* task now: dump the full declaration entries for these three screens + and look for a word that sorts like the measured orders. + ✅ Input was never the blocker — the game receives the Ⓐ press + (`vk=5800 flags=0001`, measured); four harness bugs were. Boots now reach the + main menu, whose composite scores **0.9591** against a live capture. + ❔ `GP_DIALOG` DIFFICULTY remains unreached: Ⓐ on NEW GAME hits the standing + black-screen hang. + See [`structures/ui-paint-order-key.md`](structures/ui-paint-order-key.md) and [`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md). * ❔ **Blend mode.** Everything is straight alpha-over. The near-white flash quads (`0xf0ffffff`) and coloured ones (`0x60ff0000`) may be additive. The diff --git a/docs/re/ui-paint-order-third-permutation.md b/docs/re/ui-paint-order-third-permutation.md index 58aa62d2..b11106a6 100644 --- a/docs/re/ui-paint-order-third-permutation.md +++ b/docs/re/ui-paint-order-third-permutation.md @@ -73,46 +73,51 @@ skipped, which is most of why a boot takes seven minutes here. That second bug looked like it would explain the standing "Ⓐ at the title works about half the time" note. **It does not.** See below. -## 🔴 The blocker: Ⓐ does not advance the title +## ✅ Resolved: Ⓐ was never the problem — the harness was -With the pad verified end to end — `pad.py` writes `/tmp/xenia_pad.txt`, the -emulator was launched with `--hid=file --pad_file=/tmp/xenia_pad.txt`, and the -log shows `[file-pad] keystroke vk=5800 down/up` for every press — the title -screen does not advance. Holds of 0.10 s, 0.25 s and 0.40 s, Ⓐ and START, on a -screen that unambiguously renders PRESS Ⓐ BUTTON -([capture](captures/title-with-press-a-live.png)). - -### ✅ A root cause found, measured, and fixed — a sign-in dialog - -Keeping the emulator's stdout (see below) produced the line immediately: +Instrumenting the *other* side of the keystroke path settled it. The existing +`[RE-INPUT]` line only fires when `IsUIActive()` swallows a keystroke, so its +silence was ambiguous between "the game polls and gets nothing" and "the game +does not poll". Two logs were added on the reaching path (canary +`f9170fd3f`, corrected in `8d3299975`), and the boot said: ``` -w> [RE-INPUT] XamInputGetKeystrokeEx swallowed by IsUIActive (dialogs=1 nui=0, 8388601 so far) +[RE-INPUT] XamInputGetKeystrokeEx -> user=0 vk=5800 flags=0001 (call flags 00000003) +[RE-INPUT] XamInputGetKeystrokeEx -> user=0 vk=5800 flags=0002 (call flags 00000003) ``` -`xam_dialogs_shown_` is **1**, so `XamState::IsUIActive()` returns true and -`xam_input.cc` discards every keystroke — **8 388 601 of them in one boot**, -while the pad log shows presses arriving normally the whole time. +Exactly two events — a KEYDOWN and a KEYUP for `0x5800` (`VK_PAD_A`) — out of +~6 500 polls. **The game polls constantly and receives precisely the press that +was sent.** Input delivery was never broken. -The dialog is a **sign-in UI opened because the requested profile does not -exist**. `boot_menu.sh` passed `--logged_profile_slot_0_xuid=E0300000EFBEA3D4`; -the only profile on disc is `B13EBABEBABEBABE`, and the boot log says so at line -309: `FindProfiles: Adding profile B13EBABEBABEBABE to profile list`, -`ProfileManager: Found 1 Profiles`. Naming a XUID with nothing behind it is not -a harmless no-op. +With all four harness bugs fixed the boot then went straight through: title at +289 s, one Ⓐ, **main menu** ([capture](captures/main-menu-oracle.png)). -Fixed — `boot_menu.sh` now signs in whichever profile exists. **Swallowed -keystrokes: 8 388 601 → 0.** +### A slip in the instrumentation, kept because it nearly misled -### 🔴 Refuted: that was not sufficient +The first version logged on `XSUCCEEDED(result)`. `X_ERROR_EMPTY` is `0x10D2` +and `XSUCCEEDED` is `((s & 0xC0000000) == 0)`, so an **empty poll passes it** — +6 499 lines of `vk=0000` buried the two that mattered, and for a few minutes the +reading was "the driver is flooding the guest with junk keystrokes". Testing +`result == X_ERROR_SUCCESS` exactly fixes it. (The pre-existing assignment above +shares the quirk and writes `user_index_ptr` on an empty poll; left alone, since +the struct is zeroed first.) -Fixing the swallow does **not** make the title accept Ⓐ. With a valid profile -signed in and **zero** swallowed calls, the title still does not advance. So the -dialog bug was real and worth fixing, and it is not the explanation. +## ✅ And the third permutation was obtained — from the main menu -That also means `menu_draw_capture.sh`'s note — "the title that ends the boot -sequence accepts a single (A) (2 of 2 runs)" — no longer reproduces. The run -here reached the title at 239 s, pressed once, and stayed. +Not from `GP_DIALOG`: pressing Ⓐ on NEW GAME leads to the standing black-screen +hang, and no dialog object was ever constructed. But the **main menu itself** +carries two primitives, which is what the question needed. Recorded in +[`structures/ui-paint-order-key.md`](structures/ui-paint-order-key.md): + +``` +GP_TITLE.pak ratc-index 8, 16 elements +paint order: 1 3 4 2 5 8 9 6 7 15 10 11 12 13 14 0 +``` + +`pteff02.prm` (the 25 % dim) paints 4th, beneath the UI; `pteff00.prm` (the +transition fade) paints **last** — both exactly where they sit on the title +screen. The composite scores **0.9591 at shift (0,0)** against the live capture. ## Three more harness bugs, all of which read as the game misbehaving @@ -156,14 +161,13 @@ of itself can only ever report symptoms. It now keeps a log and prints its path. ## What is not settled -* 🔴 The third permutation. The reader is ready and validated; the screen is not - reachable. -* 🔴 **Why the title does not advance.** The sign-in dialog is excluded, the - `vgamepad` no-op is excluded, and the pad is confirmed delivering. The next - probe needs a log level that records kernel *calls* — at `--log_mask=13` the - only mentions of `XamInputGetKeystrokeEx` in an 84 KB log are import-table - entries, so it is not even known whether the game polls at the title. A - targeted log on the **successful** return path (mirroring the existing one on - the swallow path) would answer it in one boot. -* ❔ Only **one** screen object was resident when the harness believed the main - menu was up, where the title has seven. +* ❔ **`GP_DIALOG` DIFFICULTY is still unreached.** Ⓐ on NEW GAME leads to a + black screen the run never comes back from — the standing post-load hang, now + the only thing between here and a fourth permutation. +* ❔ **The derivation for primitives.** Three measured permutations now, and the + positions are stable *by role* (backdrop first, dim at slot 4, fade last), but + nothing in the file predicts them. A primitive has no `T8aD` header, so any + key must be in the 60-byte declaration entry; four of its words are still + unread. +* ❔ `ptframe1`/`ptframe2` rest at alpha 0 and so are not composited, but the + capture shows the menu frame plainly.