Phase 3a: decode captured VPX render stream to pixels (SMPTE bars)
- vpxlog.cpp: VPX_FIFODUMP=<path> records every FIFO burst ('VPXM' records)
- decode_fifodump.py: action census + payload dumps of a capture
- render_capture.py: reconstruct the DPL scene graph from a capture and
software-render each draw_scene frame (camera, view, materials, geometry
all taken from the wire)
- divrgb.conf + divrgb.fifodump: flyk divrgb.scn capture fixture
- divrgb-decoded.png / divrgb-frame0.png: first images ever produced from
the Rel 4.10 VPX protocol without a real board -- the textbook SMPTE
color-bar pattern, validating verts/conns/materials/camera in one shot
- PHASE3-PROGRESS.md: the established Rel 4.10 wire protocol (action map,
node types, message layouts); RENDER-HARNESS.md updated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,40 @@ static bool frame_outstanding = false; /* draw_scene sent, frame-ack owed
|
||||
|
||||
static void fifo_arm_action(void) { fifo_arm = true; fifo_cap_pos = 0; fifo_cap = 0; }
|
||||
|
||||
/* ---- Phase 3: full FIFO message dump (VPX_FIFODUMP=<path>) -------------- *
|
||||
* The FIFO wire format (VR_COMMS.C velocirender_transmit + OUTSW.ASM): each
|
||||
* transmit is TWO tag-delimited bursts. The C caller fires the first 3 bytes
|
||||
* of the protocol word at outputData, outsw() sends 0x40 as its final byte
|
||||
* and REP OUTSWs the payload into the FIFO port. Burst 1 carries the 4-byte
|
||||
* action, burst 2 the data (protocol word (0xff<<16)|(data+4)). So recording
|
||||
* every FIFO byte between outputData writes yields alternating action/data
|
||||
* records that a decoder can pair back into [action][data] messages.
|
||||
* Record format: 'VPXM' u32 magic, u32 length LE, then the raw burst bytes. */
|
||||
static FILE *fifo_dump_fp = NULL;
|
||||
static unsigned char *fifo_buf = NULL;
|
||||
static size_t fifo_buf_len = 0, fifo_buf_cap = 0;
|
||||
|
||||
static void fifo_buf_push(unsigned char v) {
|
||||
if (fifo_dump_fp == NULL) return;
|
||||
if (fifo_buf_len == fifo_buf_cap) {
|
||||
size_t ncap = fifo_buf_cap ? fifo_buf_cap * 2 : 4096;
|
||||
unsigned char *nb = (unsigned char *)realloc(fifo_buf, ncap);
|
||||
if (nb == NULL) return; /* drop byte rather than crash */
|
||||
fifo_buf = nb; fifo_buf_cap = ncap;
|
||||
}
|
||||
fifo_buf[fifo_buf_len++] = v;
|
||||
}
|
||||
static void fifo_flush_record(void) {
|
||||
if (fifo_dump_fp == NULL || fifo_buf_len == 0) return;
|
||||
unsigned char hdr[8] = { 'V','P','X','M',
|
||||
(unsigned char)(fifo_buf_len), (unsigned char)(fifo_buf_len >> 8),
|
||||
(unsigned char)(fifo_buf_len >> 16), (unsigned char)(fifo_buf_len >> 24) };
|
||||
fwrite(hdr, 1, sizeof hdr, fifo_dump_fp);
|
||||
fwrite(fifo_buf, 1, fifo_buf_len, fifo_dump_fp);
|
||||
fflush(fifo_dump_fp);
|
||||
fifo_buf_len = 0;
|
||||
}
|
||||
|
||||
static void parse_fifo_byte(unsigned char v) {
|
||||
if (!fifo_arm) return;
|
||||
fifo_cap |= ((unsigned)v) << (fifo_cap_pos * 8);
|
||||
@@ -175,6 +209,7 @@ static int vpx_max_postboot_acks = 200; /* safety cap */
|
||||
static int empty_polls = 0;
|
||||
static const int POLL_THRESHOLD = 6; /* consecutive empty polls => blocking receive */
|
||||
static void queue_render_ack_node(unsigned char action, unsigned node) {
|
||||
fifo_flush_record(); /* a receive means the outstanding burst is complete */
|
||||
unsigned char m[12] = {
|
||||
0x08, 0x00, 0x00, 0x00, /* length_word 0x00000008 (nb=8) */
|
||||
action, 0x00, 0x00, 0x00, /* payload[0..3] = action (LE) */
|
||||
@@ -342,13 +377,16 @@ static void vpx_write(Bitu port, Bitu val, Bitu iolen) {
|
||||
wf_payload_left = -1; wf_action_pos = 0; wf_action = 0; last_action = 0;
|
||||
fifo_arm = false; fifo_cap_pos = 0; fifo_cap = 0;
|
||||
expect_sync_token = false; sync_pending = false; sync_token = 0; frame_outstanding = false;
|
||||
fifo_flush_record();
|
||||
note("board reset");
|
||||
} else if (off == 1) {
|
||||
saw_write = true; /* outputData: a download/response byte */
|
||||
empty_polls = 0; /* a write means the game isn't blocking-reading */
|
||||
fifo_flush_record(); /* outputData write = FIFO burst boundary */
|
||||
if (parse_frames) { parse_out_byte((unsigned char)val); fifo_arm_action(); }
|
||||
} else if (off == 4 || off == 5) {
|
||||
/* FIFO data port (link B): payload words, low/high bytes. */
|
||||
fifo_buf_push((unsigned char)val);
|
||||
if (parse_frames) parse_fifo_byte((unsigned char)val);
|
||||
}
|
||||
}
|
||||
@@ -367,6 +405,12 @@ void VPXLOG_Init(void) {
|
||||
const char *h = getenv("VPX_HANDSHAKES");
|
||||
if (h && atoi(h) > 0) vpx_max_handshakes = atoi(h);
|
||||
|
||||
const char *fd = getenv("VPX_FIFODUMP");
|
||||
if (fd && fd[0]) {
|
||||
fifo_dump_fp = fopen(fd, "wb");
|
||||
if (fifo_dump_fp == NULL) LOG_MSG("VPXLOG: cannot open fifodump '%s'", fd);
|
||||
}
|
||||
|
||||
IO_RegisterReadHandler(VPX_BASE, vpx_read, IO_MB, 18);
|
||||
IO_RegisterWriteHandler(VPX_BASE, vpx_write, IO_MB, 18);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user