mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
[video] supersample_disable_at_lines: drop SSAA on 4K/8K displays (opt-in)
This commit is contained in:
@@ -702,16 +702,23 @@ player's `settings.toml`, and a game may ship a default the same way:
|
||||
[video]
|
||||
internal_resolution = "4k" # native | 720p | 1080p | 1440p | 4k | 5k | 8k | display, or a number of lines
|
||||
resolution_reference_lines = 240 # game.toml only: the title's usual display height (120..1024)
|
||||
supersample_disable_at_lines = 0 # game.toml only: supersample 1.0 at/above this display height (0 = off, 240..8640)
|
||||
match_display_max_lines = 0 # game.toml only: cap on the display height Match display uses (0 = none, 240..8640)
|
||||
```
|
||||
|
||||
`match_display_max_lines` caps the monitor height that Match display, its
|
||||
dynamic-resolution floor (`display`) and graphics-preset detection resolve
|
||||
against. With no cap, an 8K panel asks 18x (27x with `supersample = 1.5`), which is
|
||||
against. It also caps the final Match display target after supersampling,
|
||||
so a larger saved factor cannot exceed it. Fixed presets keep their own target.
|
||||
With no cap, an 8K panel asks 18x (27x with `supersample = 1.5`), which is
|
||||
past the full-VRAM surface. The high-resolution window then engages, and
|
||||
dynamic resolution cannot step there. A title whose GPU budget is set for
|
||||
4K lines sets 2160.
|
||||
|
||||
`supersample_disable_at_lines` uses the physical monitor height before the cap.
|
||||
At or above its threshold the effective factor is 1.0; the saved factor is
|
||||
retained for smaller monitors. Zero preserves the default behaviour.
|
||||
|
||||
A preset is a target height. The runtime renders at the integer scale
|
||||
`S = ceil(target / resolution_reference_lines)`: at the default 240 lines,
|
||||
720p is 3x, 1080p is 5x (1200 lines, area-resolved to 1080), 1440p 6x, 4K 9x,
|
||||
|
||||
@@ -1 +1 @@
|
||||
75a8d9834efb1c994169a939fbe043073b1b4b133bfe7b0235b80338af7f2f08
|
||||
61bf4f6d29680623d215fbe407958408cab0a1e08dbda3c62baa25e607d63b7b
|
||||
|
||||
@@ -780,6 +780,13 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path&
|
||||
}
|
||||
rt.video_match_display_max_lines = static_cast<int>(n);
|
||||
}
|
||||
if (video.contains("supersample_disable_at_lines")) {
|
||||
const auto n = toml::find<int64_t>(video, "supersample_disable_at_lines");
|
||||
if (n != 0 && (n < 240 || n > 8640))
|
||||
throw std::runtime_error(fmt::format(
|
||||
"[video] supersample_disable_at_lines must be 0 or 240..8640: {}", n));
|
||||
rt.video_supersample_disable_at_lines = static_cast<int>(n);
|
||||
}
|
||||
if (video.contains("window_width")) {
|
||||
const auto n = toml::find<int64_t>(video, "window_width");
|
||||
if (n < 640 || n > 7680) {
|
||||
|
||||
@@ -472,6 +472,8 @@ struct RuntimeConfig {
|
||||
/* [video] match_display_max_lines: cap on the display height Match
|
||||
* display (and its dynamic-resolution floor) resolves against; 0 = none. */
|
||||
int video_match_display_max_lines = 0;
|
||||
/* Disable target supersampling on displays at least this tall (0 = off). */
|
||||
int video_supersample_disable_at_lines = 0;
|
||||
|
||||
// Optional initial window width declared by the title profile. Zero keeps
|
||||
// the historical fit-to-display behavior; player settings may override it.
|
||||
|
||||
@@ -226,14 +226,17 @@ static void test_internal_resolution_game_toml() {
|
||||
"resolution_reference_lines defaults to 240");
|
||||
check(gc.runtime.video_match_display_max_lines == 0,
|
||||
"match_display_max_lines defaults to 0 (no cap)");
|
||||
check(gc.runtime.video_supersample_disable_at_lines == 0, "display SS policy defaults off");
|
||||
fs::remove(p);
|
||||
|
||||
p = write_game_toml("psxrecomp_ir_match_cap.toml",
|
||||
"[video]\n"
|
||||
"internal_resolution = \"display\"\n"
|
||||
"match_display_max_lines = 2160\n");
|
||||
"match_display_max_lines = 2160\n"
|
||||
"supersample_disable_at_lines = 2160\n");
|
||||
gc = PSXRecompV4::load_game_config(p);
|
||||
check(gc.runtime.video_match_display_max_lines == 2160, "match_display_max_lines parses");
|
||||
check(gc.runtime.video_supersample_disable_at_lines == 2160, "display SS policy parses");
|
||||
fs::remove(p);
|
||||
|
||||
p = write_game_toml("psxrecomp_ir_4k.toml",
|
||||
@@ -257,6 +260,7 @@ static void test_internal_resolution_game_toml() {
|
||||
"internal_resolution = 1\n",
|
||||
"resolution_reference_lines = 50\n",
|
||||
"match_display_max_lines = 100\n",
|
||||
"supersample_disable_at_lines = 100\n",
|
||||
"supersampling = 33\n" }) {
|
||||
p = write_game_toml("psxrecomp_ir_bad.toml", std::string("[video]\n") + bad);
|
||||
bool rejected = false;
|
||||
|
||||
@@ -143,6 +143,13 @@ static inline int psx_ss_parse_milli(const char *s) {
|
||||
return (int)m;
|
||||
}
|
||||
|
||||
/* Opt-in display policy; keep the saved factor intact for smaller displays. */
|
||||
static inline int psx_ir_display_supersample(int ss_milli, int display_px_h,
|
||||
int disable_at_lines) {
|
||||
return disable_at_lines > 0 && display_px_h >= disable_at_lines
|
||||
? PSX_SS_MILLI_MIN : ss_milli;
|
||||
}
|
||||
|
||||
/* psx_resolve_internal_scale with the supersample factor on the target. */
|
||||
static inline int psx_resolve_internal_scale_ss(int value, int ref_lines,
|
||||
int display_px_h, int s_max,
|
||||
@@ -160,6 +167,18 @@ static inline int psx_resolve_internal_scale_ss(int value, int ref_lines,
|
||||
return psx_resolve_internal_scale(value, ref_lines, display_px_h, s_max);
|
||||
}
|
||||
|
||||
/* A Match display cap bounds the final target, including supersampling.
|
||||
* Fixed presets and the legacy integer scale retain their own ceilings. */
|
||||
static inline int psx_resolve_internal_scale_ss_cap(int value, int ref_lines,
|
||||
int display_px_h, int s_max, int ss_milli, int max_display_lines) {
|
||||
int s = psx_resolve_internal_scale_ss(value, ref_lines, display_px_h, s_max, ss_milli);
|
||||
if (value == PSX_IR_DISPLAY && max_display_lines > 0) {
|
||||
int cap = psx_resolve_internal_scale(max_display_lines, ref_lines, 0, s_max);
|
||||
if (s > cap) s = cap;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* A legacy [video] supersampling factor as a value the launcher can show:
|
||||
* the preset that resolves to the same scale (1 -> Native, 3 -> 720p,
|
||||
* 5 -> 1080p, 6 -> 1440p, 9 -> 4K, 12 -> 5K, 18 -> 8K at 240 lines),
|
||||
|
||||
+22
-11
@@ -1272,6 +1272,11 @@ static int g_video_ss_milli = 1000; /* [video] supersample / PSX_SUPER
|
||||
* full-VRAM surface, where the high-resolution window engages and dynamic
|
||||
* resolution cannot step; a title can cap it at, say, 4K lines. */
|
||||
static int g_video_match_max_lines = 0;
|
||||
static int g_video_ss_disable_at_lines = 0;
|
||||
static int display_supersample(SDL_Window *window) {
|
||||
return psx_ir_display_supersample(g_video_ss_milli,
|
||||
psx_sdl_display_pixel_height(window), g_video_ss_disable_at_lines);
|
||||
}
|
||||
static int match_display_px_h(SDL_Window *window) {
|
||||
const int h = psx_sdl_display_pixel_height(window);
|
||||
return (g_video_match_max_lines > 0 && h > g_video_match_max_lines)
|
||||
@@ -1454,9 +1459,8 @@ static int effective_internal_resolution(void) {
|
||||
static void apply_internal_resolution(int display_px_h) {
|
||||
const int preset = effective_internal_resolution();
|
||||
if (preset == PSX_IR_UNSET) return;
|
||||
g_video_scale = psx_resolve_internal_scale_ss(preset, g_video_ref_lines,
|
||||
display_px_h, video_scale_ceiling(),
|
||||
g_video_ss_milli);
|
||||
g_video_scale = psx_resolve_internal_scale_ss_cap(preset, g_video_ref_lines,
|
||||
display_px_h, video_scale_ceiling(), display_supersample(nullptr), g_video_match_max_lines);
|
||||
}
|
||||
|
||||
/* The value the launcher row starts on: the preset, or the legacy factor shown
|
||||
@@ -17860,6 +17864,7 @@ int main(int argc, char** argv) {
|
||||
g_video_internal_res = gc.runtime.video_internal_resolution;
|
||||
g_video_ref_lines = gc.runtime.video_resolution_reference_lines;
|
||||
g_video_match_max_lines = gc.runtime.video_match_display_max_lines;
|
||||
g_video_ss_disable_at_lines = gc.runtime.video_supersample_disable_at_lines;
|
||||
g_video_dynres = gc.runtime.video_dynamic_resolution ? 1 : 0;
|
||||
g_video_dynres_min = gc.runtime.video_dynamic_resolution_min;
|
||||
if (gc.runtime.video_window_width > 0) {
|
||||
@@ -20353,9 +20358,10 @@ session_reboot:
|
||||
else if (!std::strcmp(e, "fxaa_hq")) g_video_post_aa = GL_POST_AA_FXAA_HQ;
|
||||
else std::fprintf(stdout, "psxrecomp: PSX_AA_MODE=%s not understood (off, fxaa, fxaa_hq)\n", e);
|
||||
}
|
||||
if (g_video_ss_milli != 1000)
|
||||
const int effective_ss = display_supersample(nullptr);
|
||||
if (!g_video_ss_disable_at_lines && effective_ss != 1000)
|
||||
std::fprintf(stdout, "psxrecomp: supersample %.3gx on the internal-resolution target\n",
|
||||
g_video_ss_milli / 1000.0);
|
||||
effective_ss / 1000.0);
|
||||
apply_internal_resolution(match_display_px_h(nullptr));
|
||||
if (g_video_scale < 1) g_video_scale = 1;
|
||||
if (const char* e = std::getenv("PSX_DYNRES"))
|
||||
@@ -20996,17 +21002,22 @@ session_reboot:
|
||||
/* Match display: the monitor's pixel height, now that the window says
|
||||
* which monitor. glb_set_scale only records the request; the hr
|
||||
* surface is allocated at context init below. */
|
||||
if (effective_internal_resolution() == PSX_IR_DISPLAY && g_video_scale_applies) {
|
||||
const int ir = effective_internal_resolution();
|
||||
if (g_video_scale_applies && ir != PSX_IR_UNSET &&
|
||||
(ir == PSX_IR_DISPLAY || g_video_ss_disable_at_lines > 0)) {
|
||||
const int dh = match_display_px_h(sdl_window);
|
||||
const int s = psx_resolve_internal_scale_ss(PSX_IR_DISPLAY, g_video_ref_lines,
|
||||
dh, GL_MAX_INTERNAL_SCALE,
|
||||
g_video_ss_milli);
|
||||
const int ss = display_supersample(sdl_window);
|
||||
const int s = psx_resolve_internal_scale_ss_cap(ir, g_video_ref_lines,
|
||||
dh, GL_MAX_INTERNAL_SCALE, ss, g_video_match_max_lines);
|
||||
gr_set_scale(s);
|
||||
g_video_requested_scale = s;
|
||||
std::fprintf(stdout, "psxrecomp: internal resolution Match display: "
|
||||
"%d px -> %dx requested\n", dh, s);
|
||||
const char *label = psx_ir_label_for(ir);
|
||||
std::fprintf(stdout, "psxrecomp: internal resolution %s: "
|
||||
"%d px -> %dx requested (supersample %.3gx)\n",
|
||||
label ? label : "custom", dh, s, ss / 1000.0);
|
||||
}
|
||||
gl_renderer_set_swap_interval(present_effective_swap_interval()); /* applied at context init */
|
||||
|
||||
/* Dynamic resolution: the surfaces are allocated at the scale above
|
||||
* (the ceiling) and the level steps under it (dynres_setup). */
|
||||
#ifndef PSX_NO_DEBUG_TOOLS
|
||||
|
||||
@@ -222,6 +222,21 @@ int main() {
|
||||
expect("ss clamps to the ceiling", psx_resolve_internal_scale_ss(4320, 240, 0, 32, 4000), 32);
|
||||
expect("ss unknown display stays 1", psx_resolve_internal_scale_ss(PSX_IR_DISPLAY, 240, 0, 32, 2000), 1);
|
||||
|
||||
expect("ss policy opt-out", psx_ir_display_supersample(1500, 4320, 0), 1500);
|
||||
expect("ss below threshold", psx_ir_display_supersample(1500, 2159, 2160), 1500);
|
||||
expect("ss at threshold", psx_ir_display_supersample(1500, 2160, 2160), 1000);
|
||||
expect("ss on 8K", psx_ir_display_supersample(1500, 4320, 2160), 1000);
|
||||
expect("ss unknown display", psx_ir_display_supersample(1500, 0, 2160), 1500);
|
||||
expect("cap includes SS below threshold", psx_resolve_internal_scale_ss_cap(
|
||||
PSX_IR_DISPLAY, 240, 1440, 32, 4000, 4320), 18);
|
||||
expect("cap below 8K", psx_resolve_internal_scale_ss_cap(
|
||||
PSX_IR_DISPLAY, 240, 1080, 32, 1500, 4320), 7);
|
||||
expect("8K capped after SS", psx_resolve_internal_scale_ss_cap(
|
||||
PSX_IR_DISPLAY, 240, 8640, 32, 4000, 4320), 18);
|
||||
expect("fixed preset keeps own ceiling", psx_resolve_internal_scale_ss_cap(
|
||||
4320, 240, 8640, 32, 4000, 4320), 32);
|
||||
expect("cap opt-out", psx_resolve_internal_scale_ss_cap(
|
||||
PSX_IR_DISPLAY, 240, 4320, 32, 1500, 0), 27);
|
||||
launcher_round_trips();
|
||||
|
||||
if (g_failures) return 1;
|
||||
|
||||
Reference in New Issue
Block a user