From 56e1b7662215a5550774a6db10fe393518045202 Mon Sep 17 00:00:00 2001 From: woutermans Date: Sun, 4 Oct 2026 00:13:23 +0200 Subject: [PATCH] Restore behavioral render preset override coverage --- packaging/RELEASE_NOTES.md | 4 ++ tests/test_shim_config.py | 77 +++++++++++++++++++++++++++++++++++++- tools/d4r_nvngx_shim.cpp | 11 +++--- tools/d4r_render_presets.h | 32 ++++++++++++++++ 4 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 tools/d4r_render_presets.h diff --git a/packaging/RELEASE_NOTES.md b/packaging/RELEASE_NOTES.md index a3d9360..d98820b 100644 --- a/packaging/RELEASE_NOTES.md +++ b/packaging/RELEASE_NOTES.md @@ -54,6 +54,10 @@ frame retirement. Rebuilt shim/bridge and rechecked a loaded Cyberpunk scene with camera motion, RR E and path tracing at 1080p Ultra Performance on gfx1201. Removed brittle source-text/wording tests; configuration validation remains covered. +- Restore behavioral preset-override coverage through a shared, allocation-free policy used by + feature creation: SR/RR isolation, every quality mode, unset/empty overrides, and explicit + default-preset selection. Tests compile the helper directly without extracting shim source + or matching diagnostic wording; polling configuration validation and precedence remain covered. # d4r 0.1.3 diff --git a/tests/test_shim_config.py b/tests/test_shim_config.py index 0358af7..a7b9e6e 100644 --- a/tests/test_shim_config.py +++ b/tests/test_shim_config.py @@ -1,4 +1,4 @@ -"""Marker polling configuration validation and environment precedence.""" +"""Engine opt-in, preset-selection behavior and polling configuration precedence.""" import configparser import os from pathlib import Path @@ -29,6 +29,7 @@ class ShimConfigTests(unittest.TestCase): ini.write_text('[Engine]\nEnabled = maybe\n') result = subprocess.run(cmd, env=env, text=True, capture_output=True) self.assertEqual(result.returncode, 2) + def test_launcher_marker_poll_defaults_overrides_and_validation(self): with tempfile.TemporaryDirectory() as temporary: ini = Path(temporary) / 'd4r.ini' @@ -46,7 +47,79 @@ class ShimConfigTests(unittest.TestCase): ini.write_text(f'[Interop]\nMarkerPollUs = {value}\n') result = subprocess.run(cmd, env=env, text=True, capture_output=True) self.assertEqual(result.returncode, 2) - self.assertIn('MarkerPollUs must be a number of microseconds', result.stderr) + + +class RenderPresetPolicyTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.directory = tempfile.TemporaryDirectory() + cls.addClassCleanup(cls.directory.cleanup) + cls.runner = Path(cls.directory.name) / 'render-presets' + source = r''' +#include "d4r_render_presets.h" +#include +int main(int argc, char** argv) { + if (argc != 2) return 2; + const bool rr = argv[1][0] == '1'; + unsigned int presets[6] = {21, 22, 23, 24, 25, 26}; + if (rr) { + for (unsigned int& preset : presets) preset += 10; + } + const auto overrideValue = d4r_parse_render_preset_override( + std::getenv(d4r_render_preset_variable(rr))); + overrideValue.apply(presets); + for (unsigned int preset : presets) std::printf("%u ", preset); + std::puts(""); +} +''' + subprocess.run( + ['c++', '-std=c++17', '-Wall', '-Wextra', '-Werror', + '-I', str(ROOT / 'tools'), '-x', 'c++', '-', '-o', str(cls.runner)], + input=source, text=True, capture_output=True, check=True) + + def select(self, rr=False, **overrides): + env = dict(os.environ) + for name in ('D4R_DLSS_PRESET', 'D4R_RR_PRESET'): + env.pop(name, None) + env.update(overrides) + result = subprocess.run( + [str(self.runner), '1' if rr else '0'], env=env, + text=True, capture_output=True, check=True, timeout=5) + return [int(value) for value in result.stdout.split()] + + def test_sr_models_override_every_quality_mode(self): + for value in (5, 11, 12, 13): + with self.subTest(preset=value): + self.assertEqual( + self.select(D4R_DLSS_PRESET=str(value), D4R_RR_PRESET='4'), + [value] * 6) + + def test_rr_models_do_not_use_the_sr_override(self): + for value in (4, 5): + with self.subTest(preset=value): + self.assertEqual( + self.select(rr=True, D4R_RR_PRESET=str(value), D4R_DLSS_PRESET='13'), + [value] * 6) + + def test_unset_override_preserves_quality_specific_game_presets(self): + for rr, foreign in ((False, 'D4R_RR_PRESET'), (True, 'D4R_DLSS_PRESET')): + with self.subTest(rr=rr): + expected = list(range(31, 37) if rr else range(21, 27)) + self.assertEqual(self.select(rr=rr), expected) + self.assertEqual(self.select(rr=rr, **{foreign: '13'}), expected) + + def test_empty_override_does_not_fall_back_to_the_other_feature(self): + self.assertEqual( + self.select(D4R_DLSS_PRESET='', D4R_RR_PRESET='5'), + list(range(21, 27))) + self.assertEqual( + self.select(rr=True, D4R_RR_PRESET='', D4R_DLSS_PRESET='13'), + list(range(31, 37))) + + def test_explicit_default_preset_overrides_game_presets(self): + self.assertEqual(self.select(D4R_DLSS_PRESET='0'), [0] * 6) + self.assertEqual(self.select(rr=True, D4R_RR_PRESET='0'), [0] * 6) + if __name__ == '__main__': diff --git a/tools/d4r_nvngx_shim.cpp b/tools/d4r_nvngx_shim.cpp index 9fe8b6b..63d48d3 100644 --- a/tools/d4r_nvngx_shim.cpp +++ b/tools/d4r_nvngx_shim.cpp @@ -74,6 +74,7 @@ #include #include "d4r_event_wait.h" #include "d4r_frame_completion.h" +#include "d4r_render_presets.h" #include "d4r_win32_wait.h" #include "d4r_vkd3d_interop.h" #include "../engine/game.h" @@ -7109,18 +7110,18 @@ static NgxResult create_feature(unsigned int featureId, void* parameters, NgxHan unsigned int presets[6]; for (int index = 0; index < 6; ++index) presets[index] = get_uint_or(parameters, presetNames[index], 0); - const std::string forced = env_string(rayReconstruction ? "D4R_RR_PRESET" : "D4R_DLSS_PRESET"); - if (!forced.empty()) + const std::string forced = env_string(d4r_render_preset_variable(rayReconstruction)); + const auto presetOverride = d4r_parse_render_preset_override(forced.c_str()); + if (presetOverride.enabled) { - const unsigned int value = static_cast(strtoul(forced.c_str(), nullptr, 0)); + const unsigned int value = presetOverride.value; const char* model = value == 5 ? "E" : value == 11 ? "K" : value == 12 ? "L" : value == 13 ? "M" : "custom"; logf("DLSS model override: D4R_DLSS_PRESET=%s (model %s) overrides game/OptiScaler presets " "[DLAA=%u Quality=%u Balanced=%u Performance=%u UltraPerformance=%u UltraQuality=%u]; " "using preset=%u for all quality modes", forced.c_str(), model, presets[0], presets[1], presets[2], presets[3], presets[4], presets[5], value); - for (unsigned int& preset : presets) - preset = value; } + presetOverride.apply(presets); feature->preset = presets[1]; // Direct output needs the native output kernel of the preset in use (verified: K = 11 through // hiluma_engine_output, M = 13 through rrlite_downsample_kernel, its last kernel). Only a forced diff --git a/tools/d4r_render_presets.h b/tools/d4r_render_presets.h new file mode 100644 index 0000000..f2831e9 --- /dev/null +++ b/tools/d4r_render_presets.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +// Platform-specific environment reads stay in the caller. SR and RR deliberately +// use separate settings, even when both are configured for the same feature call. +inline constexpr const char* d4r_render_preset_variable(bool rayReconstruction) +{ + return rayReconstruction ? "D4R_RR_PRESET" : "D4R_DLSS_PRESET"; +} + +// An absent/empty override leaves every game-selected quality preset unchanged. +// An explicit zero is an override too: it requests NGX's default preset. +struct D4rRenderPresetOverride +{ + bool enabled; + unsigned int value; + + void apply(unsigned int (&presets)[6]) const + { + if (enabled) + for (unsigned int& preset : presets) + preset = value; + } +}; + +inline D4rRenderPresetOverride d4r_parse_render_preset_override(const char* overrideValue) +{ + if (overrideValue == nullptr || *overrideValue == '\0') + return {false, 0}; + return {true, static_cast(std::strtoul(overrideValue, nullptr, 0))}; +}