# Real-render walls: Vulkan and Xorg on the emulated vGPU Status: OPEN (2026-10-29, SESSION 64). This page records the measured state of the guest's *display/graphics* consumers - the Vulkan ICD and the Xorg server - on the emulated vGPU, with the exact evidence and the next subsystem to implement. It complements [05-operations/06-guest-frame-path-and-looking-glass.md](../05-operations/06-guest-frame-path-and-looking-glass.md) (which covers the CUDA -> ivshmem -> host frame transport that is already proven). ## 1. What works today * The guest's shipped 570.144 Vulkan userspace **loads and enumerates**: `vkCreateInstance` succeeds and two physical devices are reported - `NVIDIA GeForce RTX 2080 SUPER` (discrete, Vulkan 1.4.303) and the software `llvmpipe` - from `/etc/vulkan/icd.d/nvidia_icd.json`. Probes: `tools/vk/vk_probe.py`, `tools/vk/vk_probe2.py`. * `eglInitialize` succeeds with `vendor=NVIDIA` on the guest EGL device platform (the EGL probe `tools/guest-diag/egl_retry.c` and the older `egl_frame`). * CUDA is unaffected (its clients run through the same emulated GSP; see the battery evidence in the handoff). ## 2. Wall 1 - `vkCreateDevice` fails in nvidia-modeset's ALLOC_DEVICE `vkCreateDevice` returns `VK_ERROR_INITIALIZATION_FAILED`. An `LD_PRELOAD` ioctl logger (`tools/guest-diag/nvkmstrace.c`) shows the ICD's first nvKms ioctl failing: ``` NVKMS_IOCTL cmd=0 size=1488 addr=0x... rc=-1 # NVKMS_IOCTL_ALLOC_DEVICE ``` i.e. the kernel's `nvKmsAllocDevice` (in `nvidia-modeset`) returned a non-success status; the userspace frees everything and reports the generic initialization error. Reading the driver's own modeset source (`nvkms-rm.c`) gives the alloc order and the two gates we hit and fixed: 1. `ProbeHeadCountAndWindowAssignment()` -> `NV0073_CTRL_CMD_SYSTEM_GET_NUM_HEADS` (`0x730102`): a zero reply logs `No heads found on board!` and fails the alloc. The emulated GSP RSP answered all NV0073 controls through the generic zero-reply path. 2. After the heads: `NoValidDisplays()` -> `NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED` (`0x730107`) must report at least one display id, and the connector path (`SPECIFIC_OR_GET_INFO` `0x73028b`, `SPECIFIC_GET_CONNECTOR_DATA` `0x730250`, `DFP_GET_INFO` `0x731140`) must describe a connector. The host GSP-RM emulation now implements a minimal headless display: one head (`0x730102`/`0x730287`), flexible window assignment (`0x7302ad`), one static HDMI connector on display id 0 (SOR + single-link TMDS, which avoids the DP-AUX library), plus DDC support. With this shim the alloc gets past heads and `NoValidDisplays` and proceeds through the connector queries and the display-object allocations (classes `0xc570`, `0xc57d`, `0xc372`, controls `0x50700709`, `0x73010c`, `0xc3700201`) before failing later in the display-core/modeset-channel path. That remaining subsystem is the wall: the modeset core channel and the per-display dpy objects must be emulated (a coupled object + channel + memory set whose exact wire forms should be captured from a real-GPU session). A related experiment ruled out one shortcut: booting the guest with `nvidia-modeset`/`nvidia-drm` blacklisted (no `/dev/nvidia-modeset`) does not avoid the wall - the ICD's nvKms client still issues ALLOC_DEVICE and fails, so the display path cannot be sidestepped by disabling KMS. ## 3. Wall 2 - Xorg ScreenInit fails in nvidia-push's channel test Xorg starts (the GPU is detected, `Virtual screen 1280x1024`) and then: ``` (EE) NVIDIA(GPU-0): Failed to initialize DMA. (EE) NVIDIA(0): Failed to allocate push buffer ``` `nvidia-push` logs `Failed to initialize DMA.` from `__nvPushTestPushBuffer()`: right after allocating a push buffer the driver writes a NOP and waits (10 s) for the channel to consume it. Host evidence shows why it never does: * the X driver's channel registers (`class 0xc46f` GPFIFO channel, `gpfifo=0x120090000`, `userd=0x350000` sysmem) and lives with **`submissions=0`** - its published GP_PUT never advances in the host's view, because the host needs the channel's VA->PA translations to read its USERD/GPFIFO and that resolution comes from the guest-side scanner that currently follows *CUDA clients only* (`targeted resolve va=0x20400f000: full RAM scan found nothing`); * on a busy boot (Xorg started while a CUDA battery ran) the channel's completion-counter slot is rejected: `counter auto h=0x1000013 rank=0 pa=0x11c827ff0 rejected (slot owned by another channel)` - two concurrent clients both derive rank 0's slot from the per-device structural formula. Fixing Xorg therefore needs (1) a platform-wide (non-CUDA) VA-resolution path for the scanner or the host, and (2) counter-slot ownership keyed by client identity (or a per-client slot domain), not just rank. ## 4. Wall 3 - the EGL/glsi engine-init gate (unchanged) `eglMakeCurrent` returns `EGL_BAD_ALLOC (0x3003)`; the glsi engine-init entry returns a "busy" status once, sets a state bit, and the eglcore caller does not retry. Ten in-process retries (`egl_retry`) all fail, so the state machine fails on a real input - the return-value trace of its callees remains the way in (see [userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md](../../userspace/cuda/570.144/docs/ANALYSIS-egl-engine-selection.md)). ## 5. Why this matters for the frame path Everything downstream of a working GL/Vulkan context is already in place: a guest publisher writes frames into the kvmfr ivshmem BAR (`tools/vk/vk_frame.c`, `tools/guest-diag/xshm_pub.c` use the same layout as the proven CUDA `frame_producer`), the host reader decodes them (`tools/lg/frame_reader.py`) and ffmpeg assembles video. The missing piece is a *working* graphics API on the guest GPU - the two subsystems above.