watchthelight labs

Intel panel: NVIDIA compositing onto the Intel panel (NVAccel head 4 copy path) #16

openarea:gpuarea:display
watchthelight 2026-10-21

Once NMIntelFB publishes the panel: WindowServer composites on the RTX 5070 and NVAccel copies each frame into the Intel scanout (debug.nvaccel_igpu=1). Open: cache mode of the kernel map, pacing at 165 Hz, tearing (copy not synced to the Intel raster). Parent: #12

watchthelight 2026-10-21

Built for N-202 (branch intel-xe a7a5aac + 0.2 claim fix). Two findings and two changes:

  1. In BIOS Hybrid mode the RTX 5070 is not on PCI under macOS (root port RP01 logs nolink, link status 0x5081), while Linux enumerates it at boot. The firmware leaves the dGPU powered down in Hybrid and expects the OS to run the PXP power resource's _ON (Linux and Windows do through _PR0); macOS never does. New SSDT (native/acpi/SSDT-DGPU-ON.dsl in the project repo, Legion-specific): an _INI under _OSI("Darwin") that, only when the GPU is absent, runs Lenovo's own PON + L23D and the root-port enable from PXP._ON, with a bounded 500 ms wait instead of the original unbounded loop and without the EC write.
  2. NVAccel needs a head-0 NVIDIA framebuffer for its device handle, VRAM and RM handles, and in Hybrid NVIDIA has no display. NVRMFB proxy head (boot-arg nvfbigpu=1): when NVKMS lists no connected display and the boot console is the iGPU's stolen-memory range (recorded by IGPUConsoleRange), head 0 still starts: NVIDIA device and VRAM as usual, one mode at the panel's size, aperture = the Intel framebuffer, and the scanout it reports to NVAccel is a CPU mapping with no VRAM address, so NVAccel takes its existing copy path (flips are refused). The class stays NVRMNVDAFramebuffer, so CoreDisplay keeps SkyLight's Metal compositor. IGPUConsoleRange 0.2 holds the iGPU's framebuffer slot in this mode (only when an NVIDIA GPU is on PCI), so Apple's IONDRV does not put a second display on the same memory.

Expected on success: NVIDIA on PCI, NVRMFB: fb0: no NVIDIA display; PROXY for the Intel panel 2560x1600, WindowServer Metal compositor activated, NVAccel frame counters rising. Fallback if the dGPU does not come up: Apple's IONDRV software desktop (N-201).

watchthelight 2026-10-21

N-202 result: booted to the software desktop (the fallback worked), not accelerated: the RTX 5070 was still absent from PCI. Reason found in Lenovo's ACPI: in Hybrid mode the EC detaches the unused dGPU (an eject request plus an EC flag, HPFF), and the power resource's _ON refuses to power the GPU while that flag is set. Clearing it needs the EC, which is not usable during _INI, so v1 of the SSDT could not work.

N-203: the SSDT now has a run-time method doing Lenovo's own attach (clear the EC flag, mark the GPU active, power on with a bounded wait, bus check), and IGPUConsoleRange 0.3 (8a5a673) calls it 4 s after start, rescans the root port, logs the EC state, and returns the panel to Apple's IONDRV if no NVIDIA GPU shows up within 24 s.

watchthelight 2026-10-21

N-203 result: the laptop powered off on every boot. Four Hybrid boots in a row, each one lost power 40 to 80 s in. No panic anywhere (no panic file, no DiagnosticReports entry, no aapl,panic-info in NVRAM) and no shutdown_stall, so this is a hard power cut, most likely by the EC. The first boot was still running at 23 s (dmesg, WindowServer up). The attach runs about 4 s after IGPUConsoleRange starts, so the cut came later, close to when the auxiliary kext collection with NVRM loads.

What Lenovo's ACPI says (disassembled from the 1401 probe's table dump):

  • GATY = 2 is not a GPU mode switch. Lenovo's own PXP._ON writes it every time the dGPU powers up in Hybrid, which Windows does all the time with runtime D3cold. So that write alone shouldn't cut power.
  • EC byte 0x8E holds IGPS (the Vantage GPU working mode), CUMA (UMA flag; PXSX._STA returns 0 while it is set), HPFF (detached) and GSTA. GZFD.HTPL only ejects the dGPU for IGPS 1, or IGPS 2 on battery. Windows reports IGPS 0 on this machine, and both Windows and the probe's Linux see the RTX 5070 in Hybrid.
  • Lenovo's _ON leaves GC6 through GC6O instead of PON when TDGC is 1. Our DGON always runs PON + L23D.

N-204 bisects it: the same attach (SSDT on, IGPUConsoleRange 0.3) with -nvoff, so NvGfx stays out.

  • No cut and the GPU on PCI: the attach is safe. N-205 brings NvGfx back without the TGP/NVPCF/physctl boot-args, since the power limits forced in Hybrid are the main suspect.
  • Cut again: the attach itself is the problem. DGON v3 then calls Lenovo's own WEJF(5, 0) + PXP._ON(), which handles GC6, instead of our copy of its steps.
watchthelight 2026-10-21

