The Problems I Ran Into Streaming Windows Games to My Mac
The Problems I Ran Into Streaming Windows Games to My Mac
My Mac mini M4 received GTA5 video from a Windows laptop running Sunshine. The RTX 3050 Ti Laptop had 4 GiB of dedicated VRAM. Troubleshooting occurred on August 30–31, with observations through September 15; the publication date follows the KB's first Git commit on September 15.
The main correction is causal: process crashes, encoder wait timeouts, and color banding are separate failures. High VRAM use is evidence to investigate, while HAGS remains a hypothesis without a matched system-level on/off experiment.
Establish a verifiable baseline session
Separate capture, encoding, transport, decoding, and display. Sunshine's web UI, pairing control channel, and video traffic are different checks. A reachable page or low-latency ping does not validate UDP streaming or decoder performance.
Windows game/desktop → Sunshine capture → NVENC encoding
↓
transport and buffering
↓
Moonlight decoding → macOS displayInstall from official releases and record versions, GPU driver, display/MUX mode, and network topology. Create the Sunshine management account, inspect installer firewall rules and their network scope, pair through Moonlight, and open Desktop before introducing the game. Moonlight setup guide
Validate pairing, desktop video, input/audio, and hardware encode/decode before adding load. Fix initial resolution and frame rate; change one variable at a time. Verify actual ports against the installed version and custom base-port configuration. Do not copy the case's nondefault ports or expose all ports as a troubleshooting shortcut.
Running can hide repeated crashes
Sunshine 0.23.1 froze and failed to reconnect while the service remained Running. Repeated full startup sequences indicated restarts, possibly hidden by service recovery. Inspect process identity and events together:
Get-Service SunshineService
Get-Process sunshine -ErrorAction SilentlyContinue | Select-Object Id,StartTime,Responding
Get-WinEvent -FilterHashtable @{
LogName='Application'; Id=1000; StartTime=(Get-Date).AddHours(-3)
} | Where-Object Message -match 'Sunshine' |
Select-Object TimeCreated,Id,Message
Get-Content 'C:\Program Files\Sunshine\config\sunshine.log' -Tail 100The record contains 6 crashes within one minute, with 0x80000003 and matching module/offset. That supports a repeated crash path, not the exact assertion or certificate-validation bug. Pairing-state observations are leads; without a dump and stack, their causal role remains unproven.
Back up configuration, pairing state, and events before supported re-pairing or upgrade. Editing sunshine_state.json is not a universal first step. The historical upgrade to v2025.628.4510 yielded 50 crash-free minutes, demonstrating improvement in that window without proving every timeout disappeared or recommending that old version today.
An encoder wait timeout is not a VRAM allocation trace
Another window showed frame 1 encode wait timeout, 3688/4096 MiB used, 92% utilization, and 60 W. These establish high activity and a missed encoding deadline, not a recorded allocation failure or proven permanently blocked driver stack.
nvidia-smi --query-gpu=timestamp,name,memory.used,memory.total,utilization.gpu,power.draw --format=csv -l 2Align telemetry and Sunshine timestamps, retaining game scene, resolution, encoder settings, and client statistics. Keep unsupported WDDM fields as N/A. Record failed termination errors and remaining PIDs rather than calling every stuck Windows process a Unix zombie.
Reducing textures/background load or opening the stream before the game are useful local experiments. Fixed “80% safe” thresholds, universal MiB savings, and mandatory dedicated-GPU MUX mode are not established. Capture paths and cross-adapter behavior also need inspection.
Encoder priority is different from disabling system HAGS
nvenc_realtime_hags changes encoding priority while Windows HAGS is enabled. Setting it to disabled does not disable HAGS itself. Official documentation describes a potential NVIDIA freeze involving realtime priority and high VRAM use, with capture-performance tradeoffs when priority is reduced. Sunshine configuration
The case had HAGS enabled and recurrent timeouts after changing this option. No matched system HAGS-off trial followed, so HAGS/driver scheduling remains a hypothesis. Upstream issue #863 suggests an experiment, but describes different hardware, driver, and software.
For the next test, fix software, driver, display mode, scene, resolution, frame rate, and bitrate. Compare system HAGS on/off with required reboots, measuring encoder latency, timeout count, game frame rate, and recovery. Test driver upgrades separately. This proposed experiment was not performed during writing.
Verify negotiated video format
The KB interpreted hevc_mode=4 as 10-bit 4:4:4. The official mapping does not support that: documented 0/1/2/3 values concern capability advertisement, and Main10 does not imply 4:4:4. Verify bit depth, chroma, HDR, color range, and actual profile separately.
Banding changed during historical parameter adjustments, but complete negotiation records were not archived. Consequently, neither guaranteed 10-bit 4:4:4 nor precisely halved buffers are claimed. Inspect encoder creation and Moonlight session statistics before comparing the same scene.
Fix resolution/frame rate, then vary bitrate, codec, HDR, or game quality individually. Client capability does not establish support throughout the server/driver/display path. Network drops, decoder drops, and encode latency have different meanings.
What the two-week record establishes
| Period | Recorded timeout-restart actions | Interpretation |
|---|---|---|
| September 1 | 10:50, 23:54 | 2 actions |
| September 2 | 23:52 | 1 action |
| September 3 | 00:46, 11:54, 22:35, 22:45, 23:50 | 5 actions; correct the original claim of 4 |
| September 4–15 | No additional timeout actions listed | No recorded action; not a reliability test with a workload denominator |
There were 8 timeout-associated restarts and 5 separate service-start actions. The KB reports restored sessions, but action logs alone cannot prove zero dropped frames, zero impact, or preserved game state universally.
The original watchdog searched recent log tails with a three-minute age limit and five-minute deduplication. A revised design should preserve event identity, processed offset, before/after PID, exit codes, and session probes. Do not mark success after failed restart. Validate rotation, clock changes, concurrent runs, and stale errors without active sessions before presenting an automatic restart script as generally usable.
Choose the next evidence and preserve rollback
| Symptom | Next evidence | Minimal intervention |
|---|---|---|
| Running service, changing PIDs | Event 1000, startup log, dump | Back up and investigate version/pairing |
| Stable PID, encode timeout | Encoder log, synchronized GPU data | Controlled load/scheduling experiment |
| Encoding works, client drops | Moonlight stats, network and decoder data | Single bitrate or output-load adjustment |
| Incorrect colors | Negotiated codec/profile/HDR/range | Same-scene format comparison |
Record original settings and disable the old watchdog when evaluating a replacement, so recovery does not hide failures. Restore individual settings or backups if needed and preserve evidence before maintenance reboots. Background GPU and virtual-display management addresses another layer; stopping LegionZone is not an encoder-root-cause diagnosis.
The date is the main KB's first Git commit date, 2026-09-15 (UTC+8), commit 6d198b9. Merged sources are retained in metadata; historical operation dates are separate from repository dates. Revised configuration examples were not executed on production devices.
