Experimental PyroWave on Windows¶
The Windows integration targets SDR BT.709 and HDR10 BT.2020/PQ at 4:2:0 or 4:4:4 through LuminalShine’s existing GPU capture path. The default target is 700 Mbps. It does not require a LuminalVGD driver update. H.264, HEVC and AV1 keep their encoder selection, capability snapshots and transport defaults.
Pinned client and codec¶
Aurora (Moonlight Qt fork):
Koloses/aurora-qtat2c574a9e79da5b3fa95bab90ffd3d322f5d63ac0.Its protocol submodule:
Koloses/moonlight-common-cata5228faeeda949a3ab0140f55a75bd14fe74e899.Vendored codec and initial host adapter reference:
Koloses/Solarflareat48ae555e73428926ae4be234f15513967a839397.
The host uses stream format 3 and SDP PYROWAVE/90000. It probes the four wire
profiles independently and advertises only those that initialize successfully:
SDR 4:2:0:
0x00800000SDR 4:4:4:
0x01000000HDR10 4:2:0:
0x02000000HDR10 4:4:4:
0x04000000
Aurora selects the profile through its corresponding video-format bit, with
the existing dynamic-range and chroma attributes identifying the selected
format in ANNOUNCE. Optional exact 0/1 ANNOUNCE attributes negotiate
adaptive RTP FEC and adaptive bitrate per session. A stock Moonlight client
continues to negotiate a regular codec. The client’s phase-offset extension is
not applied to the Windows capture clock in this milestone.
Building and selecting¶
Use the normal Windows clang build with Vulkan headers (including Vulkan-Hpp), Python 3 and glslangValidator available:
cmake -S . -B build -DSUNSHINE_ENABLE_PYROWAVE=ON -DBUILD_DOCS=OFF
cmake --build build --target sunshine test_sunshine
Optional CMake overrides: Vulkan_INCLUDE_DIR, Vulkan_LIBRARY,
PYROWAVE_GLSLANG. Shaders are compiled and embedded at build time. The system
GPU driver supplies the Vulkan loader at runtime; no Vulkan SDK is needed on
the streaming host. PyroWave requires Vulkan 1.3 and Windows external-memory /
keyed-mutex interoperability on the capture adapter.
In Advanced settings enable experimental PyroWave and retain 700 Mbps, or set:
pyrowave_enabled = enabled
pyrowave_bitrate_mbps = 700
pyrowave_quality_bias = 0
pyrowave_refresh_interval = 0
Select PyroWave in the pinned client. Start with 1920x1080 at 60 FPS and SDR 4:2:0, then test the intended resolution, frame rate, and advertised 4:4:4 profile. For HDR, enable HDR in the client and ensure display preparation enables HDR on the LuminalVGD monitor. A requested HDR stream with an SDR capture source fails setup rather than falsely labelling SDR pixels as HDR.
The target describes compressed video, not total link traffic. FEC/audio/header overhead requires additional capacity. Use a network with sufficient headroom. When a pinned client negotiates adaptive FEC, each parity increase reduces the next submitted video/RDO budget by the matching ratio, so video plus FEC stays inside the session’s original video-and-base-FEC envelope. Negotiated adaptive bitrate composes with that reduction; the controllers remain session-local. Zero selects the 700 Mbps automatic default. The UI accepts up to 10,000 Mbps, but the current four-block GameStream transport cannot carry all combinations of bitrate and FPS: excessive frame budgets are rejected before capture. Large frames may use the existing no-FEC fallback. Full 10 Gbps transport and client-coordinated fragmentation are a separate milestone.
pyrowave_quality_bias ranges from 0 to 3 and adds that many bits to the
encoder’s initial quantization ceiling. Keep the default 0 unless a measured
high-bitrate workload is saturating the default ceiling; higher values allow
the rate-distortion optimizer to spend more of the available frame budget.
pyrowave_refresh_interval ranges from 0 to 255 frames. The safe default 0
sends a complete intra frame every time. A value greater than zero is an
experimental operator opt-in to conditional replenishment: unchanged blocks
may keep their previously decoded state, while every block is forced to refresh
within the configured interval. The wire protocol has no separate
replenishment-capability attribute, so that mode is certified only for the exact
Aurora and moonlight-common-c SHAs pinned above. Leave it at 0 for stock or
differently-versioned clients. This control is not pyrowaveAdaptiveFec; it
neither enables nor changes GameStream FEC.
Capture and recovery contract¶
LuminalVGD completes its copy and releases the driver ring slot before the encoder receives the host-owned pooled D3D11 texture. PyroWave imports that NT shared texture on the same adapter (matched by LUID), acquires/releases key 0 through Vulkan’s keyed-mutex submit extension, and finishes source consumption before returning the borrowed image. No uncompressed CPU readback is used.
The existing driver D3D11 and D3D12 fence transports converge on that pooled image. NVENC’s separate D3D11On12/native D3D12 encoder route is unchanged; PyroWave compute itself uses Vulkan. FP16 scRGB capture is converted from linear BT.709 at 80 nits/unit to BT.2020/PQ for HDR. The capture layer already composites the cursor. Static desktops re-encode retained YCbCr planes, without retaining a driver ring slot or pooled image.
Worker IPC version 10 carries the negotiated packet-size bound, Step 2 feature snapshot, and per-frame adaptive pacing rate. The three regular codec capability arrays and the 32 MiB worker message cap remain unchanged. The experimental codec has a separate bounded dispatch. Pending GPU resources are retained on fence timeout until worker exit.
Verification¶
Run the regular guard suite and the new contract checks after each change:
.\build\tests\test_sunshine.exe --gtest_filter='Vgd*:VideoWorker*:WebRtcExclusivity.*:VideoPacketQueue.*:VideoPacketQos.*:PyrowaveContract.*:PyrowavePacing.*'
The opt-in PyrowaveGpu.* checks exercise actual D3D11 texture import and SDR /
HDR encoding without modifying displays. They require
LUMINALSHINE_TEST_PYROWAVE_GPU=1 and a build with PyroWave enabled. They are not
a substitute for a LuminalVGD-to-Moonlight session.
Hardware acceptance still requires the pinned client: SDR and HDR playback, color ramps/highlights, cursor, idle desktop, reconnect, resolution/HDR changes, display restoration, and regular-codec sessions before and after PyroWave. Repeat on NVIDIA, AMD and Intel where the required Vulkan interop is available. Record actual bitrate, dropped frames and latency; do not infer performance from a successful build or capability probe.
Development checkpoint (2026-09-29)¶
The Windows host and test executable build with PyroWave enabled, and the web UI production build succeeds. The final targeted run passed 87 tests: existing VGD/worker/transport guards, configuration consistency, PyroWave contract/pacing, and the opt-in GPU test. The GPU test uses 128x128 shared textures at a 700 Mbps target, decodes with the pinned Aurora decoder, checks SDR/HDR colors, verifies HDR bootstrap black, idle refresh, and keyed-mutex return. This is functional validation, not a 1080p/4K throughput measurement. Eleven targeted frontend settings tests also pass. The modified video/RTSP/HTTP/worker integration files pass syntax compilation with PyroWave disabled.
Broader validation has existing failures: three locale consistency checks report legacy locale lists versus the English-only General page; repository-wide frontend lint and typechecking report errors outside this change. These remain unresolved. No installed service or driver was replaced, and no live remote client session has been certified.
Remaining acceptance sequence:
Use the pinned Aurora revision for paired 1080p60 SDR and HDR sessions at 700 Mbps, then repeat at the intended resolution and refresh rate.
Exercise each existing LuminalVGD transport configuration (D3D11, D3D11On12 where applicable, and D3D12), checking display transitions, restoration, reconnects and GPU ownership. PyroWave encoding remains Vulkan.
Before and after each change, run the guard suite and live H.264, HEVC and AV1 sessions on ordinary clients. Repeat GPU interop checks across supported vendors before widening availability.
Measure bitrate, frame loss, latency and color fidelity. Keep the feature opt-in until those checks pass. Extending the full 10 Gbps range requires a separate transport/client agreement and corresponding validation.