N-204 (attach on, NvGfx off with -nvoff): power lost again, so NVRM is not the cause. The unified log answers it:

  • 24 s after IGPUConsoleRange starts, no NVIDIA GPU has appeared, so the kext gives the iGPU's framebuffer slot back to IONDRVFramebuffer. Matching IONDRV makes IOPCIFamily log [getResources()] Performing FLR on nub IGPU, a function level reset of the iGPU that is driving the panel.
  • The log stops 7 s later on N-204 (FLR 01:36:32.5, last line 01:36:39.1) and 8 s later on the last N-203 boot (01:15:17.0 / 01:15:25.4).
  • No 10de device and no new PXSX under RP01 after the attach, so DGON did not bring the RTX 5070 up either.

So there are two separate bugs: the late slot hand-back, which resets a live iGPU and loses power, and the attach itself not working. Next boot is the safe config (SSDT off, no nvfbigpu), which gives N-201's software desktop. The fix plan is to attach first and decide on the slot afterwards, so the iGPU never changes hands after it is in use; then fix DGON using the EC values the kext logged (to be read with log show on the Mac).

watchthelight 2026-10-21

N-203 to N-205 (2026-10-20 21:12 to 21:47 EDT), Hybrid mode

  • N-203 / N-204: the laptop lost power 40-80 s into each boot. Cause found (I-093): IGPUConsoleRange 0.3 claimed the iGPU's framebuffer slot and, when no NVIDIA GPU had appeared after 24 s, terminated itself so IONDRV could take over. IOPCIFamily marks a nub whose client was terminated as needing a reset (IOPCIDevice::detachFromChild), and the next match runs an FLR on it (getResources, "Performing FLR on nub IGPU"). Resetting the iGPU while it scans out the panel cut power 7-8 s later. N-204 had -nvoff, so the NVIDIA driver is not involved.
  • N-205: safe config (no slot claim, SSDT off). IONDRV desktop, stable, no FLR.
  • The DGON attach result was lost: this kext's IOLog lines reach neither the unified log nor dmesg here.

N-206 (staged, NvGfx intel-xe eec12da): IGPUConsoleRange 0.4

  • The slot is decided once, in probe, and never handed back: with nvfbigpu=1 it attaches the dGPU from probe and claims only if the RTX 5070 is there.
  • sysctl debug.wtlacpi evaluates ACPI methods live (EC REJF, DGON, RP01 rescan), so the dGPU attach in Hybrid can be iterated on one boot instead of one reboot per try. The trace lives in debug.wtlacpi_log.
  • N-206 boots with IONDRV on the panel as in N-205; the attach is then tried live.
watchthelight 2026-10-21

N-206 (2026-10-20 21:59 EDT): live dGPU attach in Hybrid, result: power cut

IGPUConsoleRange 0.4 booted cleanly (IONDRV desktop, no FLR), and debug.wtlacpi read the Lenovo state live:

  • EC: IGPS 0, HPFF 0, CUMA 0, GSTA 0. The RTX 5070 is not detached in Hybrid, only powered off (PXP status 0). macOS never runs _PR0.
  • No GC6 (TDGC 0). Root port RP01 present (VDID ae4d8086), PXSX NVID 0xffff, RP01 LDIS 1.

DGON (Lenovo's PXP._ON power branch with a bounded wait) timed out: power was on (PSTA 1) but the link never trained (NVID still 0xffff). The laptop lost power about 12 s later, with no FLR this time. So I-093 is revised: the cut follows powering the dGPU while RP01's link stays down. N-203/N-204 fit the same timing. The FLR fix in 0.4 stays, but the FLR was probably not what cut power.

Live power-on experiments are paused: each one is a hard power loss. Next is a read-only study of Lenovo's Hybrid path (PXP._OFF is \STMC(4,0), so the real on/off goes through STMC), and of how Linux/Windows bring the link up, before any new attempt.

watchthelight 2026-10-21

N-207 (2026-10-20 22:08 EDT): DGON v3, power cut again. Hybrid dGPU attach parked.

  • RP01's Link Disable is set before any attach (LDIS 1 at 45 s; IOPCIFamily logged it clear at 1.8 s, so it gets set after boot).
  • DGON v3 cleared it after power-on and waited 1 s: the link still did not train (NVID 0xffff, LASX 0). Lenovo's POFF then did not drop power (PSTA stayed 1), and the laptop lost power seconds later.
  • Every live power-on of the RTX 5070 in Hybrid has now ended in a hard power cut: N-206, N-207, and the probe-time attach in N-203/N-204. That is too costly for the laptop and its disks, so the attach is stopped and SSDT-DGPU-ON is off again.
  • Consequence: the "NVIDIA renders, Intel panel scans out" proxy path needs the dGPU on PCI in Hybrid, so it is parked with the attach.
  • State now: Hybrid gives a stable IONDRV desktop on the iGPU (unaccelerated, N-201/N-205); Discrete gives the accelerated NVIDIA desktop. Accelerated Intel graphics needs a real Intel GPU driver (i915/xe port), which is the M2+ part of this plan.

Reply on GitHub