Skip to content

Streaming

The Hyper-V console only shows the basic Hyper-V display, not what the GPU draws. To see the VM with the GPU, GpuVM installs a streaming server inside the VM and opens it with a client on the host.

Component Where Role Pinned version
Sunshine VM Captures the virtual display and encodes with NVENC. v2026.914.233613
Virtual Display Driver VM A monitor drawn by the GPU. 25.7.23
nefcon VM Command-line driver installer; creates the virtual display device. v1.14.0
usbip-win2 VM Plugs in GpuVM’s USB speaker, which Sunshine captures. 0.9.8.0
Moonlight Host Shows the VM. Installed separately

The installers are downloaded on the host when the VM is created, verified against the SHA-256 pinned in streaming/components.json and copied to the VM’s disk. The guest downloads nothing. They are kept in a cache folder (in %ProgramData%\GpuVM when installed).

nefcon is pinned to v1.14.0, the version the official VDD install script uses, even though v1.21.0 exists.

Sunshine runs inside the VM. Its username and password are generated when the VM is created; on the host they are stored encrypted with DPAPI. The password travels in plain text to the guest only for the install and is deleted afterwards.

Each time you start and open a VM, GpuVM reads Sunshine’s display list through its API, sets output_name to the virtual display and restarts Sunshine if that changed, so it never captures the Hyper-V display by mistake. When GpuVM has already turned the Hyper-V display off, it also sets dd_configuration_option to disabled: if Sunshine changes the display on every session, it re-tests all its encoders and the first frame takes 22 to 27 s instead of about 2 s (lab 008). Changing the resolution or FPS still costs 10 to 15 s, because Sunshine sees the display change. Otherwise it uses ensure_only_display.

Sunshine can capture the virtual display in two ways, chosen per VM in Options → Captura (Capture) or with Set-GpuVMCapture -Name <vm> -Mode ddx|wgc:

Mode In the app How Sunshine runs Shows Doesn’t show
ddx (desktop duplication) Estándar (Standard, the default) As a Windows service (SYSTEM). Everything, including Windows’ administrator prompts. Programs in exclusive fullscreen: black.
wgc (Windows.Graphics.Capture) Pantalla completa exclusiva (Exclusive fullscreen) In the signed-in user’s session, started by a logon task (conhost --headless, so no console window); the service is set to manual. Programs in exclusive fullscreen, at any resolution. Administrator prompts (they are drawn on the secure desktop).

With ddx, desktop duplication gets no new frames from the virtual display while a program is in exclusive fullscreen, so the stream stays black; it only shows the program when it loses focus (lab 009). The mode is applied right away if the VM is running and checked on every Encender y abrir (Start and open); when it’s already set, Sunshine isn’t restarted. Applying it needs the guest password.

The Virtual Display Driver adds a monitor drawn by the GPU. It is installed with nefcon, and only the certificate that signed the driver is trusted.

  • After the first boot the VM restarts once on its own to leave the virtual display as its only display.
  • If the virtual display works, the Hyper-V display is turned off so Windows and Sunshine use the virtual one (disableHyperVVideo in the profile).
  • On every Encender y abrir (Start and open), with the guest password saved, the virtual display is kept as the only and primary display of the VM. GPU-P VMs get an extra hidden 1024×768 output of the shared GPU; if it became the primary one, new windows (Steam, installers) would open where the stream doesn’t show them. When it’s already set, nothing is changed, so Sunshine doesn’t re-test its encoders.
  • If something fails, the VM is still reachable over Remote Desktop.

Moonlight on the host shows the VM. Pairing is automatic: Moonlight generates the PIN and GpuVM hands it to Sunshine through its API. The paired client is this PC’s name.

  • To pair again: Volver a emparejar Moonlight in the app’s menu, or ./gpuvm.ps1 connect -Name <vm> -Pair.
  • The resolution and FPS are set in the app’s Options, or per connection:
Terminal window
./gpuvm.ps1 connect -Name win11 -Resolution 2560x1440 -Fps 120 -BitrateKbps 40000 -Codec HEVC

Codecs: auto, H.264, HEVC, AV1. Moonlight opens the Desktop app of Sunshine by default.

Hyper-V Generation 2 VMs have no sound card. GpuVM gives the VM its own USB speaker: a small server inside the VM (GpuVMAudio.exe) presents itself as a USB audio device (48 kHz, stereo), usbip-win2 plugs it in, and Windows drives it with its built-in USB audio driver as if it were real hardware. It shows up as Speakers (GpuVM Audio) and Sunshine captures it (virtual_sink).

  • Nothing leaves the VM: the server listens on 127.0.0.1 only, runs as LOCAL SERVICE and its program lives in C:\Program Files\GpuVM\Audio, where only administrators can write.
  • usbip-win2 installs only its client, silently. Its drivers are signed by Microsoft: no test mode, no certificate of its own. GpuVM checks both and uninstalls it if either fails.
  • The speaker is persistent: usbip-win2 plugs it in again every time Windows starts, so no restart or sign-in is needed. Encender y abrir (Start and open) checks it every time, plugs it in again if it was lost and updates the server when GpuVM brings a new one.
  • VMs created with VB-CABLE move to the speaker the next time they are opened. VB-CABLE’s output is silent to Sunshine inside a VM, so the earlier sound came from Steam Streaming Speakers (labs 011 and 012).

The streaming section of the profile sets the defaults:

"streaming": {
"provider": "sunshine", // or "none" to create the VM without streaming
"virtualDisplay": true,
"disableHyperVVideo": true,
"audio": "usb", // or "none" to skip audio
"sunshine": { }, // extra keys for sunshine.conf
"client": { "app": "Desktop", "resolution": "1920x1080", "fps": 60, "bitrateKbps": 0, "codec": "auto" }
}

client also accepts vsync, framePacing, performanceOverlay (true/false) and displayMode (fullscreen, windowed, borderless). They are only passed to Moonlight when the profile defines them. captureSystemKeys (never, fullscreen, always; fullscreen if not set) decides when Alt+F4, Alt+Tab and the Windows key go to the VM; Ctrl+Alt+Shift+Q always quits the stream.

Moonlight is started as the signed-in user, without administrator rights, even though GpuVM runs elevated: it talks to a server the VM controls.

Terminal window
./gpuvm.ps1 components-update -WhatIf # see whether newer versions exist

It looks up the latest GitHub release of each component and updates version, URL and SHA-256 in streaming/components.json. usbip-win2 stays on 0.9.8.0 (hold in the file) until a lab proves a newer one. A new version isn’t tested: validate it in a lab before creating VMs with it. The app can’t run this command.