Files
BFM-decomp/docs/gen3-parking-lot.md
T
Drew T 808ec6ff7e feat(phase-25): T5b batch-1 COMPLETE — continuation +541 fns (fleet 72.02->72.18%)
- batch-1 cheap tier (83) now 100% drafted: the 29-continuation recovered via
  resumeFromRunId (9 session-cap failures re-run, 20 cached-replay, 0 errors).
- 22/29 -O2 match_one-MATCH; gate banked 8 clean (main 3, _a 2, _after 3) +
  family_sweep +533 siblings across 133 overlays (5 exemplars, ~0 tokens).
- R22 clean-fleet 136/136; dedup-check 1813/0; 0 NON_MATCHING (G4).
- backlog: func_801457A4 (MATCH but -O0-only -> batch-3), func_80135004/8013AD38
  (need the T7 caller-decl reconcile), func_80168828 (close=8, permuter fuel).
- frontier map now 93 exemplars measured (.run/t5_frontier.jsonl).
- docs/gen3-parking-lot.md: captured the Gen3 native-port recomp architecture
  (PsyQ-SDK HLE boundary on Vulkan; recomp-front-end + decomp-incrementally hybrid).
- session totals: fleet 71.36 -> 72.18% (+2820 fns). Cheap tier done; giants next (hold).
2026-07-09 15:47:30 -06:00

