igc_conformance.py pins the reference behaviour any port (RTL/GPU/C) must reproduce: the DUMP packet parse, a synthetic raster, the bars pipeline (texu==x+2 from the real cap7 tile programs), and the fxtest effect primitives (coverage + z pinned) -- fixtures committed under conformance/. GPU-RETARGET.md maps the DOSBox-renderer path: EMC tile as compute shader (pixel=thread), 4 milestones, conformance-gated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
3.3 KiB
Markdown
71 lines
3.3 KiB
Markdown
# GPU-compute retarget — the DOSBox-renderer path (2026-07-19)
|
||
|
||
Companion to FPGA-RECONSTRUCTION.md. This is the plan for shipping the decoded
|
||
IGC/EMC model as a real-time renderer behind the existing DOSBox seam — the
|
||
practical answer to "use this as the renderer for the pod."
|
||
|
||
## Why GPU compute
|
||
The EMC array is 8,192 bit-serial PEs per 64×128 tile. On a GPU that is one
|
||
thread per pixel executing the same decoded op stream — a literal 1:1 mapping,
|
||
no hardware, ships as software next to the renderer we already deploy.
|
||
The original array ran ~40 MHz bit-serial; any integrated GPU exceeds the
|
||
whole frame's work by orders of magnitude.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
DOSBox (game, unmodified)
|
||
│ wire protocol (known) ── existing seam: render-bridge/live_bridge
|
||
▼
|
||
emu860 geometry stage ── the i860 firmware, C/JIT port for realtime
|
||
│ per-draw DMA stream + payloads (the coefficient programs)
|
||
▼
|
||
IGC translator (host) ── igc_exec.parse -> flat op records
|
||
│ SSBO: op stream + payload floats + tile list
|
||
▼
|
||
compute shader "EMC tile" ── pixel = thread; fields in registers/LDS:
|
||
│ texz/texu/texv/zbuf as uint20, r/g/b as uint8, enable as bool;
|
||
│ ops = a switch over the named table (TREE*, MEM*, CPY, sweeps, SCA*)
|
||
▼
|
||
readout pass ── ramp(texu) / rgb24 -> RGBA8 frame texture
|
||
▼
|
||
present (the existing renderer window / vr_readpixels reply)
|
||
```
|
||
|
||
## What ports 1:1 from the golden model
|
||
- The op table (data) and parser — host-side, unchanged.
|
||
- Tile semantics — each `Tile.run` branch becomes a shader case; the pixel
|
||
memory bit-fields become packed uints (no bit-serial emulation needed:
|
||
field-level semantics are already proven equivalent by the conformance
|
||
suite).
|
||
- Readout — ramp LUT as a small texture.
|
||
|
||
## Conformance gate
|
||
`igc_conformance.py` (C1-C4, committed fixtures) is the acceptance bar: the
|
||
shader path must reproduce C2-C4 outputs exactly (C1 is host-side parse).
|
||
Add a C5 full-frame image hash (bars + fxtest frames) once texel sampling
|
||
lands.
|
||
|
||
## Realtime budget (per frame)
|
||
- 52 tiles × ~100-3000 op-steps × 8,192 px ≈ 1-10 G pixel-ops worst case —
|
||
a compute-shader trifle at 60 fps on integrated graphics.
|
||
- Geometry stage: the real wall. emu860 in Python ≈ 600K steps/s; a frame is
|
||
~10-50M steps → need the C/JIT step-core (planned; the i860 ISA semantics
|
||
are fully pinned by emu860 + MAME cross-validation). Interim: pre-captured
|
||
streams replay at full speed for validation.
|
||
|
||
## Milestones
|
||
1. **M1 shader tile**: WGPU/GL compute kernel executing the named ops;
|
||
passes C2-C4. (small)
|
||
2. **M2 frame loop**: DMA-stream walker + tile dispatch + readout; renders
|
||
the bars + fxtest fixtures. (small-medium)
|
||
3. **M3 texel path**: TXDN stream -> texture sampling (needs the remaining
|
||
spec work — the io-port fetch protocol). (medium, spec-gated)
|
||
4. **M4 live seam**: behind live_bridge in place of / beside the GL renderer;
|
||
real-time gate = the C step-core for emu860. (the big one, independent)
|
||
|
||
## Open spec items feeding this (tracked in IGC-ENCODING-DERIVATION.md)
|
||
- op-0x2c edge exact semantics (winding rule) — affects M1 fidelity.
|
||
- TXDN io-port texel stream — gates M3.
|
||
- The texz coordinate-seed op + the real ramp tables — purity for M2 images.
|