Hold world confirmations across invalid SLAM samples instead of
resetting on every miss; a candidate drops only when stale (>3 s) or
from an older SLAM session. The 3-vote bar, 4 cm / 3 deg agreement and
the chained 3 s window are unchanged, so transient wrong matches still
cannot accumulate votes.
Wait up to 250 ms for the exposure's SLAM sample and accept the same
250 ms gap the display pose path tolerates, so a loaded backend does
not make recognition samples unusable while published poses stay valid.
Skip feature matching while proximity reports off-head standby, and
verify at 0.2 Hz once the room is localized; match every queued pair
while searching or recording. Attempts and diagnostics freeze visibly
while skipping.
Count the first failing usability gate per unusable attempt
(paused/sample/gap/flags/generation/guard) in diagnostics, the
per-second world log, the pending-room warning and the status file, so
the next worn session shows which condition dominates.
Triangulate at most one landmark per second-view pixel, with separate
live and reference-image sets so temporal pairs keep their own domain.
Replay: same-room recognition still confirms in ~0.5 s with tighter
votes on fewer map points; sparse valid samples confirm where the old
window reset could not.
Refcount frameserver storage so destroy defers munmap/free/close
until outstanding ROI frames return; always join the stream thread
via a joinable flag instead of the running flag; wake blocked DQBUF
with poll timeout plus STREAMOFF; make running/used state atomic.
Add per-command monotonic deadline (1500 ms, beyond the device 1000 ms
timeout) so a missing response fails the head instead of wedging the
queue. Bound send and poll transport errors (8 each) with 5 ms doubling
to 100 ms backoff so a persistent STALL cannot spin HID ioctls.
Retries resend only the unsent head with identical bytes; once sent the
head is polled, never resent. The response carries no command echo
(seqnum/busy only), so a late reply after a timeout can be misattributed
to the next command; last seq is retained to ignore duplicates and
callers must validate payload status/length.
Fail callbacks once via a shared helper; clear stays safe after timeouts.
HID -1/errno semantics unchanged; valid busy polls every tick.
Add fake-HID/fake-time tests for success pipelining, busy timeout
advance, send/poll/short backoff bounds, clear-once safety, stale seq,
and null HID expiry.
USB thread calls rift_s_tracker_device_lost before camera frameserver stop.
Retains tracker, passthrough pointer, and SLAM/constellation xfctx; marks
ready_for_data=false, pauses via existing restart path with forced pending
restart, resets hw clock/IMU/frame epochs and fusion history for counter
reset, bumps slam_generation and invalidates world candidate so stale worker
results cannot publish, preserves saved map/anchor, joins world worker.
tracker_start restarts worker after reconnect. Controller/SLAM/IMU paths
already drop while !ready; no xfctx teardown here.
Bake the fixed per-pixel resampling (integer base pixel plus dx/dy and
1-dx/1-dy weights) at camera-create time instead of re-deriving it from
the float UV map on every conversion. The per-frame path keeps the live
source bounds check (integer form, exactly equivalent for validated
payloads) and per-capture stride, and preserves the original float
expression ordering so converted bytes match bit-for-bit.
Skipped in-place output reuse: get_frame hands out references that
outlive the provider, so a fresh conversion buffer per timestamp stays
required for torn-frame safety.
Adds a focused comparison test: verbatim original scalar path vs the new
path over the full 320x320x2 map on a fisheye/rolled calibration with
per-eye distortion, at tight and padded source strides, frames held
immutable.
recover_rings ran vkQueueWaitIdle while holding the global layer mutex,
stalling every other thread in any intercepted Vulkan call for the whole
GPU drain. Collect candidates under the lock, wait unlocked, then revalidate
before resetting the cursor.
The wait window allows destroy/recreate reusing the same buffer handle, a
concurrent recovery, or a disable (unmap, author change) to land mid-drain.
Each drain carries its ring's slot, buffer/memory identity, cursor, and reset
count plus a per-ring draining flag: a replacement (draining==false, own
slot/identity) is left alone instead of being reset or disabled, a concurrent
drain skips instead of double-resetting, and a ring disabled during the wait
is never reset. A failed wait stays a failure even if the cursor reads zero.
failed stayed set after a handled repair, so every later immediate
RoomSetupFinished re-restored the stale pre-failure snapshot over the new
calibration and posted a duplicate persistent notification each time.
A second start overwrote pid/ack, orphaning the first guard (own VR
connection, overlay, mailbox registration) and leaking its pipe fd.
Return early while the child is alive; reset ack state on respawn.
Keeping a disabled entry let a later buffer reusing the same handle inherit
dead state and skip re-detection at map time. Erase it; identify_ring
re-validates from scratch on the next map.
Buffers already handled Bind2 but images did not, so SDF images bound via
vkBindImageMemory2 never recorded memory/layout and missed the linear R8
initialization on map. Mirror the vkBindImageMemory bookkeeping.
The gravity solver rejects null observation arrays and oversized
counts up front; the per-camera PnP path dereferenced obs[eye]
unchecked once counts reached MIN_POINTS. Same fail-closed check.
One mismatched edge pixel or non-finite landmark aborted the whole
multi-camera gravity solve, delaying room recognition by a cycle.
Skip the point; the support/coverage gates still decide.
cached_version only returned a hit when the cached value was Some, so
failures recomputed every snapshot poll despite the minute-cache claim.
It also served the previous runtime's driver hash for up to 60 s after a
restart. Replace the generic helper with a PID-keyed cache mirroring
steam_version: same-PID results (including None) are cached for 60 s and
any PID change forces recompute. Pass the PID into the uncached probe to
avoid a second pgrep per poll.
Bare python is absent on several distributions, so a present launcher
failed after SteamVR had already been terminated. Try python3 first
and fall back to python only when the interpreter binary is missing,
never re-running a script that already failed.
(cherry picked from commit 1dc1a1d7929d802221730c7547ff6d1f3baf4fb5)
inotify drops watches on moved or deleted directories and wait()
drains the fd without parsing, so the remembered path set kept dead
entries forever. Re-add watches every pass so watch mode recovers
after a Steam reinstall instead of stalling until service restart.
(cherry picked from commit 9cd08b0d7a4cb095f6bae516f42d141e1d2b0d64)