Files
issn_pc/tests/test_graphics_settings.cpp
Claude 0a1b680385 Motion blur and chromatic aberration switches, and a live list to find their passes
Discord poll (11-04, 13 votes). Each effect is a full-screen post pass known by its shader's program
hash, as fs_a6d23116 is the T2x resolve. gpu issn_postfx.h keeps the switches and the hash lists;
the rasterizer neutralises a pass on the back (PostFxDraw on the split and inline draw paths,
PostFxDispatch for compute): its target gets a copy (or blit) of its input of the same size, or, with
none, the draw is dropped. Nothing changes per draw while everything is on and the test is closed
(five relaxed loads).

The hashes are not known yet. Insert > Image > "Find post effects (test)" lists the full-screen
passes of the last frame up to the T2x resolve (after the scene, before the HUD): hash, target size,
inputs, a live "off" per pass (copy its input, or skip the draw) and a button that writes the list
with the inputs to the log. ISSN_POSTFX_LOG=1 writes it every second. The found hashes go in
MotionBlurHashes / ChromaticHashes, or in ISSN_POSTFX_MB / ISSN_POSTFX_CA meanwhile.

Switches: Insert > Image "Motion blur" / "Chromatic aberration" (live, shown once a hash is known)
and the launcher's Graphics > Effects (issn.ini motion_blur / chromatic_aberration, PT/ES texts).
Tests: tests/test_postfx.cpp (postfx-test), the ini keys in graphics-settings-test and the launcher.
Not compiled here (no SDL3 / Vulkan SDK in this workspace): the header and its test are.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_014CsPEK5qoeXL1N43SRenp7
2026-11-04 23:58:37 -03:00

103 lines
5.0 KiB
C++

// issn.ini graphics keys (issn_settings.cpp, issn_graphics.h).
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <string>
#include "issn_graphics.h"
#include "issn_settings.h"
namespace G = IssnGraphics;
static std::string Read(const char* path) {
std::ifstream in(path);
std::stringstream s;
s << in.rdbuf();
return s.str();
}
int main() {
assert(G::ParseDisplayMode("borderless") == G::Borderless && G::ParseDisplayMode("bogus") == G::Windowed);
assert(G::ParseFpsLimit(240) == 240 && G::ParseFpsLimit(75) == 0);
assert(G::ParseResolution("1440p") == 3 && G::ParseResolution("8K") == 0);
assert(G::ParseEngineFps(240) == 240 && G::ParseEngineFps(90) == 120);
assert(G::ParseFramesQueued(2) == 2 && G::ParseFramesQueued(0) == 0 && G::ParseFramesQueued(5) == 1);
assert(G::ParseRcasStrength(100) == 100 && G::ParseRcasStrength(101) == 75 && G::ParseRcasStrength(-1) == 75);
assert(G::RcasAttenuation(100) == 0.0f && G::RcasAttenuation(0) == 2.0f && G::RcasAttenuation(75) == 0.5f);
assert(G::FsrPassRuns(true, false, 1280, 720, 2560, 1440) && !G::FsrPassRuns(false, false, 1280, 720, 2560, 1440));
assert(G::FsrPassRuns(false, true, 1920, 1080, 1920, 1080) && !G::FsrPassRuns(true, false, 1920, 1080, 1920, 1080));
assert(!G::FsrPassRuns(true, true, 2560, 1440, 1920, 1080)); // larger image: regular scaling
assert(G::EffectiveFps(0, 120) == 120 && G::EffectiveFps(240, 120) == 120 && G::EffectiveFps(60, 240) == 60);
// An unpatched engine steps 1/60 s per frame: presenting faster speeds the game up.
assert(G::PresentLimit(120, 60) == 60 && G::PresentLimit(240, 120) == 120 && G::PresentLimit(240, 240) == 240);
assert(G::PresentLimit(0, 60) == 0 && G::PresentLimit(30, 60) == 30); // 0: paced by vblank
const char* path = "graphics-settings-test.ini";
{
std::ofstream out(path);
out << "display_mode=borderless\nvsync=0\nfps_limit=240\nasync_shaders=0\n"
"render_resolution=1440p\nengine_fps=240\ndeferred_readback=0\nstale_readback=1\n"
"fsr1=1\nrcas=0\nrcas_strength=40\nframes_queued=2\n";
}
_putenv_s("ISSN_CONFIG", path);
_putenv_s("ISSN_ASYNC_SHADERS", "");
auto& v = IssnSettings::Get();
IssnSettings::Load();
assert(v.display_mode == G::Borderless && !v.vsync && v.fps_limit == 240 && !v.async_shaders);
assert(v.render_resolution == 3 && v.engine_fps == 240 && !v.deferred_readback && v.stale_readback);
// FSR 1 left the menus in 2.2.0: a saved fsr1=1 (or ISSN_FSR1) no longer turns it on.
assert(!v.fsr1 && !v.rcas && v.rcas_strength == 40 && v.frames_queued == 2);
_putenv_s("ISSN_FSR1", "1");
IssnSettings::Load();
assert(!v.fsr1);
_putenv_s("ISSN_FSR1", "");
assert(!IssnSettings::GraphicsNeedRestart());
assert(v.applied_engine_fps == 240); // no ISSN_ENGINE_FPS: the configured rate
_putenv_s("ISSN_ENGINE_FPS", "60"); // run.py: the frame rate patch did not apply
IssnSettings::Load();
assert(v.engine_fps == 240 && v.applied_engine_fps == 60 && !IssnSettings::GraphicsNeedRestart());
_putenv_s("ISSN_ENGINE_FPS", "");
v.engine_fps = 120;
assert(IssnSettings::GraphicsNeedRestart());
v.fps_limit = 60; // live: no restart because of it
v.engine_fps = 240;
assert(!IssnSettings::GraphicsNeedRestart());
IssnSettings::Save();
const std::string saved = Read(path);
for (const char* line : {"display_mode=borderless\n", "vsync=0\n", "fps_limit=60\n", "async_shaders=0\n",
"render_resolution=1440p\n", "engine_fps=240\n", "deferred_readback=0\n",
"stale_readback=1\n", "fsr1=0\n", "rcas=0\n", "rcas_strength=40\n",
"frames_queued=2\n"}) {
assert(saved.find(line) != std::string::npos);
}
{
std::ofstream out(path);
out << "display_mode=huge\nfps_limit=7\nrender_resolution=8K\nengine_fps=1\n"
"rcas_strength=250\nframes_queued=9\n";
}
_putenv_s("ISSN_ASYNC_SHADERS", "1"); // the environment still wins at start
v.async_shaders = false;
IssnSettings::Load();
assert(v.display_mode == G::Windowed && v.fps_limit == 0 && v.render_resolution == 0 && v.engine_fps == 120);
assert(v.rcas_strength == 75 && v.frames_queued == 1);
assert(v.async_shaders);
{
std::ofstream out(path);
out << "cheat_double_jumps=1\ncheat_very_hard=1\nmotion_blur=0\n";
}
IssnSettings::Load();
// issn 11-04: the game's motion blur and chromatic aberration (on unless the file says 0).
assert(!v.motion_blur && v.chromatic_aberration);
IssnSettings::Save();
const std::string cheats = Read(path);
assert(cheats.find("cheat_double_jumps=1\n") != std::string::npos);
assert(cheats.find("cheat_very_hard=1\n") != std::string::npos);
assert(cheats.find("motion_blur=0\n") != std::string::npos);
assert(cheats.find("chromatic_aberration=1\n") != std::string::npos);
std::remove(path);
std::puts("PASS: graphics settings");
}