Python: headless viewer, vsync control, pipelined frame capture#11
Merged
sebcrozet merged 3 commits intoJul 16, 2026
Merged
Conversation
haixuanTao
force-pushed
the
feat/python-headless-capture
branch
from
July 8, 2026 19:56
e000dc5 to
5bd7f21
Compare
haixuanTao
force-pushed
the
feat/python-headless-capture
branch
from
July 9, 2026 07:05
5bd7f21 to
6a3c7e1
Compare
…thon) The windowed capture loop was vsync-locked: kiss3d's swapchain defaults to AutoVsync and the blocking per-frame snap_rgb() readback defeats frame pipelining, so each render_frame+render iteration ate ~2 vblanks (~30 fps at 60 Hz) no matter how fast the GPU was. Fixes, exposed through nexus3d: - NexusViewer(width, height, headless=True): no OS window, no swapchain — frames render into an off-screen texture (kiss3d headless Window), never throttled by the display and usable without a display server. - NexusViewer.set_vsync(enabled)/vsync(): uncap a windowed viewer instead. - NexusViewer.render_async()/render_flush(): pipelined capture — returns the previous frame while this frame's GPU->CPU copy runs in the background (one frame of latency; flush collects the last frame). Cube-drop capture at 640x480: 33.1 -> 92.1 gen-fps (GPU physics), 26.5 -> 37.5 (Rapier CPU backend). Requires kiss3d feat/headless-capture-pipeline (new_headless_with_setup + snap_begin/snap_finish).
sebcrozet
force-pushed
the
feat/python-headless-capture
branch
from
July 16, 2026 12:01
6a3c7e1 to
2185c94
Compare
Member
|
Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #8 (which stacks on #7) — merge order: #7 → #8 → this. After those merge, this PR reduces to its single commit (
feat: headless viewer, vsync control, and pipelined frame capture (Python)); until then the diff below includes their changes.New capture API in the
nexus3dPython bindings:NexusViewer(..., headless=True)— no OS window, no swapchain: frames render into an off-screen texture, never throttled by display vsync, and it works without a display server.set_vsync(enabled)/vsync()— uncap a windowed viewer instead.snap_rgb_async()/snap_rgb_flush()— pipelined capture: returns the previous frame while the current frame's GPU→CPU copy runs in the background (one frame of latency; flush collects the last frame).Why: the windowed capture loop was vsync-locked at ~30 fps — the swapchain defaults to Fifo and the blocking per-frame
snap_rgb()readback defeats frame pipelining, so each iteration ate ~2 vblanks regardless of GPU load. Headless + pipelined readback reaches 92 gen-fps at 640×480 (GPU physics; 37.5 with the Rapier CPU backend) on an RTX 5080, up from 33.🤖 Generated with Claude Code