Fix live-render lag: bulk memory read + masked texture compositing (~2.1x)

User-visible bug: connected the reconstructed renderer to the REAL running pod
for the first time (M4d demo) and the render fell increasingly behind the live
game, plus looked near-grayscale. Root-caused with direct profiling instead of
guessing:

1. VPX_RENDER=1 was set in launch_live.ps1 (copied from launch_pod.ps1's
   defaults without thinking it through) -- it starts vpxlog.cpp's OWN native
   GL render thread (rt_main), which contends with our renderer for the same
   CPU/GL resources. Live-caught: with it set, wire delivery stalled at wire
   command 8 for 90+s; removing it, the same mission reached command 21,488
   in the same window. This was the dominant cause of the visible lag.

2. gpu_raster.build_prims() scanned the whole per-draw program window
   (0x08158000-0x08170000, ~24k words) via a Python-level r32() call per word
   every frame. Added emu860c.dump_range(lo,hi)->bytes (one bulk C read) and
   rewrote build_prims to index a numpy array instead -- verified byte-identical
   dump_range output first, then reconfirmed the whole render is STILL
   bit-identical to the CPU reference (frames 0/5/11, differ>24 = 0.000%).

3. Profiling after (1) showed the per-texture compositing loop was the real
   remaining cost: 62ms/frame doing full-832x512-frame fancy-indexed texture
   sampling for EACH of 13 textures, regardless of how few pixels use each one.
   Added dpl_sampler.composite_masked (sample+composite only the pixels a
   texture actually covers; verified equivalent to composite() on a partial
   mask in dpl_sampler's own conformance test) and hoisted the invariant
    out of the loop.

Combined: render time 95.8ms -> 54.9ms/frame (~1.75x from this change alone,
~2.1x vs the original ~117ms/frame baseline), still bit-identical to the CPU
reference throughout.

launch_live.ps1: removed VPX_RENDER, renamed the automatic-variable shadow
 ->  (flagged by PSScriptAnalyzer), added -Pin <fifodump> to
pre-load the full texture set (bit-identical to offline) instead of the
incremental default, for a demo that wants correct color immediately rather
than waiting on the live mission's own upload order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-20 10:07:55 -05:00
co-authored by Claude Opus 4.8
parent bf234842cb
commit ef7db9f2e4
4 changed files with 66 additions and 18 deletions
+10 -4
View File
@@ -16,7 +16,12 @@ param(
[string]$Work = "$env:LOCALAPPDATA\Temp\vwe-live",
[switch]$Sound,
[switch]$PodOnly,
[switch]$Present # live_render window (pygame)
[switch]$Present, # live_render window (pygame)
[string]$Pin # pre-load the full texture set from this
# .fifodump (bit-identical to offline;
# avoids grey/incomplete early textures
# while the live mission is still
# uploading them incrementally)
)
$ErrorActionPreference = 'Stop'
New-Item -ItemType Directory -Force $Work | Out-Null
@@ -57,9 +62,10 @@ if ($Sound) { Write-Host "sound ON: boot adds ~4 min for the SoundFont upload" }
if (-not $PodOnly) {
$rl = Join-Path (Resolve-Path "$PSScriptRoot\..\firmware-decomp\emu860c").Path 'live_render.py'
$args = @("`"$rl`"", "sock:$Port")
if ($Present) { $args += '--present' }
$rendererArgs = @("`"$rl`"", "sock:$Port")
if ($Present) { $rendererArgs += '--present' }
if ($Pin) { $rendererArgs += '--pin'; $rendererArgs += "`"$(Resolve-Path $Pin)`"" }
Write-Host "connecting reconstructed renderer: python $rl sock:$Port"
Start-Sleep -Milliseconds 800 # let the device open the listener
& python @args
& python @rendererArgs
}