Repository navigation
Description
Summary
On WSL2, hyperframes render never uses the GPU, even with an NVIDIA card that WSL can see (/dev/dxg, nvidia-smi and CUDA all work). The auto probe logs browserGpuMode probe → software (WebGL unavailable) and Chrome draws with SwiftShader. --browser-gpu doesn't help either: Chrome's GPU process exits during init. For a long 1080p composition this makes capture CPU-bound: a 7:23 render took 48 min, with the three SwiftShader GPU processes using about 23 of 28 threads.
Running the same CLI natively on Windows on the same machine works: the probe finds the GPU (ANGLE / D3D11) and capture is about 5x faster on the same composition. The workaround is below. On Windows we also hit a hang with segmented capture plus more than one worker (section 4).
Environment
- Windows 11, build 10.0.26300.9550
- GPU: NVIDIA GeForce RTX 4070 SUPER, Windows driver 616.92
- WSL 2.4.13.0, kernel 5.15.167.4-microsoft-standard-WSL2, WSLg 1.0.65 (
DISPLAY=:0,WAYLAND_DISPLAY=wayland-0) - Ubuntu 22.04.5 LTS, Mesa 23.2.1 (
libegl-mesa0,libgl1-mesa-driwithd3d12_dri.so); no Vulkan ICDs installed - hyperframes 0.8.153 (
npx --yes hyperframes@latest), chrome-headless-shell 152.0.7977.30 (the CLI's own download), Node v22.17.0 - 28 logical CPUs; 15 GB RAM for WSL, 32 GB on the Windows host
- Composition: 1920x1080 at 30 fps, 7:23 (13,303 frames), 26
<video>(VP9 alpha WebM and H.264), 165<audio>, 11 elements withdata-color-grading
1. What happens in WSL2
The render log:
GPU: browser GPU (auto-detect)
[hyperframes] browserGpuMode probe → software (WebGL unavailable)
[BrowserManager] Browser launched (HeadlessChrome/152.0.7977.30, beginframe, gl=--use-gl=angle --use-angle=swiftshader, headlessShell=true, platform=linux)
...
rendered in 48m 12.6s
beginframe capture · software gpu · ... · capture 46m 16.5s · encode 45m 54.4s
While it ran, the three --type=gpu-process Chrome processes sat at 600 to 970% CPU each (load average 34 on 28 threads). ffmpeg (libx264, preset slow, CRF 15) used about 25% of one core. The encoder isn't the limit: on its own it encodes 450 of these frames in 4 s.
2. Why: Chrome's EGL path can't open the render node
I launched chrome-headless-shell from the CLI's cache via puppeteer-core, with getHardwareGpuProbeArgs("linux") (--use-gl=angle --use-angle=gl-egl --enable-gpu-rasterization --disable-software-rasterizer) and --enable-logging=stderr --v=1. The GPU process exits:
ERROR:ui/gl/gl_surface_egl.cc:277] No suitable EGL configs found.
ERROR:ui/gl/gl_surface_egl.cc:1021] No suitable EGL configs found for initialization.
ERROR:gpu/config/gpu_info_collector.cc:85] gl::GLContext::CreateOffscreenGLSurface failed
ERROR:gpu/config/gpu_info_collector.cc:593] Could not create surface for info collection.
ERROR:gpu/ipc/service/gpu_init.cc:123] CollectGraphicsInfo failed.
ERROR:components/viz/service/main/viz_main_impl.cc:190] Exiting GPU process due to errors during initialization
Mesa's own EGL fails the same way outside Chrome. I tested with a small ctypes program calling eglInitialize (surfaceless and default platforms) under EGL_LOG_LEVEL=debug:
libEGL warning: failed to open /dev/dri/renderD128: Permission denied
libEGL debug: EGL user error 0x3001 (EGL_NOT_INITIALIZED) in eglInitialize: DRI2: failed to load driver
$ ls -l /dev/dri/ /dev/dxg
crw-rw-rw- 1 root root 10, 127 /dev/dxg
crw-rw---- 1 root video 226, 0 /dev/dri/card0
crw-rw---- 1 root render 226, 128 /dev/dri/renderD128
$ id # user is in 'video', NOT in 'render'
A default WSL2 Ubuntu user is in video but not render. Mesa therefore can't open the render node it uses to reach the D3D12 Gallium driver, and every EGL route fails.
Every WebGL probe we tried returns WebGL unavailable:
--use-angle=gl-egl,--use-angle=gl,--use-angle=vulkan --enable-features=Vulkan(no Vulkan ICD installed) and--use-gl=egl, each with a plain environment and withGALLIUM_DRIVER=d3d12.--use-angle=gl-egland--use-angle=gles-eglwithEGL_PLATFORMset tosurfaceless,device,x11orwayland.--use-angle=gl-egland--use-angle=gles-eglwithEGL_PLATFORM=surfaceless GALLIUM_DRIVER=d3d12 MESA_LOADER_DRIVER_OVERRIDE=d3d12.
Not tested: whether sudo usermod -aG render $USER plus wsl --shutdown lets ANGLE gl-egl reach the RTX through Mesa's d3d12 driver. Fixing the permission should at least get Mesa past the first failure. I'll report back if we try it.
3. Workaround: render from Windows
The same CLI, started from Windows on a copy of the project on C:, with portable Node 22.17.0 and FFmpeg on that process's PATH, and --browser-gpu:
[hyperframes] browserGpuMode probe → hardware (WebGL renderer vendor="Google Inc. (NVIDIA)" renderer="ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 SUPER (0x00002783) Direct3D11 vs_5_0 ps_5_0, D3D11)")
[BrowserManager] Browser launched (HeadlessChrome/152.0.7977.30, screenshot, gl=--use-gl=angle --use-angle=d3d11, headlessShell=true, platform=win32)
Capture rate on the composition's first 15 s (data-duration cut to 15, everything else unchanged), --quality delivery --fps 30:
| Setup | Capture |
|---|---|
WSL2, SwiftShader, 3 workers, HF_SEGMENTED_CAPTURE=true |
about 3.2 frames/s |
Windows, --browser-gpu, 1 worker |
8.5 frames/s |
Windows, --browser-gpu, 3 workers, HF_SEGMENTED_CAPTURE=false |
about 16 frames/s |
The Windows output matches the WSL render: 450 frames, SSIM 0.989. The only visible difference is text antialiasing, because Windows rasterises fonts with DirectWrite instead of FreeType.
Our wrapper, run from WSL, works like this:
- It mirrors the project to
C:\Users\<user>\hf-render\<project>. It skipsnode_modules,rendersand similar folders, plus files over 32 MB that no.html/.cssreferences. - It writes a
.cmdfile that runsnpx.cmd --yes hyperframes@latest render ... --browser-gpuwithHF_SEGMENTED_CAPTURE=false. - It copies the output back.
We render from a C: copy rather than \\wsl.localhost\... because npx.cmd runs under cmd.exe, which can't start in a UNC directory.
4. Related: Windows, segmented capture with more than one worker hangs page navigation
With HF_SEGMENTED_CAPTURE=true HF_SEGMENT_FRAMES=450 HF_SEGMENT_BROWSER_RECYCLE=1 --workers 3 --browser-gpu on Windows (screenshot capture, since BeginFrame is Linux-only), all three workers load in the same Chrome. The first page initialises; the second page's page.goto never completes:
[BrowserManager] Browser launched (HeadlessChrome/152.0.7977.30, screenshot, gl=--use-gl=angle --use-angle=d3d11, headlessShell=true, platform=win32)
[initSession:screenshot] page.goto start (0ms)
[initSession:screenshot] page.goto complete (649ms)
...
[initSession:screenshot] media + fonts + tailwind ready (46186ms)
[initSession:screenshot] page.goto start (0ms)
25% Failed: Navigation timeout of 180000 ms exceeded
What we observed on the same composition and machine:
- 1 worker with segmented capture: works.
- 3 workers with
HF_SEGMENTED_CAPTURE=false: works. The log shows threeBrowser launchedlines and all three pages load in under 1 s. - 3 workers with segmented capture, and the composition stripped to its 2 in-range videos and no
<audio>: works.
So the hang needs segmented capture, more than one worker and a media-heavy page together. We haven't isolated the cause. One guess is Chrome's limit of 6 connections per host: the first page's 26 videos and 165 audio elements could hold every connection to the local file server, so the second tab's document request never gets one. #4881 (navigation hangs with data-color-grading on a <video>, ANGLE / D3D11) may be related. This composition has 11 graded elements, but they render fine on Windows without segmented capture.
Suggestions
- Make the WSL fallback actionable. When
/dev/dxgexists or/proc/versioncontainsmicrosoft, and the hardware probe fails, the warning could say why (/dev/dri/renderD128not accessible to the user, or the EGL init error) and suggest therendergroup or a native Windows render. Today the only output isprobe → software (WebGL unavailable), and the--browser-gpuremediation text talks about Docker passthrough. - Document WSL2 in the rendering docs, including that a Windows-native render of the same project uses the GPU.
- On Windows, give each worker its own browser when segmented capture is on, or find and fix the second-tab navigation hang above. Segmented capture is what we use in WSL to avoid OOM, so its default on Windows matters.
- Minor: the render's local file server listens on all interfaces. On Windows that triggers a Windows Defender Firewall prompt for node.exe the first time. Binding to
127.0.0.1would avoid it, since the browser only uses localhost.
We can share full logs, the probe scripts and the timing data.
Activity
jrusso1020 commentedon Oct 13, 2026
Thanks for the detailed report. On the segmented-capture hang: on Windows all segmented workers share one Chrome, and they all load media from the same local server, so they compete for Chrome's 6 connections per host. On Linux we could reproduce the connection wait but not a full hang. Could you rerun the failing segmented command with
PRODUCER_ENABLE_BROWSER_POOL=falseset? If that completes, the shared browser is the trigger and we'll give each worker its own.ajp-productions commentedon Oct 13, 2026
Thanks @jrusso1020. Results below, all on 0.8.154, same machine as the report (RTX 4070 SUPER, Windows driver 616.92, Chrome 152.0.7977.30).
1. Requested test:
PRODUCER_ENABLE_BROWSER_POOL=falsefixes the Windows hangThe setup is the 15 s copy from the report (all 26
<video>and 165<audio>kept, 11 withdata-color-grading), withHF_SEGMENTED_CAPTURE=true HF_SEGMENT_FRAMES=450 HF_SEGMENT_BROWSER_RECYCLE=1 render --quality delivery --fps 30 --workers 3 --browser-gpu, run on native Windows.PRODUCER_ENABLE_BROWSER_POOLpage.goto complete (589ms); page 2 never completesNavigation timeout of 180000 ms exceeded(still reproduces on 0.8.154)falsepage.goto completein about 0.6 sSo the shared browser is the trigger.
One more observation with the pool off: the three worker sessions initialise one after another. Each
page.goto startcomes only after the previous session'smedia + fonts + tailwind ready, so any media-readiness wait is paid once per worker in series. In this trimmed copy, 24 out-of-range videos never become ready, so each session waits about 46 s. Capture took 3m18s, against 1m13s forHF_SEGMENTED_CAPTURE=falsewith 3 workers on 0.8.153, where the threepage.gotocalls start together.2. New bug: segmented capture renders the first frame of a segment ungraded when a
data-color-gradingvideo is playingFound in a full render. We rendered a 7:23 composition (13,303 frames,
HF_SEGMENT_FRAMES=450, WSL, BeginFrame) and compared it frame by frame with a non-segmented Windows render of the same composition. Three single frames, 5400, 6750 and 11250, show the B-roll ungraded (brighter and cooler). The frames on either side are graded:Those are exactly the 3 of the 29 segment boundaries that land inside a graded
<video>. No other boundary shows a change, and the non-segmented render is clean at all three.Repro. We used the same composition with
data-durationset to 30 s. Gradedbr01(H.264 1920x1080 30 fps, muted,class="clip") is on screen for frames 682 to 808, andHF_SEGMENT_FRAMES=700puts a segment boundary inside it. Its grade is{"preset":null,"intensity":1,"adjust":{"contrast":0.3,"highlights":-0.1,"blacks":-0.15,"temperature":0.35,"saturation":-0.35},"details":{"vignette":0.45,"vignetteFeather":0.65,"grain":0.5,"grainSize":0.3,"grainRoughness":0.6},"effects":{"tapeNoise":1,"tapeSpeed":0.5,...}}, written byhyperframes media-treatment --apply.Mean RGB at frames 698 to 702:
HF_SEGMENT_BROWSER_RECYCLE=1HF_SEGMENT_BROWSER_RECYCLE=0PRODUCER_ENABLE_BROWSER_POOL=falseHF_SEGMENTED_CAPTURE=falseAll four runs used 3 workers and
--quality delivery --fps 30. Both WSL runs loggedbrowserRecycles: 0. Insidebr01the only single-frame flash is frame 700, the only frame that jumps and then returns to its neighbours' colour. The other large frame-to-frame changes (684, 783, 808) are one-way: the clip's entry and its own motion.So the flash is independent of platform, capture mode (BeginFrame or screenshot) and browser recycling. What it takes is the first frame of a segment, landing in the middle of a graded video. Our guess is that the first captured frame after a segment's seek is drawn before the grade pipeline has the video frame. We haven't tested whether a worker's first frame in a non-segmented render has the same problem when it lands inside a graded video. #4881 (
data-color-gradingreadiness) might be related.Detection tip.
checkand our cut checks don't catch this. A PSNR comparison against a non-segmented render does: it spikes at exact multiples ofHF_SEGMENT_FRAMES.3. Full-length timing for the workaround
Same 7:23 composition (13,303 frames, 1920x1080 at 30 fps,
--quality delivery --workers 3):--browser-gpu,HF_SEGMENTED_CAPTURE=falseThe two outputs pass the same frame-count, loudness (-13.1 LUFS, true peak -1.5 dBFS) and cut checks. The audio correlates at 0.999. The picture differs only in text antialiasing, plus the three ungraded frames above, which only the WSL render has.
4. On #5560
Thanks for the WSL diagnostics. You're right about the firewall: the render's file server binds 127.0.0.1. Our suggestion 4 came from misreading the
previewport check, sorry for the noise. If it helps, we can test therendergroup change on this NVIDIA card. Your Intel run couldn't cover that case.ajp-productions commentedon Oct 13, 2026
The
rendergroup fix on NVIDIA (the case #5560 couldn't test)We ran
sudo usermod -aG render joe, thenwsl --shutdown. After that the user is inrender(110) and/dev/dri/renderD128is readable and writable. Same machine as before: RTX 4070 SUPER, driver 616.92, WSL 2.4.13, Mesa 23.2.1, hyperframes 0.8.154.Mesa now reaches the RTX. A ctypes EGL test (system Python) creates a GLES context and reports
GL_RENDERER = D3D12 (NVIDIA GeForce RTX 4070 SUPER). Config counts per platform:chrome-headless-shell152.0.7977.30 (the CLI's browser) still fails, and it fails instantly. This isn't the slow start #5560 saw on Intel. The probe answers "WebGL unavailable" in under 0.2 s, and the GPU process logs the same error as before the fix:That holds for
--use-angle=gl-egl/gles-egl/gl/vulkan, withEGL_PLATFORMset tox11,wayland,deviceorsurfaceless, and withGALLIUM_DRIVER=d3d12. Our guess: on Mesa's D3D12 driver the surfaceless display has pbuffer configs but no window configs, and the headless shell's config selection doesn't accept that.Full Chrome works. Chrome for Testing 139.0.7258.154 (
~/.cache/puppeteer) in--headless=newgets WebGL onANGLE (Microsoft Corporation, D3D12 (NVIDIA GeForce RTX 4070 SUPER), OpenGL ES 3.1)in about 0.1 s. We saw the same with no ozone flag, with--ozone-platform=x11and with--ozone-platform=wayland, and also with--use-angle=gl, which reports OpenGL 4.2.HyperFrames renders on the GPU in WSL with that browser. We rendered the 15 s copy with
HYPERFRAMES_BROWSER_PATH=<Chrome 139> --browser-gpu,HF_SEGMENTED_CAPTURE=false, 3 workers,--quality delivery --fps 30:Results against the default headless shell on SwiftShader (same copy, same flags, no
HYPERFRAMES_BROWSER_PATH):media_readiness_timeout: 3 videos never decode (45 s)Both outputs have 450 frames and match each other (PSNR 49.8 dB, min 47.1, SSIM 0.995). So on WSL with NVIDIA, the GPU path works once the user is in
render, but only with full Chrome. On this light opening it doesn't capture faster than SwiftShader. Its gain here came from full Chrome decoding every video, so it never waited out the 45 s readiness timeout the headless shell hit. We haven't run a full-length WSL render on this path.Correction to our earlier numbers
Our 15 s capture rates in the report (WSL 3.2, Windows 1 worker 8.5, Windows 3 workers about 16 frames/s, "about 5x") were wrong as drawing speeds. They divided 450 frames by capture phases that included startup waits: the 45 s
media_readiness_timeouton videos the trimmed copy never plays, paid once per worker in series in segmented mode. They also compared segmented runs (HF_SEGMENT_FRAMES=450on a 450-frame render, which captured at about 8 frames/s, like a single worker) with non-segmented ones. Please disregard them as drawing speeds. Like for like (3 workers, no segments, measured after the pages are ready), this light opening captures at about 28 frames/s on WSL SwiftShader and about 22 on WSL D3D12 (full Chrome). Windows D3D11 with screenshot capture comes out around 16, estimated from the capture phase minus the 46 s wait.The reliable comparison is the full-length one in our previous comment. The 7:23 composition captured in 46m16s on WSL SwiftShader (segmented) against 14m31s on Windows
--browser-gpu(no segments), about 3.2x, with a total of 48m13s against 18m38s. The gain comes from the heavy sections (graded B-roll, blurs, split screens), where SwiftShader dropped to about 2 frames/s.fix(engine): say why WSL renders fall back to software and how to get…
fix(engine): stop multi-worker renders hanging on media-heavy pages o…
ajp-productions commentedon Oct 14, 2026
Retested on 0.8.155, same machine (Windows 11, RTX 4070 SUPER, driver 616.92; WSL 2.4.13, user now in
render). Thanks for the quick turnaround.#5565, the Windows segmented hang: fixed. The exact command from the report, with default settings and no
PRODUCER_ENABLE_BROWSER_POOL(HF_SEGMENTED_CAPTURE=true HF_SEGMENT_FRAMES=450 HF_SEGMENT_BROWSER_RECYCLE=1 render --quality delivery --fps 30 --workers 3 --browser-gpu), now launches one GPU Chrome per worker. Eachpage.gotocompletes in about 0.6 s, and the render finishes with all 450 frames. On 0.8.154 it timed out after 180 s. One small thing remains: the worker sessions still initialise one after another (eachpage.goto startfollows the previous session'smedia + fonts + tailwind ready). That only costs time when readiness is slow.#5560, the WSL diagnostics: working. In auto mode, with the user in
render:A suggestion for that branch: once permissions are ruled out, it currently gives no route to the GPU. On NVIDIA (our comment above) the two routes that work are rendering from native Windows, and
HYPERFRAMES_BROWSER_PATHpointing at full Chrome in--headless=new, which reaches the GPU through Mesa D3D12 wherechrome-headless-shellfails with "No suitable EGL configs found". The native Windows line that theusermodbranch prints would help here too.Still open: the ungraded first frame of a segment. It reproduces unchanged on 0.8.155. We used the 30 s repro from our earlier comment (graded
br01on screen for frames 682 to 808) withHF_SEGMENTED_CAPTURE=true HF_SEGMENT_FRAMES=700, 3 workers,--browser-gpu, on native Windows:The two merged PRs don't touch it, so this is just confirmation it's still there. Happy to run a build against it. Until it's fixed we render without segments when a composition has
data-color-gradingvideo.miguel-heygen commentedon Oct 14, 2026
Thanks for retesting, and for running the
rendergroup test on NVIDIA; that pinned it down.Two more fixes are up:
HYPERFRAMES_BROWSER_PATH, and points to native Windows. It no longer implies therendergroup alone is enough.The ungraded first frame of a segment is being worked on next.
We can't check #5574 on NVIDIA ourselves. Would you try the branch on your machine?
You should see
browserGpuMode probe → software (WebGL unavailable)for the headless shell, thenbrowserGpuMode probe → hardware (full Chrome: ...)and aBrowser launched (..., screenshot, ...)line.ajp-productions commentedon Oct 14, 2026
Tested #5574 (
fix/wsl-gpu-full-chromeat 600ffd0) on the NVIDIA machine: Windows 11, RTX 4070 SUPER, driver 616.92, WSL 2.4.13, Ubuntu 22.04, Mesa 23.2.1, user inrender. Short version: the fallback works, but only with Chrome 149 or older. Every Chrome from 150 on fails the same way the headless shell does, and that includeschrome@stable(155 today).1. As instructed: no GPU
bun installput Chrome for Testing 152.0.7977.42 in~/.cache/puppeteer(Puppeteer's postinstall).resolveFullChromePathtakes the newest version there, so the render used it:It rendered fine on SwiftShader: 450 frames, 2m15s.
2. With Chrome 139 as the newest full Chrome: works exactly as described
We moved 152 out of the cache, leaving 139.0.7258.154, and ran the same command:
It rendered 450 frames in 46.2s, against 2m15s for run 1, and matches the SwiftShader output (PSNR 49.5 dB, min 46.9). GPU load peaked at 23%.
Caveat on that speed-up: this is our trimmed 15 s copy. Most of the gap is the headless shell's 45 s
media_readiness_timeoutper session on videos outside the trimmed duration, which full Chrome never hits. Measured after the pages are ready, all runs capture this light opening at about 23 to 31 frames/s. We haven't run a heavy composition in WSL on the GPU.3. Bisect: Chrome 150 is where it breaks
We used
browsers install chrome@N/chrome-headless-shell@Ninto a scratch path and probed WebGL with the CLI's Linux hardware flags (--use-gl=angle --use-angle=gl-egl --enable-gpu-rasterization --ignore-gpu-blocklist --disable-software-rasterizer):chrome@stabletoday)From 150 on, the GPU process fails at initialisation (
CreateOffscreenGLSurface failed→Exiting GPU process due to errors during initialization). On 152 the log also shows the original report'sgl_surface_egl.cc: No suitable EGL configs found.--headless=new,--ozone-platform=x11|wayland,--use-angle=gl|vulkanandEGL_PLATFORMoverrides made no difference. Mesa's surfaceless display on D3D12 offers 48 pbuffer configs and 0 window configs (x11: 64 / 64), so something in 150 seems to have changed which configs it accepts.So the variable is the Chrome major, not headless shell vs full Chrome. With 0.8.155 released and
HYPERFRAMES_BROWSER_PATHpointed atchrome-headless-shell149:That's BeginFrame capture on the GPU in WSL. The output matches (450 frames, PSNR 49.6 dB) and GPU load peaked at 73%.
Suggestions
chrome@stableinstalls one.chromeMajorCeilingmechanism could apply to the headless shell too, which keeps BeginFrame. In the note,chrome@149would be the install line that actually works today.Two minor notes:
bun run buildon Node 22.17.0 failed in@hyperframes/sdk-playground(ERR_UNKNOWN_FILE_EXTENSION ".ts"forpackages/sdk/src/adapters/fs.ts). It looks like it needs Node's type stripping (22.18 and later).cli,engineandproducerbuilt fine.fix(engine): renders under WSL use the GPU through full Chrome when t…
fix(core): keep the colour grade on a graded video's first rendered f…
fix(engine): renders under WSL reach the GPU on Chrome 150 and later
fix(engine): renders under WSL reach the GPU on Chrome 150 and later (h…
miguel-heygen commentedon Oct 14, 2026
Thanks for the bisect. It found the cause: since Chrome 150, Chrome picks its Wayland graphics backend whenever
WAYLAND_DISPLAYis set, and WSLg always sets it. That backend has no offscreen configs on Mesa's D3D12 driver, so the GPU process exits. Without the variable, Chrome uses X11 graphics, which works. It is tracked upstream at https://issues.chromium.org/issues/567222741.0.8.157 is on npm with the fix (#5591). Under WSL, when the GPU check finds no GPU and
WAYLAND_DISPLAYis set, HyperFrames checks once more without it. If that reaches the GPU, renders launch that way. Otherwise nothing changes. It also removes the full-Chrome fallback from #5574, which could not help.Could you try it on the NVIDIA machine, with the default GPU setting (no
--browser-gpu, which skips the check)? Clear anyHYPERFRAMES_BROWSER_PATHfirst:Expected in the log:
Our WSL test PC has an Intel GPU whose X11 graphics are broken, so it never takes the GPU path; your machine is the one that can confirm it. A render time against your 149 runs would help too.
ajp-productions commentedon Oct 14, 2026
Confirmed on 0.8.157, NVIDIA machine (RTX 4070 SUPER, driver 616.92, WSL 2.4.13 with WSLg, user in
render, noHYPERFRAMES_BROWSER_PATH). Everything we reported in this issue is fixed on our side.#5591: WSL reaches the GPU with the CLI's own Chrome 152
npx [email protected] render --output out.mp4, default GPU setting:That's exactly the expected sequence: the headless shell's own Chrome 152, BeginFrame on the RTX, no older Chrome needed. The 450-frame output matches the SwiftShader render of the same copy (PSNR 49.6 dB, min 47.1, SSIM 0.995).
Render times. On our trimmed 15 s copy the three setups are a tie, because that copy's 45 s media-readiness timeouts dominate and the content is light:
without WAYLAND_DISPLAY)HYPERFRAMES_BROWSER_PATH= headless shell 149 (our earlier run)--no-browser-gpuOn heavier content the GPU path pays off. All rows below are WSL,
--quality delivery --fps 30 --workers 3:HF_SEGMENT_FRAMES=700)--no-browser-gpu, screenshot capture)The full-length WSL GPU render is now faster than our native Windows route on the same composition: 17m18s, with D3D11 and screenshot capture, no segments. It passes our frame-count, loudness and cut checks identically, and compared frame by frame with the Windows render it gives SSIM 0.991, with only text antialiasing differing (FreeType vs DirectWrite).
#5575: ungraded first frame of a segment, fixed
The 30 s repro (graded
br01on frames 682 to 808,HF_SEGMENT_FRAMES=700), mean RGB at frames 698 / 699 / 700 / 701 / 702:--no-browser-gpu, screenshot--browser-gpu, screenshotOn 0.8.155 frame 700 was 90 65 61. The full-length render above also has no ungraded frame at any of its 29 segment boundaries; 0.8.153 had three (5400 / 6750 / 11250).
#5573 and #5565: segmented workers on Windows
On Windows with 0.8.157 and default settings (no
PRODUCER_ENABLE_BROWSER_POOL), the three workers now start together, one Chrome each:The readiness waits overlap. The same 30 s segmented test took 3m33.9s against 5m03.1s on 0.8.155.
Thanks for the fast turnaround on all four fixes. From our side this issue can be closed.
jrusso1020 commentedon Oct 24, 2026
Closing as fixed. The WSL2 GPU probe and Windows capture fixes landed in #5560, #5565, #5573, #5574, #5575 and #5591, and you confirmed on 0.8.157 that everything reported here is fixed on your side. Thanks for the detailed report.