VGL_LABS cockpit test suite as pod-launch 'test' mode The WC hang, root-caused in three layers (each necessary): 1. WC was rendered-samples + 100ms-capped interpolation; AWEUTIL's poll storm (~550k port-ops/s) starved the render thread of awe_lock, so the clock crawled ~90x slow. Fixed: free-running host-clock derivation + a fairness gate so the render thread can always take the lock. 2. Free-running at true 44.1kHz still failed: trapped port reads cost ~30us -- MORE than one 22.7us tick -- so consecutive reads skipped counter values, and AWEUTIL's WaitUntilWC (decoded at COM offset 0x5F42) exits only on EQUALITY with a target tick: skipped value = missed target = 1.49s wrap penalty, or forever. 3. Advancing +1 per read still failed: WaitUntilWC reads WC TWICE per iteration, so its equality sample saw only every 2nd value -- wrong parity = infinite loop. Final semantics: during a poll storm the counter advances once per FOUR reads (every value observable by all of AWEUTIL's loop shapes; its 8192-unchanged-reads dead-clock bailout never trips), and resyncs to true wall time after any 50ms idle gap. Result: the full stock TEST.BAT (DIAGNOSE + AWEUTIL /S on both cards) completes in seconds. Also: pod-launch 'test' mode -> vwetest.conf (stock TEST.BAT -> TSTALL), DOSBox window defaults to 900,600 in test mode (the DOS screen is the suite's UI), VWE_AWE_LOG gains storm bursts with guest cs:ip + caller and rare-read tracing (the instrumentation that cracked this). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
120 lines
5.3 KiB
Markdown
120 lines
5.3 KiB
Markdown
# pod-launch
|
|
|
|
The supervising launch **entry-point** for the two DOSBox titles (BattleTech /
|
|
Red Planet 4.10). TeslaConsole → TeslaLauncher invokes this exe in the game dir
|
|
with args selecting game/mode; it is the single authoritative handle for the
|
|
whole session. See [`../DEPLOYMENT-PLAN.md`](../DEPLOYMENT-PLAN.md).
|
|
|
|
## Why an exe, not a batch/script
|
|
|
|
The entry-point must **own** the child processes' lifetime, not hand off and
|
|
exit. `pod-launch`:
|
|
|
|
1. Creates a **Windows Job Object** with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`.
|
|
2. Launches **DOSBox-X** and the **render bridge** *into* the job.
|
|
3. **Blocks** on DOSBox for the whole mission.
|
|
|
|
Kill this process (TeslaLauncher force-killing a hung DOSBox on a console
|
|
command) → the job's last handle closes → the **kernel** kills DOSBox + the
|
|
renderer. This holds even on a hard `TerminateProcess`, where no cooperative
|
|
shutdown can run. When DOSBox exits on its own (mission end) the supervisor
|
|
tears the job down and returns DOSBox's exit code.
|
|
|
|
A batch file / `cmd.exe` / `start` / `Start-Process` can't do this: they decouple
|
|
from the child, which then survives the parent. Verified: hard-killing the
|
|
supervisor reaps its child via the kernel (see the job-object cascade test).
|
|
|
|
## Build
|
|
|
|
Dev (needs the .NET 8 runtime present):
|
|
|
|
```
|
|
dotnet build -c Release
|
|
```
|
|
|
|
Deploy — self-contained single-file, so the air-gapped pod needs no .NET runtime
|
|
installed:
|
|
|
|
```
|
|
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
|
|
```
|
|
|
|
## Console argument reference
|
|
|
|
`pod-launch [mode] [options]` — the single installed entry-point. The product is
|
|
installed once; the console activates features by the args it passes. The per-rig
|
|
layout is fixed at `postinstall` time, so a typical call is just `pod-launch bt`.
|
|
|
|
### Mode — the primary feature selector (positional, or `--mode <name>`)
|
|
|
|
| Arg | Activates | Status |
|
|
|---|---|---|
|
|
| `bt` | BattleTech, networked cockpit (`net_loop.conf`, looped) | wired |
|
|
| `rp` | Red Planet, networked cockpit (`net_rp.conf`, looped) | wired |
|
|
| `test` | VGL_LABS factory cockpit test suite (`vwetest.conf` → `C:\VWETEST` → `TSTALL.EXE`): RIO, plasma, audio, video/Division calibration, Munga-net. DOSBox window defaults to 900,600 (the DOS screen is the suite's UI) | wired |
|
|
| `review` | mission-review PLAYBACK of `last.spl` | recognized, exits 3 (DOS arg TBD) |
|
|
| `test-plasma` | plasma-display diagnostic | recognized, exits 3 |
|
|
| `reset-rio` | RIO reset diagnostic | recognized, exits 3 |
|
|
| `audio-test` | audio test diagnostic | recognized, exits 3 |
|
|
|
|
Camera ship and LIVE mission-review are **not** modes — same `bt`/`rp` boot; the
|
|
console sets the role per-IP via the egg `hostType` (0 pod / 1 camera / 2 review),
|
|
see `../CAMERA-REVIEW-NOTES.md`. Default mode: `bt`.
|
|
|
|
### Feature toggles
|
|
|
|
| Arg | Effect |
|
|
|---|---|
|
|
| `--no-sound` | skip the ~4-min AWE32 SoundFont upload — **freezes bt/rp**: no AWE32 = no SOS ticks, and the default confs use the FAST (SOS) clock, so BTL4 hangs in the RIO-reset busy-wait (`L4RIO.cpp` `SetDTR`/`Now()`; root-caused 2026-07-10). Only safe with a SLOW-clock conf (`setenv` arg2=`s`) |
|
|
| `--mipmap` | mip-filter minified textures (fixes RP floor shimmer; non-authentic) |
|
|
| `--layout cockpit\|explode` | `cockpit` = borderless VDB head windows (default); `explode` = 7-window debug |
|
|
| `--no-bridge` | pod only, no GL render window |
|
|
| `--no-focus` | skip the renderer-topmost / DOSBox-focus pass |
|
|
|
|
### Window placement (per-rig; normally fixed, overridable per-launch)
|
|
|
|
| Arg | Effect |
|
|
|---|---|
|
|
| `--bridge-pos x,y` | main render window position (default `0,0`) |
|
|
| `--bridge-size w,h` | main render size (default `832,512` — the dPL3 board's native framebuffer res; see `../LAUNCH.md`) |
|
|
| `--dosbox-xy x,y` | DOSBox window position + focus (default `10,10`) |
|
|
|
|
### Path / asset overrides (dev / edge — `postinstall` already wires these)
|
|
|
|
`--root <dir>` · `--conf <path>` · `--dosbox <exe>` · `--renderer <exe>` ·
|
|
`--bridge-script <py>` · `--awe-rom <raw>` · `--work <dir>`
|
|
|
|
### Diagnostics
|
|
|
|
`--dry-run` (resolve + print the launch plan, don't launch) · `-h` / `--help`
|
|
|
|
```
|
|
pod-launch bt --root C:\VWE\TeslaRel410\emulator --dry-run
|
|
```
|
|
|
|
### Exit codes the console reads back
|
|
|
|
- **normal run** → returns **DOSBox's exit code** = the game's **`ExitCodeID`**,
|
|
passed straight through (the same remote-ops code the pod loop dispatched on).
|
|
- **`2`** → bad arguments (usage on stderr).
|
|
- **`3`** → recognized mode not yet wired (reason on stderr).
|
|
|
|
## Deploy layout it expects (under the game dir / `--root`)
|
|
|
|
```
|
|
pod-launch.exe dosbox-x.exe net_loop.conf net_rp.conf
|
|
renderer.exe (frozen) roms\awe32.raw <game content + net-boot drivers>
|
|
```
|
|
|
|
`postinstall.bat` lays this out and renders the `net_*.conf` (paths, `realnic`,
|
|
`WATTCP my_ip = bayIP+100`). This exe just selects + launches.
|
|
|
|
## TODO (tracked in DEPLOYMENT-PLAN.md OPEN items)
|
|
|
|
- Wire the distinct non-networked modes once their DOS launch args are
|
|
confirmed: `review` (playback app + `last.spl`) and the diagnostics. (The mode
|
|
table in `Modes.cs` is the single place to add each.)
|
|
- Swap the dev `pyw live_bridge.py` for the frozen renderer exe once packaging
|
|
is decided (freeze vs embedded Python — with David).
|
|
- Per-rig cockpit head RECTS (currently the `pod_deploy.ps1` defaults).
|