diff options
| -rw-r--r-- | kernel/gsp_phys_booter.c | 124 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 171 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.h | 2 | ||||
| -rw-r--r-- | tools/guest-diag/params-r1624.txt | 1 | ||||
| -rw-r--r-- | wiki/Project-Status.md | 37 |
5 files changed, 317 insertions, 18 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index cf3107f..e43ba23 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -5280,7 +5280,7 @@ MODULE_PARM_DESC(sema_mme_post_ms, */ static u32 gsp_phys_mme_shadow_read(void __iomem *bar0, u32 nvclass, u32 mthd) { - iowrite32(nvclass | ((mthd & 0xfffu) << 16) | (1u << 30), + iowrite32(nvclass | (((mthd >> 2) & 0xfffu) << 16) | (1u << 30), bar0 + 0x00404488u); return ioread32(bar0 + 0x0040448cu); } @@ -19957,6 +19957,35 @@ module_param_named(sema_sph_bind_mask, gsp_phys_rmcall_gr_sph_bind_mask, MODULE_PARM_DESC(sema_sph_bind_mask, "Synth SPH-BIND slot mask (bit j = slot j; 0x20 = PS only, 0x01/0x10 = VSA/GS VTG image, 0x25 = VSA+PS) used when sema_gl_sph_bind=0"); +/* + * eng51 (CONT.512): the synthesized VSA/GS (j0/j4) bind the VTG SPH image. + * The historical address was family+0x900, but the live direct-GL family + * page reads zero there (c716: DS 0x86040624 with stage=01df0900,...). + * family+0x600 was tried as the VTG image (INLINE-WRITER: 0x020a0481), but + * the engine-visible alias shadow at +0x600 is the client's SASS upload + * (0x0b0b7208), so binding it poisons the DS (c718/c720: badf1201 with the + * j1 override off too). Default 0 = keep the historical +0x900 zero page + * until a real VTG SPH is authored at an engine-visible VA; A/B with 1. + */ +static bool gsp_phys_rmcall_gr_sph_vtg600; +module_param_named(sema_gl_sph_vtg600, gsp_phys_rmcall_gr_sph_vtg600, + bool, 0644); +MODULE_PARM_DESC(sema_gl_sph_vtg600, + "Bind the synthesized VSA/GS (j0/j4) stages to family+0x600 instead of the historical family+0x900 page (default 0: the live +0x600 alias shadow is SASS and poisons the DS)"); + +/* + * eng51 A/B (c718): overriding the window's own slot-1 bind (j1) with the + * family+0x600 image is a separate question. c718 (override on) poisoned the + * DS (badf1201) while c716 (j0/j4 at 0x900, j1 at the client's 0x300 SASS + * pointer) reached 0x86040624, so the j1 override is default OFF until a + * same-boot A/B says otherwise. + */ +static bool gsp_phys_rmcall_gr_sph_vtg_j1; +module_param_named(sema_gl_sph_vtg_j1, gsp_phys_rmcall_gr_sph_vtg_j1, + bool, 0644); +MODULE_PARM_DESC(sema_gl_sph_vtg_j1, + "Also point the window's own slot-1 (VTG) bind at family+0x600 instead of the client's captured bind (default 0; c718 poison A/B)"); + bool gsp_phys_rmcall_gr_sph_bind_value(void) { return READ_ONCE(gsp_phys_rmcall_gr_sph_bind); @@ -30660,6 +30689,8 @@ gr_page_unmapped: static u32 sph_bind_log; u64 fam = req->prog_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1); + u64 vtg_va = READ_ONCE(gsp_phys_rmcall_gr_sph_vtg600) ? + (fam + 0x600u) : (fam + 0x900u); u32 in[96], out[96]; u32 nfin = 0, nrun = 0, on = 0, odrop = 0, orel; u32 bi; @@ -30960,6 +30991,16 @@ gr_page_unmapped: if (!va || nfin + 3u > 96u) continue; + /* + * eng51: the window's own slot-1 bind can be + * a SASS pointer (c716: family+0x300 starts + * 0x0d0d7623); the VTG SPH image is at + * family+0x600. Point the VTG slot at the + * real image when the knob is on. + */ + if (sl == 1u && + READ_ONCE(gsp_phys_rmcall_gr_sph_vtg_j1)) + va = vtg_va; in[nfin++] = 0x20000000u | (2u << 16) | ((0x2014u + sl * 0x40u) >> 2); in[nfin++] = (u32)(va >> 32) & 0xffu; @@ -30981,9 +31022,7 @@ gr_page_unmapped: (emit_j5 ? (bind_binding ? 8u : 7u) : 0u) + (emit_gsimg ? (9u + ((gs_mode & 1u) ? 11u : 0u) + ((gs_ctx & 1u) ? 2u : 0u) + - ((gs_ctx & 2u) ? 2u : 0u)) : 0u) + - (emit_raster ? 17u : 0u) + - (emit_raster_extra ? 16u : 0u) + ((gs_ctx & 2u) ? 2u : 0u)) : 0u) <= 96u) { /* * SESSION 155 CONT 9: pair_safe emits each @@ -31043,14 +31082,14 @@ gr_page_unmapped: if (emit_j0) { in[nfin++] = 0x20000000u | (2u << 16) | (0x2014u >> 2); - in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu; - in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu; + in[nfin++] = (u32)(vtg_va >> 32) & 0xffu; + in[nfin++] = (u32)vtg_va & 0xfffffffcu; } if (emit_j4) { in[nfin++] = 0x20000000u | (2u << 16) | (0x2114u >> 2); - in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu; - in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu; + in[nfin++] = (u32)(vtg_va >> 32) & 0xffu; + in[nfin++] = (u32)vtg_va & 0xfffffffcu; } if (emit_j2) { in[nfin++] = 0x20000000u | (2u << 16) | @@ -31259,6 +31298,19 @@ gr_page_unmapped: nrun++; if (emit_gsimg) nrun++; + } else if (sph_bind_log < 64u) { + /* + * eng51 (CONT.512): name the silent budget + * skip. Before this receipt the stage block + * (j0/j2/j4/j5/gsimg) could vanish while the + * prelude still emitted with only the j1 bind, + * leaving VSA/TCS/GS unbound and the DS latch + * at the a2040a04 class. + */ + sph_bind_log++; + pr_info("vgsp-gr: SPH-BIND-STAGE-SKIP reason=budget nfin=%u mask=0x%x h=0x%x push=0x%llx\n", + nfin, sph_bind_mask, req->h_object, + req->push_va); } orel = gsp_phys_rmcall_gr_3d_patch_window( in, nfin, out, &on, &odrop, req, &n_shadow, @@ -31272,8 +31324,8 @@ gr_page_unmapped: sph_bind_log++; pr_info("vgsp-gr: SPH-BIND emitted fam=0x%llx win-binds=%u j0=0x%llx j2=0x%llx j4=0x%llx j5=0x%llx j1-type=0x11 rc=0x1a initblk=17 win=%u (pre=%u) h=0x%x push=0x%llx\n", fam, req->n_prog_binds, - fam + 0x900u, fam + 0x200u, - fam + 0x900u, fam, + vtg_va, fam + 0x200u, + vtg_va, fam, win3d_n, nfin, req->h_object, req->push_va); @@ -37250,6 +37302,52 @@ static const struct file_operations gsp_phys_init_push_fops = { }; /* + * eng51 (CONT.512): gsp-phys-last-push - the most recent >=4 KiB beef push + * (the direct-GL draw stream; c714: 0x4250110). Same text format as the + * init-push dump so the RT bind / draw methods can be decoded offline after + * the guest recycles its pushbuffer. + */ +static int gsp_phys_last_push_show(struct seq_file *m, void *unused) +{ + const u8 *buf; + u32 len, h, off; + u64 va; + + buf = gsp_sema_last_cap_get(&len, &h, &va); + if (!len) { + seq_puts(m, "vgsp-last-push: empty (no later >=4 KiB beef push captured yet)\n"); + return 0; + } + seq_printf(m, "vgsp-last-push: h=0x%x va=0x%llx len=%u\n", h, va, len); + for (off = 0; off + 4u <= len; off += 16u) { + u32 k, n = min_t(u32, 4u, (len - off) / 4u); + + seq_printf(m, "%06x:", off); + for (k = 0; k < n; k++) { + u32 w; + + memcpy(&w, buf + off + k * 4u, 4); + seq_printf(m, " %08x", w); + } + seq_putc(m, '\n'); + } + return 0; +} + +static int gsp_phys_last_push_open(struct inode *inode, struct file *file) +{ + return single_open(file, gsp_phys_last_push_show, NULL); +} + +static const struct file_operations gsp_phys_last_push_fops = { + .owner = THIS_MODULE, + .open = gsp_phys_last_push_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* * SESSION 153-CONTINUED-95: gsp-phys-ctx-dump - raw binary readback of the * engine context buffer (see gsp_phys_ctx_readback_try). Empty until the * first launch of the boot has run the CE readback. @@ -37483,6 +37581,12 @@ int gsp_phys_boot_debugfs_init(void) &gsp_phys_init_push_fops); if (IS_ERR_OR_NULL(file)) pr_warn("vgsp-boot: debugfs file gsp-phys-init-push creation failed (init-push capture unavailable)\n"); + /* eng51 (CONT.512): the most recent large beef push (direct-GL draw). */ + file = debugfs_create_file("gsp-phys-last-push", 0444, + gsp_phys_debugfs_root, NULL, + &gsp_phys_last_push_fops); + if (IS_ERR_OR_NULL(file)) + pr_warn("vgsp-boot: debugfs file gsp-phys-last-push creation failed (last-push capture unavailable)\n"); /* * SESSION 153-CONTINUED-95: raw binary dump of the engine context * buffer readback (64 KB from GSP_PHYS_RMCALL_VA_GR_CTX, taken once diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 9ba7ed0..96fabcf 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -11907,12 +11907,132 @@ static bool svc_gl_window_state_push(const u8 *buf, u32 len, u32 start_off) return w0 == SVC_FB_STATE_LEAD; } +/* + * eng51 (CONT.512): the RT0-bearing class exemption for the beef draw + * window. The client's direct-GL draw window leads with a REAL + * colour-target bind run (INC cnt=6 at 0x840 binding the client's own + * surface class 0x0a000000/0x0c000000: A fmt<=1, B aligned <1<<30, + * W/H 0x780/0x438) and then continues with a large data region whose + * INC span (hdr 0x3100020x = INC cnt=0x100 mthd=0x804) makes the + * LAST-write heuristic (svc_gl_window_rt_valid) see values of the blob + * class at the RT methods (RT1 A=0xff B=0x000480a1 -> VA 0xff000480a0, + * W/H out of range), so the window was refused before SPH-BIND was ever + * reached (c704-6: `beef draw-synth: no valid last colour-target bind`, + * win=264 words @off=0x4b4). The engine walks the leading bind FIRST, + * so a window whose FIRST write to any target is a usable bind in the + * surface class is a legitimate rt0-bearing replay; windows whose only + * bind is the blob class (eng25 c344 garbage) stay refused. + */ +static bool svc_gl_rt0_class_admit = true; +module_param_named(sema_gl_win_rt0_admit, svc_gl_rt0_class_admit, bool, 0644); +MODULE_PARM_DESC(sema_gl_win_rt0_admit, + "Admit a beef draw-synth window to the verbatim replay lane when its FIRST colour-target write is a usable surface-class bind even if the last-write heuristic refuses it (default 1)"); + +static bool svc_gl_window_rt_first_valid(const u8 *buf, u32 len, u32 start_off, + u32 at_off) +{ + u32 A[4] = { 0 }, B[4] = { 0 }, W[4] = { 0 }, H[4] = { 0 }; + bool sa[4] = { false }, sb[4] = { false }; + bool sw[4] = { false }, sh[4] = { false }; + u32 o = start_off, j; + + if (!buf || start_off >= at_off || at_off > len) + return false; + while (o + 4u <= at_off) { + u32 h, op, cnt, m, span = 1u, k; + + memcpy(&h, buf + o, 4); + op = (h >> 29) & 7u; + cnt = (h >> 16) & 0xfffu; + m = (h & 0x1fffu) << 2; + if ((op == 1u || op == 3u || op == 5u) && cnt && + o + 4u + cnt * 4u <= at_off) + span = 1u + cnt; + for (k = 0; k < span; k++) { + u32 mm = m + 4u * k, v = 0; + + if (k && op != 1u && op != 3u) + break; + if (k) + memcpy(&v, buf + o + 4u + k * 4u, 4); + else if (op == 4u) + v = (h >> 16) & 0x1fffu; + else + continue; + for (j = 0; j < 4u; j++) { + u32 base = 0x800u + j * 0x40u; + + if (mm == base && !sa[j]) { + A[j] = v; sa[j] = true; + } else if (mm == base + 4u && !sb[j]) { + B[j] = v; sb[j] = true; + } else if (mm == base + 8u && !sw[j]) { + W[j] = v; sw[j] = true; + } else if (mm == base + 0xcu && !sh[j]) { + H[j] = v; sh[j] = true; + } + } + } + o += span * 4u; + } + for (j = 0; j < 4u; j++) + if (sb[j] && sw[j] && sh[j] && + (A[j] & ~0xffu) == 0 && (A[j] & 0xffu) <= 1u && + B[j] >= 0x08000000u && B[j] < 0x40000000u && + (B[j] & 3u) == 0 && W[j] > 0 && W[j] <= 0x4000u && + H[j] > 0 && H[j] <= 0x4000u) + return true; + /* + * eng51: bounded miss witness. The c710-7 refusals were a 375-word + * window class (@off=0x640, push 0x40ef9d8/0x410f9d8) whose + * first-valid groups did not match the exemption; name the bytes + * and the groups so the next miss is one grep away. + */ + { + static u32 rt0_miss_log; + u32 w0 = 0, w1 = 0, w2 = 0, w3 = 0; + + if (gsp_sema_dbg && rt0_miss_log < 8u) { + rt0_miss_log++; + if (start_off + 16u <= at_off) { + memcpy(&w0, buf + start_off, 4); + memcpy(&w1, buf + start_off + 4, 4); + memcpy(&w2, buf + start_off + 8, 4); + memcpy(&w3, buf + start_off + 12, 4); + } + pr_info("sema-gl: RT0-FIRST-MISS start=0x%x at=0x%x w0..3=%08x %08x %08x %08x groups A=%08x,%08x,%08x,%08x B=%08x,%08x,%08x,%08x W=%08x,%08x,%08x,%08x H=%08x,%08x,%08x,%08x seen=%d%d%d%d/%d%d%d%d\n", + start_off, at_off, w0, w1, w2, w3, + A[0], A[1], A[2], A[3], + B[0], B[1], B[2], B[3], + W[0], W[1], W[2], W[3], + H[0], H[1], H[2], H[3], + sa[0], sa[1], sa[2], sa[3], + sb[0], sb[1], sb[2], sb[3]); + } + } + return false; +} + static bool svc_gl_window_drawwin_ok(const u8 *buf, u32 len, u32 start_off, u32 at_off) { if (svc_gl_window_state_push(buf, len, start_off)) return true; - return svc_gl_window_rt_valid(buf, len, start_off, at_off); + if (svc_gl_window_rt_valid(buf, len, start_off, at_off)) + return true; + if (READ_ONCE(svc_gl_rt0_class_admit) && + svc_gl_window_rt_first_valid(buf, len, start_off, at_off)) { + static u32 rt0_adm_log; + + if (rt0_adm_log < 16u) { + rt0_adm_log++; + pr_info("sema-gl: 3D mark admitted (RT0-bearing class: first-bind valid, last-write refused) start=0x%x at=0x%x win=%u words\n", + start_off, at_off, + at_off > start_off ? (at_off - start_off) / 4u : 0u); + } + return true; + } + return false; } static void svc_gl_flush(struct nv_vgpu_device *vgpu, @@ -19892,6 +20012,18 @@ static u64 svc_init_cap_va; static bool svc_init_cap_done; static u32 svc_lmem_hits; static u32 svc_lmem_seen; +/* + * eng51 (CONT.512): the LAST large beef push of the boot. The init push is + * the channel-init/setup stream; the direct-GL draw arrives in a later push + * (c714: 0x4250110, 6400 B) that is transient in guest RAM. Preserve it so + * the RT bind / draw methods can be decoded offline after the guest has + * recycled the pushbuffer (gsp-phys-last-push). + */ +static u8 svc_last_cap[SVC_INIT_CAP_BYTES]; +static u32 svc_last_cap_len; +static u32 svc_last_cap_h; +static u64 svc_last_cap_va; +static bool svc_last_cap_done; static void svc_mme_prelude_capture(const u8 *buf, u32 len, u64 push_va, u32 h_object); @@ -19966,6 +20098,24 @@ static void svc_init_push_scan(const u8 *buf, u32 len, u64 push_va, u32 h_object h_object, mn, mg, an, ag); } } + /* + * eng51 (CONT.512): keep the most recent large beef push too. The + * init capture above is one-shot (the channel-init stream); the + * direct-GL draw push arrives later and is the window the RT/draw + * admission must decode. Copy is bounded (64 KiB) and only for + * beef-family pushes that carry a non-zero head. 256 B (not 4 KiB): + * c716's direct-GL draw pushes are 2252/324 B, so the 4 KiB floor + * preserved only the 59 KB setup push. + */ + if ((h_object & 0xfffff000u) == 0xbeef0000u && + len >= 256u && len <= SVC_INIT_CAP_BYTES && + memchr_inv(buf, 0, min_t(u32, len, 64u))) { + svc_last_cap_len = len; + memcpy(svc_last_cap, buf, len); + svc_last_cap_h = h_object; + svc_last_cap_va = push_va; + svc_last_cap_done = true; + } } const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen) @@ -19977,6 +20127,14 @@ const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen) return svc_init_cap; } +const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va) +{ + *len = svc_last_cap_len; + *h = svc_last_cap_h; + *va = svc_last_cap_va; + return svc_last_cap; +} + /* * SESSION 153-CONTINUED-53: MME context-setup prelude buffer. * @@ -31123,6 +31281,17 @@ static bool svc_gr_ram_ring_scan(struct nv_vgpu_device *vgpu, u64 chunk = min_t(u64, SVC_SCAN_CHUNK, end - gpa); u32 o; + /* + * eng51 (CONT.512): the linear scan walks the guest's + * non-RAM windows too (legacy VGA/BIOS below 1 MiB and the + * sub-4-GiB PCI hole). Every 64 KiB read there fails, and + * the per-GPA witness used to emit ~32k lines per sweep, + * rotating dmesg and hiding the draw-capture evidence. + * Those windows can never hold the ring; skip them. + */ + if ((gpa >= 0xa0000ULL && gpa < 0x100000ULL) || + (gpa >= 0x80000000ULL && gpa < 0x100000000ULL)) + continue; if (svc_read(vgpu, gpa, buf, chunk)) { if (gsp_sema_dbg && (ch->h_object & 0xfffff000u) == 0xbeef0000u) { diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h index b40dad2..f2a0777 100644 --- a/kernel/gsp_sema_service.h +++ b/kernel/gsp_sema_service.h @@ -305,6 +305,8 @@ void gsp_sema_service_fwd_gr_stats(u64 *req, u64 *ok, u64 *fallback, * emitted the download-state local-memory block). */ const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen); +/* eng51 (CONT.512): the most recent >=4 KiB beef push (direct-GL draw). */ +const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va); /* * Discover and pin GR (compute) channel rings after the CE region of the diff --git a/tools/guest-diag/params-r1624.txt b/tools/guest-diag/params-r1624.txt index 4bf9afe..473a6f6 100644 --- a/tools/guest-diag/params-r1624.txt +++ b/tools/guest-diag/params-r1624.txt @@ -2,3 +2,4 @@ gsp_phys_gpu=1 gsp_phys_hazard_ack=1 gsp_phys_boot=1 gsp_phys_nocat=1 gsp_phys_f sema_gr_grace_ms=500 sema_gl_mme_keep_done_across_recycle=1 sema_mme_prelude_cap_any=1 sema_gl_rt0_bind=1 sema_gl_mme_partial_keep_window=1 sema_gl_mme_pack_keep_gen=1 sema_gl_mme_cb_alias=1 + sema_gl_win_rt0_admit=1 diff --git a/wiki/Project-Status.md b/wiki/Project-Status.md index d556f4f..445b00d 100644 --- a/wiki/Project-Status.md +++ b/wiki/Project-Status.md @@ -10,7 +10,8 @@ > (the execution frontier). When this page and the docs disagree, the docs tree > wins. -Status: 2026-11-14, tree `master @ 339da842`. Tags: `[live]` proven with the +Status: 2026-11-15, tree `master @ 444ae2c1` plus in-flight graphics changes in +the working tree. Tags: `[live]` proven with the stock guest driver; `[gated]` implemented, default-off or behind supervised gates; `[wip]` partially implemented; `[wall]` current blocker; `[target]` named success state; `[planned]` designed, not built. @@ -28,7 +29,30 @@ named success state; `[planned]` designed, not built. | Physical backend on real hardware (module-owned GPU running its real GSP-RM) | `[live]` boot, RPC session, object creation, copy-engine work and GR execution proven — the verified guest CUDA kernel clients execute through this backend, and graphics method streams execute on the engine ([`Graphics-Execution.md`](Graphics-Execution.md)) | | Display and KMS on the emulated vGPU (nvidia-modeset/NvKms, `/dev/dri`, X) | `[live]` in the campaign configuration — the emulated display engine serves the guest's display push-buffer channels (notifier plus `UPDATE -> FINISHED`), nvidia-modeset/NvKms registers (`/dev/dri/card0`, `renderD128`, `fb0`), `nvidia-smi -L` enumerates and X settles. The X DDX idle-DMA/ScreenInit, USERD-latch lifetime, re-probe-thrash, Xorg kernel-mode-spin and flip-event walls were closed (X green for >10 minutes in a validated window); what remains is the per-boot **first-generation X start lottery**, which by 11-13/11-14 was the dominant throughput limiter for the graphics A/B runs (only an X started immediately after boot passes DDX DMA init; long stretches of dead starts, one green first-start boot). The display-capability seam is parameterised ([`Graphics-Execution.md`](Graphics-Execution.md)) | | Multi-tenant isolation (mdev per VM, per-context page directories) | `[wip]` device-level coexistence works — multiple mediated devices with different emulated VRAM sizes and multiple guests coexist (two guests demonstrated); per-guest execution isolation for simultaneous CUDA guests is in progress | -| OpenGL (3D graphics) | `[wip]` — the display/KMS stack registers, X and the stock NVIDIA GLX path are fully green (`glxinfo -B` returns 0 with OpenGL 4.6.0 and direct rendering; `glxgears` renders ~520 FPS with the emulated GPU's NVIDIA renderer), and the **first non-black GPU-rendered output** is proven: the pbuffer frame path produced 500/500 non-black 640x480 frames per run and captured videos (45.4 s on 2026-11-11; a 50 s 640x480 h264 capture on 2026-11-12). GZDoom reaches `V_Init: allocate screen` with its GL 4.6.0 context whenever the shared nvClip `modeNum` is even. **The direct-GL submission is now fully decoded:** no client push carries a method-grammar draw header — the channel's 9 NV906F entries tile one contiguous buffer and its per-frame work is carried as rewritten data-block blobs plus small state pushes (324/476/728 B) that invoke MME macros (the QMD-carrier hypothesis was tested and refuted). A content-gated FB-shadow rescue and a LOW-band rescue recover the recycled pushes: the client's draw-state push now opens a C597 section, is captured and marked for the verbatim 3D lane (the first direct-GL stream3d marks), and reaches the engine (`GR LAUNCH submitted`/`OK`, golden MME overlay accepted). **The current wall is MME macro completion:** the beef lane's 2799-word packed program cannot complete inside its <=2048-word block together with the 156-400-word draw window, so the load-only carrier gate drops each beef window and `live_gen` never promotes (a multi-part keep-window mechanism is committed default-off and enabled in the campaign params; A/B pending). RT routing was tested and refuted as the store cause (RT0 bind verified 16x but still `wrote=0`), and the earlier `CODESRC` fault-park class is prevented (zero `FAULT_PDE`/`WEDGE-REARM` on the validated boot). The window stays black (`px0=0`, `wrote=0`); the window/screen present path is unproven, and the X start lottery is the throughput limiter ([`OpenGL.md`](OpenGL.md)) | +| OpenGL (3D graphics) | `[wip]` — the display/KMS stack registers, X and the stock NVIDIA GLX path are fully green (`glxinfo -B` returns 0 with OpenGL 4.6.0 and direct rendering; `glxgears` renders ~520 FPS with the emulated GPU's NVIDIA renderer), and the **first non-black GPU-rendered output** is proven: the pbuffer frame path produced 500/500 non-black 640x480 frames per run and captured videos (45.4 s on 2026-11-11; a 50 s 640x480 h264 capture on 2026-11-12). GZDoom reaches `V_Init: allocate screen` with its GL 4.6.0 context whenever the shared nvClip `modeNum` is even. **The direct-GL submission is now fully decoded:** no client push carries a method-grammar draw header — the channel's 9 NV906F entries tile one contiguous buffer and its per-frame work is carried as rewritten data-block blobs plus small state pushes (324/476/728 B) that invoke MME macros (the QMD-carrier hypothesis was tested and refuted). A content-gated FB-shadow rescue and a LOW-band rescue recover the recycled pushes: the client's draw-state push now opens a C597 section, is captured and marked for the verbatim 3D lane (the first direct-GL stream3d marks), and reaches the engine (`GR LAUNCH submitted`/`OK`, golden MME overlay accepted). **The MME chain now completes and executes the draw macro.** The multi-part +keep-window mechanism won multi-frame windows; the part-launch poison was +eliminated (the real fault was the client's own +`SET_REPORT_SEMAPHORE`/`SET_NOTIFY` writes to client VAs that the host scratch +page-table pool remaps — redirected to a mapped scratch slot; 49 cycles with +zero poison and zero MMU faults); the 2799-word pack completes (2799/2799); +engine-global completion plus keep-done-across-recycle produced the first +`MME-PACK-REARM`; the fixed-CB region is aliased; and the released calls run +macros through to **`DRAW_IAB` (`mac=0x22`)**. Two synthesized-prelude defects +were then fixed: the SPH-BIND prelude self-destructed because an auto-dropped +run broke its kept/final count (`444ae2c1`), and the stage block was silently +skipped by a double-counted budget; with both fixed the prelude emits 84 words +and the DS stage VAs populate (one validated boot carried the full post-REARM +chain, `mac=0x22` and `DS 86040624`). The remaining gap is the **DS stage-0/1 +image**: the synthesized binds read `family+0x900` (zero in the live family +page). Binding `family+0x600` was tried and poisons the DS (`badf1201`) because +the engine-visible alias shadow there is the client's SASS upload, not an SPH +header; the next step is authoring a VTG SPH at an engine-visible VA the +client does not overwrite (`family+0x900`). Stores still miss (`wrote=0`, +`px0=0`); the +window/screen present path is unproven; and the per-boot binding lottery (the +GL client usually rides the X channel in indirect mode, and X start keeps a +first-generation lottery) is the throughput limiter +([`OpenGL.md`](OpenGL.md)) | | Vulkan (3D/compute) | `[wip]` — the guest Vulkan pipeline runs end to end on the emulated vGPU (device, allocation, pipeline, command buffer, fence, queue submit, readback) and the engine executes translated launches; frames are still black — program delivery and program-VA mapping are the frontier ([`Vulkan.md`](Vulkan.md)) | | DirectX / Windows guests | `[planned]` (target) — no Windows guest booted yet; the architecture is the same emulation target ([`DirectX.md`](DirectX.md)) | | Video (NVENC/NVDEC) | `[planned]` | @@ -80,11 +104,10 @@ with direct rendering, `glxgears` renders ~520 FPS); the first non-black GPU-rendered frames are proven off-screen (the pbuffer path produced a 500-frame 45.4 s video on 2026-11-11 and a 50 s capture on 2026-11-12), and GZDoom reaches its screen-allocation stage with GL 4.6.0 on an even modeNum. -The direct-GL submission is fully decoded (no classic draw header; the work is -macro-driven and the client's state push now reaches the engine), but -windowed/screen pixels remain the frontier (the MME multi-part program cannot -yet complete, the store still misses, and X start keeps a first-generation -lottery) — see [`OpenGL.md`](OpenGL.md). The +The direct-GL submission is fully decoded, the MME multi-part program now +completes and the draw macro executes, but windowed/screen pixels remain the +frontier (the DS stage image is the last named gate before stores, and X start +keeps a first-generation lottery) — see [`OpenGL.md`](OpenGL.md). The risc-v-gsp-rm-debugger workbench ([`Riscv-GSP-RM-Debugger.md`](Riscv-GSP-RM-Debugger.md)) is the host-side tooling used to study the firmware side of that frontier. |
