mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Log dynamic resolution's target against the one the log last named, from the start line on.
The review found that dynres.c dynres_frame compared a changed target with a static that started at 0 and outlived a restart: with fps_limit = display the first refresh-rate wander under 1 % after the start was logged, against the comment's rule, and after dyn_res off and on a move back to the earlier run's last logged target said nothing, so the start line and the live lines disagreed. A test of the menu's path found a third case: a limit or dyn_res_target changed in the menu bumps cfg_version, dynres_read takes the new target first, and dynres_frame, which logged only when its own reading differed from D.target_ns, never named it. The last logged target now lives in D (logged_ns), the start line sets it, and dynres_frame logs any move of more than 1 % from it, naming the set target as "as set". No lock and no wait; the target and the steps are what they were. The review's stale "(dyn_res_target 16.7 in 1..100)" in cfg.c misfit now reads 0..100, as the row's set has been since the commit that changed the default target. tests/dynres_check.py gains these cases (a menu limit, a menu target, a wander after the start, the earlier run's target after off and on); they fail on the old dynres.c and pass. The -Wall compile of dynres.c and cfg.c shows no warning, and cfg_rows_check reports 0 problems. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -795,9 +795,10 @@ refused, and two images of one frame never evict each other. No GPU, no game fil
|
||||
A change to dynamic resolution's target or step hold (`runtime/dynres.c`) passes `python tests\dynres_check.py`, which
|
||||
builds that file with stand-ins for the settings, the GPU's busy time, the clock and the game's rate under the limit:
|
||||
the default target is the frame time of 60, 144 and 240 fps and 16.7 ms for an unknown or unlimited rate, a target
|
||||
that is set wins, a limit changed while it runs moves the target with one log line, and each step is held for
|
||||
`dyn_res_step` 60ths of a second at 60, 144 and 240 fps, down while the GPU is over the target and back up once it is
|
||||
under three quarters of it. No GPU, no game files.
|
||||
that is set wins, a limit or target changed while it runs (in the menu too) moves the target with one log line, a
|
||||
refresh rate wandering under 1 % after the start line logs none, and each step is held for `dyn_res_step` 60ths of a
|
||||
second at 60, 144 and 240 fps, down while the GPU is over the target and back up once it is under three quarters of
|
||||
it. No GPU, no game files.
|
||||
|
||||
A change to the ASTC decoder's scratch trim (`runtime/vk_astc.c` `vk_astc_scratch_trim`, with the upload lock it only
|
||||
tries, `runtime/vk_memory.c` `vk_defer_buffer_try`) passes `python tests\astc_trim_check.py`, which builds `vk_astc.c`
|
||||
|
||||
@@ -644,7 +644,7 @@ static const char *misfit(const char *set, const char *v, char *buf, size_t cap)
|
||||
if (*end) return NULL;
|
||||
double hi = strtod(dots + 2, &end);
|
||||
if (end == dots + 2 || *end) return NULL;
|
||||
// any number: some rows with whole ends take fractions (dyn_res_target 16.7 in 1..100)
|
||||
// any number: some rows with whole ends take fractions (dyn_res_target 16.7 in 0..100)
|
||||
double x = strtod(v, &end);
|
||||
if (end != v && !*end && x == x && x >= lo && x <= hi) return NULL;
|
||||
snprintf(buf, cap, "is not a number in %s", set);
|
||||
|
||||
@@ -40,6 +40,7 @@ static struct {
|
||||
double avg_ns; // moving average of the GPU's busy time per frame
|
||||
double target_ms; // NX2NAVI_DYN_RES_TARGET; under 1: the frame time of the game's rate
|
||||
double target_ns; // the target in use
|
||||
double logged_ns; // the target the log last named (the start line's, or dynres_frame's last line)
|
||||
uint64_t last_busy; // vk_gpu_busy_all at the previous presented frame
|
||||
unsigned cfg_seen; // cfg_version the settings were read at
|
||||
char base_mode[32];
|
||||
@@ -73,6 +74,7 @@ static void dynres_read(void) {
|
||||
D.base = D.level = base;
|
||||
D.low = base > 2 ? base : 2;
|
||||
D.held_from = plat_now_ns(), D.avg_ns = 0, D.last_busy = vk_gpu_busy_all();
|
||||
D.logged_ns = D.target_ns;
|
||||
rt_log("resolution: dynamic resolution on: target %.1f ms (%s), each step held %.2f s, DLSS %s down to %s",
|
||||
D.target_ns / 1e6, D.target_ms >= 1 ? "as set" : "the frame limit's", D.hold_ns / 1e9,
|
||||
DYN_MODE[D.base], DYN_MODE[D.low]);
|
||||
@@ -94,15 +96,18 @@ const char *dynres_override(void) { return D.on && D.level != D.base ? DYN_MODE[
|
||||
void dynres_frame(void) {
|
||||
if (cfg_version() != D.cfg_seen) dynres_read();
|
||||
if (!D.on) return;
|
||||
double target = target_now_ns(); // the limit, the monitor's rate and frame generation change without a setting
|
||||
if (target != D.target_ns) { // logged when it moves by more than 1 %: a measured refresh rate wanders a little
|
||||
static double logged_ns;
|
||||
// The limit, the monitor's rate and frame generation move the target without a dyn_res setting changing, so it is
|
||||
// read every frame. A move of more than 1 % from the target the log last named is logged, whether it came from the
|
||||
// frame, from the menu (dynres_read takes a changed limit or dyn_res_target already) or since the start line: a
|
||||
// measured refresh rate wanders a little. At most 20 lines a run.
|
||||
D.target_ns = target_now_ns();
|
||||
if (fabs(D.target_ns - D.logged_ns) > D.logged_ns * 0.01) {
|
||||
static int said;
|
||||
if (fabs(target - logged_ns) > logged_ns * 0.01 && said < 20) {
|
||||
said++, logged_ns = target;
|
||||
rt_log("resolution: dynamic resolution: target %.2f ms (the frame limit's)", target / 1e6);
|
||||
if (said < 20) {
|
||||
said++, D.logged_ns = D.target_ns;
|
||||
rt_log("resolution: dynamic resolution: target %.2f ms (%s)", D.target_ns / 1e6,
|
||||
D.target_ms >= 1 ? "as set" : "the frame limit's");
|
||||
}
|
||||
D.target_ns = target;
|
||||
}
|
||||
uint64_t now = vk_gpu_busy_all(), d = now - D.last_busy;
|
||||
D.last_busy = now;
|
||||
|
||||
@@ -4,7 +4,9 @@ and checks that
|
||||
|
||||
- the default target is the frame time of the game's rate (1000 / the limit: 60, 144 and 240 fps), 16.7 ms while
|
||||
that rate is unknown or unlimited, and a target that is set wins at any rate;
|
||||
- a limit changed while it runs moves the target on the next frame, with one log line;
|
||||
- a limit changed while it runs moves the target on the next frame, with one log line, also when the menu changed
|
||||
it (or dyn_res_target) and dynres_read took the new target first; a refresh rate wandering under 1 % after the
|
||||
start line logs nothing, and after dyn_res off and on a move back to the earlier run's last target is logged;
|
||||
- each step is held for dyn_res_step 60ths of a second of the clock at 60 and 240 fps (45: 0.75 s; 90: 1.5 s), down
|
||||
while the GPU is over the target and back up once it is under three quarters of it.
|
||||
|
||||
@@ -110,6 +112,36 @@ int main(void) {
|
||||
before = logs;
|
||||
for (int k = 0; k < 100; k++) frame(144, 1);
|
||||
CHECK(logs == before, "a steady limit logged %%d lines", logs - before);
|
||||
// A limit or a target changed in the menu (a new cfg_version, so dynres_read takes the new target first): one line.
|
||||
before = logs;
|
||||
game_hz = 120, ver++;
|
||||
frame(120, 1);
|
||||
CHECK(NEAR(D.target_ns, 1e9 / 120) && logs == before + 1 && strstr(last_log, "8.33 ms (the frame limit's)"),
|
||||
"the menu's limit: %%.3f ms, %%d lines (%%s)", D.target_ns / 1e6, logs - before, last_log);
|
||||
before = logs;
|
||||
set_target_ms = 20, ver++;
|
||||
frame(120, 1);
|
||||
CHECK(NEAR(D.target_ns, 20e6) && logs == before + 1 && strstr(last_log, "20.00 ms (as set)"),
|
||||
"the menu's target: %%.3f ms, %%d lines (%%s)", D.target_ns / 1e6, logs - before, last_log);
|
||||
set_target_ms = 0;
|
||||
// A refresh rate wandering under 1 %% after the start line: no line. Off and on again, then back to the target the
|
||||
// earlier run logged last: one line, measured from the new start line.
|
||||
game_hz = 60;
|
||||
restart();
|
||||
before = logs;
|
||||
game_hz = 59.9;
|
||||
frame(59.9, 1);
|
||||
CHECK(logs == before, "a wander of 0.17 %%%% after the start logged %%d lines (%%s)", logs - before, last_log);
|
||||
game_hz = 144;
|
||||
frame(144, 1);
|
||||
dyn = "0", ver++, frame(144, 1);
|
||||
game_hz = 60;
|
||||
dyn = "1", ver++, frame(60, 1);
|
||||
before = logs;
|
||||
game_hz = 144;
|
||||
frame(144, 1);
|
||||
CHECK(logs == before + 1 && strstr(last_log, "6.94"), "back to the earlier run's last target: %%d lines (%%s)",
|
||||
logs - before, last_log);
|
||||
// Each step is held for a time, whatever the frame rate.
|
||||
static const struct { double hz; int step; double hold_s; } holds[] = {{60, 45, 0.75}, {240, 45, 0.75},
|
||||
{240, 90, 1.5}, {144, 8, 8 / 60.0}};
|
||||
|
||||
Reference in New Issue
Block a user