summaryrefslogtreecommitdiffstats
path: root/docs/04-implementation/04-real-render-walls.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/04-implementation/04-real-render-walls.md')
-rw-r--r--docs/04-implementation/04-real-render-walls.md149
1 files changed, 149 insertions, 0 deletions
diff --git a/docs/04-implementation/04-real-render-walls.md b/docs/04-implementation/04-real-render-walls.md
index f6ea39d..56b5e11 100644
--- a/docs/04-implementation/04-real-render-walls.md
+++ b/docs/04-implementation/04-real-render-walls.md
@@ -185,3 +185,152 @@ gdb leaves the VM stopped (recover with a detach-only connect);
`stepi` loops over the stub freeze the guest's userspace for minutes -
prefer breakpoints; every probe run with the caps-fill breakpoint changes
the driver's path, so keep the fill in each experiment.
+
+## 8. UPDATE 2026-10-25 #3 (SESSION 126): the fence fold landed - the service authors the Vulkan fence releases from the driver's own push bytes; the compute-dispatch shape decoded (direct C5C0 method stream, no inline QMD)
+
+**The fence wall is closed.** The client's per-frame fence wait polls a
+16 KB BO word that a submit-push INC-5 semaphore group targets
+(`[2005c017][0x45ba090][0][payload 1][0][0x02100001]`). The group sits in a
+GPFIFO entry beyond the driver's kick boundary (GP_PUT=11 while the ring
+already carries the entries it pre-built for the next submits, idx12..46),
+so the GP_PUT-bounded pump walk never decoded it and a host-side assist had
+to write the word. The service now sweeps that pre-built continuation
+itself: `sema_gr_ahead` (default 64) walks entries beyond GP_PUT through the
+ring's validated translation, accepts only pushes that pass the strict
+method-stream gate, extracts the addr-0x5c RELEASE groups and applies them
+forward-only through the standard pending ledger. Live evidence: the sweep
+finds the groups and the ledger applies the fence word once per frame;
+`VKFRAME seq=1..3/DONE` completes with no assist. The frames are still
+black - the shader work itself is unexecuted.
+
+**The compute-dispatch shape (why nothing executes).** The workload is a
+single compute dispatch (640x480 storage image). Its push is a DIRECT
+method-stream programming of the Turing compute class: `SET_OBJECT 0xC5C0`
+on subchannel 1, then the context windows (`0x7b4` local-memory window B,
+`0x2a4` shared-memory window B, `0x270`), an immediate-config block, and
+the code/const data runs (`0x3800`/`0x39C8` pairs plus a subchannel-0 data
+port stream of `0x11c`/`0x114` runs in a separate 17 KB push). There is NO
+inline-QMD write (no `0x318/0x31c/0x320..0x41c` run), so the launch capture
+that feeds the physical-engine forward path never fires - and the CE-shaped
+ops path is not even consulted for GR-class channels by construction. Real
+pixels therefore require a translator that recognizes the C5C0 section,
+builds the vendor launch the physical channel expects (the same prelude/QMD
+shape the CUDA path already executes) from the section's fields and data
+runs, and forwards it with the existing operand/relocation machinery. The
+method vocabulary overlaps the physical prelude's existing knowledge
+(`0x7b0/0x7b4`, `0x2a4`), so the landmarks for that translator are known.
+
+## 9. UPDATE 2026-10-26 (SESSION 130): the utility-channel LOAD_INLINE_DATA arm fires; the payloads are the driver's zero buffer; the SASS delivery is the remaining non-black gate
+
+**The arm was dead by branch order.** The utility channel's engine-side
+uploads ride subchannel 2 (the A140/KEPLER_INLINE_TO_MEMORY_B lane), and
+their operand group (`0x188/0x18c` destination, `0x180` line length,
+`0x184` line count) was parsed only by an `else if (subch == 1 || subch ==
+2)` branch that could never run: the preceding `if (xlate && subch >= 2)`
+TURING-copy parser also matches subchannel 2 and swallowed the group
+unread. With `have_out`/`line_len` unset, the `0x1b4
+LOAD_INLINE_DATA` arm never opened (`saw=0`). The 0x180..0x18c group is now
+parsed first for subchannel 1|2; the arm reaches its write decision and
+authors (`writes=2` on r744: 256 B -> vidmem 0x1e0000, 12288 B -> vidmem
+0x1c0000).
+
+**The payloads are stably zero - and that is the driver's zero buffer.**
+Four independent reads (the sweep's channel path, the direct
+registered-VAS walk - 22k attempts, never non-zero - the guest's own
+`/proc/<pid>/mem` view of the client's mapping, and the guest's
+`/proc/kcore` physical read) plus a whole-run 1 MB staging-BO poller and a
+gdb hardware write-watchpoint that never fires agree: the driver never
+writes the payload chunks for these entries. The 256 B size equals
+`GF100_ZERO_BUFFER_SIZE`, and the driver's `gf100DownloadZeroBuffer()`
+uploads exactly 256 B of zeros through this path. The arm therefore
+applies zero payloads under a variant once-key (`h | 1`) - idempotent over
+an empty destination - while a later non-zero payload for the same entry
+still lands under its own key.
+
+**The non-black gate, precisely.** The launch's `prog=0xdfd8feb900`
+resolves to vidmem `0x62b000`, which is empty; the compute shader SASS is
+not delivered by any decoded entry. The utility channel's ring holds
+exactly 14 entries (`GP_PUT=14`), of which two carry LOAD_INLINE_DATA -
+both the zero objects above. The Vulkan (NVN) download path uploads via a
+separate download state and points its destination view at the pitch-pool
+allocation, so the SASS/constants i2m shape is a different destination
+family than the observed zero-buffer uploads. Next steps: find the SASS
+upload shape (pitch-pool destination, possibly on another channel or a
+non-LID copy) and then the `n_data` descriptor/operand wiring
+(section 8); with both, the physical forward can execute the dispatch.
+
+## 10. UPDATE 2026-10-26 (SESSION 131): the utility-ring translation is the live problem - the decoded LID entries are from a STALE ring page; the live ring is in vidmem
+
+**The ring is in vidmem, and its content varies per client.** The
+utility channel's ring VA (0x4020000) resolves through the service's
+learned map to a **vidmem** offset (PA 0xa0000, next to the channel's
+USERD at 0x8fe00), and the pump's own entry read shows the live ring's
+content: on the r750-era clients `entry[0] va=0x120100000 len=0x28`
+(`sema-chan: entry[0] h=0xbeef0100 eng=0 raw=0000280120100000
+va=0x120100000 len=40`). A dump of the vidmem ring (dump_vidmem 0xa0000)
+confirms exactly one entry there.
+
+**The decoded LID entries (the 14-entry ring at 0x4000000/0x4250000) are
+from a STALE page.** The sweep's ring read (`svc_read_va` of the ring VA)
+can resolve a **guest-RAM** page (e.g. PA 0x13003d000) that holds an
+EARLIER client's ring - a coherent 14-entry ring whose LID uploads target
+the Vulkan client's own allocations (dst 0x423f000 -> vidmem 0x1e0000,
+dst 0x4448000 -> vidmem 0x1c0000, 256 B = GF100_ZERO_BUFFER_SIZE and
+12288 B). Those entries are real, but they belong to a dead session: the
+payload chunks they point at (VA 0x4250000/0x4250110 -> the session's
+1 MB staging BO) read zero through EVERY path - the sweep's channel read,
+the direct registered-VAS walk, the learned map, the guest's own
+`/proc/<pid>/mem` view of the BO, `/proc/kcore`, a whole-run
+high-frequency poller of every 1 MB BO the client maps, and a gdb
+hardware write-watchpoint that never fires - because the session ended
+and the BO's pages were freed/reused. **The payload is not missing from a
+live upload; it is a stale-session artifact.**
+
+**The CUDA contrast proves the mechanism.** A CUDA client's LID rows on
+the same boot show the arm working with real payloads:
+`h=0x5c000019 i=2 va=0x2004002c0 len=0xb8 ... tail_va=0x200400378
+tail=0x1c t8=200125a6 00000001 ... saw=1 fired=1 zero=0
+dst=0xd2e00000` - the tail (the next GPFIFO entry) is CONTIGUOUS with the
+push and holds a real method stream, the arm materializes it into the
+high vidmem family, and the CUDA battery passes.
+
+**Next steps (ranked).**
+1. Read the LIVE client's ring through the map (vidmem 0xa0000) during a
+ client run and decode its entries - that is the live upload path; the
+ sweep's `svc_read_va` source preference must not answer with a stale
+ RAM page (verify the ring page by content: the entries must lie in the
+ client's current VA allocations, and the ring must be the same page the
+ pump reads).
+2. With the live ring decoded, the SASS upload shape follows; the
+ descriptor/operand wiring (`n_data=0`) remains the second gate.
+3. `sema_util_dec_log` (96/boot) and `svc_gr_util_log` (24/boot) budgets
+ were exhausted early in multi-client boots, hiding later rows; make
+ them per-session for diagnosis.
+
+## 11. UPDATE 2026-10-26 (SESSION 131b): the A/B that names the frontier - CUDA's uploads land in the emulated vidmem, the Vulkan client's do not
+
+`dump_vidmem map` (new: one line per 1 MB block with non-zero content,
+`nz` = non-zero dwords) on a fresh boot, same module:
+
+* **CUDA client (`victory_mail`, STATUS OK)** - the shadow fills up:
+ `blk 0x200000 nz=40811`, `blk 0x1400000 nz=178868`,
+ `blk 0x1500000 nz=96346`, `blk 0x2a00000 nz=22880`,
+ `blk 0x7800000 nz=98257`, ... (~450k dwords total). The CUDA driver's
+ uploads (LID i2m writes with real payloads + CE copies) materialize in
+ the emulated vidmem.
+* **Vulkan client (`vk_frame120`)** - the shadow stays at the 14
+ baseline dwords (the fence/counter words at 0xfee88, the GR param bank
+ at 0x385e08, one word at 0x4d0b10). **Nothing the Vulkan client uploads
+ reaches the emulated vidmem at all.**
+
+That is the frontier in one measurement: the Vulkan (NVN/GL) driver's
+upload path is not among the writes the emulation can see. Combined with
+section 10 (the utility ring lives in vidmem via the learned map but the
+sweep can read a stale RAM page for it; the live ring holds a single
+`0x120100000/40` entry, not the 14-entry LID ring), the next session must:
+(1) capture the LIVE ring through the same source the pump uses while the
+client is up and decode its entries (the 14-entry LID ring is a
+stale-session page); (2) trace where the live client's upload writes go
+(the map shows they are NOT in the first 256 MB of the shadow - check the
+guest's own view of the client's staging BOs during the upload window);
+(3) the descriptor/operand wiring (`n_data=0`) after that.