mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-25 18:05:12 -04:00
PGXP seam expansion for opaque 3D polygons (opt-in)
[video] pgxp_seam = "off" | "fine" | "wide" (default off; PSX_PGXP_SEAM, PSX_PGXP_SEAM_PX). Above 1x, a vertex that sits on a neighbour's edge only to the PS1's precision leaves a hairline crack. Opaque 3D triangles move each edge outward (mitred, limited at sharp corners): fine = 1 output px, wide = half a native px; UVs, colour, q and SZ extrapolate with the barycentric coordinates of the new corners so textures do not slide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+22
-2
@@ -1209,7 +1209,7 @@ pixel. LWL at byte 3 / LWR at byte 0 (and SWL / SWR likewise) move the whole
|
||||
word and copy its shadow. Result in the Fossil Field scene: every ground
|
||||
triangle dataflow-precise, `tri_mixed` from ~10% of triangles to 474 of 2.05M,
|
||||
seams gone (`test_pgxp` pins the sequence).
|
||||
### G1.14 — PGXP renderer: depth buffer, perspective-correct colour (2026-10-06)
|
||||
### G1.14 — PGXP renderer: depth buffer, perspective-correct colour, seam expansion (2026-10-06)
|
||||
|
||||
**Audit against the references.** Read from DuckStation's published source
|
||||
(`github.com/stenzek/duckstation`, CC BY-NC-ND 4.0, so behaviour only, no
|
||||
@@ -1232,7 +1232,7 @@ vertex depth, `src/core/settings.cpp` defaults). GooseStation
|
||||
| Tolerance | `PGXPTolerance` -1 | `pgxp_tolerance` | same |
|
||||
| Depth buffer | `PGXPDepthBuffer`: per-vertex w as depth, LEQUAL, only for polygons whose w differ (3D) and opaque unless `PGXPTransparentDepthTest`; cleared on drawing-area change and when average z rises by `PGXPDepthThreshold` (4096) | no | **yes**, `pgxp_depth_buffer` |
|
||||
| 2D polygons | sprite mode for non-3D precise polygons; `PGXPDisableOn2DPolygons` draws invalid-w polygons native | unproven vertices native per vertex; precise axis-aligned quads bypass the rect path (G1.11) | same; 2D never tests/writes depth |
|
||||
| T-junction / seam handling | none for polygons (line expansion only) | none | same |
|
||||
| T-junction / seam handling | none for polygons (line expansion only) | none | **seam expansion**, `pgxp_seam` |
|
||||
|
||||
**Depth buffer.** gpu.c passes each triangle's SZ when all three vertices
|
||||
are dataflow-precise (`gr_set_depth_triangle`). The GL backend draws an
|
||||
@@ -1270,6 +1270,26 @@ differ by 801 / 92 / 25 / 0 px, none in the tachometer area.
|
||||
**Perspective-correct colour.** Gouraud colour on 3D triangles interpolates
|
||||
with 1/SZ (textured triangles with perspective UVs share their w).
|
||||
|
||||
**Seam expansion.** At internal scale > 1 a vertex that lies on its
|
||||
neighbour's edge only to the PS1's precision leaves a hairline onto the
|
||||
background (T-junctions of R4's subdivided near polygons; tunnel walls).
|
||||
Opaque 3D triangles move each edge outward (mitred, limited at sharp
|
||||
corners): `fine` = 1 output px (`PSX_PGXP_SEAM_PX` tunes it), `wide` = half a
|
||||
native px. UVs, colour, q and SZ are extrapolated with the barycentric
|
||||
coordinates of the new corners (perspective-correct where the attribute is),
|
||||
so textures do not slide. `wide` closes larger gaps but smears edge texels
|
||||
and thickens silhouettes (beam undersides at the R4 tunnel entrance); `fine`
|
||||
is the recommended setting.
|
||||
|
||||
**R4 (hook flavor, 10x headless-opengl, Helter Skelter tunnel, savestates
|
||||
at the entrance and inside).** Thin-feature pixel counts (features narrower
|
||||
than half a native pixel against both neighbours, HUD excluded):
|
||||
entrance base 1524 / PGXP 3560 / +depth+colour 2070 / +seam fine 1410-1518;
|
||||
inside base 2323 / PGXP 539 / +depth+colour 540 / +seam fine 541-547. The
|
||||
remaining counts are mostly texture detail; the visible base cracks along
|
||||
the tunnel walls are gone with PGXP and the residual short ones with `fine`.
|
||||
Dataflow 99.86%, mixed triangles 0, 0 dispatch / segment misses; guest pace
|
||||
equal with the features on and off.
|
||||
Diagnostic: `PSX_PGXP_TRI_LOG=<file>` logs every triangle (depth mode, x y
|
||||
SZ) while `<file>.on` exists.
|
||||
|
||||
|
||||
@@ -802,6 +802,13 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path&
|
||||
rt.video_pgxp_color_correction = toml::find<bool>(video, "pgxp_color_correction");
|
||||
if (video.contains("pgxp_depth_threshold"))
|
||||
rt.video_pgxp_depth_threshold = toml::find<double>(video, "pgxp_depth_threshold");
|
||||
if (video.contains("pgxp_seam")) {
|
||||
const auto m = toml::find<std::string>(video, "pgxp_seam");
|
||||
if (m == "off") rt.video_pgxp_seam = 0;
|
||||
else if (m == "fine") rt.video_pgxp_seam = 1;
|
||||
else if (m == "wide") rt.video_pgxp_seam = 2;
|
||||
else throw std::runtime_error("[video] pgxp_seam must be \"off\", \"fine\" or \"wide\"");
|
||||
}
|
||||
if (video.contains("pgxp_mod_only")) {
|
||||
rt.video_pgxp_mod_only = toml::find<bool>(video, "pgxp_mod_only");
|
||||
}
|
||||
|
||||
@@ -550,8 +550,11 @@ struct RuntimeConfig {
|
||||
// or write), cleared per drawing area, after fills and when the average
|
||||
// SZ jumps back by pgxp_depth_threshold (SZ units, default 4096).
|
||||
// pgxp_color_correction: perspective-correct Gouraud colour.
|
||||
// pgxp_seam: expand opaque 3D polygons to close T-junction cracks above
|
||||
// 1x ("off", "fine" = 1 output px, "wide" = half a native px).
|
||||
bool video_pgxp_depth_buffer = false;
|
||||
bool video_pgxp_color_correction = false;
|
||||
int video_pgxp_seam = 0;
|
||||
double video_pgxp_depth_threshold = 4096.0;
|
||||
|
||||
// pgxp_mod_only: the title ships PGXP through the psx.enhancement.pgxp
|
||||
|
||||
@@ -423,7 +423,7 @@ static void test_pgxp_title_keys() {
|
||||
check(!gc.runtime.video_pgxp_mod_only,
|
||||
"pgxp_mod_only defaults OFF (unchanged behaviour)");
|
||||
check(!gc.runtime.video_pgxp_depth_buffer && !gc.runtime.video_pgxp_color_correction &&
|
||||
gc.runtime.video_pgxp_depth_threshold == 4096.0,
|
||||
gc.runtime.video_pgxp_seam == 0 && gc.runtime.video_pgxp_depth_threshold == 4096.0,
|
||||
"PGXP renderer features default OFF (G1.14)");
|
||||
fs::remove(p);
|
||||
|
||||
@@ -431,13 +431,23 @@ static void test_pgxp_title_keys() {
|
||||
"[video]\n"
|
||||
"pgxp_depth_buffer = true\n"
|
||||
"pgxp_color_correction = true\n"
|
||||
"pgxp_seam = \"wide\"\n"
|
||||
"pgxp_depth_threshold = 2048.0\n");
|
||||
gc = PSXRecompV4::load_game_config(p);
|
||||
check(gc.runtime.video_pgxp_depth_buffer && gc.runtime.video_pgxp_color_correction &&
|
||||
gc.runtime.video_pgxp_depth_threshold == 2048.0,
|
||||
gc.runtime.video_pgxp_seam == 2 && gc.runtime.video_pgxp_depth_threshold == 2048.0,
|
||||
"PGXP renderer keys are honoured");
|
||||
fs::remove(p);
|
||||
|
||||
p = write_game_toml("psxrecomp_pgxp_render_bad.toml",
|
||||
"[video]\n"
|
||||
"pgxp_seam = \"huge\"\n");
|
||||
{
|
||||
bool bad = false;
|
||||
try { (void)PSXRecompV4::load_game_config(p); } catch (const std::exception&) { bad = true; }
|
||||
check(bad, "pgxp_seam must be off, fine or wide");
|
||||
}
|
||||
fs::remove(p);
|
||||
|
||||
p = write_game_toml("psxrecomp_pgxp_keys_dataflow.toml",
|
||||
"[video]\n"
|
||||
|
||||
@@ -267,6 +267,7 @@ float gl_renderer_get_post_gamma(void);
|
||||
void gl_renderer_set_wide_fast(int on);
|
||||
/* PGXP renderer features (docs/ENHANCEMENTS.md G1.14), all off by default:
|
||||
* depth buffer for opaque 3D polygons, perspective-correct Gouraud colour,
|
||||
* seam expansion (0 off, 1 = 1 output px above 1x, 2 = 0.5 native px),
|
||||
* and the depth clear threshold in SZ units (DuckStation's default 4096). */
|
||||
/* Nonzero when a PGXP renderer feature is on: only then does gpu.c send
|
||||
* gr_set_depth_triangle (no extra command per triangle otherwise). Any thread. */
|
||||
@@ -275,8 +276,11 @@ void gl_renderer_set_pgxp_depth(int on);
|
||||
int gl_renderer_get_pgxp_depth(void);
|
||||
void gl_renderer_set_pgxp_color_perspective(int on);
|
||||
int gl_renderer_get_pgxp_color_perspective(void);
|
||||
void gl_renderer_set_pgxp_seam(int mode);
|
||||
int gl_renderer_get_pgxp_seam(void);
|
||||
void gl_renderer_set_pgxp_depth_threshold(float sz);
|
||||
void gl_renderer_pgxp_render_stats(uint64_t *depth_tris, uint64_t *depth_clears);
|
||||
void gl_renderer_pgxp_render_stats(uint64_t *depth_tris, uint64_t *depth_clears,
|
||||
uint64_t *seam_tris);
|
||||
|
||||
/* Internal-resolution scale state of the live GL context (0 before init). */
|
||||
typedef struct GlScaleInfo {
|
||||
|
||||
@@ -741,13 +741,14 @@ static float s_pq[3];
|
||||
static int s_pz_valid = 0;
|
||||
static float s_pz[3];
|
||||
/* PGXP renderer features (docs/ENHANCEMENTS.md G1.14), all off by default:
|
||||
* depth buffer for opaque 3D polygons and perspective-correct Gouraud
|
||||
* colour. */
|
||||
static int s_pgxp_depth = 0, s_pgxp_cpersp = 0;
|
||||
* depth buffer for opaque 3D polygons, perspective-correct Gouraud colour,
|
||||
* and the seam expansion of opaque 3D polygons (0 off, 1 = 1 output px
|
||||
* above 1x, 2 = half a native px). */
|
||||
static int s_pgxp_depth = 0, s_pgxp_cpersp = 0, s_pgxp_seam = 0;
|
||||
static float s_pgxp_depth_threshold = 4096.0f; /* SZ units, as DuckStation */
|
||||
static int s_depth_need_clear = 1, s_depth_used = 0;
|
||||
static float s_depth_last_avg = 0.0f;
|
||||
static uint64_t s_depth_clears = 0, s_depth_tris = 0;
|
||||
static uint64_t s_depth_clears = 0, s_depth_tris = 0, s_seam_tris = 0;
|
||||
|
||||
/* TEX program uniforms. */
|
||||
static GLint s_uVram = -1, s_uTpage = -1, s_uClut = -1, s_uDepth = -1;
|
||||
@@ -2936,7 +2937,7 @@ int gl_renderer_get_wide_fast(void) { return s_wide_fast; }
|
||||
* the middle of a replayed frame; they are safe at session_reboot. */
|
||||
static int s_pgxp_render_wanted = 0; /* any PGXP renderer feature on */
|
||||
static void pgxp_render_wanted_update(void) {
|
||||
__atomic_store_n(&s_pgxp_render_wanted, (s_pgxp_depth || s_pgxp_cpersp) ? 1 : 0, __ATOMIC_RELEASE);
|
||||
__atomic_store_n(&s_pgxp_render_wanted, (s_pgxp_depth || s_pgxp_cpersp || s_pgxp_seam) ? 1 : 0, __ATOMIC_RELEASE);
|
||||
}
|
||||
int gl_renderer_pgxp_render_wanted(void) {
|
||||
return __atomic_load_n(&s_pgxp_render_wanted, __ATOMIC_ACQUIRE);
|
||||
@@ -2955,12 +2956,20 @@ void gl_renderer_set_pgxp_color_perspective(int on) {
|
||||
pgxp_render_wanted_update();
|
||||
}
|
||||
int gl_renderer_get_pgxp_color_perspective(void) { return s_pgxp_cpersp; }
|
||||
void gl_renderer_set_pgxp_seam(int mode) {
|
||||
GL_RT_SYNC("set_pgxp_seam");
|
||||
s_pgxp_seam = mode < 0 ? 0 : mode > 2 ? 2 : mode;
|
||||
pgxp_render_wanted_update();
|
||||
}
|
||||
int gl_renderer_get_pgxp_seam(void) { return s_pgxp_seam; }
|
||||
void gl_renderer_set_pgxp_depth_threshold(float sz) {
|
||||
GL_RT_SYNC("set_pgxp_depth_threshold"); s_pgxp_depth_threshold = sz; }
|
||||
void gl_renderer_pgxp_render_stats(uint64_t *depth_tris, uint64_t *depth_clears) {
|
||||
void gl_renderer_pgxp_render_stats(uint64_t *depth_tris, uint64_t *depth_clears,
|
||||
uint64_t *seam_tris) {
|
||||
GL_RT_SYNC("pgxp_render_stats");
|
||||
if (depth_tris) *depth_tris = s_depth_tris;
|
||||
if (depth_clears) *depth_clears = s_depth_clears;
|
||||
if (seam_tris) *seam_tris = s_seam_tris;
|
||||
}
|
||||
static int wide_fast_center_valid(void) {
|
||||
/* An explicitly stretched sky differs inside the canonical viewport too.
|
||||
@@ -3790,7 +3799,7 @@ static void line_to_quad(const float *v, float *q) {
|
||||
/* Flat / gouraud triangles and lines share the GEO program. mode: GL_TRIANGLES
|
||||
* or GL_LINES; verts are (x, y, r, g, b, a) tuples with colors as 1555. */
|
||||
|
||||
/* ---- PGXP depth buffer and perspective colour (G1.14) ------------ -------
|
||||
/* ---- PGXP depth buffer, perspective colour, seam expansion (G1.14) -------
|
||||
* A triangle is "3D" here when gpu.c proved all three vertices from GTE
|
||||
* dataflow shadows: sub-pixel positions (s_pc_valid) and their SZ
|
||||
* (s_pz_valid). Everything else (2D, HUD, sprites, CPU-built or unproven
|
||||
@@ -3878,6 +3887,95 @@ static void depth_before_tri(void) {
|
||||
s_depth_tris++;
|
||||
}
|
||||
|
||||
/* Seam expansion of an opaque 3D triangle. At internal scale > 1 a vertex
|
||||
* that sits on a neighbour's edge only to within the PS1's precision (R4's
|
||||
* subdivided near polygons, T-junctions) leaves a hairline crack onto the
|
||||
* background. Each edge moves outward by e native px (mitred corners,
|
||||
* limited at sharp angles); B[k][i] are the barycentric coordinates of new
|
||||
* corner k in the original triangle, so attributes extrapolate exactly:
|
||||
* affine ones as sum B a, perspective ones as sum B q a / sum B q, depth as
|
||||
* 1/sz' = sum B / sz. The depth buffer resolves the overlap. */
|
||||
static float pgxp_seam_width(void) {
|
||||
static float fine_px = -1.0f; /* PSX_PGXP_SEAM_PX: "fine" width in output px */
|
||||
if (fine_px < 0.0f) {
|
||||
const char *e = getenv("PSX_PGXP_SEAM_PX");
|
||||
fine_px = e && *e ? (float)atof(e) : 1.0f;
|
||||
if (fine_px < 0.0f) fine_px = 0.0f;
|
||||
}
|
||||
if (s_pgxp_seam == 1) return s_out_scale > 1 ? fine_px / (float)s_out_scale : 0.0f;
|
||||
if (s_pgxp_seam == 2) return 0.5f;
|
||||
return 0.0f;
|
||||
}
|
||||
static int seam_expand(float x[3], float y[3], float e, float B[3][3]) {
|
||||
if (e <= 0.0f) return 0;
|
||||
const float area = (x[1] - x[0]) * (y[2] - y[0]) - (y[1] - y[0]) * (x[2] - x[0]);
|
||||
if (fabsf(area) < 1e-4f) return 0;
|
||||
const float sgn = area > 0.0f ? 1.0f : -1.0f;
|
||||
float nx[3], ny[3]; /* outward unit normal of edge k (k -> k+1) */
|
||||
for (int k = 0; k < 3; k++) {
|
||||
const int k1 = (k + 1) % 3;
|
||||
const float ex = x[k1] - x[k], ey = y[k1] - y[k], l = sqrtf(ex * ex + ey * ey);
|
||||
if (l < 1e-5f) return 0;
|
||||
nx[k] = sgn * ey / l; ny[k] = -sgn * ex / l;
|
||||
}
|
||||
float ox[3], oy[3];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
const int kp = (k + 2) % 3; /* edges kp and k meet at corner k */
|
||||
float mx = nx[kp] + nx[k], my = ny[kp] + ny[k];
|
||||
const float d = 1.0f + nx[kp] * nx[k] + ny[kp] * ny[k];
|
||||
if (d < 0.25f) { /* sharp corner: limit the mitre to 2e */
|
||||
const float l = sqrtf(mx * mx + my * my);
|
||||
if (l > 1e-6f) { mx *= 2.0f / l; my *= 2.0f / l; }
|
||||
} else { mx /= d; my /= d; }
|
||||
ox[k] = x[k] + e * mx; oy[k] = y[k] + e * my;
|
||||
}
|
||||
const float inv = 1.0f / area;
|
||||
for (int k = 0; k < 3; k++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const int i1 = (i + 1) % 3, i2 = (i + 2) % 3;
|
||||
B[k][i] = ((x[i2] - x[i1]) * (oy[k] - y[i1]) - (y[i2] - y[i1]) * (ox[k] - x[i1])) * inv;
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < 3; k++) { x[k] = ox[k]; y[k] = oy[k]; }
|
||||
s_seam_tris++;
|
||||
return 1;
|
||||
}
|
||||
/* Extrapolate n attributes (stride apart) of 3 vertices with B. q != NULL:
|
||||
* perspective-correct with weights q (left unchanged; see seam_q). */
|
||||
static void seam_attr(const float B[3][3], float *a, int stride, int n, const float *q) {
|
||||
float src[3][8];
|
||||
for (int i = 0; i < 3; i++) for (int j = 0; j < n; j++) src[i][j] = a[i * stride + j];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
float Q = 0.0f;
|
||||
if (q) for (int i = 0; i < 3; i++) Q += B[k][i] * q[i];
|
||||
for (int j = 0; j < n; j++) {
|
||||
float v = 0.0f;
|
||||
if (q && Q > 1e-12f) {
|
||||
for (int i = 0; i < 3; i++) v += B[k][i] * q[i] * src[i][j];
|
||||
v /= Q;
|
||||
} else {
|
||||
for (int i = 0; i < 3; i++) v += B[k][i] * src[i][j];
|
||||
}
|
||||
a[k * stride + j] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void seam_q(const float B[3][3], float q[3]) {
|
||||
float o[3];
|
||||
for (int k = 0; k < 3; k++) { o[k] = 0.0f; for (int i = 0; i < 3; i++) o[k] += B[k][i] * q[i]; }
|
||||
for (int k = 0; k < 3; k++) q[k] = o[k] > 1e-9f ? o[k] : q[k];
|
||||
}
|
||||
static void seam_sz(const float B[3][3], float z[3]) {
|
||||
float o[3];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
float iz = 0.0f;
|
||||
for (int i = 0; i < 3; i++) iz += B[k][i] / z[i];
|
||||
o[k] = iz > 1e-9f ? 1.0f / iz : z[k];
|
||||
if (o[k] < 1.0f) o[k] = 1.0f;
|
||||
if (o[k] > 65535.0f) o[k] = 65535.0f;
|
||||
}
|
||||
for (int k = 0; k < 3; k++) z[k] = o[k];
|
||||
}
|
||||
|
||||
static void gpu_geometry(GLenum mode, const int *xs, const int *ys,
|
||||
const uint16_t *cs, int n, int semi) {
|
||||
@@ -4069,6 +4167,16 @@ static void gpu_geometry(GLenum mode, const int *xs, const int *ys,
|
||||
}
|
||||
if (n == 3 && pgxp_tri_is_3d()) {
|
||||
float z[3] = { s_pz[0], s_pz[1], s_pz[2] };
|
||||
if (semi < 0 && s_pgxp_seam) {
|
||||
float x[3], y[3], B[3][3];
|
||||
for (int i = 0; i < 3; i++) { x[i] = v0[i * 6]; y[i] = v0[i * 6 + 1]; }
|
||||
if (seam_expand(x, y, pgxp_seam_width(), B)) {
|
||||
float qc[3] = { 1.0f / z[0], 1.0f / z[1], 1.0f / z[2] };
|
||||
seam_attr(B, v0 + 2, 6, 3, s_pgxp_cpersp ? qc : NULL);
|
||||
seam_sz(B, z);
|
||||
for (int i = 0; i < 3; i++) { v0[i * 6] = x[i]; v0[i * 6 + 1] = y[i]; }
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
v0[i * 6 + 5] = mask_a + 2.0f * pgxp_vertex_code(z[i]);
|
||||
}
|
||||
@@ -4238,6 +4346,22 @@ static void gpu_textured_triangle(const int *xs, const int *ys,
|
||||
if (pgxp_tri_is_3d()) {
|
||||
float *t0 = &s_tb[s_tb_n * TEXV];
|
||||
float z[3] = { s_pz[0], s_pz[1], s_pz[2] };
|
||||
if (semi < 0 && s_pgxp_seam) {
|
||||
float x[3], y[3], B[3][3];
|
||||
for (int i = 0; i < 3; i++) { x[i] = t0[i * TEXV]; y[i] = t0[i * TEXV + 1]; }
|
||||
if (seam_expand(x, y, pgxp_seam_width(), B)) {
|
||||
float q[3] = { t0[19], t0[TEXV + 19], t0[2 * TEXV + 19] };
|
||||
float qc[3] = { 1.0f / z[0], 1.0f / z[1], 1.0f / z[2] };
|
||||
seam_attr(B, t0 + 2, TEXV, 2, s_pq_valid ? q : NULL); /* uv */
|
||||
seam_attr(B, t0 + 4, TEXV, 3, s_pgxp_cpersp ? (s_pq_valid ? q : qc) : NULL);
|
||||
if (s_pq_valid) {
|
||||
seam_q(B, q);
|
||||
for (int i = 0; i < 3; i++) t0[i * TEXV + 19] = q[i];
|
||||
}
|
||||
seam_sz(B, z);
|
||||
for (int i = 0; i < 3; i++) { t0[i * TEXV] = x[i]; t0[i * TEXV + 1] = y[i]; }
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const float code = pgxp_vertex_code(z[i]);
|
||||
if (code > 0.0f) t0[i * TEXV + 7] = -code; /* a_col.a (TEX_VS) */
|
||||
|
||||
@@ -1276,9 +1276,10 @@ static float g_video_pgxp_tolerance = 0.5f;
|
||||
* Defaults keep the historical behaviour. game.toml [video] only. */
|
||||
static int g_video_pgxp_position_fallback = 1;
|
||||
static int g_video_pgxp_preserve_projection = 0;
|
||||
/* PGXP renderer features (G1.14); PSX_PGXP_DEPTH / _COLOR override. */
|
||||
/* PGXP renderer features (G1.14); PSX_PGXP_DEPTH / _COLOR / _SEAM override. */
|
||||
static int g_video_pgxp_depth_buffer = 0;
|
||||
static int g_video_pgxp_color_correction = 0;
|
||||
static int g_video_pgxp_seam = 0;
|
||||
static float g_video_pgxp_depth_threshold = 4096.0f;
|
||||
/* [video] pgxp_mod_only (G1.12): the title ships PGXP through the
|
||||
* psx.enhancement.pgxp mod, which is then the one switch -- the [video]
|
||||
@@ -15792,6 +15793,7 @@ int main(int argc, char** argv) {
|
||||
g_video_pgxp_mod_only = gc.runtime.video_pgxp_mod_only ? 1 : 0;
|
||||
g_video_pgxp_depth_buffer = gc.runtime.video_pgxp_depth_buffer ? 1 : 0;
|
||||
g_video_pgxp_color_correction = gc.runtime.video_pgxp_color_correction ? 1 : 0;
|
||||
g_video_pgxp_seam = gc.runtime.video_pgxp_seam;
|
||||
g_video_pgxp_depth_threshold = (float)gc.runtime.video_pgxp_depth_threshold;
|
||||
g_video_renderer = gc.runtime.video_renderer;
|
||||
g_video_screen = gc.runtime.video_screen_kind;
|
||||
@@ -18157,8 +18159,10 @@ session_reboot:
|
||||
/* PGXP renderer features (G1.14): [video] keys, env overrides. */
|
||||
if (const char* e = std::getenv("PSX_PGXP_DEPTH")) g_video_pgxp_depth_buffer = (*e && *e != '0');
|
||||
if (const char* e = std::getenv("PSX_PGXP_COLOR")) g_video_pgxp_color_correction = (*e && *e != '0');
|
||||
if (const char* e = std::getenv("PSX_PGXP_SEAM")) g_video_pgxp_seam = std::atoi(e);
|
||||
gl_renderer_set_pgxp_depth(g_video_pgxp_depth_buffer);
|
||||
gl_renderer_set_pgxp_color_perspective(g_video_pgxp_color_correction);
|
||||
gl_renderer_set_pgxp_seam(g_video_pgxp_seam);
|
||||
if (const char* e = std::getenv("PSX_PGXP_DEPTH_THRESHOLD")) g_video_pgxp_depth_threshold = (float)std::atof(e);
|
||||
gl_renderer_set_pgxp_depth_threshold(g_video_pgxp_depth_threshold);
|
||||
/* [video] texture_window_batching A/B (same image, fewer GL draws). */
|
||||
|
||||
Reference in New Issue
Block a user