Bridge: frame coalescing -- the view can no longer fall behind real time

The main loop rendered EVERY draw_scene in arrival order, so any render
slowdown played the mission slower than real time and the view drifted
seconds behind the game (user: "renderer fell way out of sync"); the
backpressure hides in the socket, so backlog= stayed 0. Now each pass
slices all complete records, applies every state record in order, and
presents only the newest frame; superseded presents are counted in the
new skipped= report field. Live verdict over a full mission:
frames=10169 skipped=3 backlog=0B -- locked to the wire.

Also from the tuner session: seat trim granularity 0.1 (0.5 was too
jumpy) and a HUD size trim (vrview_gl u_scale + VRVIEW_HUDSCALE env,
live +/- keys) -- tuners stay enabled for pilot feedback; seat trim
turns out to be per-mech (Mad Cat vs Thor want different values).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-09 00:13:11 -05:00
co-authored by Claude Fable 5
parent 2233441812
commit 1b041d5a9e
2 changed files with 67 additions and 24 deletions
+7 -1
View File
@@ -201,6 +201,7 @@ void main() { // Division DAC gamma, once over the final image
HUD_VS = """
#version 330
uniform vec4 u_rect; // view rect x0 y0 x1 y1 (dpl2d coordinate space)
uniform float u_scale; // HUD size trim (VRVIEW_HUDSCALE / live +/- keys)
in vec2 in_pos;
void main() {
vec2 p = vec2((in_pos.x - u_rect.x) / (u_rect.z - u_rect.x),
@@ -209,10 +210,14 @@ void main() {
// twist dial UNDER the reticle and the range bar filling top-to-bottom;
// mapping straight onto GL's Y-up NDC rendered the whole HUD flipped.
p.y = -p.y;
gl_Position = vec4(p, 0.0, 1.0);
gl_Position = vec4(p * u_scale, 0.0, 1.0);
}
"""
# HUD size trim, live-adjustable from the bridge (+/- keys); pin with
# VRVIEW_HUDSCALE once the right size is found vs period footage.
HUDSCALE = [float(os.environ.get('VRVIEW_HUDSCALE', '1.0'))]
HUD_FS = """
#version 330
uniform vec3 u_col;
@@ -566,6 +571,7 @@ class GLRenderer(vrview.Renderer):
self._set(self._hud_prog, 'u_rect',
(float(vp['x0']), float(vp['y0']),
float(vp['x1']), float(vp['y1'])))
self._set(self._hud_prog, 'u_scale', float(HUDSCALE[0]))
MODES = {'strip': mgl.LINE_STRIP, 'segs': mgl.LINES,
'poly': mgl.TRIANGLE_FAN, 'points': mgl.POINTS}
for kind, col, wd, pts in prims:
+60 -23
View File
@@ -21,11 +21,14 @@ board.munga = False
r = Renderer(w=832, h=512,
title=f"dpl3-revive renderer (Dave) -- LIVE from our pod [{backend}]")
r.fps = int(os.environ.get('BRIDGE_FPS', '60' if backend == 'GL' else '30'))
# eye-height TRIM on top of the camera position (UP/DOWN arrows = +-5,
# LEFT/RIGHT = +-1, live; render window must be focused). The chain camera
# carries the true cockpit eye so the default trim is 0; the vehicle-root
# fallback adds VEH_EYE below (12 was the hand-tuned value).
# eye TRIM on top of the camera position (live; render window must be
# focused): UP/DOWN = height +-1, LEFT/RIGHT = seat forward/back +-0.5
# along the look direction (user: the canopy reads as "sitting too far
# back" -- tune, then pin with FP_UPOFF / FP_FWDOFF). The chain camera
# carries the true cockpit eye so the default trims are 0; the vehicle-
# root fallback adds VEH_EYE below (12 was the hand-tuned value).
UPOFF = [float(os.environ.get('FP_UPOFF', '0'))]
FWDOFF = [float(os.environ.get('FP_FWDOFF', '0'))]
VEH_EYE = 12.0
# the un-overridden munga cam-chain method (fp_cam overrides r.cam_matrix
# every frame, so grab the bound original once)
@@ -137,6 +140,7 @@ def fp_cam(board, cache):
cs, sn = math.cos(th), math.sin(th)
fwd = np.array([cs * fwd[0] + sn * fwd[2], fwd[1],
-sn * fwd[0] + cs * fwd[2]])
eye = eye + fwd * FWDOFF[0] # seat forward/back trim
back = -fwd
right = np.cross(worldup, back)
rn = np.linalg.norm(right)
@@ -180,11 +184,26 @@ def render(board):
if ev.type == pg.QUIT:
raise KeyboardInterrupt
if ev.type == pg.KEYDOWN:
step = {pg.K_UP: 5, pg.K_DOWN: -5,
pg.K_RIGHT: 1, pg.K_LEFT: -1}.get(ev.key)
if step:
UPOFF[0] = max(0.0, UPOFF[0] + step)
print(f"eye height = {UPOFF[0]:.0f}", flush=True)
hstep = {pg.K_UP: 1, pg.K_DOWN: -1}.get(ev.key)
fstep = {pg.K_RIGHT: 0.1, pg.K_LEFT: -0.1}.get(ev.key)
sstep = {pg.K_EQUALS: 0.05, pg.K_MINUS: -0.05,
pg.K_KP_PLUS: 0.05, pg.K_KP_MINUS: -0.05}.get(ev.key)
if hstep:
UPOFF[0] += hstep
if fstep:
FWDOFF[0] += fstep
if sstep:
try:
import vrview_gl
vrview_gl.HUDSCALE[0] = max(
0.2, vrview_gl.HUDSCALE[0] + sstep)
print(f"HUD scale = {vrview_gl.HUDSCALE[0]:.2f}",
flush=True)
except Exception:
pass
if hstep or fstep:
print(f"eye trim: height {UPOFF[0]:+.1f} "
f"forward {FWDOFF[0]:+.1f}", flush=True)
r.cache.maybe_rebuild(board)
M = fp_cam(board, r.cache)
if M is not None:
@@ -270,11 +289,20 @@ print("tailing live wire -> Dave's renderer; drive the pod")
pending = b''
frames = 0
skipped = 0
last_report = time.time()
while True:
chunk = read_chunk()
if chunk:
pending += chunk
# Slice ALL complete records out of the buffer first, so we know which
# draw_scene is the newest. Rendering every draw_scene in arrival order
# means any render slowdown plays the mission slower than real time and
# the view drifts seconds behind the game (backpressure hides in the
# socket, not in len(pending)). State records all still apply, in order;
# only superseded frame PRESENTS are skipped -- the view latches to the
# freshest frame no matter how slow GL is.
records = []
off = 0
n = len(pending)
while n - off >= 8:
@@ -284,22 +312,31 @@ while True:
ln = struct.unpack_from('<I', pending, off + 4)[0]
if n - off < 8 + ln:
break # incomplete record: wait for more
body = pending[off + 8:off + 8 + ln]
records.append(pending[off + 8:off + 8 + ln])
off += 8 + ln
if len(body) >= 4:
action = struct.unpack_from('<I', body, 0)[0]
if action < 0x100:
try:
board.handle(Msg(False, 0xff, action, body[4:]))
except Exception:
pass
if action == 0x1f: # torso/limb joint angles ride here
try: track_joints(body[4:])
except Exception: pass
if action == 9: # draw_scene -> present a frame
pending = pending[off:]
last_draw = -1
for i, body in enumerate(records):
if len(body) >= 4 and struct.unpack_from('<I', body, 0)[0] == 9:
last_draw = i
for i, body in enumerate(records):
if len(body) < 4:
continue
action = struct.unpack_from('<I', body, 0)[0]
if action < 0x100:
try:
board.handle(Msg(False, 0xff, action, body[4:]))
except Exception:
pass
if action == 0x1f: # torso/limb joint angles ride here
try: track_joints(body[4:])
except Exception: pass
if action == 9: # draw_scene -> present a frame
if i == last_draw:
render(board)
frames += 1
pending = pending[off:]
else:
skipped += 1
if not chunk:
try: r.pump()
except KeyboardInterrupt: break
@@ -308,7 +345,7 @@ while True:
time.sleep(0.02) # socket mode already waited in recv
if time.time() - last_report > 4:
last_report = time.time()
print(f"frames={frames} nodes={len(board.nodes)} "
print(f"frames={frames} skipped={skipped} nodes={len(board.nodes)} "
f"uploads={len(board.uploads)} tex={len(board.tex)} "
f"munga={board.munga} anim_abs={len(board.anim_abs)} "
f"backlog={len(pending)}B", flush=True)