mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
widescreen(8C): backdrop screenX squash on native + interp paths
The 16:9 edge pop-in is the parallax 2D BACKDROP layer (ocean/cloud/mountain/
grass), drawn by overlay actor handlers (FUN_801216bc family) that compute
screenX = (worldX - camX) >> parallax in pure integer math and store it to the
object's +0x12 field WITHOUT the GTE — so the GTE X-squash that gives 3D the
wider 16:9 FOV never reaches them and far pieces sit past the 320px edge,
clipped (the blue void / half-rectangles at the edges). See TombaRecomp
ISSUES.md #8C for the full root-cause trail.
Fix = psx_ws_backdrop_x() (gpu.c): squash screenX around screen-centre by the
same ws factor as the GTE, identity at 4:3. Applied on BOTH execution paths
because overlay code runs interpreted when no cache DLL is loaded (the common
case in dev — see #8G):
- Native: recompiler emits write_half(.., psx_ws_backdrop_x(rt)) at the
[widescreen.backdrop] x_sites store (config_loader + code_generator +
main_psx --ws-config so the overlay compile gets the sites). Forwarded into
overlay DLLs via OverlayCallbacks {ws_backdrop_x, ws_x_margin, ws_sprite_tag}
(overlay ABI v2->v3 as the cache discriminator); compile_overlays.py glue +
--ws-config passthrough.
- Interp: dirty_ram_interp SH hook keyed by psx_ws_is_backdrop_site(pc); the
runtime registers the x_sites from game.toml (main.cpp).
Verified in data: backdrop slot screenX squashes 371 -> 318 (pulled on-screen).
PARTIAL: visible culling persists -> remaining cause is the backdrop spawn/
despawn window (separate from screenX clip); see #8C "REMAINING CAUSE".
Also added (earlier this session): ws_census draw ring, ws_margin override,
gpu_state ws fields.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,13 @@ struct CodeGenConfig {
|
||||
std::set<uint32_t> ws_cull_range_sites;
|
||||
std::set<uint32_t> ws_cull_a1_sites;
|
||||
|
||||
// Widescreen backdrop screenX squash ([widescreen.backdrop] x_sites). Each
|
||||
// address is a `sh rt,off(base)` storing a parallax 2D backdrop layer's
|
||||
// final screen-X; emitted as write_half(base+off, psx_ws_backdrop_x(rt))
|
||||
// so the un-GTE'd backdrop is squashed around screen centre for the 16:9
|
||||
// FOV (identity at 4:3). Overlay-resident; see config_loader.h. Empty=default.
|
||||
std::set<uint32_t> ws_backdrop_x_sites;
|
||||
|
||||
CodeGenConfig()
|
||||
: emit_comments(true)
|
||||
, emit_line_numbers(true)
|
||||
|
||||
@@ -717,6 +717,25 @@ std::string CodeGenerator::translate_instruction(uint32_t addr, uint32_t instr)
|
||||
return fmt::format("cpu->gpr[5] = cpu->gpr[5] + psx_ws_x_margin();"
|
||||
" /* ws cull a1 bias */{}", comment);
|
||||
}
|
||||
// Widescreen backdrop screenX squash ([widescreen.backdrop] x_sites). The
|
||||
// site is the `sh rt,off(base)` storing a parallax 2D backdrop layer's
|
||||
// final screen-X; squash the stored value around the screen centre so the
|
||||
// un-GTE'd backdrop tracks the 16:9 FOV (psx_ws_backdrop_x is identity at
|
||||
// 4:3). Instruction type is verified; a mismatch is a loud build error.
|
||||
if (config_.ws_backdrop_x_sites.count(addr)) {
|
||||
if (opcode != 0x29) { // sh
|
||||
fmt::print(stderr, "ERROR: [widescreen.backdrop] x site 0x{:08X} is not "
|
||||
"sh (opcode 0x{:02X})\n", addr, opcode);
|
||||
std::exit(1);
|
||||
}
|
||||
uint32_t rs = get_rs(instr), rt = get_rt(instr);
|
||||
int16_t offset = get_imm16(instr);
|
||||
if (offset == 0)
|
||||
return fmt::format("cpu->write_half({}, (uint16_t)psx_ws_backdrop_x((int16_t){}));{}",
|
||||
reg_name(rs), reg_name(rt), comment);
|
||||
return fmt::format("cpu->write_half({} + {}, (uint16_t)psx_ws_backdrop_x((int16_t){}));{}",
|
||||
reg_name(rs), offset, reg_name(rt), comment);
|
||||
}
|
||||
|
||||
// SPECIAL opcode (0x00)
|
||||
if (opcode == 0x00) {
|
||||
@@ -1672,7 +1691,8 @@ std::string CodeGenerator::generate_file(
|
||||
ss << "#include \"psx_runtime.h\"\n\n";
|
||||
ss << "extern void debug_server_log_call_entry(uint32_t func_addr);\n";
|
||||
ss << "extern void psx_ws_sprite_tag(CPUState* cpu); /* widescreen prim tag (gpu.c) */\n";
|
||||
ss << "extern int psx_ws_x_margin(void); /* widescreen cull-margin term (gpu.c) */\n\n";
|
||||
ss << "extern int psx_ws_x_margin(void); /* widescreen cull-margin term (gpu.c) */\n";
|
||||
ss << "extern int psx_ws_backdrop_x(int x); /* widescreen backdrop screenX squash (gpu.c) */\n\n";
|
||||
|
||||
// Emit reference implementations for unaligned memory helpers.
|
||||
// These implement the MIPS lwl/lwr/swl/swr semantics.
|
||||
|
||||
@@ -511,6 +511,19 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
}
|
||||
}
|
||||
|
||||
// Optional [widescreen.backdrop] block — parallax 2D backdrop screenX squash.
|
||||
std::vector<uint32_t> ws_backdrop_x_sites;
|
||||
if (cfg.contains("widescreen")) {
|
||||
const toml::value& ws = toml::find(cfg, "widescreen");
|
||||
if (ws.contains("backdrop")) {
|
||||
const toml::value& bd = toml::find(ws, "backdrop");
|
||||
if (bd.contains("x_sites"))
|
||||
for (const auto& a : toml::find<std::vector<std::string>>(bd, "x_sites"))
|
||||
ws_backdrop_x_sites.push_back(
|
||||
parse_hex(a, "widescreen.backdrop.x_sites"));
|
||||
}
|
||||
}
|
||||
|
||||
return GameConfig{
|
||||
/*config_path*/ config_path,
|
||||
/*project_root*/ root,
|
||||
@@ -537,6 +550,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
/*ws_cull_bias_sites*/ ws_cull_bias_sites,
|
||||
/*ws_cull_range_sites*/ ws_cull_range_sites,
|
||||
/*ws_cull_a1_sites*/ ws_cull_a1_sites,
|
||||
/*ws_backdrop_x_sites*/ ws_backdrop_x_sites,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -238,6 +238,19 @@ struct GameConfig {
|
||||
std::vector<uint32_t> ws_cull_bias_sites;
|
||||
std::vector<uint32_t> ws_cull_range_sites;
|
||||
std::vector<uint32_t> ws_cull_a1_sites;
|
||||
|
||||
// Backdrop screen-X squash ([widescreen.backdrop] x_sites). The parallax
|
||||
// 2D backdrop layer (ocean/cloud/mountain/grass — overlay actor handlers)
|
||||
// computes screenX = (worldX - camX) >> parallax in pure integer math and
|
||||
// stores it to the object's screen-X field WITHOUT the GTE, so the GTE
|
||||
// X-squash that gives 3D the wider 16:9 FOV never reaches it; far pieces
|
||||
// sit past the 320px edge and are clipped (the edge "void"/pop-in). Each
|
||||
// x_site is a `sh rt,off(base)` storing the FINAL screenX; we emit it as
|
||||
// `write_half(base+off, psx_ws_backdrop_x(rt))` so the value is squashed
|
||||
// around screen centre (identity at 4:3). These addresses live in OVERLAY
|
||||
// code, so the overlay compile must see this config (--ws-config). A regen
|
||||
// is required; empty by default.
|
||||
std::vector<uint32_t> ws_backdrop_x_sites;
|
||||
};
|
||||
|
||||
// UserSettings — the launcher-written, user-editable override layer.
|
||||
|
||||
@@ -61,6 +61,12 @@ int main(int argc, char** argv) {
|
||||
// If --config is provided, all paths come from the TOML and other
|
||||
// CLI flags are ignored. Positional form below stays for back-compat.
|
||||
std::filesystem::path config_path;
|
||||
// --ws-config <path>: load ONLY the [widescreen] site lists from this TOML
|
||||
// without treating it as the full game config. Used by compile_overlays.py
|
||||
// so overlay compilation gets the widescreen emits (sprite-tag / cull /
|
||||
// backdrop) whose addresses live in overlay code — the overlay path is
|
||||
// positional (no --config), so this is the channel for those sites.
|
||||
std::filesystem::path ws_config_path;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string a = argv[i];
|
||||
if (a == "--config" && i + 1 < argc) {
|
||||
@@ -72,6 +78,14 @@ int main(int argc, char** argv) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string a = argv[i];
|
||||
if (a == "--ws-config" && i + 1 < argc) { ws_config_path = argv[i + 1]; break; }
|
||||
if (a.rfind("--ws-config=", 0) == 0) {
|
||||
ws_config_path = a.substr(std::string("--ws-config=").size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path exe_path;
|
||||
std::string extra_funcs_storage; // lifetime anchor for the .c_str() below
|
||||
@@ -80,6 +94,7 @@ int main(int argc, char** argv) {
|
||||
bool overlay_mode = false;
|
||||
std::set<uint32_t> ws_tag_funcs; // [widescreen] sprite_tag_funcs
|
||||
std::set<uint32_t> ws_cull_bias, ws_cull_range, ws_cull_a1; // [widescreen.cull]
|
||||
std::set<uint32_t> ws_backdrop_x; // [widescreen.backdrop] x_sites
|
||||
std::filesystem::path out_dir = "generated";
|
||||
|
||||
if (!config_path.empty()) {
|
||||
@@ -93,6 +108,7 @@ int main(int argc, char** argv) {
|
||||
ws_cull_bias.insert(cfg.ws_cull_bias_sites.begin(), cfg.ws_cull_bias_sites.end());
|
||||
ws_cull_range.insert(cfg.ws_cull_range_sites.begin(), cfg.ws_cull_range_sites.end());
|
||||
ws_cull_a1.insert(cfg.ws_cull_a1_sites.begin(), cfg.ws_cull_a1_sites.end());
|
||||
ws_backdrop_x.insert(cfg.ws_backdrop_x_sites.begin(), cfg.ws_backdrop_x_sites.end());
|
||||
fmt::print("config: {}\n", config_path.string());
|
||||
fmt::print(" exe = {}\n", exe_path.string());
|
||||
fmt::print(" seeds = {}\n", extra_funcs_storage);
|
||||
@@ -131,6 +147,23 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// --ws-config: merge the [widescreen] site lists from a side config WITHOUT
|
||||
// adopting its exe/paths. The overlay path is positional (no --config), so
|
||||
// this is how overlay compilation receives the widescreen emits whose
|
||||
// addresses live in overlay code (backdrop screenX, and any sprite-tag /
|
||||
// cull sites that resolve there). No-op when --config already provided the
|
||||
// sites (same TOML) — std::set insert dedupes.
|
||||
if (!ws_config_path.empty()) {
|
||||
const auto wscfg = PSXRecompV4::load_game_config(ws_config_path);
|
||||
ws_tag_funcs.insert(wscfg.ws_sprite_tag_funcs.begin(), wscfg.ws_sprite_tag_funcs.end());
|
||||
ws_cull_bias.insert(wscfg.ws_cull_bias_sites.begin(), wscfg.ws_cull_bias_sites.end());
|
||||
ws_cull_range.insert(wscfg.ws_cull_range_sites.begin(), wscfg.ws_cull_range_sites.end());
|
||||
ws_cull_a1.insert(wscfg.ws_cull_a1_sites.begin(), wscfg.ws_cull_a1_sites.end());
|
||||
ws_backdrop_x.insert(wscfg.ws_backdrop_x_sites.begin(), wscfg.ws_backdrop_x_sites.end());
|
||||
fmt::print("ws-config: {} (backdrop_x sites={})\n",
|
||||
ws_config_path.string(), ws_backdrop_x.size());
|
||||
}
|
||||
|
||||
// Parse the PS1-EXE file
|
||||
std::string error_msg;
|
||||
fmt::print("Parsing PS1-EXE: {}\n", exe_path.string());
|
||||
@@ -623,6 +656,7 @@ int main(int argc, char** argv) {
|
||||
codegen_config.ws_cull_bias_sites = ws_cull_bias;
|
||||
codegen_config.ws_cull_range_sites = ws_cull_range;
|
||||
codegen_config.ws_cull_a1_sites = ws_cull_a1;
|
||||
codegen_config.ws_backdrop_x_sites = ws_backdrop_x;
|
||||
|
||||
// Load per-game annotations: annotations/<exe_stem>_annotations.csv
|
||||
// Silently skipped if the file doesn't exist.
|
||||
|
||||
@@ -103,6 +103,21 @@ int gpu_ws_present_native_43(void);
|
||||
* cull immediates by the recompiler ([widescreen.cull]); 0 unless stretching. */
|
||||
int psx_ws_x_margin(void);
|
||||
|
||||
/* Backdrop screen-X correction ([widescreen.backdrop] x_sites). The parallax
|
||||
* 2D backdrop layer computes screen-X without the GTE, so it misses the
|
||||
* widescreen squash; the recompiler emits this on each backdrop handler's
|
||||
* final screenX store to squash it around the screen centre (identity at 4:3).
|
||||
* Pulls far backdrop pieces in from past the 320px edge to cover the 16:9 FOV. */
|
||||
int psx_ws_backdrop_x(int x);
|
||||
|
||||
/* Backdrop store-site registry: the runtime registers the [widescreen.backdrop]
|
||||
* x_sites here (from game.toml) so the dirty-RAM interpreter applies the same
|
||||
* psx_ws_backdrop_x() squash at those `sh` PCs that the recompiler emits into
|
||||
* native cache DLLs — overlay code frequently runs interpreted, where the emit
|
||||
* can't reach. PCs are masked to the physical (KUSEG) range. */
|
||||
void psx_ws_set_backdrop_sites(const uint32_t* pcs, int n);
|
||||
int psx_ws_is_backdrop_site(uint32_t pc);
|
||||
|
||||
/* Live widescreen state for diagnostics (TCP gpu_state). All pointers
|
||||
* optional. last_tag_frame/cur_frame let the caller see game_mode freshness. */
|
||||
typedef struct {
|
||||
|
||||
@@ -16,8 +16,15 @@
|
||||
*
|
||||
* v2: dispatch call-contract (Bug D family) — DLL call sites carry (ra, sp)
|
||||
* contract checks and share the runtime's bail state via the appended
|
||||
* callback pointers below. */
|
||||
#define PSX_OVERLAY_ABI_VERSION 2
|
||||
* callback pointers below.
|
||||
* v3: widescreen backdrop screenX squash ([widescreen.backdrop] x_sites) —
|
||||
* overlay backdrop handlers now emit psx_ws_backdrop_x() at their screenX
|
||||
* store. This is an EMIT-content change (not a struct-ABI change), but the
|
||||
* version is the cache discriminator: bumping it forces the loader to
|
||||
* reject pre-backdrop DLLs so autocompile regenerates them with the squash.
|
||||
* (The deferred follow-up is to auto-derive this tag from a hash of the
|
||||
* widescreen config + emit headers; until then it's a manual bump.) */
|
||||
#define PSX_OVERLAY_ABI_VERSION 3
|
||||
|
||||
typedef struct {
|
||||
/* Core dispatch: routes call_by_address() and out-of-overlay jal */
|
||||
@@ -44,6 +51,15 @@ typedef struct {
|
||||
int *call_bail_flag;
|
||||
uint64_t *bail_first;
|
||||
uint64_t *bail_resolved;
|
||||
/* Widescreen hooks (ABI v3). The recompiler can emit psx_ws_* calls into
|
||||
* OVERLAY code (backdrop screenX squash; and, for other games, sprite-tag
|
||||
* or cull sites that resolve into overlays). These compute against the
|
||||
* host's live widescreen state (gpu.c), so the DLL forwards to the runtime
|
||||
* through these. Appended LAST (struct grows back-compatibly); may be NULL
|
||||
* on a host that predates them — the DLL glue falls back to identity. */
|
||||
int (*ws_backdrop_x)(int x);
|
||||
int (*ws_x_margin)(void);
|
||||
void (*ws_sprite_tag)(CPUState *cpu);
|
||||
} OverlayCallbacks;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "debug_server.h"
|
||||
#include "interrupts.h"
|
||||
#include "psx_cycles.h"
|
||||
#include "gpu.h" /* psx_ws_is_backdrop_site / psx_ws_backdrop_x (interp hook) */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -795,7 +796,15 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x29: { /* SH */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
cpu->write_half(addr, (uint16_t)cpu->gpr[rt]);
|
||||
uint16_t val = (uint16_t)cpu->gpr[rt];
|
||||
/* Widescreen backdrop screenX squash on the interpreter path: mirrors
|
||||
* the recompiler emit at [widescreen.backdrop] x_sites. Overlay code
|
||||
* (the parallax backdrop handlers) runs interpreted when no cache DLL
|
||||
* is loaded, so without this the squash never happens. Identity at 4:3
|
||||
* (psx_ws_backdrop_x gates on ws_active). */
|
||||
if (psx_ws_is_backdrop_site(pc))
|
||||
val = (uint16_t)psx_ws_backdrop_x((int16_t)val);
|
||||
cpu->write_half(addr, val);
|
||||
return 0;
|
||||
}
|
||||
case 0x2A: { /* SWL */
|
||||
|
||||
@@ -82,6 +82,10 @@ extern int mdec_recently_active(uint32_t within_frames); /* mdec.c */
|
||||
|
||||
static int ws_configured(void) { return ws_xnum != ws_xden; }
|
||||
|
||||
/* Forward decls: defined later but used by psx_ws_backdrop_x above them. */
|
||||
static int32_t ws_scale_about(int32_t x, int32_t ax);
|
||||
static int32_t ws_disp_w(void);
|
||||
|
||||
/* Gameplay vs full-2D screen. Character/billboard prims tag (psx_ws_sprite_tag)
|
||||
* within the last couple of frames => the actor render funnel is running =>
|
||||
* gameplay. A menu/title/save screen draws no tagged prims. The 2-frame window
|
||||
@@ -135,6 +139,49 @@ int psx_ws_x_margin(void) {
|
||||
return (160 * (ws_xden - ws_xnum) + ws_xnum / 2) / ws_xnum;
|
||||
}
|
||||
|
||||
/* Widescreen backdrop screen-X correction ([widescreen.backdrop] x_sites).
|
||||
* The parallax 2D backdrop layer (ocean/cloud/mountain/grass — overlay actor
|
||||
* handlers e.g. 0x801216BC) computes its screen-X in pure integer math
|
||||
* (screenX = (worldX - camX) >> parallax) and NEVER goes through the GTE, so
|
||||
* the GTE X-squash (gte_set_display_aspect) that gives 3D the wider 16:9 FOV
|
||||
* does not touch it. The recompiler emits this on each handler's final
|
||||
* screenX store so the backdrop is squashed by the SAME factor around the
|
||||
* screen centre: a far piece whose 4:3 screenX sat past the 320px edge (and
|
||||
* was GPU-clipped → the blue void / half-rectangles at the edges) is pulled
|
||||
* in to cover the revealed FOV. Identity at 4:3 / boot / FMV / full-2D (the
|
||||
* exact ws_active() predicate the GTE squash uses), so one build serves both.
|
||||
* x is the int16 screenX the handler was about to store. */
|
||||
int psx_ws_backdrop_x(int x) {
|
||||
if (!ws_active()) return (int16_t)x;
|
||||
int32_t cx = ws_disp_w() / 2; /* screen centre (=160 @ 320) */
|
||||
return ws_scale_about((int16_t)x, cx);
|
||||
}
|
||||
|
||||
/* Backdrop store-site registry. The [widescreen.backdrop] x_sites are emitted
|
||||
* into native cache-DLL code by the recompiler, but overlay code very often
|
||||
* runs INTERPRETED (no DLL loaded), where the emit can't reach. So the runtime
|
||||
* also registers the same site PCs here and the dirty-RAM interpreter applies
|
||||
* psx_ws_backdrop_x() at those `sh` PCs — same transform, both paths. Tiny set;
|
||||
* a linear scan per matching SH is negligible. */
|
||||
#define WS_BACKDROP_SITES_MAX 16
|
||||
static uint32_t ws_backdrop_sites[WS_BACKDROP_SITES_MAX];
|
||||
static int ws_backdrop_site_n = 0;
|
||||
|
||||
void psx_ws_set_backdrop_sites(const uint32_t* pcs, int n) {
|
||||
ws_backdrop_site_n = 0;
|
||||
if (!pcs) return;
|
||||
for (int i = 0; i < n && ws_backdrop_site_n < WS_BACKDROP_SITES_MAX; i++)
|
||||
ws_backdrop_sites[ws_backdrop_site_n++] = pcs[i] & 0x1FFFFFFFu;
|
||||
}
|
||||
|
||||
int psx_ws_is_backdrop_site(uint32_t pc) {
|
||||
if (!ws_backdrop_site_n) return 0;
|
||||
pc &= 0x1FFFFFFFu;
|
||||
for (int i = 0; i < ws_backdrop_site_n; i++)
|
||||
if (ws_backdrop_sites[i] == pc) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Snapshot live widescreen state for the TCP gpu_state diagnostic. Mirrors
|
||||
* the predicates above so a probe can see, mid-gameplay, whether the squash
|
||||
* and the cull-margin are actually engaged (8C). */
|
||||
|
||||
@@ -1417,6 +1417,13 @@ int main(int argc, char** argv) {
|
||||
g_video_aspect_den = gc.runtime.video_aspect_den;
|
||||
g_ws_anchor_addr = gc.ws_sprite_anchor_addr;
|
||||
g_ws_hud_sprt = gc.ws_hud_sprt_squash;
|
||||
/* Register the [widescreen.backdrop] store PCs so the dirty-RAM
|
||||
* interpreter applies the backdrop screenX squash on the interp
|
||||
* path (overlay backdrop handlers run interpreted when no cache
|
||||
* DLL is loaded — the recompiler emit only covers native). */
|
||||
if (!gc.ws_backdrop_x_sites.empty())
|
||||
psx_ws_set_backdrop_sites(gc.ws_backdrop_x_sites.data(),
|
||||
(int)gc.ws_backdrop_x_sites.size());
|
||||
g_audio_spu_hq = gc.runtime.audio_spu_hq;
|
||||
{ const char *e = std::getenv("PSX_GL_FORCE_CPU_PRESENT");
|
||||
if (e && e[0] && e[0] != '0') g_gl_fbo_present = 0; }
|
||||
|
||||
@@ -413,6 +413,16 @@ static void init_callbacks(void) {
|
||||
s_callbacks.call_bail_flag = &g_psx_call_bail;
|
||||
s_callbacks.bail_first = &g_psx_bail_first;
|
||||
s_callbacks.bail_resolved = &g_psx_bail_resolved;
|
||||
/* Widescreen hooks (ABI v3): overlay-emitted psx_ws_* calls forward to
|
||||
* the runtime's live widescreen state (gpu.c). */
|
||||
{
|
||||
extern int psx_ws_backdrop_x(int x);
|
||||
extern int psx_ws_x_margin(void);
|
||||
extern void psx_ws_sprite_tag(CPUState *cpu);
|
||||
s_callbacks.ws_backdrop_x = psx_ws_backdrop_x;
|
||||
s_callbacks.ws_x_margin = psx_ws_x_margin;
|
||||
s_callbacks.ws_sprite_tag = psx_ws_sprite_tag;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- DLL loading and export enumeration -------------------------------- */
|
||||
|
||||
@@ -792,6 +792,18 @@ void debug_server_log_call_entry(uint32_t func_addr) {
|
||||
void psx_restore_state_escape(void) {
|
||||
if (g_cbs.psx_restore_state_escape) g_cbs.psx_restore_state_escape();
|
||||
}
|
||||
/* Widescreen hooks (ABI v3): forward to the runtime's live widescreen state.
|
||||
* Identity fallback if the host predates the callbacks (NULL) — so a v3 DLL
|
||||
* stays correct (4:3) on an older host. */
|
||||
int psx_ws_backdrop_x(int x) {
|
||||
return g_cbs.ws_backdrop_x ? g_cbs.ws_backdrop_x(x) : (int)(short)x;
|
||||
}
|
||||
int psx_ws_x_margin(void) {
|
||||
return g_cbs.ws_x_margin ? g_cbs.ws_x_margin() : 0;
|
||||
}
|
||||
void psx_ws_sprite_tag(CPUState *cpu) {
|
||||
if (g_cbs.ws_sprite_tag) g_cbs.ws_sprite_tag(cpu);
|
||||
}
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
"""
|
||||
@@ -1186,7 +1198,12 @@ def main():
|
||||
cmd = [args.recompiler, psx_path,
|
||||
'--seeds', seeds_path,
|
||||
'--out-dir', out_dir_tmp,
|
||||
'--overlay']
|
||||
'--overlay',
|
||||
# Forward the [widescreen] site lists so overlay-resident
|
||||
# emits (backdrop screenX squash, and any sprite-tag/cull
|
||||
# sites that resolve into overlay code) are applied. --ws-config
|
||||
# only adopts the widescreen lists, not the game's exe/paths.
|
||||
'--ws-config', os.path.abspath(args.game_toml)]
|
||||
print(f' recompile: {args.recompiler} ...')
|
||||
toml_dir = os.path.dirname(os.path.abspath(args.game_toml))
|
||||
r = subprocess.run(cmd, capture_output=True, text=True,
|
||||
|
||||
Reference in New Issue
Block a user