Commit Graph

29 Commits

Author SHA1 Message Date
tetrisgm ada331a401 pgxp/gte: exact-sign NCLIP hardening — validate-on-read, shadow-silent replay, idempotent enable
Root-causes the transient 1-frame sign-corner flicker at wide aspects
(sign faces blink when the exact-sign NCLIP path silently loses its
shadows for one frame):

- gte_nclip was the only shadow consumer skipping the engine's single
  safety invariant (packed-word validation). A stale FIFO shadow (e.g.
  after an SXYP MTC2 shifts the real FIFO but not shadows 12/13) could
  invent a silently WRONG winding sign. New pgxp_get_gte_sxy_checked
  validates the shadow's word against the live SXY register; staleness
  now demotes to the honest integer fallback.
- Overlay shadow-diff REPLAY passes ran the pgxp memory hooks live
  (record pass's stale FIFO shadows re-validated against different
  vertices -> flags dropped, live slots overwritten -> arena-wide
  provenance kill = one-frame integer-sign blink, plus false
  SHDIFF_GTE_DATA divergences permanently demoting shards to interp).
  gte_replay_side_effects_begin/end now bracket pgxp_suppress so replay
  is shadow-silent, like the speculative validation passes. The nclip
  precise path is additionally gated off inside the sandbox and
  speculative passes.
- pgxp_set_enabled is now idempotent: a redundant re-derive (config
  apply, correction toggle, debug A/B) no longer costs a generation
  bump, which killed every live shadow and blinked one frame of
  exact-sign coverage.
- Observability: free-running NCLIP precise/fallback/corrected counters
  and a PGXPStats.invalidations counter (bumped at the generation-bump
  site), both exposed in the geom_correction debug reply.

All changes are inert at 4:3 (ws_precise_nclip gate) and touch
host-only state exclusively.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 10:39:10 -07:00
tetrisgm 249057f93f Widescreen precision: exact-sign NCLIP + GTE clamp rescue; backend-invariant entry hooks
Three changes that ride the existing PGXP dataflow engine:

- Arm the PGXP engine whenever a precision consumer needs it, not only when
  a correction feature is on. gpu_pgxp_rederive_enable() derives the arm from
  texture correction OR geometry correction OR the widescreen precise-NCLIP
  opt-in, and every setter re-derives. Previously disabling both corrections
  silently disabled the shadows precise_nclip depends on.

- gte_nclip: when the sub-pixel shadow of all three SXY FIFO entries is live,
  take the winding SIGN from the exact double cross product and keep the
  hardware integer magnitude. The X-squash scales areas by a positive factor,
  so only integer rounding ever flips a sign; this removes both the vanished
  trackside signs and the per-frame tile flicker at wide aspects without any
  epsilon tolerance. The producer clamps shadow coords to +/-4096 px so a
  projection blowup cannot wrap the 16.16 int32.

- Clamp rescue (prepare_precise_triangle): a vertex parked exactly on a GTE
  saturation rail (+/-1024) is hardware-mangled; when the validated dataflow
  shadow knows its true position, rasterize with that instead. Kills the
  "polygon spike" streak class that 4:3 framing plus CRT overscan hid. Every
  in-range vertex stays native, so normal geometry is bit-identical.

- dirty_ram_interp: fire psx_mod_function_entry on interp dispatch so
  function-entry mod hooks do not depend on which backend executes a
  mod-patched page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 23:30:17 -07:00
