Snapshot: fog implementation + fidelity tooling baseline (pre bilinear-clamp fix)
Per-vertex GS fog end-to-end (gs_stub emit incl. persp_emit5, gs_prim_list_feeder XYZ2->XYZF2 on PRIM.FGE, gs_make_sh3_scheduler_fixture.py F/FGE packing), new fog TBs, fidelity attribution tooling. Functional baseline before removing the dead bilinear lerp8 clamps (Codex: 161-node comb loop -> -0.042ns setup fail). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,10 +35,21 @@
|
||||
#define OFF_TEX_RD_ERRS 0x068 // R: fill non-OKAY read responses (expect 0)
|
||||
#define OFF_TEX_FILL_CRC 0x070 // R: sum32 of EVERY word the cache wrote into tex_mem (must == file sum32)
|
||||
#define OFF_FEEDER_GO 0x0E8 // W[0]: trigger/retrigger the feeder
|
||||
// Ch353 — GS_SH3_LPDDR_FB (--lpddr-fb) additions: preclear the LPDDR framebuffer + drive Codex's host-start sequence.
|
||||
#define OFF_LPDDR_CTRL 0x018 // W: [0]arm [1]canary [2]video_src [3]scanout_lb (arm/base/canary latch on write)
|
||||
#define OFF_LPDDR_FB_BASE 0x01C // W: FB base byte addr (writer fb_base); set BEFORE the 0x018 arm-commit
|
||||
#define OFF_LPDDR_STATUS 0x02C // R: [0]idle (writer drained, stable post-render) [3]rd_pending
|
||||
#define OFF_LPDDR_BYTES 0x030 // R: FB writer beats written (snapped at idle) — non-zero after a real render
|
||||
#define OFF_FEEDER_STATUS 0x0D8 // R: [0] feeder control FSM in C_READY (setup + CLUT done)
|
||||
#define IDLE_BIT 0x1 // 0x02C bit0 — writer idle (TRANSIENT: pulses between feeder render batches)
|
||||
#define FRAME_DRAINED_BIT 0x40 // 0x02C bit6 — Ch353 STABLE ordered drain ack (poll THIS, not idle)
|
||||
#define READY_BIT 0x1 // 0x0D8 bit0
|
||||
|
||||
#define N_WORDS 65536 // 512*512 PSMT8 / 4
|
||||
#define TEX_BYTES 262144
|
||||
#define N_BEATS 8192 // TEX_BYTES / 32
|
||||
#define FB_WORDS 85504 // Ch353 — 256*334 PSMCT32 framebuffer (0x000000..0x0537FF)
|
||||
#define FB_BYTES 342016
|
||||
|
||||
typedef struct { volatile uint8_t *base; int dry; } bridge_t;
|
||||
static void wr32(bridge_t *b, int off, uint32_t v){ if(!b->dry) *(volatile uint32_t*)(b->base+off)=v; }
|
||||
@@ -48,7 +59,7 @@ int main(int argc, char **argv){
|
||||
unsigned long base = 0x40000000UL; // PS2 HPS-bridge base (override --base or PS2_BRIDGE_BASE)
|
||||
unsigned long lpddr_base = 0x00200000; // EMIF byte base where the texture is staged (= TEX_LPDDR_BASE RTL)
|
||||
const char *texfile = "sh3_real_tex_lpddr.mem";
|
||||
int dry=0, do_fill=1, do_retrig=1;
|
||||
int dry=0, do_fill=1, do_retrig=1, lpddr_fb=0, fb_rows=334; // fb_rows: 334 (Ch353 single) / 338 (Ch354 multi)
|
||||
char *env = getenv("PS2_BRIDGE_BASE"); if (env) base = strtoul(env,NULL,0);
|
||||
for (int i=1;i<argc;i++){
|
||||
if (!strcmp(argv[i],"--base") && i+1<argc) base = strtoul(argv[++i],NULL,0);
|
||||
@@ -56,8 +67,10 @@ int main(int argc, char **argv){
|
||||
else if (!strcmp(argv[i],"--dry-run")) dry=1;
|
||||
else if (!strcmp(argv[i],"--no-fill")) do_fill=0;
|
||||
else if (!strcmp(argv[i],"--no-retrigger")) do_retrig=0;
|
||||
else if (!strcmp(argv[i],"--lpddr-fb")) lpddr_fb=1; // Ch353 — preclear FB + Codex host-start sequence
|
||||
else if (!strcmp(argv[i],"--fb-rows") && i+1<argc) fb_rows = (int)strtoul(argv[++i],NULL,0); // Ch354 — 338 for multi
|
||||
else if (argv[i][0] != '-') texfile = argv[i];
|
||||
else { fprintf(stderr,"usage: %s [tex.mem] [--base 0x40000000] [--lpddr-base 0x200000] [--dry-run] [--no-fill] [--no-retrigger]\n", argv[0]); return 2; }
|
||||
else { fprintf(stderr,"usage: %s [tex.mem] [--base 0x40000000] [--lpddr-base 0x200000] [--dry-run] [--no-fill] [--no-retrigger] [--lpddr-fb]\n", argv[0]); return 2; }
|
||||
}
|
||||
|
||||
// ---- load the texture hex (.mem: one 32-bit word per line) ----
|
||||
@@ -88,6 +101,26 @@ int main(int argc, char **argv){
|
||||
br.base=(volatile uint8_t*)map;
|
||||
}
|
||||
|
||||
// ---- Ch353 GS_SH3_LPDDR_FB (Codex host sequence, steps 1-2): wait for the feeder to reach C_READY (setup +
|
||||
// CLUT complete; with FEEDER_AUTOSTART=0 this happens WITHOUT a boot render), then PRECLEAR the LPDDR
|
||||
// framebuffer 0x000000..0x0537FF (85504 words) via the same proven write-probe. This is the "no hardware clear
|
||||
// engine" path (Codex): ~30% more traffic than the 65536-word texture upload, poll write_pending + check BRESP. ----
|
||||
if (lpddr_fb && !dry){
|
||||
int g=0; while(!(rd32(&br,OFF_FEEDER_STATUS)&READY_BIT) && g<20000000) g++;
|
||||
printf("[ps2_sh3_tex_upload] (lpddr-fb) feeder ready=%d (setup+CLUT done, no boot render)\n",
|
||||
(rd32(&br,OFF_FEEDER_STATUS)&READY_BIT)?1:0);
|
||||
unsigned fb_words = 256u*(unsigned)fb_rows; // 256x334=85504 (Ch353) ; 256x338=86528=0x54800 (Ch354)
|
||||
wr32(&br, OFF_LPDDR_WRADDR, 0x00000000u); // FB base 0
|
||||
for (unsigned i=0;i<fb_words;i++){
|
||||
wr32(&br, OFF_LPDDR_WRDATA, 0u);
|
||||
{ int h=0; while ((rd32(&br,OFF_TEX_FILL_CTRL)&WR_PENDING_BIT) && h<2000000) h++; }
|
||||
}
|
||||
uint32_t perr = rd32(&br, OFF_LPDDR_WR_ERRS);
|
||||
printf("[ps2_sh3_tex_upload] (lpddr-fb) precleared FB %u words (%u rows, %u KiB) @0..0x%x wr_bresp_errs=%u (exp 0)\n",
|
||||
fb_words, (unsigned)fb_rows, fb_words*4/1024, fb_words*4, perr);
|
||||
if (perr) fprintf(stderr,"WARN: %u preclear BRESP errors.\n", perr);
|
||||
}
|
||||
|
||||
// ---- (1) upload: set WRADDR then stream WRDATA. CRITICAL: poll wr_busy (0x054 bit1) clear after each word
|
||||
// so the write-probe actually COMMITS before the next write — otherwise the fast mmap writes outrun the
|
||||
// CDC/AXI commit and get DROPPED (the bug: most words read back as 0). The Ch322 devmem script got away with
|
||||
@@ -138,8 +171,27 @@ int main(int argc, char **argv){
|
||||
fprintf(stderr,"WARN: cache fill_crc mismatch — tex_mem corrupt on board (NOT a divider/sampler issue).\n");
|
||||
}
|
||||
|
||||
// ---- (4) retrigger the feeder so the scene re-renders with the warm cache ----
|
||||
if (do_retrig && !dry){ wr32(&br, OFF_FEEDER_GO, 0x1); printf("[ps2_sh3_tex_upload] feeder retriggered.\n"); }
|
||||
// ---- Ch353 GS_SH3_LPDDR_FB (Codex host sequence, steps 5-8): base 0 + canary off + ARM the writer, GO, await
|
||||
// the ordered drain, then enable the scanout. The render epoch (RTL) emits exactly ONE EOF on the post-GO
|
||||
// feeder_ready rise -> ONE frame_drained, which HARD-gates the line-buffer scanout (no timeout; failure stays
|
||||
// black). Confirm the drain via LPDDR_STATUS[0] idle (stable post-render) + LPDDR_BYTES!=0 (a frame was written). ----
|
||||
if (lpddr_fb && !dry){
|
||||
wr32(&br, OFF_LPDDR_FB_BASE, 0x00000000u); // step 5: FB base 0 ...
|
||||
wr32(&br, OFF_LPDDR_CTRL, 0x1); // ... canary off, ARM the writer (commit snapshots base/arm)
|
||||
wr32(&br, OFF_FEEDER_GO, 0x1); // step 6: GO -> render epoch -> one EOF -> one frame_drained
|
||||
printf("[ps2_sh3_tex_upload] (lpddr-fb) writer armed (base 0, canary off), feeder GO issued.\n");
|
||||
// step 7: await the ORDERED drain ack (0x02C[6] frame_drained) — STABLE, asserts only after the EOF marker's
|
||||
// last BRESP. Do NOT poll [0]idle: it pulses between the feeder's render batches and reads a mid-render count.
|
||||
{ int g=0; while(!(rd32(&br,OFF_LPDDR_STATUS)&FRAME_DRAINED_BIT) && g<40000000) g++; }
|
||||
uint32_t fd = (rd32(&br,OFF_LPDDR_STATUS)&FRAME_DRAINED_BIT)?1:0, fbb = rd32(&br,OFF_LPDDR_BYTES);
|
||||
printf("[ps2_sh3_tex_upload] (lpddr-fb) drain: frame_drained=%u, FB beats written=%u (exp ~6500 for the full frame)\n", fd, fbb);
|
||||
if (!fd || fbb==0)
|
||||
fprintf(stderr,"WARN: drain not confirmed (frame_drained=%u beats=%u) — display stays BLACK (hard gate, no timeout).\n", fd, fbb);
|
||||
wr32(&br, OFF_LPDDR_CTRL, 0x1|0x4); // step 8: arm=1 + video_src=1 -> HDMI sources the LPDDR scanout
|
||||
printf("[ps2_sh3_tex_upload] (lpddr-fb) video_src=1 -> HDMI now sources the LPDDR line-buffer scanout (256x%u).\n", (unsigned)fb_rows);
|
||||
}
|
||||
// ---- (4) retrigger the feeder so the scene re-renders with the warm cache (crop profile path) ----
|
||||
else if (do_retrig && !dry){ wr32(&br, OFF_FEEDER_GO, 0x1); printf("[ps2_sh3_tex_upload] feeder retriggered.\n"); }
|
||||
|
||||
if (!dry){ munmap(map,0x1000); close(fd); }
|
||||
printf("[ps2_sh3_tex_upload] DONE — check HDMI vs the crop reference (recon/sh3_real_ref.png).\n");
|
||||
|
||||
Reference in New Issue
Block a user