Add typed native-wide textured edge expansion

This commit is contained in:
douglasjv
2026-07-11 08:45:46 -07:00
committed by Matthew Stanley
parent 4c50b9740e
commit 9a8cdb6772
6 changed files with 75 additions and 5 deletions
@@ -0,0 +1,10 @@
# Typed native-wide textured edge expansion
Source: [PSXRecomp PR #15](https://github.com/mstan/psxrecomp/pull/15),
commit [`cab3946855e74918d3ce006062d3e1b843b155d6`](https://github.com/douglasjv/psxrecomp-tweaks/commit/cab3946855e74918d3ce006062d3e1b843b155d6).
This branch preserves the source feature for direct temperature testing. It is
opt-in. The known review question is software-renderer parity: the GL path
distinguishes outside-edge expansion from ordinary backdrop stretch, while the
software path currently consumes the gate as a boolean. Signed bounds and
title-specific configuration are excluded.
+18
View File
@@ -780,6 +780,9 @@ GameConfig load_game_config(const fs::path& config_path_in) {
bool ws_clear_reveal = false;
bool ws_nw_flat_backdrop = false;
bool ws_nw_phase_backdrop = false;
bool ws_nw_textured_edges = false;
int ws_nw_textured_edge_scale = 0;
bool ws_nw_full_mirror = false;
bool ws_offered = true;
bool ws_ultrawide_offered = false;
if (cfg.contains("widescreen")) {
@@ -836,6 +839,18 @@ GameConfig load_game_config(const fs::path& config_path_in) {
ws_nw_flat_backdrop = toml::find<bool>(ws, "nw_flat_backdrop");
if (ws.contains("nw_phase_backdrop"))
ws_nw_phase_backdrop = toml::find<bool>(ws, "nw_phase_backdrop");
if (ws.contains("nw_textured_edges"))
ws_nw_textured_edges = toml::find<bool>(ws, "nw_textured_edges");
if (ws.contains("nw_textured_edge_scale")) {
ws_nw_textured_edge_scale = toml::find<int>(ws, "nw_textured_edge_scale");
if (ws_nw_textured_edge_scale != 0 &&
(ws_nw_textured_edge_scale < 100 || ws_nw_textured_edge_scale > 400))
throw std::runtime_error(fmt::format(
"{}: [widescreen] nw_textured_edge_scale must be 0 or in [100, 400]",
config_path.string()));
}
if (ws.contains("nw_full_mirror"))
ws_nw_full_mirror = toml::find<bool>(ws, "nw_full_mirror");
if (ws.contains("offer"))
ws_offered = toml::find<bool>(ws, "offer");
if (ws.contains("offer_ultrawide"))
@@ -1026,6 +1041,9 @@ GameConfig load_game_config(const fs::path& config_path_in) {
/*ws_clear_reveal*/ ws_clear_reveal,
/*ws_nw_flat_backdrop*/ ws_nw_flat_backdrop,
/*ws_nw_phase_backdrop*/ ws_nw_phase_backdrop,
/*ws_nw_textured_edges*/ ws_nw_textured_edges,
/*ws_nw_textured_edge_scale*/ ws_nw_textured_edge_scale,
/*ws_nw_full_mirror*/ ws_nw_full_mirror,
/*ws_offered*/ ws_offered,
/*ws_ultrawide_offered*/ ws_ultrawide_offered,
/*ws_bg2d_count_site*/ ws_bg2d_count_site,
+11
View File
@@ -559,6 +559,17 @@ struct GameConfig {
// off by default because draw ordering is title-specific.
bool ws_nw_phase_backdrop = false;
// Expand only textured polygon vertices that already lie beyond the
// canonical 4:3 boundary. Useful for finite arena/background meshes while
// leaving actors, HUD, sprites, and centre geometry untouched.
bool ws_nw_textured_edges = false;
int ws_nw_textured_edge_scale = 0; // percent; 0 = aspect-derived
// Render the complete wide mirror instead of splicing its centre from
// canonical VRAM. Required when edge-crossing polygon interpolation is
// transformed in the mirror.
bool ws_nw_full_mirror = false;
// [widescreen] offer — whether the launcher OFFERS its EXPERIMENTAL
// Widescreen toggle for this title. Default true. Set false while a
// title's widescreen is unported/unvalidated (e.g. MMX4 at bring-up):
+11
View File
@@ -1185,6 +1185,12 @@ static int ws_tagged_anchor(int32_t *out_ax) {
uint32_t g_ws_backdrop_lo = 0, g_ws_backdrop_hi = 0;
static int ws_nw_phase_backdrop = 0;
void gpu_ws_set_nw_phase_backdrop(int on) { ws_nw_phase_backdrop = on ? 1 : 0; }
static int ws_nw_textured_edges = 0;
int g_ws_tex_edge_pct = 0;
void gpu_ws_set_nw_textured_edges(int on, int scale_pct) {
ws_nw_textured_edges = on ? 1 : 0;
g_ws_tex_edge_pct = scale_pct;
}
/* diag: per-frame min/max of the prim source addrs the GL gate sees */
uint32_t g_bdg_src_lo = 0xFFFFFFFFu, g_bdg_src_hi = 0;
static uint32_t bdg_src_frame = 0xFFFFFFFFu;
@@ -1270,6 +1276,11 @@ int psx_ws_prim_in_backdrop(void) {
if (gp0_cmd_source_addr > g_bdg_src_hi) g_bdg_src_hi = gp0_cmd_source_addr;
}
if (g_dbg_mode != 0) return dbg_gate_match(); /* correlation override */
if (ws_nw_textured_edges) {
uint32_t op = (gp0_cmd_buf[0] >> 24) & 0xFFu;
if (op >= 0x20u && op <= 0x3Fu && (op & 0x04u))
return 2; /* GL gate: expand only vertices beyond canonical edges */
}
if (ws_nw_phase_backdrop && !ws_bg_phase_over()) return 1;
/* Real gate: stretch the 2D backdrop = sprite-tagged prims drawn in the
* background phase (before the 3D world). Fills the native-wide void for both
+21 -5
View File
@@ -754,7 +754,12 @@ static const char *GEO_VS =
"uniform float u_xcenter;/* stretch centre in VRAM px; 0 canonical */\n"
"noperspective out vec4 v_col;\n"
"void main(){ v_col = a_col;\n"
" float xb = (a_pos.x - u_xcenter)*u_xscale + u_xcenter;\n"
" float xb = a_pos.x;\n"
" if (u_xscale < 0.0) {\n"
" float s = -u_xscale; float h = u_xhalf / s;\n"
" float l = u_xcenter - h, r = u_xcenter + h;\n"
" if (xb < l) xb = l + (xb-l)*s; else if (xb > r) xb = r + (xb-r)*s;\n"
" } else xb = (xb - u_xcenter)*u_xscale + u_xcenter;\n"
" gl_Position = vec4((xb+u_shift+u_xoff)/u_xhalf - 1.0, (a_pos.y+u_shift)/256.0 - 1.0, 0.0, 1.0); }\n";
static const char *GEO_FS =
"#version 330\n"
@@ -798,7 +803,12 @@ static const char *TEX_VS =
" v_limits = ivec4(floor(a_limits + 0.5));\n"
" /* u_shift: align GL's center-sample grid with the PS1 integer grid (see\n"
" * GEO_VS) so interpolated uv at a fragment equals the PS1 DDA value. */\n"
" float xb = (a_pos.x - u_xcenter)*u_xscale + u_xcenter;\n"
" float xb = a_pos.x;\n"
" if (u_xscale < 0.0) {\n"
" float s = -u_xscale; float h = u_xhalf / s;\n"
" float l = u_xcenter - h, r = u_xcenter + h;\n"
" if (xb < l) xb = l + (xb-l)*s; else if (xb > r) xb = r + (xb-r)*s;\n"
" } else xb = (xb - u_xcenter)*u_xscale + u_xcenter;\n"
" gl_Position = vec4((xb+u_shift+u_xoff)/u_xhalf - 1.0, (a_pos.y+u_shift)/256.0 - 1.0, 0.0, 1.0); }\n";
static const char *TEX_FS =
"#version 330\n"
@@ -1370,13 +1380,19 @@ static int mirror_geo_center_only(const int *xs, int n) {
/* Set / clear the 2D-backdrop x-stretch for a wide-mirror draw, per the current
* gate (s_bd_gate, set by the caller from bd_prim_gate / the batch gate). */
static void wide_set_bd_scale(GLint uScale, GLint uCenter) {
static void wide_set_bd_scale(GLint uScale, GLint uCenter) {
extern int g_ws_tex_edge_pct;
float scale = 1.0f, center = 0.0f;
if (s_bd_gate && g_ws_bd_stretch_on && g_wide_w > 0) {
int native_w = g_wide_w - 2 * g_wide_off;
if (native_w > 0) {
scale = g_ws_bd_stretch_pct > 0 ? (float)g_ws_bd_stretch_pct / 100.0f
: (float)g_wide_w / (float)native_w;
scale = g_ws_bd_stretch_pct > 0 ? (float)g_ws_bd_stretch_pct / 100.0f
: (float)g_wide_w / (float)native_w;
if (s_bd_gate == 2) {
scale = g_ws_tex_edge_pct > 0
? (float)g_ws_tex_edge_pct / 100.0f : scale;
scale = -scale; /* shader: expand only beyond canonical edges */
}
center = (float)g_wide_cur_base + (float)native_w / 2.0f;
}
}
+4
View File
@@ -346,6 +346,7 @@ static bool g_ws_hud_sprt = false;
/* Runtime-only transition cleanup; kept out of gpu.h because generated game
* units include that ABI header and do not need this frontend-only setter. */
extern "C" void gpu_ws_set_clear_reveal(int on);
extern "C" void gpu_ws_set_nw_textured_edges(int on, int scale_pct);
/* Widescreen engages at game entry (fntrace_is_game_started): the BIOS boot
* — Sony logo, PS logo, shell — presents authentic 4:3 with no GTE squash.
* Starts true when the configured aspect is already 4:3 (nothing to engage). */
@@ -2844,6 +2845,9 @@ int main(int argc, char** argv) {
/* [widescreen] nw_phase_backdrop — stretch only the textured
* backdrop phase emitted before shaded 3D foreground geometry. */
gpu_ws_set_nw_phase_backdrop(gc.ws_nw_phase_backdrop ? 1 : 0);
gpu_ws_set_nw_textured_edges(gc.ws_nw_textured_edges ? 1 : 0,
gc.ws_nw_textured_edge_scale);
gl_renderer_set_wide_fast(gc.ws_nw_full_mirror ? 0 : 1);
/* [widescreen] clear_reveal — enable opted-in scene/map-boundary
* cleanup of synthetic native-wide margins. */
gpu_ws_set_clear_reveal(gc.ws_clear_reveal ? 1 : 0);