Sync 1080p60: thermal load caps the GPU clock and collapses encoding
23 September 2026 · Research report · Headed browser, Syphon and 32-channel USB audio on a fanless Apple M2
Finding: thermal load is the collapse source. On this fanless MacBook Air, sustained Noisedeck 1080p60 output with WING audio raises macOS thermal pressure to level 2 after about five minutes. The system then caps the GPU clock at 444–612 MHz. Chrome keeps the render at 60 fps, and the WebCodecs encoder's GPU-side input path receives only the remainder, so encoding collapses. Reducing render GPU work removes the cap and the collapse. E1 E3
1. Question and design
Earlier research showed a recurring collapse in browser H.264 output after several minutes, with a helper that stayed alive and low canvas capture and worker lag. This study asks what starts the collapse. Each run sent actual Noisedeck 1920 × 1080 output through installed, signed Sync 0.2.88 to an independent Syphon receiver while Sync captured 32 WING Rack USB channels, each carrying a distinct tone. Runs were serial; the 48 WING routes and Ethernet DHCP were restored after each. E1 E2
Table 1. Configuration
| Parameter | Configuration |
|---|---|
| Host | Mac14,2 MacBook Air, Apple M2, fanless; macOS 14.8.3; headed Chrome 153.0.8010.53. |
| Program | Default Noisedeck noise effect, seed 1, at 1920 × 1080 and 60 fps. |
| Video route | Noisedeck renderer → WebCodecs H.264 sender (production configuration) → Sync helper → Syphon → marker-checking receiver. |
| Thermal and GPU sampling | Thermal pressure level every 5 s; GPU performance-state residency and power every 1 s through IOReport; per-process GPU time every 5 s. No elevated privileges. |
2. Measurement contract
Delivered frames are receiver callbacks carrying the expected ordered marker. Missed sequences, duplicates and invalid markers are counted separately. Thermal pressure is the system level from com.apple.system.thermalpressurelevel: 0 nominal, 1 moderate, 2 heavy. GPU clock is the residency-weighted mean of the active performance states, using the host's frequency table (444–1398 MHz). A clock cap is the first second with no residency at 808 MHz or above, at least 90% in the 444 MHz state and at most 2% idle: the GPU is saturated at its lowest clock. ProcessInfo.thermalState reported fair throughout both collapses, so it is not used as the signal. E1
3. Thermal collapse
Table 2. Combined WING and Noisedeck runs
| Run | Window, s | Pressure level 2 at | Clock cap at | Video outcome | Worklet underrun frames |
|---|---|---|---|---|---|
| Default shader, warm start | 720 | not sampled | busy 100% from 381 s (sampler time) | collapsed to 32–42 accepted/s | 108,260 |
| Default shader | 600 | 285 s | 411 s | collapsed to 33.0–35.6 accepted/s | 80,178 |
| Guarded shader | 900 | never (max level 1) | none | 53,999 frames, 0 missed | 0 |
| Live CDN guarded shader, nice 0 | 3600 | never | none | 215,938 frames, 9 missed | 59,646 |
With the default shader, pressure reached level 1 at 108 s and level 2 at 285 s after the window began. The clock cap followed at 411 s. Within seconds, accepted frames fell from 60 per second, the sender queue filled and the AudioWorklet began to underrun. The same collapse occurred in a run that started from a warm chassis. E1
Before the cap, Chrome used a median of 729 ms of GPU time per second (10th–90th percentile 704–755 ms) and the Sync helper a median of 14 ms (at most 18 ms). After the cap, every process's GPU time rose together because the same work ran at a lower clock. E1
4. Mechanism and ruled-out causes
A peer session reproduced the mechanism on a fanless Apple M4 MacBook Air with a synthetic GPU load: thermal pressure rose, the governor capped the clock, and encode delay rose about five seconds after the first capped sample while the render held 60 fps. On the real Noisedeck program the M4 never left pressure level 0 and delivered 43,140 of 43,140 frames in 12 minutes. E3
- Encoder settings. At the cap, H.264 Level 4.2, 20 Mb/s constant bitrate and HEVC all stalled. The encoder emits Level 4.2 when Level 4.0 is requested. E3
- Frame or surface leaks. Live VideoFrames stayed at zero and IOSurface counts stayed flat. E3
- Sync helper. Each publish is one staging blit with at most three command buffers in flight; its GPU time stayed at or below 18 ms/s until the cap. E1
- Canvas visibility and backend. Hidden and visible canvases gave the same clock residency. WebGL2 and WebGPU both rendered at a mean of 82–89% GPU busy. An uncompressed NV12 transport dropped 16–19% on both backends, so it does not avoid the limit. E3
5. Thermal-load reduction
The default noise effect sets refraction mode to color-topology with a refraction amount of zero. At zero it still computed two refraction lookups and a second noise octave per octave, then multiplied them by zero: 10 of 17 simplex evaluations per pixel. Noisemaker fde2ea40 skips that work when the amount is zero, in both shader languages; e11f0767 attests exact GLSL/WGSL parity with refraction active. The change is released to shaders.noisedeck.app/1. E2
Table 3. Render-only GPU power at 1920 × 1080 and 60 fps
| Backend and shader | Mean GPU power, W | Clock-state residency (≥5%) | Pixel hashes at two times |
|---|---|---|---|
| WebGL2, CDN shader | 1.89 | OFF 18%, P1 16%, P2 26%, P3 21%, P4 15% | 88002d6fcdd62d3b59455c32 / 833d5557d1cb94c891494f7c |
| WebGL2, CDN shader | 1.89 | OFF 18%, P1 13%, P2 26%, P3 23%, P4 15% | 88002d6fcdd62d3b59455c32 / 833d5557d1cb94c891494f7c |
| WebGL2, Guarded shader | 0.99 | OFF 18%, P1 74% | 88002d6fcdd62d3b59455c32 / 833d5557d1cb94c891494f7c |
| WebGL2, Guarded shader | 1.02 | OFF 20%, P1 67% | 88002d6fcdd62d3b59455c32 / 833d5557d1cb94c891494f7c |
| WebGPU, CDN shader | 1.68 | OFF 18%, P1 24%, P2 30%, P3 14%, P4 11% | b62edc6eb2f6a074788893c4 / bfc9ac2389ab6eef531c7b9a |
| WebGPU, Guarded shader | 0.94 | OFF 33%, P1 49%, P2 5%, P3 5%, P4 5% | b62edc6eb2f6a074788893c4 / bfc9ac2389ab6eef531c7b9a |
Pixel hashes are identical with and without the change on both backends. GPU power roughly halves; the governor then runs the GPU mostly at 444 MHz. With the guarded shader, the combined 15-minute run stayed at pressure level 1 or below, never capped, and delivered 53,999 marked frames with 0 missed sequences, zero backpressure, zero native audio drops, zero worklet underruns and 32/32 tone identities. The only failed strict assertion was one duplicate marker at the first sequence, a receiver startup artifact also present in the unguarded control. E1
6. One-hour qualification
The one-hour run used the live CDN shader with no test interception, at nice 0. The receiver saw 215,938 marked frames against 216,000 display ticks (99.97%), with 9 missed sequences (0.004%) and receiver p95 72.1 ms. Sender backpressure and native video drops were zero. Native audio delivered 158,919,168 frames with 0 drops and 0 cursor gaps; 32/32 tone identities matched. Maximum thermal pressure was level 1 and the GPU clock was never capped; mean GPU power was 1.2 W. E1
One system disturbance occurred. The 60 s window from 2656 s averaged 3.14 W of CPU power against a run median of 1.47 W, while GPU clock and thermal pressure were unchanged. Eight of the nine receiver gaps fall at 2663 s, inside that window; one isolated gap follows at 3119 s. All AudioWorklet loss inside the measurement window occurred from 2663 to 2666 s (57,852 dropped and 59,646 underrun frames); the final totals of 61,178 and 62,972 include loss during stop. Together they are 0.078% of native frames. The harness therefore reports a strict failure on its zero-loss worklet assertion. E1
Against the operator's criterion of at most 1% dropped frames, the hour passed. It is the first full hour of simultaneous 1080p60 Noisedeck output and 32-channel WING audio through Sync on this host.
7. Graceful degradation under a cap
On the peer M4 at a synthetic load that forces the cap, skipping a render while three or more frames await encoding kept the first minute at 59.0 fps, held encode latency below 82 ms and eliminated backpressure drops. It delivered 82.4% of display ticks against 57.0% unpaced, where encode delay reached 1,376 ms. On the real Noisedeck program with the guarded shader, the same rule skipped 2 of 43,140 draws (0.005%) and delivered 60 fps in every minute of a 12-minute run. The pacing is therefore nearly free on a healthy host and bounds latency under a cap. It is a candidate product hardening; it does not replace reducing load. E3
8. Decision
Treat thermal load as the root cause of the recurring collapse on fanless hosts. Keep H.264 as the transport. Ship render-cost reductions for default programs, beginning with the released noise-effect change. Evaluate encoder-aware render pacing for graceful degradation when a host caps its GPU. Report thermal pressure level and GPU clock residency in future endurance runs. E1 E3
9. Limits
- One fanless M2 host carried the combined WING measurements. Peer M4 results are reported by that session; their raw files remain on that host.
- All comparison arms ran at a lowered CPU priority (nice 5) under the same condition; only the one-hour qualification ran at nice 0.
- Ambient temperature and chassis surface temperature were not measured.
- Other Noisedeck programs can carry more GPU load than the default noise effect and can still reach a cap on this host.
- A Windows Direct3D shader compile check of the change has not run.
- Only Syphon output was measured; the macOS virtual camera was not tested.
Evidence references
- E1. Run measurements. Per-run delivery, audio, thermal pressure, clock-cap timing, GPU power and private receipt digests.
- E2. Source identity. Sync build, Noisedeck head, Noisemaker commits, tested bundle digests and sampler digests.
- E3. Findings. Collapse source, ruled-out causes, peer-host results and harness corrections.
- E4. Timeline figure. Generated from the same receipts as E1.
- E5. Prior WING and H.264 endurance research. The collapse this study explains.