mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-28 02:56:36 -04:00
Widescreen: restore title-scoped exact NCLIP branches
This commit is contained in:
@@ -150,6 +150,10 @@ struct CodeGenConfig {
|
||||
// widescreen reveals extra world. 4:3 keeps the original branch predicate.
|
||||
std::set<uint32_t> ws_cull_nclip_keep_sites;
|
||||
|
||||
// Exact `bltz MAC0, reject`-style NCLIP/backface sites that consume the
|
||||
// validated precise sign while wide, without changing guest-visible MAC0.
|
||||
std::set<uint32_t> ws_cull_nclip_exact_sites;
|
||||
|
||||
// Exact branch PCs whose reject target is suppressed while widescreen
|
||||
// reveals extra world. 4:3 keeps the original branch predicate.
|
||||
std::set<uint32_t> ws_cull_branch_keep_sites;
|
||||
|
||||
@@ -806,6 +806,9 @@ std::string CodeGenerator::generate_branch_condition(uint32_t instr, uint32_t ad
|
||||
if (regimm_op == 0x00 && config_.ws_cull_nclip_keep_sites.count(addr))
|
||||
return fmt::format("psx_ws_x_margin() > 0 ? 0 : ((int32_t){} < 0) /* ws nclip keep */",
|
||||
reg_name(rs));
|
||||
if (regimm_op == 0x00 && config_.ws_cull_nclip_exact_sites.count(addr))
|
||||
return fmt::format("psx_ws_x_margin() > 0 ? gte_nclip_precise_bltz((int32_t){}) : ((int32_t){} < 0) /* ws exact nclip */",
|
||||
reg_name(rs), reg_name(rs));
|
||||
return keep_branch_if_wide(
|
||||
fmt::format("(int32_t){} < 0", reg_name(rs)));
|
||||
} else { // bgez family (incl. bgezal + undefined mirrors)
|
||||
|
||||
@@ -73,6 +73,7 @@ uint32_t overlay_codegen_config_hash(const GameConfig& c) {
|
||||
h.words("cull_plane_nx", c.ws_cull_plane_nx_sites);
|
||||
h.words("cull_xclip_load", c.ws_cull_xclip_load_sites);
|
||||
h.words("cull_nclip_keep", c.ws_cull_nclip_keep_sites);
|
||||
h.words("cull_nclip_exact", c.ws_cull_nclip_exact_sites);
|
||||
h.words("cull_branch_keep", c.ws_cull_branch_keep_sites);
|
||||
h.words("cull_w_imms", c.ws_cull_w_imms);
|
||||
h.words("cull_h_imms", c.ws_cull_h_imms);
|
||||
@@ -1680,6 +1681,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
std::vector<uint32_t> ws_cull_plane_nx_sites;
|
||||
std::vector<uint32_t> ws_cull_xclip_load_sites;
|
||||
std::vector<uint32_t> ws_cull_nclip_keep_sites;
|
||||
std::vector<uint32_t> ws_cull_nclip_exact_sites;
|
||||
std::vector<uint32_t> ws_cull_branch_keep_sites;
|
||||
std::vector<WidescreenCullKeepSite> ws_cull_keep_sites;
|
||||
std::vector<WidescreenCullWidenSite> ws_cull_widen_sites;
|
||||
@@ -1716,6 +1718,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
load_sites("plane_nx_sites", ws_cull_plane_nx_sites);
|
||||
load_sites("xclip_load_sites", ws_cull_xclip_load_sites);
|
||||
load_sites("nclip_keep_sites", ws_cull_nclip_keep_sites);
|
||||
load_sites("nclip_exact_sites", ws_cull_nclip_exact_sites);
|
||||
load_sites("branch_keep_sites", ws_cull_branch_keep_sites);
|
||||
if (cull.contains("keep")) {
|
||||
std::set<uint32_t> seen;
|
||||
@@ -2195,6 +2198,7 @@ GameConfig load_game_config(const fs::path& config_path_in) {
|
||||
/*ws_cull_plane_nx_sites*/ ws_cull_plane_nx_sites,
|
||||
/*ws_cull_xclip_load_sites*/ ws_cull_xclip_load_sites,
|
||||
/*ws_cull_nclip_keep_sites*/ ws_cull_nclip_keep_sites,
|
||||
/*ws_cull_nclip_exact_sites*/ ws_cull_nclip_exact_sites,
|
||||
/*ws_cull_branch_keep_sites*/ ws_cull_branch_keep_sites,
|
||||
/*ws_cull_keep_sites*/ ws_cull_keep_sites,
|
||||
/*ws_cull_widen_sites*/ ws_cull_widen_sites,
|
||||
|
||||
@@ -999,6 +999,9 @@ struct GameConfig {
|
||||
// not-taken only while widescreen reveals extra world. This is deliberately
|
||||
// separate from bltz_sites, whose helper adjusts screen-X edge thresholds.
|
||||
std::vector<uint32_t> ws_cull_nclip_keep_sites;
|
||||
// Exact NCLIP/backface branch sites that use the validated tracked sign
|
||||
// only while wide. Guest MAC0 remains native and 4:3 remains bit-exact.
|
||||
std::vector<uint32_t> ws_cull_nclip_exact_sites;
|
||||
// Exact branch PCs whose reject path is forced not-taken only while
|
||||
// widescreen reveals extra world. Use only after screenshot-validated
|
||||
// evidence that the target is a visibility reject.
|
||||
|
||||
@@ -210,6 +210,7 @@ int main(int argc, char** argv) {
|
||||
std::set<uint32_t> ws_cull_plane_nx; // [widescreen.cull] plane_nx_sites
|
||||
std::set<uint32_t> ws_cull_xclip_load; // [widescreen.cull] xclip_load_sites
|
||||
std::set<uint32_t> ws_cull_nclip_keep; // [widescreen.cull] nclip_keep_sites
|
||||
std::set<uint32_t> ws_cull_nclip_exact; // [widescreen.cull] nclip_exact_sites
|
||||
std::set<uint32_t> ws_cull_branch_keep; // [widescreen.cull] branch_keep_sites
|
||||
std::vector<PSXRecompV4::WidescreenCullKeepSite> ws_cull_keep;
|
||||
std::vector<PSXRecompV4::WidescreenCullWidenSite> ws_cull_widen;
|
||||
@@ -274,6 +275,7 @@ int main(int argc, char** argv) {
|
||||
ws_cull_plane_nx.insert(cfg.ws_cull_plane_nx_sites.begin(), cfg.ws_cull_plane_nx_sites.end());
|
||||
ws_cull_xclip_load.insert(cfg.ws_cull_xclip_load_sites.begin(), cfg.ws_cull_xclip_load_sites.end());
|
||||
ws_cull_nclip_keep.insert(cfg.ws_cull_nclip_keep_sites.begin(), cfg.ws_cull_nclip_keep_sites.end());
|
||||
ws_cull_nclip_exact.insert(cfg.ws_cull_nclip_exact_sites.begin(), cfg.ws_cull_nclip_exact_sites.end());
|
||||
ws_cull_branch_keep.insert(cfg.ws_cull_branch_keep_sites.begin(), cfg.ws_cull_branch_keep_sites.end());
|
||||
ws_cull_keep = cfg.ws_cull_keep_sites;
|
||||
ws_cull_widen = cfg.ws_cull_widen_sites;
|
||||
@@ -370,6 +372,7 @@ int main(int argc, char** argv) {
|
||||
ws_cull_plane_nx.insert(wscfg.ws_cull_plane_nx_sites.begin(), wscfg.ws_cull_plane_nx_sites.end());
|
||||
ws_cull_xclip_load.insert(wscfg.ws_cull_xclip_load_sites.begin(), wscfg.ws_cull_xclip_load_sites.end());
|
||||
ws_cull_nclip_keep.insert(wscfg.ws_cull_nclip_keep_sites.begin(), wscfg.ws_cull_nclip_keep_sites.end());
|
||||
ws_cull_nclip_exact.insert(wscfg.ws_cull_nclip_exact_sites.begin(), wscfg.ws_cull_nclip_exact_sites.end());
|
||||
ws_cull_branch_keep.insert(wscfg.ws_cull_branch_keep_sites.begin(), wscfg.ws_cull_branch_keep_sites.end());
|
||||
if (ws_cull_keep.empty()) ws_cull_keep = wscfg.ws_cull_keep_sites;
|
||||
if (ws_cull_widen.empty()) ws_cull_widen = wscfg.ws_cull_widen_sites;
|
||||
@@ -1251,6 +1254,7 @@ int main(int argc, char** argv) {
|
||||
codegen_config.ws_cull_plane_nx_sites = ws_cull_plane_nx;
|
||||
codegen_config.ws_cull_xclip_load_sites = ws_cull_xclip_load;
|
||||
codegen_config.ws_cull_nclip_keep_sites = ws_cull_nclip_keep;
|
||||
codegen_config.ws_cull_nclip_exact_sites = ws_cull_nclip_exact;
|
||||
codegen_config.ws_cull_branch_keep_sites = ws_cull_branch_keep;
|
||||
codegen_config.ws_cull_keep_sites = ws_cull_keep;
|
||||
codegen_config.ws_cull_widen_sites = ws_cull_widen;
|
||||
|
||||
@@ -245,6 +245,15 @@ branch_keep_sites = ["0x80012340"]
|
||||
std::vector<uint32_t>{0x80012340u},
|
||||
"parser preserves branch keep sites");
|
||||
|
||||
const auto nclip_exact = write_config(root, "nclip-exact", R"toml(
|
||||
[widescreen.cull]
|
||||
nclip_exact_sites = ["0x80012340"]
|
||||
)toml");
|
||||
const auto nclip_exact_config = PSXRecompV4::load_game_config(nclip_exact);
|
||||
check(nclip_exact_config.ws_cull_nclip_exact_sites ==
|
||||
std::vector<uint32_t>{0x80012340u},
|
||||
"parser preserves exact NCLIP branch sites");
|
||||
|
||||
const auto vxrange = write_config(root, "vxrange", R"toml(
|
||||
[widescreen.cull]
|
||||
vxrange_sites = ["0x80012340"]
|
||||
@@ -729,6 +738,16 @@ void codegen_tests() {
|
||||
branch_keep.find("ws branch keep") != std::string::npos,
|
||||
"codegen emits guarded branch keep predicate");
|
||||
|
||||
PSXRecomp::CodeGenConfig nclip_exact_config;
|
||||
nclip_exact_config.ws_cull_nclip_exact_sites.insert(0x80010000u);
|
||||
const std::string nclip_exact = generate_first_instruction(
|
||||
0x04400002u, {}, false, nclip_exact_config); // bltz v0,+2
|
||||
check(nclip_exact.find(
|
||||
"gte_nclip_precise_bltz((int32_t)cpu->gpr[2])") !=
|
||||
std::string::npos &&
|
||||
nclip_exact.find("ws exact nclip") != std::string::npos,
|
||||
"codegen emits title-scoped exact NCLIP predicate");
|
||||
|
||||
PSXRecomp::CodeGenConfig plane_nx_config;
|
||||
plane_nx_config.ws_cull_plane_nx_sites.insert(0x80010000u);
|
||||
const std::string plane_nx = generate_first_instruction(
|
||||
|
||||
@@ -228,6 +228,10 @@ extern void gte_geometry_correction_stats(uint32_t *lookups, uint32_t *hits,
|
||||
* where sub-pixel and guest-visible integer signs differ. MAC0 stays native. */
|
||||
extern void gte_nclip_precise_stats(uint64_t *hits, uint64_t *fallbacks,
|
||||
uint64_t *disagreements);
|
||||
/* Title-scoped widescreen cull consumer. Returns the exact tracked NCLIP sign
|
||||
* only when it belongs to the supplied native MAC0; otherwise preserves the
|
||||
* native comparison. This does not change guest-visible GTE state. */
|
||||
extern int gte_nclip_precise_bltz(int32_t native_mac0);
|
||||
|
||||
/* pc=0 escape journal (traps.c). Every runtime site that publishes a null PC
|
||||
* (the "continue the native chain below" convention) or rescues one records
|
||||
|
||||
@@ -942,12 +942,20 @@ void gte_rtpt(GTEState* gte, uint32_t instr) {
|
||||
static uint64_t s_nclip_precise_hits = 0;
|
||||
static uint64_t s_nclip_fallbacks = 0;
|
||||
static uint64_t s_nclip_disagreements = 0;
|
||||
static int32_t s_nclip_last_native = 0;
|
||||
static int8_t s_nclip_last_precise_sign = 0;
|
||||
static bool s_nclip_last_precise_valid = false;
|
||||
extern "C" void gte_nclip_precise_stats(uint64_t *hits, uint64_t *fallbacks,
|
||||
uint64_t *disagreements) {
|
||||
if (hits) *hits = s_nclip_precise_hits;
|
||||
if (fallbacks) *fallbacks = s_nclip_fallbacks;
|
||||
if (disagreements) *disagreements = s_nclip_disagreements;
|
||||
}
|
||||
extern "C" int gte_nclip_precise_bltz(int32_t native_mac0) {
|
||||
if (!s_nclip_last_precise_valid || native_mac0 != s_nclip_last_native)
|
||||
return native_mac0 < 0;
|
||||
return s_nclip_last_precise_sign < 0;
|
||||
}
|
||||
|
||||
void gte_nclip(GTEState* gte, uint32_t instr) {
|
||||
gte->FLAG = 0;
|
||||
@@ -962,6 +970,8 @@ void gte_nclip(GTEState* gte, uint32_t instr) {
|
||||
(int64_t)sx2 * (sy0 - sy1);
|
||||
gte->check_mac0_overflow(mac0);
|
||||
int32_t out = static_cast<int32_t>(mac0);
|
||||
s_nclip_last_native = out;
|
||||
s_nclip_last_precise_valid = false;
|
||||
/* Precise NCLIP is observational only. MAC0 is guest-visible and games
|
||||
* branch on its sign, so a host precision enhancement must never turn a
|
||||
* hardware-visible face into a culled face (or vice versa). Compute the
|
||||
@@ -981,6 +991,8 @@ void gte_nclip(GTEState* gte, uint32_t instr) {
|
||||
const int64_t dx20 = (int64_t)px2 - px0;
|
||||
const int64_t dy20 = (int64_t)py2 - py0;
|
||||
const int64_t cross = dx10 * dy20 - dy10 * dx20;
|
||||
s_nclip_last_precise_sign = cross < 0 ? -1 : (cross > 0 ? 1 : 0);
|
||||
s_nclip_last_precise_valid = true;
|
||||
if ((cross > 0 && out <= 0) || (cross < 0 && out >= 0))
|
||||
s_nclip_disagreements++;
|
||||
} else if (gpu_ws_precise_nclip_enabled() &&
|
||||
|
||||
@@ -49,6 +49,7 @@ extern "C" int gpu_ws_precise_nclip_enabled(void) {
|
||||
return g_test_precise_nclip_enabled;
|
||||
}
|
||||
extern "C" void gpu_pgxp_rederive_enable(void) {}
|
||||
extern "C" void gpu_pgxp_vertex_cache_invalidate(void) {}
|
||||
extern "C" uint32_t memory_get_ram_bytes(void) { return 2u * 1024u * 1024u; }
|
||||
extern "C" void psx_ws_note_gte_project(int) {}
|
||||
extern "C" {
|
||||
@@ -596,6 +597,9 @@ int test_precise_nclip_never_flips_guest_sign() {
|
||||
disagree1 != disagree0 + 1u)
|
||||
return fail_value("precise NCLIP preserves guest sign", 0, 0x06u,
|
||||
0, 1u, cpu.gte_data[24]);
|
||||
if (!gte_nclip_precise_bltz(1) || gte_nclip_precise_bltz(2))
|
||||
return fail_value("title-scoped precise NCLIP predicate", 0, 0x06u,
|
||||
0, 1u, 0u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user