150 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gen3 Parking Lot — asset export / native rebuild (speculative; NOT in scope)
> The evolvable docs/-layer home for Gen3 ideas (`PROJECT_CONTEXT.md` is static/permanent — P1 — so
> its "Gen3" + "Parking Lot" sections can't be appended to; this file is where Gen3 speculation and
> its supporting findings accumulate). **Gen3 is PARKED** per the roadmap: do not start until Gen2 is
> substantially matched. Recorded 2026-07-01 at Drew's request, after a "could we export the town mesh
> / Musashi model and rebuild it in Unity?" discussion + a read-only survey of the current state.
## The idea
Export BFM's 3D assets — location/town **meshes + textures**, and **character models** (Musashi et al.) —
and rebuild / inspect them in **Unity** (or any modern engine). This is *enabled by* the code decomp but
is a **separate axis** from it (the decomp byte-matches CODE; this interprets DATA). None of the
asset-export tooling exists yet.
## Current state — what we ALREADY have (VERIFIED 2026-07-01, read-only survey)
**Rendering = stock PsyQ libgpu (understood).** The game builds primitives with `SetPolyF3/F4/FT3/FT4/
G3/G4/GT3/GT4`, manages ordering tables (`AddPrim`/`CatPrim`/`NextPrim`/`TermPrim`/`DrawOTag`/`DrawSync`),
all byte-matched/linked (Phase 7/8). So on-screen geometry is standard PS1 polys (flat/gouraud,
textured/untextured tris & quads) with vertices/colors/UVs/tpage/clut.
**Model data = the libgs TMD path IS used (the key positive finding).** Verified by real `jal` call
sites in the disassembly — not grep-count speculation (R14):
- `jal GsMapModelingData` (maps/relocates a **TMD** in RAM) in the EXE model subsystem —
`func_8001C214 / C320 / C4A4 / C5B8 / C810 / C924 / C97C` clustered at ~`0x8001C2xx–0x8001C9xx` —
**and in ≥1 overlay** (`ov_SC02_005/func_801871E4`).
- `jal GsLinkObject5` (link a TMD → a texture-mapped GsDOBJ) in `func_8001C320 / C5B8`.
- ⇒ BFM's model data is **TMD (or GsMapModelingData-compatible)** — a **documented Sony format**. This
makes static geometry substantially more exportable than a fully custom format would.
**Animation / scene mgmt likely CUSTOM.** No call sites found for `GsSortObject*`, `GsInitCoordinate2`,
or `GsGetLws` (the libgs LWS/TOD animation + auto-sort path). Read: the game uses libgs for **model data**
but a **custom sort/draw loop and custom animation** on top. ⇒ static town geometry (TMD) is the easy
case; **animated characters (Musashi) are harder** (bespoke skeleton + animation format to RE).
**Textures — the tractable half.** The upload/handling path is named (`LoadTPage`/`LoadClut`/`GetTPage`/
`GetClut`/`SetDrawTPage`/`DumpTPage`/`DumpClut`). PS1 textures live in **VRAM** (1024×512 16-bit; texture
pages + CLUTs), so a **VRAM dump → texpage/CLUT decode → PNG** rip needs no full format RE, and PCSX-Redux
is already wired (Phase 3). The **type-0 PAC entries** (301 extracted `.0` "graphics" blobs, each with a
`+0x08` dimension/format param — see `formats.md`) are the prime TIM-candidate source.
**Data is all extracted; WHERE a town's geometry lives is TBD.** Every raw byte is on disk
(`extracted/retail/SCxx.CD.dir/...`). Candidate geometry/texture blobs: **type-0** (301, "graphics"),
**type-7** (139, uninterpreted `.7`), and possibly the **type-4 overlay data tails**. Which blob holds a
given town's TMDs is unknown — trace it from a `GsMapModelingData` caller's source pointer.
**Tooling: NONE.** No TIM/TMD/mesh decoder or exporter in `tools/`; `formats.md` has zero geometry
coverage (only disc-sector "geometry"). This is greenfield.
## Difficulty read
| Target | Difficulty | Why |
|---|---|---|
| **Town textures** | **Low** | VRAM rip (no format RE); type-0 "graphics" blobs; harness exists |
| **Town static mesh** | **Medium** | TMD is documented; locate the blob + confirm stock-TMD vs a Square tweak, then decode |
| **Musashi character model** | **High** | Skinned + **custom** animation (no libgs LWS) — bespoke skeleton/anim format on top of the mesh |
| **Unity rebuild (static)** | **Low–Med** | Import glTF/OBJ + PNG; handle fixed-point→float, handedness, unlit/vertex-color + affine→perspective |
| **Unity rebuild (animated)** | **High** | Needs the recovered rig + anim export |
## Decisive next probes (in order, WHEN we pick this up)
1. **VRAM texture rip first** (quick, high-reward): PCSX-Redux VRAM dump at a town → decode texpages/CLUTs → PNG.
2. **Trace a `GsMapModelingData` caller** (Ghidra) → find which loaded blob/offset the TMD is read from → **locate town geometry on disc** (map the type-0/7/overlay-tail question).
3. **Confirm stock-TMD vs Square variant**: parse a candidate blob as TMD (header id `0x41`, flags, primitive list); a stock TMD decodes with existing PS1 tooling.
4. **Write a `TMD→glTF/OBJ` exporter + `TIM→PNG` converter** (`tools/` — leverage existing PS1 TMD/TIM knowledge).
5. **Unity import** + the PS1-ism handling above.
6. **Animated (Musashi)**: RE the custom skeleton + animation format (separate, harder sub-project).
## Related Gen3 / parking-lot items (from PROJECT_CONTEXT.md, kept here for continuity)
- Shiftable build; **asset repack** (LZSS recompression becomes real here — a standing Gen3 problem).
- **Native recomp / PC port** (the original psxrecomp ambition, properly sequenced).
- Randomizer-grade tooling; JP/proto as extra splat versions; text/translation tooling; decomp.me preset;
frogress/decomp.dev dashboards; the public flip (Phase 14, deferred to Gen3+).
## Honest caveat
This is speculation + a survey, not committed RE. The load-bearing new fact — **BFM uses libgs TMD model
data** — is byte-verified (real `jal` sites). Everything downstream (which blob, stock-vs-variant, the
exporter, Musashi's anim) is **unstarted** and belongs to a future Gen3 effort. The decomp is the enabler:
the matched renderer + the located call sites are the format spec.
---
# Native PC port — the recomp architecture (PsyQ→Vulkan HLE boundary)
> Spitball with Drew, 2026-07-08 (during a T5b wait). The fleshed-out "native recomp / PC port" parking-lot
> item. **PARKED — Gen3.** Not committed; captured while fresh (R30). The key architectural insight is the
> **PsyQ-SDK HLE boundary**, which is what makes a PS1 port tractable rather than "write another emulator."
## The idea
A **native PC build** of BFM via a **static-recomp front-end** for the game's MIPS code + a **PsyQ-SDK
HLE layer** on modern backends (**Vulkan** for the GPU, an audio lib for the SPU, native FS for the CD).
Distinct from the asset-export axis above (that interprets DATA; this makes the CODE run natively).
## The key insight — HLE the SDK API, not the hardware
A naïve PS1 recomp is hard because you end up re-emulating the GPU at the command/register level (the
emulator problem). **But BFM never touches GPU registers — it goes through the PsyQ SDK** (libgpu
`GsSortObject`/`DrawOTag`, libgte `RotTransPers`, libspu, libcd). The SDK is a **finite, documented API**,
and **we've already isolated it byte-exact** (Phase 7/8 linked libgpu/libgte/libspu/libcd from the real
PsyQ 4.0 objects; we know precisely which addresses are SDK vs game code). So reimplement the **API**, not
the **hardware** — Wine/Proton-shaped, not emulator-shaped.
**Our decomp already draws the exact boundary:** every function is partitioned "game code (matched C)" vs
"PsyQ library (linked object)." That split **IS** the "translate vs HLE" partition — Phase 7/8 hands the
port its function partition for free. So: **game code → static-recomp** (or use our decomp'd C where it
exists); **PsyQ SDK → replace with the Vulkan/audio/FS HLE layer** (don't translate it).
## Three architectures (and the winning hybrid)
- **A — full static recomp** (N64Recomp-style): translate ALL MIPS + emulate the GPU at command level. Hard;
re-does emulator work.
- **B — PsyQ-HLE port (this idea):** game code recomp'd/decomp'd, boundary cut at the SDK, HLE'd on Vulkan.
The sweet spot.
- **C — decomp port:** compile our matched C native + a PsyQ shim — converges with B (both need a PsyQ
reimplementation).
- **Hybrid (the winning move):** a recomp front-end boots a native build **far sooner than a 100% decomp**,
then the **decomp incrementally replaces** recomp'd functions with readable C (recomp-now, decomp-forever).
This is the N64 world's proven pattern.
## Hard parts (honest)
- **Overlays — the #1 PS1 gotcha, and BFM is overlay-heavy** (134 overlays streamed to `0x80128158`). Static
recomp hates "same address = different code over time." N64Recomp handles it by recompiling each overlay
separately + dispatching on which is loaded — and **we've already mapped every overlay boundary + the
loader state machine** (Phase 3), so this is derisked *for us specifically*. This is the biggest reason our
recomp is more feasible than a cold one.
- **GPU HLE (biggest single chunk):** walk the OT in `DrawOTag`, translate each primitive (`POLY_FT4`, …) to
Vulkan. Choose fidelity — replicate PS1 quirks (affine warp, OT painter's-algo, 15-bit dither) *or* "fix"
them (perspective-correct, hi-res). DuckStation's hardware renderer = a *reference* for the mapping.
- **GTE:** mostly free via libgte HLE, **except** BFM uses inline GTE macros (`gte_rtps` → raw cop2; why our
import auto-detects GTEMAC + `gte_macros.inc`) — those cop2 ops land in recomp'd game code → still need a
small **software GTE** (fully documented, a few hundred lines).
- **SPU + CD:** HLE libspu (SEQ/VAB) + libcd → read our extracted assets. The CD loader is **already RE'd**
(Phase 3), so the streaming state machine maps to a file/event model.
## The gap + the reusability sleeper
- **No mature PS1→PC static recompiler exists** the way N64Recomp does (the PS1 world went the emulator +
per-game-decomp routes). Drew's own **psxrecomp** (rocky v1–v3 post-mortem) is the closest prior art.
⚠️ **Verify via web before committing** (X2/R17) — check for recent experimental MIPS-R3000/PS1 static-BT
efforts or anyone extending N64Recomp's `RabbitizerLib`/`N64ModernRuntime` toward R3000.
- **Reusability:** because ~every PS1 game used PsyQ, a **PsyQ-HLE + MIPS-R3000-recomp toolkit generalizes to
the whole PsyQ library** — "N64Recomp for PS1," a genuinely new community tool + a Gen2-public-flip hook.
## Sequencing
Gen3, parked — do NOT fork Gen2 focus. This capture **is** the architecture decision to revisit at Gen3:
*port architecture = PsyQ-SDK HLE boundary on Vulkan; recomp front-end for early boot, decomp replaces
incrementally; overlays per-N64Recomp; reuses the Phase-7/8 SDK partition + the Phase-3 overlay/loader map.*
## Also worth noting — C++ vs C# (from the same discussion)
- **C++** = natural port target: closest to the decomp's C (structs/unions/pointer-math/manual-memory carry
over ~mechanically), best perf, direct graphics/audio interop. Port native first, modernize incrementally.
- **C#** = a *reimplementation* character (pointer arithmetic/unions fight the managed model) using the decomp
as an executable spec/oracle — the Unity-remake route. Valid, more freedom, much more work.
- The decomp enables both; C++ is pragmatic, C# is the "remake."