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:
@@ -0,0 +1,136 @@
|
||||
# Ch438 — source-space 3x3 binomial scanout (pre-fit)
|
||||
|
||||
## Why this chapter
|
||||
|
||||
Ch437 proved exact horizontal and vertical linear presentation, but the complete
|
||||
f52 framebuffer still contains high-frequency speckle that the PCSX2 reference
|
||||
does not. Adding more draws does not address that deficit. An offline filter
|
||||
sweep identified a source-space separable `[1 2 1]/4` low-pass followed by the
|
||||
authentic nearest presentation map as the best small, bounded scanout change.
|
||||
|
||||
The renderer and LPDDR framebuffer are unchanged. Ch438 only changes pixels at
|
||||
the final HDMI scanout boundary, so the accepted f52 framebuffer SHA remains the
|
||||
rollback and equivalence anchor.
|
||||
|
||||
## RTL architecture
|
||||
|
||||
- `gs_lpddr_scanout_lb.sv` adds opt-in `BINOMIAL_3X3_FILTER`.
|
||||
- SH3 full-frame scanout disables the Ch436/437 linear filters and enables the
|
||||
binomial filter.
|
||||
- A third rotating line buffer retains source rows `y-1`, `y`, and `y+1`.
|
||||
- Each physical line RAM still has one unconditional registered video read, the
|
||||
Quartus-safe inference form established in Ch437.
|
||||
- Six 256-bit register-cache slots retain the even/odd beats for all three rows.
|
||||
- Horizontal and vertical passes each compute `(a + 2*b + c + 2) >> 2`.
|
||||
- Horizontal edges clamp at source columns 0 and 511. Vertical edges clamp at
|
||||
source rows 32 and 479.
|
||||
- The filtered source pixel is presented with the captured nearest maps:
|
||||
`sx=floor(x*4/5)` and `sy=32+floor(y*14/15)`.
|
||||
- The AXI prefetcher still stays one source row ahead; its physical write target
|
||||
now rotates 0/1/2 rather than alternating 0/1.
|
||||
|
||||
Expected fit delta from the accepted Ch437 build is one 640-pixel physical RAM
|
||||
bank (approximately five M20Ks in the established 256-bit implementation), two
|
||||
additional 256-bit beat-cache registers, and small shift/add logic. Ch437 used
|
||||
344/358 RAM blocks, so the expected result is about 349/358.
|
||||
|
||||
## Exact preview result
|
||||
|
||||
Input framebuffer:
|
||||
|
||||
- `captures/gs/silenthill3/extracted/sh3_zsrt139f52_ch435_board.png`
|
||||
- Its underlying f52 board dump is byte-identical to the accepted Ch436/437
|
||||
framebuffer (`d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b`).
|
||||
|
||||
Reference: `captures/gs/silenthill3/pcsx2_ref_224139.png`.
|
||||
|
||||
| Scanout | MAE | RMSE |
|
||||
|---|---:|---:|
|
||||
| Ch437 separable linear | 13.9525 | 20.6568 |
|
||||
| Ch438 3x3 binomial + nearest | 13.1111 | 19.1051 |
|
||||
|
||||
Preview:
|
||||
`captures/gs/silenthill3/extracted/recon/sh3_zsrt139f52_ch438_binomial_preview.png`
|
||||
|
||||
Preview SHA-256:
|
||||
`5a0402c523b64e252746067488177b08f0d23ab8a4a7dc09857e914c07f269f1`
|
||||
|
||||
The preview is generated by `tools/preview_scanout_ch438.py`, which reproduces
|
||||
the RTL's rounding after each separable pass.
|
||||
|
||||
## Pre-fit verification
|
||||
|
||||
- `make -C sim tb_gs_lpddr_scanout_lb_binomial`
|
||||
- 2,400/2,400 output pixels exact
|
||||
- zero underflow
|
||||
- zero read errors
|
||||
- `make -C sim tb_gs_lpddr_scanout_lb_hstretch`
|
||||
- Ch437 compatibility: 2,400/2,400 exact
|
||||
- zero underflow/read errors
|
||||
- `make -C sim tb_gs_lpddr_scanout_lb`
|
||||
- legacy scanout PASS under its established one-pixel-per-line simulation
|
||||
alignment allowance
|
||||
- zero underflow/read errors
|
||||
- Targeted Verilator lint of the binomial parameterization: no errors, latches,
|
||||
multidriven signals, combinational loops, or range errors.
|
||||
- Repository `git diff --check`: clean.
|
||||
|
||||
The repository-wide `make lint` still stops at the pre-existing unsupported
|
||||
default-valued `rewind_i` input in `sif_dma_ee_ram_bridge_stub.sv`; the targeted
|
||||
scanout lint is clean and this unrelated baseline issue was not changed.
|
||||
|
||||
## Owner fit gate
|
||||
|
||||
Ready for a fresh Quartus 26.1 GUI compile. Accept only if:
|
||||
|
||||
1. fit succeeds;
|
||||
2. all setup/hold/recovery/removal/pulse-width checks are clean;
|
||||
3. RAM use remains at or below 358 blocks;
|
||||
4. all three scanline arrays infer as RAM rather than register banks.
|
||||
|
||||
## First fit and timing-root correction
|
||||
|
||||
The first Ch438 GUI fit completed successfully and confirmed the scanout
|
||||
resource projection:
|
||||
|
||||
- 38,904 ALMs
|
||||
- 57,173 registers
|
||||
- 349/358 RAM blocks
|
||||
- 160 DSP blocks
|
||||
|
||||
All non-setup checks were clean, but EMIF setup failed at `-0.120 ns`, TNS
|
||||
`-3.122`, across 64 endpoints. The actual top-ten family was unrelated to the
|
||||
new filter datapath:
|
||||
|
||||
- launch: `u_zc_emit|u_req|raddr_q[6]`
|
||||
- capture: the deep request FIFO's packed `mem_rtl_0` port-B address banks
|
||||
- launch-register fanout: 744
|
||||
- data path: one 2.886 ns route, zero logic levels
|
||||
|
||||
This is the established 93-bit x 16K request-FIFO physical-address family. The
|
||||
additional scanout RAM changed placement enough to expose it again.
|
||||
|
||||
The correction keeps the full 16K request depth and banks only the payload into
|
||||
two independently inferred RAM arrays. Each half has a separate preserved
|
||||
registered read address, reducing the single 744-load launch net to two roughly
|
||||
half-sized physical trees. FIFO order, pointer CDC, and registered-read latency
|
||||
are unchanged. The banked form is enabled only on `u_zc_emit.u_req`; all other
|
||||
`gs_async_fifo` users retain the monolithic default.
|
||||
|
||||
Post-cut verification:
|
||||
|
||||
- default async FIFO stress: 3,285 writes/reads, zero errors;
|
||||
- monolithic registered-read stress: 3,285 writes/reads, zero errors;
|
||||
- banked registered-read stress: 3,285 writes/reads, zero errors;
|
||||
- full f52 production Verilator replay:
|
||||
- 311 epochs;
|
||||
- 2,339,914 fragments fed;
|
||||
- 2,286,292 passed;
|
||||
- zero drops, color overflow, BRESP errors, Z mismatches, or color mismatches;
|
||||
- PASS;
|
||||
- post-cut framebuffer SHA-256:
|
||||
`d0047677371a0f6e4e319458926f604a8599c92baaf34d09b8e1fd452e31662b`,
|
||||
byte-identical to the accepted Ch437 board framebuffer.
|
||||
|
||||
The first timing-red RBF (`7fa4724f...`) was not deployed. A fresh GUI compile
|
||||
is required for the banked-address correction.
|
||||
Reference in New Issue
Block a user