# Graphics Execution > **Scope.** How the emulated vGPU runs **3D graphics** work — the OpenGL and > Vulkan command streams a stock guest submits — on the physical GPU, and what > is proven about it. This is the shared machinery behind > [`OpenGL.md`](OpenGL.md), [`Vulkan.md`](Vulkan.md) and the Windows/DirectX > target ([`DirectX.md`](DirectX.md)); CUDA compute uses the same submission and > completion path for a different engine workload > ([`Execution-Frontier.md`](Execution-Frontier.md)). Canonical sources: > [`../docs/04-implementation/05-graphics-execution-plan.md`](../docs/04-implementation/05-graphics-execution-plan.md) > (the plan and milestone ladder) and > [`../docs/04-implementation/04-real-render-walls.md`](../docs/04-implementation/04-real-render-walls.md) > (the measured walls); the docs tree wins on disagreement. Status: 2026-11-09, tree `master @ e342bd0f`. Tags: `[live]` observed end to end; `[wip]` partially built; `[wall]` current blocker; `[target]` defined success state; `[planned]` designed, not built. ## 1. What "real pixels" means The acceptance target is strict: a **stock** guest GL or Vulkan application's draw commands are executed by the physical GPU's fixed-function 3D pipeline (vertex fetch, primitive assembly, rasterisation, fragment work, ROP), the render target is readable by the guest, and that image reaches the capture path through the emulated mdev. The pixels must not come from another GPU, a software rasteriser, or a host display round-trip. (The project has also published two deliberately-labelled two-VM demo videos that use the standard `virtio-gpu`/`virgl` virtual GPU on a host integrated GPU, and a CUDA-animation video that *does* run on the emulated vGPU through the compute path. The `virgl` videos are honest demonstrations of the guest experience; they are not this execution path, and their captions say so.) ## 2. The path a graphics command takes ```mermaid graph TD APP["Guest applications
OpenGL · Vulkan · CUDA"] --> LIB["Guest user space
GL: GLX client + the driver's GL core
Vulkan: the NVIDIA ICD
CUDA: libcuda"] APP --> X["X server (Linux GL)
GLX module + the NVIDIA DDX"] LIB --> KMD["Guest kernel: nvidia.ko
RM core, GSP client, channels, modeset/drm"] X --> KMD KMD -- "GPFIFO rings + doorbell;
method streams in push buffers" --> VG["Host module vgsp.ko
device model + emulation core"] VG --> L1["Lane 1: verbatim 3D
method-stream replay"] VG --> L2["Lane 2: synthesized launch
from a captured section"] VG --> L3["Lane 3: forwarded CUDA
launch (compute)"] L1 --> FE["Physical GPU
front-end fetch -> GR engine"] L2 --> FE L3 --> FE FE -- "engine-authored releases
(semaphores in guest memory)" --> VG VG -- "completion relay: MSI-X +
poller/event wake the guest" --> KMD ``` ```text guest apps (GL / Vulkan / CUDA) -> guest user space (GLX client + GL core, Vulkan ICD, libcuda) -> guest X server (GLX module + NVIDIA DDX) [OpenGL] -> nvidia.ko: channels, GPFIFO rings, doorbells [all APIs] -> vgsp.ko: capture sections, decode pushes, forward -> physical GPU front-end -> GR engine (3D + compute) / copy engines <- engine-authored releases written into guest memory <- completion relay (MSI-X + wakes) back to the guest ASCII fallback above; the diagram shows the three execution lanes. ``` ## 3. The three execution lanes Graphics work reaches the engines today in one of three shapes, in increasing fidelity: 1. **Verbatim 3D method-stream replay** `[live]`. The emulation captures the X server's graphics-class (`0xC597`, `TURING_A`) section from its channel, relocates the operand addresses into host-built shadow pages the engine can reach, and submits the stream unchanged. The engine retires it: the uploads (`LINE_LENGTH_IN`/`LAUNCH_DMA`), the state, program and texture binds, and the release all execute with no MMU fault. This proves the *mechanics* of 3D execution — object bind, window placement, operand relocation, completion — on real hardware. 2. **Synthesized launch from a captured section** `[live]`. A compute-shaped launch built from the captured section (operand list, program, a 64-word launch descriptor) reaches the engine and retires real `sm_75` SASS; the Turing shader-program-header form (`V3`) is accepted with zero header faults across repeated launches. This proved engine-side dispatch before the verbatim lane existed. The program itself is still a development stand-in at this rung — execution proof, not pixels. 3. **Forwarding the client's own pushes** `[wip]`. The GL client's own channels now register, submit and retire: the direct-GL GR channel (`0xbeef0100`) and its CE siblings (`0xbeef0101`/`0xbeef0102`) are discovered, their rings and releases are decoded, and the X server's DDX kick channel (`0xbfef0002`) is decoded from its ring head with its class-2D notification authored. The X DDX waits are fixed (class-aware display arm, `0x8000 -> 0` notification completion, decoded GL release applied), and GZDoom reached `MAP01` once the DDX push-buffer loop was unblocked. What remains is the renderer backend path (NVIDIA Vulkan ICD or forced GLX), the DDX get-word/notifier completion, and physical dispatch of the client's draws (§6). ## 4. The channel and object picture * **Every submission lives on a channel**: a GPFIFO ring plus engine objects, with a USERD the driver advances its put pointer in and a doorbell the host module traps. Channels are typed by engine: a graphics channel carries 3D state and draws; copy-class channels carry memory movements. * **The graphics object class** the guest's 3D stream binds is the Turing graphics class, `0xC597`. Streams now come from both the **X server's channel** and the **direct GL client's own channels** (`0xbeef0100` GR plus the `0xbeef0101`/`0xbeef0102` CE siblings); the 2D present/readback work rides lighter 2D-class and copy-engine shapes. * **Display and modeset** `[live]`. The guest's modeset path is served by an emulated display engine: the display push-buffer channels (core `0xc57d`, window `0xc57e`, immediate/window `0xc57b`) are registered, their push buffers parsed, and the notifier/`UPDATE` completion authored. The arm is class-aware (the window class has no NOTIFY bit; a bound notifier is the arm), and the X DDX's `0x8000 -> 0` notification completion is authored. This is what lets nvidia-modeset/NvKms register (`/dev/dri`), X settle and GLX clients obtain a real GL context. The display-capability seam is parameterised in the campaign configuration. * **Cells of state**: 3D streams are long—hundreds of method words per draw — and mix state binds (viewport, render target, ZS, blend/ROP), program and constant binds, vertex/index streams and draw-issuing methods. The capture machinery recognises the init-shaped operands today; the per-draw state vocabulary is being extended ([G-B in the plan]( ../docs/04-implementation/05-graphics-execution-plan.md)). * **Synchronisation**: tracking semaphores, notifications and fence values written by the engine; the guest's swap/present waits sit on top of those. ## 5. Completion, fences and presents The acceptance signal is the **engine-authored release**: a semaphore the engine writes when the work completes. For GL, completion flows through the channel's semaphores/notifications to the X server and the app's swap wait; for Vulkan, the client's fence value is released; for CUDA, the launch's release group wakes the client. The emulation relays engine completions into guest-observable memory (MSI-X plus a poller), and the guest resumes from there. For the display path, completion is the notifier write and `UPDATE -> FINISHED`; a completion event deferred by the reply path is force-retried until it posts, so the X server's mode set finishes. For the X DDX's own 2D push buffers, completion also requires the GPU-written engine get word to advance and the notifier to be recycled to `0xffff` after a kick; both are host-side levers now, and a diagnostic write of the get word released the DDX's reserve loop. During bring-up the module also carries a **diagnostics-only mirror** for apps that spin on a shared progress word; it exists so a run can proceed while the natural completion path is being finished. The 60-fps milestone explicitly requires it switched off, along with any external poke. ## 6. Where the frontier is (ranked walls) 1. **The renderer backend path** `[wall]`. GZDoom's default Vulkan backend fails at `vkCreateDevice` in the NVIDIA Vulkan ICD, and the default OpenGL/EGL path falls back to Mesa (`llvmpipe`). The campaign is forcing GLX (`SDL_VIDEO_X11_FORCE_EGL=0`) so the client uses the NVIDIA GL stack; the first NVIDIA-path frame is gated here. 2. **The X DDX push-buffer completion** `[wall]`. The DDX's 2D reserve loop exits only when the GPU-written engine get word advances (`get <= put`) and the kick requires the notifier to be recycled to `0xffff` after completion. A diagnostic host write released the loop; the kernel levers to publish/advance the get word and recycle the notifier are next. 3. **The X DDX footprint** `[wall]`. The DDX allocates 4 GB of system pages at startup; an 8 GB guest has no headroom once GZDoom's own footprint lands and both are OOM-killed. Current runs use a 12 GB guest; the allocation is a suspected emulation gap (a 512 MiB emulated VRAM falling back to a 4 GB sysmem allocation) to fix. 4. **Physical dispatch of the GL draws** `[wall]`. The direct-GL channels submit and get host-completed releases, but the forwarding path reports no dispatch to the physical GR engine (`forwarded=0`); the draws are decoded and host-completed, not executed on hardware. 5. **Non-black frames and sustained rate** `[wall]`/`[target]`. Once the NVIDIA renderer path and the DDX get-word/notifier completion land, the capture must show motion, then 60 fps in one VM with no forcing, then two VMs on two mediated devices with non-black frames in both. ## 7. What is proven today | Capability | State | |---|---| | X server initialises on the emulated vGPU (driver DMA sanity push, ScreenInit) | `[live]` | | Display engine serves the modeset push buffers; notifier plus `UPDATE -> FINISHED` | `[live]` (campaign configuration) | | nvidia-modeset/NvKms registers (`/dev/dri/card0`, `renderD128`, `fb0`); `nvidia-smi -L` enumerates | `[live]` | | `glxinfo` reports the emulated GPU with the NVIDIA renderer (OpenGL 4.6.0, direct rendering) | `[live]` | | GZDoom obtains a real GL context; windowed reaches renderer startup | `[live]` (pixels frontier) | | GZDoom reaches `MAP01` on Mesa llvmpipe (not the emulated vGPU path) | `[wip]` | | X server survives the GZDoom run on a 12 GB guest (the DDX's 4 GB sysmem allocation forces the size) | `[live]` | | GL section capture: the X server's `0xC597` stream decoded | `[live]` | | Verbatim 3D method-stream replay retired by the engine (no MMU fault) | `[live]` | | Synthesized launch executes real `sm_75` SASS; Turing `V3` program header accepted | `[live]` | | 2D screen fills and copy-engine present ops execute | `[live]` | | Direct GL client: device-init gate handled, channels allocate, readback path returns clean | `[live]` | | Direct GL client channels submit and retire (GR `0xbeef0100`, CE `0xbeef0101`/`0xbeef0102`); DDX kick channel decoded | `[live]` | | NVIDIA Vulkan ICD creates a device, or forced GLX reaches glcore | `[wall]` | | DDX push-buffer get-word publish and notifier recycle | `[wall]` | | Physical dispatch of the direct-GL draws (`forwarded=0`) | `[wall]` | | Non-black pixels from the emulated vGPU's 3D pipeline | `[wall]` | | Windows/DirectX guests | `[planned]` | ## 8. What is not claimed * No non-black pixel has been produced by the emulated vGPU's 3D pipeline yet. * Display/KMS bring-up (NvKms, `/dev/dri`, X, a real GL context) is not a rendered-frame claim; GZDoom reaching `MAP01` on Mesa llvmpipe is not the emulated-vGPU path either. The NVIDIA renderer path, the DDX get-word/notifier completion and the physical dispatch of the GL draws are the current walls. * No frame-rate or latency numbers: the scheduled measurement is defined (60 fps over 60 s, no forcing) but not yet met. * The `virgl`-based demo videos are a different, labelled path — not this one. ## 9. Related pages * [`OpenGL.md`](OpenGL.md) — the guest OpenGL path and its status. * [`Vulkan.md`](Vulkan.md) — the guest Vulkan path and its status. * [`DirectX.md`](DirectX.md) — Windows guests and the DirectX target. * [`Execution-Frontier.md`](Execution-Frontier.md) — the CUDA compute chain, proven end to end. * [`Physical-GPU-Backend.md`](Physical-GPU-Backend.md) — the backend the work is forwarded to. * [`Introduction-to-GMMU.md`](Introduction-to-GMMU.md) — channels, GPFIFO, engines, and page tables. * [`Host-Module.md`](Host-Module.md) — where capture, decode and forwarding live. * [`../docs/04-implementation/05-graphics-execution-plan.md`](../docs/04-implementation/05-graphics-execution-plan.md) — the canonical plan: gap list, three approaches, and the M-GL1..M-GL6 milestone ladder with gates.