Matthew Stanley 41c232fb47 Fix precise NCLIP on PGXP-backed GTE shadows 2026-08-15 21:46:47 -07:00
Matthew Stanley bdd7ade6e8 Merge remote-tracking branch 'origin/master' into codex/netplay-local-viewport 2026-08-15 21:40:56 -07:00
Matthew Stanley 200b5bf003 Add opt-in widescreen culling keep hooks 2026-08-15 19:42:43 -07:00
Matthew Stanley 2ba74f3b4b pgxp: land clean-room value-propagation engine (phases 0+1, issue #92)
The G1.2/G1.3 mechanism: per-word RAM/scratchpad + per-GPR + per-GTE-reg
shadows carrying sub-pixel projections BY PROVENANCE, validated against
the actual guest word on every read (never guessed from rounded position
- the measured 93.1%-ambiguous G1.4 dead end). Clean-room from psx-spx +
public design docs; vendored duckstation (CC BY-NC-ND) and beetle-psx
(GPL) trees remain black-box oracles only - no code ported.

- runtime/src/pgxp.cpp + pgxp.h: engine, per-vertex GetPreciseVertex
  (dataflow -> ambiguity-gated position cache -> native) with truncation
  agreement + tolerance safeguards; stats; test accessors.
- pgxp_hooks.h: 5-entry hook funnel; PGXP_*() macros no-op unless
  -DPSX_PGXP=1 (codegen-time gate over ONE generated tree); appended
  PGXPHooks* table member in OverlayCallbacks (ABI bump ships with the
  Phase-2 emitter change).
- Both interpreters wired: loads/stores/COP2 + precision-carrying
  arithmetic (moves, add/sub, or-merge, 16-bit shifts, LUI, HI/LO).
- gte.cpp: RTPS feeds the GTE reg shadows; retired s_precise_sxy FIFO,
  hashed s_precision_store, and plain-store invalidation (redundant
  under validate-on-read; store hot path gets 3 calls back).
- gpu.c: prepare_precise_triangle rewritten per-vertex; perspective UVs
  share the same provenance and compose per triangle.
- [video] pgxp_cpu_mode / pgxp_tolerance keys; TCP pgxp verb live-
  toggles geometry/texture/cpu_mode/tolerance; geom_correction census
  grew the pgxp dataflow counters (G1.9 gate metric).
- tests: new pgxp_test (registered); gte_register_access_test updated
  to precise invalidation contract. 33/33 enabled tests green.

Also fixed while landing (both broke a fresh master tree):
- runtime.cmake: once-only psx_game_version.txt stamp (multi-target
  file(GENERATE) collision broke every fresh single-config configure).
- test_overlay_capture_retry: SDL3 rot (SDL_SetMainReady gone, inverted
  SDL_Init check) -> psx_sdl_init.

Tracked as beads-eio.3.48; postmortem + this landing: ENHANCEMENTS.md
G1-G1.10.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 18:34:47 -07:00
Alex Vanderveen 02b08dae54 fix CTR graphics 2026-08-08 12:28:05 -04:00
Alex Vanderveen 7090727438 ok 2026-08-07 22:14:26 -04:00
Matthew Stanley b35892fc16 fix(gte): exact direct-indexed vertex table + ambiguity gate, with a miss census
The geometry side cache was an 8192-entry HASHED table with no ambiguity check.
Unrelated screen positions shared a slot, so a vertex could be handed a
different vertex's sub-pixel fraction, and eviction changed which triangles got
corrected from frame to frame — moving seams across every mesh.

Both references index this table exactly, one slot per reachable SXY
(beetle-psx vertexCache[0x800*2][0x800*2]; DuckStation 2048x2048), and gate it
on an ambiguity flag so a pixel that two DIFFERENT projections rounded to is
never used. Do the same: direct index, first writer wins, flag on a conflicting
value, allocate lazily on enable so the faithful default costs nothing, and
fail closed to the faithful path if the allocation fails.

Adds a lookup census (attempted / hit / miss_unrecorded / miss_ambiguous) on
geom_correction. With an exact table a miss_unrecorded is a genuine tracking
coverage gap rather than a cache artifact, which is what distinguishes 'the
cache was lossy' from 'the vertex path never reaches us in a matchable form'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:18:29 -07:00
Matthew Stanley 5ded80e61e Merge master (AOT overlay generation) into perf/interpreter-hotpath
Integration branch: the interpreter-perf series (interpreter fallback +
additive shard autocompile + always-on production observability + the
fail-closed alias-body emitter fix) rebased-by-merge onto master's AOT
overlay generation (play-free extraction, bounded indirect discovery,
AOT recall, shadow-diff redesign).

Semantic-union highlights:
- gte.cpp: HEAD's direct-field marshaling fast paths kept; master's
  s_gte_replay_sandbox guards grafted onto every affected site.
- psx_icache.c: HEAD's global tag array + fetch_miss split kept;
  master's transactional shadow record/replay retargeted onto it.
- overlay_capture.c: HEAD's commit/retry/wait-pending pipeline kept;
  master's durable history + autocapture APIs wired into it
  (persist_history_snapshot fed from the immutable .d contribution).
- overlay_loader.c: master's interp-record/native-replay shadow-diff
  redesign kept as base with HEAD's scheduler-bail hardening grafted
  (new SHDIFF_SCHED divergence kind); strict manifest v2 parsing keeps
  master's P pair-id lines; always-on native-call ring preserved.
- main.cpp shutdown calls BOTH overlay_autocapture_shutdown() and
  overlay_capture_wait_pending() (the latter drains the preserve-write
  FIFO the former does not).
- recompiler: master's generate_alias_group refactor retains the
  fail-closed alias-body re-entry defaults from c85f1d1.

Validated on this tree: recompiler + runtime + tests build; all six
runtime unit tests PASS; interpreter perf guards PASS; recompiler
patch/structural tests PASS (l1 decoder oracle noise = 376 pre-existing
on both parents).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 00:43:41 -07:00
Matthew Stanley d13bade9ae Speed up exact GTE command marshaling 2026-07-19 14:44:22 -07:00
Matthew Stanley 05f6ef3e02 Optimize GTE fallback and isolate interpreter perf runs 2026-07-19 14:23:36 -07:00
Matthew Stanley d73dc5f36e runtime: add transactional overlay differential replay 2026-07-19 13:40:03 -07:00
Matthew Stanley 7376e6b042 Harden additive overlay shards and speed interpreter fetch 2026-07-19 12:11:56 -07:00
Matthew Stanley 2ceaf5abee feat: park projection and perspective correction
Adapted from https://github.com/mstan/psxrecomp/commit/ec889d6e5956fc4f34acfee41d87f30b24123b7f

Co-authored-by: Kareem Olim <kareemolim@gmail.com>
2026-07-14 23:06:38 -07:00
Matthew Stanley 244474a147 widescreen: scope curved backdrop projection sites 2026-07-10 15:51:07 -07:00
Matthew Stanley c4474b9340 fix(gte): honor lm/sf from the instruction in the depth-cue/lighting family; add always-on GTE observability rings
The depth-cue tail (INTPL/DPCS/DPCT/DPCL/NCDS/NCDT/CDP) and the lighting
helpers (light_transform / light_color / color_output) hardcoded lm=1 on
every IR write-back, clamping all negative components to zero. Crash Bash
tweens its vertex animation through INTPL (cmd 0x0980011, lm=0): pose A in
IR1-3, pose B in the far-color registers, blend in IR0. With lm forced on,
every negative vertex component collapsed to 0 on tween frames, squashing
characters onto their anchor point. At 10fps keyframes / 30fps renders that
made the menu character strobe (2 of 3 renders flattened, so exactly one
display buffer ever held a healthy pose) and in-game characters flatten.
Beetle/hardware render the same frames correctly.

depth_cue_from_ir is now the faithful hardware formula: base = IR<<12,
step = lim(((FC<<12) - base) >> sf*12) with the forced-unsigned-off
intermediate clamp, MAC = (base + IR0*step) >> sf*12, final IR clamp with
lm from the instruction word. sf (bit 19) is honored instead of assuming 12.
The lighting helpers take lm from the instruction too (games light with
lm=1, so their behavior is unchanged).

Observability (always-on, build-dbg commands):
- GTE projection ring (gte_ring_dump): every RTPS/RTPT's V/RT/TR/H/OFX/OFY
  inputs and SXY/SZ/FLAG outputs, frame-stamped, with caller ra.
- GTE INTPL ring (gte_intpl_dump): every INTPL's IR0/IR1-3/FC inputs
  (snapshotted pre-op) and MAC/IR/FLAG outputs, with frame filter AND
  offset paging so a whole frame is reachable.
- gte_frame_stats: per-frame nproj/nsat/nflat/nintpl/nintpl_tiny —
  nintpl_tiny (all-tiny output from non-tiny input) is the collapse
  signature and pinned this bug to the INTPL math in one query.
- gte_latch_dump: retained ring of saturated projections.

Verified on Crash Bash SELECT GAME TYPE: nintpl_tiny 335-352/473 -> 0-3,
vertex buffer at 0x80056AC8 no longer alternates healthy/collapsed, and a
20-shot jittered screenshot burst shows the character in every frame
(was bimodal present/absent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:19:21 -07:00
Matthew Stanley d31be0e758 gte: dome-locate probe (ra-based) + ws_dome_probe TCP cmd
Tally which GUEST function (guest ra at gte_execute, not the libgte leaf
0x80000F40 that g_debug_current_func_addr reports) projects far/sky vertices,
to identify the sky-draw fn for the per-function dome-expand bracket. ws_dome_probe
on=1 thr=<SZ> arms; dump lists ra + count + max_sz. FINDING (Ape): the title sky
is a curved dome with a RANGE of depths, so the depth-gated dome-expand only
scales its farthest verts (warps it, can't cleanly fill) — confirms the per-
function bracket is required. Lead: far-sky verts came from game code in the
~0x80138xxx overlay region. Probe stays as a tool; Ape dome wiring is a follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:11 -07:00
Matthew Stanley 402fe01b11 gte: native-wide sky-dome expand (opt-in, off by default) + ws_dome tuning cmd
Depth-gated dome-expand: in native-wide (no squash), scale far-depth
(SZ >= ws_far_threshold) GTE-projected X outward from the projection centre by
(3*num)/(4*den) so a FINITE sky-dome mesh grows to fill the wider FOV instead
of leaving black corners. Live-tunable via the ws_dome + ws_far_threshold TCP
commands; off by default (no config wires it on), so inert unless toggled.

NOTE: depth alone does not cleanly isolate Ape's title dome (its sky is not the
uniquely-farthest layer — distant world geometry shares the depth range), so the
Ape title needs the per-function bracket route (find the dome draw fn, bracket
with gte_ws_set_dome_expand like the far-backdrop unsquash_funcs). The mechanism
lands here; the Ape wiring is a follow-up. Correct as-is for titles whose sky IS
the farthest layer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:10 -07:00
Matthew Stanley ee09ab9bbb widescreen: generic Ape-Escape-class support + native-wide GL perf + cutscene flicker fix
Adds full 16:9/21:9 native-wide support for fully-3D titles (Ape Escape,
SCUS-94423) as a generic, opt-in, 4:3-byte-identical framework capability, plus
a native-wide GL compositor perf fix and a cutscene present-mode flicker fix.

Widescreen (generic, per-game opt-in via [widescreen*]):
- Shared screen-extent cull detector (runtime/include/ws_cull_detect.h) used by
  all three backends (recompiler, dirty-RAM interp, sljit). Per-game signature
  immediates ([widescreen.cull] screen_w_imms/screen_h_imms) — Ape's funnel
  tests 0x181/0xF1 on its 368px display, not Tomba's 0x140/0xE0.
- Three funnel idioms widened: unsigned per-vertex sltiu (psx_ws_cull_sltiu),
  signed min/max slti right edge + bare-bltz left edge (psx_ws_cull_slti/bltz,
  new helpers + SLJIT_HLP appends), and billboard center+/-halfwidth. Explicit
  [widescreen.cull] slti_sites for X-only funnels the auto-detector can't
  qualify.
- gte_game_mode: GTE-activity gameplay detector for 3D titles with no sprite-tag
  helper (gte.cpp notes every RTPS/RTPT). STICKY (>=3 verts, 45-frame hysteresis)
  so sparse cutscene frames never flip to a 4:3 pillarbox = fixes intro flicker.
- nw_hud_corners: push outer-third screen-space HUD sprites to the true wide
  corners in native-wide (else inset by the reveal).
- nw_backdrop: stretch a full-frame axis-aligned 2D backdrop quad to fill the
  wide frame (for titles with a flat sky plane).
- Pattern-scanned interp/sljit widen hooks now gated per-game (auto_screen_x /
  auto_backdrop): fixes an ungated auto_backdrop false-positive that rewrote a
  live GPR = the ~24s native-wide crash on Ape.

Native-wide GL perf (fixes 16:9 frame drops):
- The wide surface centre equals the canonical 4:3 framebuffer, so wide_blit_center
  copies canonical->wide-centre at present (both present paths) and the per-prim
  mirror SKIPS prims fully inside the 4:3 frame (mirror_x/geo/batch_center_only).
  Only reveal-margin prims re-rasterize. Peak frame time 38.8ms -> 17.5ms, no
  vsync misses. Toggle gl_wide_fast; 4:3 untouched (all gated on g_wide_cur).

Runtime-only except the recompiler cull emit (regen needed for cull widening).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:09 -07:00
Matthew Stanley 9b7e806656 gte: hardware Unsigned Newton-Raphson reciprocal for perspective divide
gte_divide computed the perspective divide as exact
(H*0x20000/SZ3 + 1)/2; real PS1 GTE (and Beetle, mednafen psx/gte.cpp)
use the Unsigned Newton-Raphson reciprocal table. They diverge on
24.7% of inputs by +/-1 (max +/-3) in h_div_sz, which feeds screen
coords and the IR0/MAC0 depth-cue factor — a camera/distance-dependent
divergence. This implements the hardware UNR algorithm (incl. the
1<<17 overflow-flag semantics); matches Beetle bit-exactly over 400k
inputs. Faithful-core accuracy improvement for all titles.

Staged as a candidate for Ape Escape's camera-distance-dependent
black additive-glow artifact but NOT causally confirmed (the artifact
did not reproduce in the scene reachable for oracle A/B). Glow
investigation parked; this fidelity fix stands on its own.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 11:39:32 -07:00
Matthew Stanley 553d9933d1 fix mmx6 timing divergences with cosim oracle 2026-07-01 09:28:50 -07:00
Matthew Stanley ec1fd76b56 timing: faithful GTE (COP2) per-command completion-stall
Models the GTE command latency + stall-on-COP2-access, the next Stage-2 cycle
component. Mirrors the mult/div completion-stall mechanism:

- cpu->gte_ts_done (new CPUState field, appended): a GTE command sets it to
  psx_cycle_count + (cost-1); back-to-back commands serialize (psx_gte_set
  stalls to the prior deadline first). Any COP2 register access
  (MFC2/CFC2/MTC2/CTC2/LWC2/SWC2) calls psx_gte_stall, advancing guest cycles
  to the deadline if the op is still in flight.
- Cost table (psx_cycles.c, psx_gte_cmd_latency): per-op cost-1, transcribed +
  verified from beetle-psx gte.cpp op returns (RTPS15 NCLIP8 MVMVA8 NCDS19
  NCDT44 RTPT23 NCCT39 ... AVSZ4=5 not 6). cost-1 because the COP2 instruction's
  own +1 base is charged separately (Beetle GTE_Instruction returns ret-1).
- Set armed in the shared gte_execute() (one site for both backends); stall
  emitted before every COP2 reg access in both emitters (code_generator,
  strict_translator) and the dirty interp. The compiled "+1 at top" vs interp
  "base after exec_one" offset cancels (same as muldiv).

Validated EXACT on ruler #2 (new gte_rtps + gte_nclip loops): native +15/+8 ==
Beetle +15/+8. All other components unchanged (no regression); Tomba2 boots to
FMV. Requires regen (emitters changed); runtime+BIOS+game regenerated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 12:41:22 -07:00
Matthew Stanley 9669d38d28 widescreen(8C): far-backdrop GTE un-squash, depth-gated
The far backdrop (ocean/cloud/distant mountain) is GTE-projected 3D drawn
by the main-EXE driver FUN_8004db3c (sole caller of the GTE emitter
FUN_80027600). The global widescreen GTE X-squash compresses it toward
centre, so its geometry falls short of the revealed 16:9 edges -> blue void
that pops as the camera moves.

Fix: bracket the backdrop driver with gte_ws_set_suppress(1)/(0) so its
draws skip the X-squash and fill the stretched frame (skybox treatment),
while the near 3D world keeps the wider FOV.

FUN_8004db3c draws a MIX (far backdrop + nearer props/scenery), so the
suppress is DEPTH-GATED in gte_rtps_internal: only vertices with projected
SZ >= s_ws_far_threshold (default 900, tunable live via the ws_far_threshold
TCP cmd) un-squash; nearer props stay squashed and aligned. Validated:
threshold 900 fills the void, keeps the foreground door + background
scenery (path/tree) aligned. Residual: the mountain grass-top straddles the
depth band (per-vertex limitation) -> flickers when the camera dips; this
is the checkpoint before exploring native-wide rendering to remove the
squash (and this whole artifact class) entirely.

Mechanism:
- recompiler: [widescreen.backdrop] unsquash_funcs emits
  gte_ws_set_suppress(1) at entry + (0) before each jr-$ra return
  (code_generator + config_loader + main_psx). Main-EXE -> regen-class.
- runtime: gte.cpp depth-gated squash + s_ws_far_threshold; cpu_state.h
  decl; debug_server.c ws_aspect (live squash on/off) + ws_far_threshold
  (set split + read SZ stats) diagnostics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:52:17 -07:00
Matthew Stanley bd6ddc32f1 widescreen: couple squash to present (fix menu garble) + cull-margin widening
Menu fix (user-validated): per-prim center-squash mangled composite 2D
UI (dialog boxes built from tiled cap/middle/cap SPRTs no longer
aligned). Root cause was decoupling — content was squashed while the
frame presented 4:3. Now squash applies IFF the frame is stretched:
gpu_ws_present_native_43() is the single predicate (FMV video OR a
full-2D screen = no character billboards this frame), shared by the
GTE squash, the GPU per-prim squash, and the present 4:3 pin. Full-2D
menus get zero squash + 4:3 pillarbox = pixel-native. Removed the old
menu-2D squash paths (lines/flat-rects/mono-sprites/polylines).

Cull-margin widening (recompiler feature): the game's per-object draw
classifier tests (objX-camX+BIAS) <u RANGE sized for the 4:3 screen;
the GTE squash shows ~33% more world so the margin collapses and
objects pop near the wide edges. New [widescreen.cull] config emits
those immediates with a runtime term psx_ws_x_margin() (bias +margin,
range +2*margin, plus a1+=margin for param-margin variants) — 0 at
4:3/boot/menu/FMV so the original cull is byte-identical, ~53px when
stretching 16:9. Site instruction types are verified at emit (fatal on
mismatch). Requires regen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 12:52:16 -07:00
Matthew Stanley be76e4d4b5 widescreen: [video] aspect_ratio — GTE X-squash + stretched present
Adds the DuckStation-style widescreen hack as a config option,
implemented in the runtime (no regen needed):

- gte.cpp: gte_set_display_aspect(num, den). RTPS/RTPT scale the
  IR1*h/sz screen-X term by (4*den)/(3*num) around the game's own
  OFX projection centre (identity at 4:3). Games cull against the
  SXY values they read back from us, so post-projection screen-
  bounds culls stay aligned with the visible frame.
- present: GL letterbox_rect generalised to the configured aspect
  (gl_renderer_set_display_aspect); SDL_Renderer path gets an
  aspect-derived logical size + dst rect. Window opens at the
  configured aspect (clamp_window_4x3 -> clamp_window_aspect).
- config: [video] aspect_ratio = W:H (4:3 default, 16:9, up
  to 32:9) in game.toml, settings.toml (load+save), launcher seed.

World geometry keeps correct proportions on the stretched present;
screen-space 2D (HUD, FMV, sprite quad widths) stretches — the
known limitation of the squash tier. EXPERIMENTAL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-15 12:52:14 -07:00
Matthew Stanley 0c5b892904 Fix Tomba visual rendering issues 2026-05-17 21:58:55 -07:00
Matthew Stanley bd6dfa12da fix: memcard absent detection + raw texture bug + GTE exec counter + quad capture
- memcard.c: stop auto-creating blank cards when .mcd files don't
  exist; missing file now correctly means "no card in slot"
- gpu.c: fix setup_textured_draw raw texture flag (was ? 0 : 0,
  now ? 1 : 0 for identity-modulation bypass)
- gpu.c: add shaded quad vertex capture mechanism for Phase 4.5
  debug (capture_quads / get_quads debug commands)
- gte.cpp: add gte_exec_count to track total GTE compute commands
  executed (exposed via gte_state debug command)
- debug_server.c: wire up capture_quads, get_quads commands and
  gte_exec field in gte_state response

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 15:33:19 -07:00
Matthew Stanley adaea3d8bf Salvage clean hardware sim from v2/v3: GTE, SW renderer, ISO reader, CRC32
Audited psxrecomp-v3 and psxrecomp-v2 hardware simulation files.
Carried forward only pure hardware simulation with zero HLE/BIOS
contamination. Each file was read in full and checked for:
- event_deliver / bios_ / interpreter_ references (none found)
- printf/fprintf (removed from GTE, none in others)
- stubs (return 0, TODO, FIXME) (none found)
- v3-specific state dependencies (removed psx_runtime.h, automation.h)

Added files:
- gte.cpp/h: COP2 coprocessor (876 lines, all GTE commands)
- gpu_sw_renderer.c/h: Software rasterizer with texture support (723 lines)
- crc32.c/h: CRC32 utility (27 lines)
- iso_reader.cpp/h + iso_reader_c.cpp: ISO 9660 reader (490 lines)

Modified:
- cpu_state.h: Added gte_data[32] and gte_ctrl[32] arrays
- CMakeLists.txt: Added new source files

Explicitly rejected (per CLAUDE.md rule 7):
- bios.c, events.c, threads.c, interpreter.c (HLE/kernel state)
- bios_trace.c, func_logger.c, main_runner.cpp (interpreter era)
- cdrom.c (has event_deliver + hard-coded RAM writes, needs surgery)
- spu.cpp from v2 (WinMM-only, needs SDL port)

Build verified: clean compile and link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 20:57:41 -07:00