feat(deck-pose,deck-slice): draw the camera feed as the game background #913
Closed
lytedev
wants to merge 1 commit from
deck-video into deck-slice-speed
pull from: deck-video
merge into: lytedev:deck-slice-speed
lytedev:main
lytedev:propose/module-directory-scanner
lytedev:propose/special-args-cleanup
lytedev:propose/limine-fallback
lytedev:propose/household-kiosk
lytedev:propose/xwayland-ei-display-from-client
lytedev:propose/steamdeck-mouse-steps-aside-for-games
lytedev:propose/assistant-watch
lytedev:propose/lpcamm-watch
lytedev:propose/agents-where-information-lives
lytedev:propose/tuwunel-1.9.2
lytedev:propose/pin-flake-registry
lytedev:propose/headscale-0-29-3
lytedev:propose/canary-freshness-per-repo
lytedev:propose/boot-guard-efivars-fix
lytedev:propose/deck-dock-panel-under-niri
lytedev:propose/admindevice-ssh-anything
lytedev:propose/kdeconnect-announce
lytedev:steamdeck-mgba
lytedev:propose/doorbell-no-internet
lytedev:propose/ha-list-tasks
lytedev:propose/ha-music-not-found
lytedev:propose/bc250-40cu-measured
lytedev:propose/multiboot-foxtrot-dragon
lytedev:propose/pitft-stmpe-drive
lytedev:propose/foxtrot-multiboot-prep
lytedev:propose/pitft-no-smartd
lytedev:propose/kexec-luks-reboot
lytedev:propose/foxtrot-multiboot
lytedev:propose/model-eval
lytedev:propose/foxtrot-vm-seats
lytedev:iamb-sender
lytedev:propose/calendar-alarms
lytedev:pinephone-niri
lytedev:push-tsntxvxynzps
lytedev:propose/spoof-reject-cleanups
lytedev:propose/finance-pipeline
lytedev:steamframe-plan
lytedev:pinephone-buildable
lytedev:deck-pose-wip
lytedev:aerc-open-html
lytedev:local-auth-unification
lytedev:iamb-dotfiles
lytedev:esphome-music-panel
lytedev:wifi-system-profile
lytedev:gauge-history
lytedev:validate-gate-fix2
lytedev:validate-slot-no-hugepages
lytedev:pinephone-reenable
lytedev:cyberdeck-research
lytedev:git-anon-ratelimit
lytedev:headscale-basedomain
lytedev:ssd-fast-tier
lytedev:hold-impermanence-flip
lytedev:gate-dummy-eval
lytedev:zen-browser
lytedev:initrd-remote-unlock
lytedev:beefcake-rpool-backup
lytedev:sec-sso-plan
lytedev:sec-mail
lytedev:flab-lid-wake
lytedev:hearth-k8s
lytedev:zulip
lytedev:router-guest-vlan
lytedev:headscale-extra-records
lytedev:beefcake-advertise-lan
lytedev:push-qrvuuqmxtznv
lytedev:voxtype-per-host-model
lytedev:cleanup
lytedev:push-kanidm-opt-in
lytedev:push-voxtype-flake-fix
lytedev:push-uvqqknxvqlvy
lytedev:push-qrqsxkmlrevert
lytedev:fix-kanidm-uid-attr-map
lytedev:nix-on-droid
lytedev:self-hosted-dns
lytedev:fix-runner-tmpfs-revert
lytedev:beefcake-email
lytedev:beefcake-immich
lytedev:firefox-nightly-devedition
lytedev:fix-bun-baseline
lytedev:flab-stuff
lytedev:printer-sftp
lytedev:dragon-vr-monado
lytedev:clever-vr-game-clamshell-mode-detection
lytedev:wireguard-mesh
lytedev:rescue-beefcake-unpushed-nix
No reviewers
Labels
No labels
bug
enhancement
question
scary
upstream
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
lytedev/nix!913
Loading…
Reference in a new issue
No description provided.
Delete branch "deck-video"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Daniel's request: "I think we should draw the actual camera feed as the background so users can feel how the tracking relates to their bodies."
Stacked on #911.
Your design — agreed, with one rejection
I agree with almost all of it and implemented it as specified: forward the original bytes, separate socket, opt-in and off by default, rate-limited independently, drop-never-queue, drawn in the play rect mirrored and dimmed.
I did not implement daemon-side downscale, because it contradicts "do not re-encode". Any change to the pixels — including making them smaller — means decode, scale and JPEG encode on the latency-critical path, to produce a worse image than the one already in hand. There is no cheap downscale of a JPEG.
Resolution is instead chosen where it is free: at the camera, via the existing
--width/--height, which shrinks the capture, the forward and the consumer's decode all at once.--video-fps(default 30) caps the rate as you asked. If you still want a daemon-side resize I will add it, but it should be a knowing trade of daemon latency for consumer convenience, not a default.Measured, as requested
Daemon cost, isolated on dragon (720p MJPEG, video capped at 30fps):
--publish-video, no consumerThe pose path is unaffected: with the game attached and decoding, the daemon holds 60.1 fps, P95 15.4 ms end-to-end, unchanged from baseline and far inside the 80 ms budget.
GDScript decode cost: 4-7 ms per 720p frame, the dominant cost of the whole feature, and it lands on the game rather than the input path. The game held 120 fps throughout.
One honest caution. Those are desktop numbers. In one earlier run under heavy contention I saw daemon inference stretch to 24-29 ms with the game decoding concurrently — not reproducible in the controlled runs, but a handheld doing inference and a game and a 30fps JPEG decode on four cores is a different proposition.
--video-fpsand a smaller capture are the levers, which is precisely why both are configurable.Does it subsume the vignette?
Partly, and I changed it accordingly rather than stacking redundant cues. With the feed up the image itself shows where the camera can see, so the explicit border drops to a hairline. The vignette stays only to darken what the camera cannot see, which is still doing real work. Without video, both revert to their previous strength.
Implementation notes
DPV1, length, width, height) then the JPEG. Length-prefixed because JPEG has no line structure; self-describing so a consumer reconnecting mid-stream can tell it is synchronised rather than guessing, and reconnect rather than scan if not.ImageTextureis reused rather than recreated per frame; allocating a GPU texture 30 times a second would have made this look expensive when the decode is the real cost.Checks
nix buildgreen for both packages. 50 daemon tests pass, including: header integrity and byte-for-byte payload equality, non-MJPEG formats skipped rather than converted, the rate limit holding against a burst, nothing sent with no consumer, and 500 frames offered at a consumer that never reads without blocking. Module evaluates with video on and emits the right config.Untested
Superseded by #915, which consolidates the whole markerless-pose-input program into a single WIP branch against
main. Every commit from this PR is preserved there — nothing was squashed, so the root-cause writeups in the commit messages are intact. Closing here; review happens on #915.Pull request closed