Fix OptiScaler NGX routing and align marker polling defaults

- Explicitly route OptiScaler to d4r\nvngx.dll in release packages.

- Extract INI generation into a helper that preserves line endings
  and rejects missing or duplicate settings.

- Check NGX routing separately from file presence and return failure
  when the installation is incomplete or misconfigured.

- Add an optional OptiScaler patch for external DLSS backends while
  preserving AMD identity for FSR4, with matching launch guidance.

- Align portable and launcher marker polling defaults at 200 us.

- Log when d4r's model override replaces game or OptiScaler presets.

- Add configuration, package, routing and coexistence regression tests.

- Update installation documentation, add FSR/DLSS comparison videos
  and ignore local .tools artifacts.

Refs: #7, #14
This commit is contained in:
ayo committed 2026-10-02 16:32:49 -04:00
1 parent f66cccaf28
commit cb08e1c313
17 files changed
+738 -31

No files matched your search

+80
View File
@@ -0,0 +1,80 @@
"""CPU regression checks for the upstream OptiScaler coexistence patch."""
from pathlib import Path
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
PATCH = ROOT / 'patches/optiscaler/0001-proton-external-dlss-fsr4-coexistence.patch'
class OptiScalerCoexistenceTests(unittest.TestCase):
def test_backend_identity_policy(self):
patch = PATCH.read_text()
start = patch.index('diff --git a/OptiScaler/spoofing/BackendIdentity.h ')
section = patch[start:].split('\ndiff --git ', 1)[0]
# Compile the exact added header that an upstream build will consume.
header = '\n'.join(line[1:] for line in section.splitlines()
if line.startswith('+') and not line.startswith('+++'))
code = r'''
#include "BackendIdentity.h"
#include <cassert>
int main() {
for (bool nvidia : {false, true})
for (bool optedIn : {false, true})
for (bool file : {false, true})
assert(BackendIdentity::AllowDlss(nvidia, optedIn, file) ==
(nvidia || (optedIn && file)));
const char* amd[] = {"amdxc64.dll", "AMDXCFFX64.DLL", "amd_fidelityfx_dx12.dll",
"amd_fidelityfx_loader_dx12.dll", "amd_fidelityfx_upscaler_dx12.dll",
"amd_fidelityfx_framegeneration_dx12.dll", "amd_fidelityfx_denoiser_dx12.dll",
"amd_fidelityfx_radiancecache_dx12.dll"};
for (auto caller : amd) assert(BackendIdentity::IsAmdFsrCaller(caller));
const char* game[] = {"Game.exe", "Game-Win64-Shipping.exe", "nvngx.dll",
"nvngx_dlss.dll", "notamdxc64.dll", "amdxc64.dll.exe", "", "AMDXC64"};
for (auto caller : game) assert(!BackendIdentity::IsAmdFsrCaller(caller));
}
'''
with tempfile.TemporaryDirectory() as temporary:
directory = Path(temporary)
(directory / 'BackendIdentity.h').write_text(header)
runner = directory / 'identity'
subprocess.run(['c++', '-std=c++17', '-Wall', '-Wextra', '-Werror', '-I', temporary,
'-x', 'c++', '-', '-o', str(runner)], input=code,
text=True, capture_output=True, check=True)
subprocess.run([str(runner)], check=True)
def test_upstream_integration_preserves_hardware_identity(self):
additions = '\n'.join(line[1:] for line in PATCH.read_text().splitlines()
if line.startswith('+') and not line.startswith('+++'))
self.assertEqual(additions.count('BackendIdentity::IsAmdFsrCaller(caller)'), 4)
self.assertIn('DLSSAllowExternalBackend { false }', additions)
self.assertIn('readBool("DLSS", "AllowExternalBackend")', additions)
self.assertIn('ini.SetValue("DLSS", "AllowExternalBackend"', additions)
self.assertIn('std::filesystem::is_regular_file(backendPath, error)', additions)
self.assertIn('backendPath = Util::ExePath().parent_path() / backendPath', additions)
self.assertIn('NvngxPath.set_volatile_value(backendPath.wstring())', additions)
self.assertIn('if (State::Instance().isRunningOnNvidia && !Config::Instance()->DxgiSpoofing.has_value())', additions)
self.assertNotIn('isRunningOnNvidia = true', additions)
self.assertNotIn('isRunningOnRDNA4 = true', additions)
def test_checker_launch_options_follow_external_backend_config(self):
with tempfile.TemporaryDirectory() as temporary:
game = Path(temporary)
(game / 'd4r').mkdir()
for flag in ('true', 'false', 'auto'):
(game / 'OptiScaler.ini').write_bytes(
(f'[DLSS]\r\nAllowExternalBackend={flag}\r\n'
'[Libraries]\r\nNvngxPath=d4r\\nvngx.dll\r\n').encode())
result = subprocess.run(['sh', str(ROOT / 'packaging/d4r-check.sh'), temporary],
text=True, capture_output=True)
if flag == 'true':
self.assertIn('WINE_HIDE_AMD_GPU=0 %command%', result.stdout)
self.assertNotIn('PROTON_FORCE_NVAPI=1', result.stdout)
self.assertNotIn('requires the game\'s working directory', result.stdout)
else:
self.assertIn('PROTON_FORCE_NVAPI=1', result.stdout)
if __name__ == '__main__':
unittest.main()
+228
View File
@@ -0,0 +1,228 @@
"""Release NGX routing: real INI generation, full/clean ZIP staging, install diagnostics.
Package tests use disposable runtime files and stand-ins for GPU kernel compilation.
Actual OptiScaler/Proton loading additionally needs the D3D12 harness.
"""
import configparser
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
import zipfile
ROOT = Path(__file__).resolve().parents[1]
SETTINGS = ROOT / 'packaging/optiscaler.settings'
GENERATOR = ROOT / 'scripts/configure_optiscaler.py'
def upstream_ini():
sections = {}
for line in SETTINGS.read_text().splitlines():
if not line or line.startswith('#'):
continue
path, _ = line.split('=', 1)
section, key = path.split('.', 1)
sections.setdefault(section, []).append(key)
# Keep NvngxPath independent of the settings file so removing the release
# override reproduces the original bug rather than removing the fixture key.
if 'NvngxPath' not in sections['Libraries']:
sections['Libraries'].append('NvngxPath')
return '; upstream comment\n' + ''.join(
f'[{section}]\n' + ''.join(f'{key}=auto\n' for key in keys)
for section, keys in sections.items()) + '[Menu]\nShowFps=true\n'
class OptiScalerConfigTests(unittest.TestCase):
def generate(self, directory, source):
source_path = directory / 'upstream.ini'
output = directory / 'OptiScaler.ini'
source_path.write_bytes(source.encode())
result = subprocess.run(['python3', str(GENERATOR), str(source_path), str(SETTINGS), str(output)],
capture_output=True, text=True)
return result, output
def assert_routing(self, data):
ini = configparser.ConfigParser()
ini.read_string(data.decode())
self.assertEqual(ini['Libraries']['NvngxPath'], r'd4r\nvngx.dll')
self.assertEqual(ini['Libraries']['OptiDllPath'], 'd4r')
self.assertEqual(ini['Upscalers']['Dx12Upscaler'], 'dlss')
self.assertEqual(ini['DLSS']['Enabled'], 'true')
self.assertEqual(ini['Hooks']['HookOriginalNvngxOnly'], 'true')
self.assertEqual(ini['Menu']['ShowFps'], 'true')
def test_generated_config_and_line_endings(self):
for newline in ('\n', '\r\n'):
with self.subTest(newline=repr(newline)), tempfile.TemporaryDirectory() as temporary:
source = upstream_ini().replace('\n', newline)
result, output = self.generate(Path(temporary), source)
self.assertEqual(result.returncode, 0, result.stderr)
data = output.read_bytes()
self.assert_routing(data)
self.assertTrue(data.startswith(b'; upstream comment' + newline.encode()))
self.assertEqual(data.count(b'\r\n'), data.count(b'\n') if newline == '\r\n' else 0)
self.assertEqual(source.count(newline), data.count(newline.encode()))
def test_missing_or_duplicate_override_fails_without_output(self):
for replacement in ('', 'NvngxPath=auto\nnvngxpath=d4r\\ngx\\_nvngx.dll\n'):
with self.subTest(replacement=replacement), tempfile.TemporaryDirectory() as temporary:
result, output = self.generate(Path(temporary), upstream_ini().replace('NvngxPath=auto\n', replacement))
self.assertNotEqual(result.returncode, 0)
self.assertIn('exactly one NvngxPath', result.stderr)
self.assertFalse(output.exists())
def test_missing_or_duplicate_libraries_section_fails(self):
for source in (upstream_ini().replace('[Libraries]', '[Other]'),
upstream_ini() + '[libraries]\nNvngxPath=auto\n'):
with tempfile.TemporaryDirectory() as temporary:
result, output = self.generate(Path(temporary), source)
self.assertNotEqual(result.returncode, 0)
self.assertIn('exactly one [Libraries]', result.stderr)
self.assertFalse(output.exists())
def test_full_and_clean_release_archives(self):
with tempfile.TemporaryDirectory() as temporary:
repo = Path(temporary) / 'repo'
inputs = Path(temporary) / 'inputs'
inputs.mkdir()
(repo / 'scripts').mkdir(parents=True)
for name in ('package_release.sh', 'configure_optiscaler.py', 'check_glibc_compat.sh'):
shutil.copy2(ROOT / 'scripts' / name, repo / 'scripts' / name)
shutil.copytree(ROOT / 'packaging', repo / 'packaging')
for name in ('LICENSE', 'NOTICE'):
shutil.copy2(ROOT / name, repo / name)
for component in ('zluda', 'vkd3d-proton'):
(repo / 'patches' / component).mkdir(parents=True)
(repo / 'patches' / component / 'fixture.patch').write_text('fixture\n')
# All shell staging, INI generation, ABI checks and archiving are real;
# replace only expensive GPU builds/manifests with fixture artifacts.
(repo / 'kernels/tools').mkdir(parents=True)
kernel_build = repo / 'kernels/build.sh'
kernel_build.write_text('#!/bin/sh\nmkdir -p "$2"\nprintf fixture > "$2/layer.hsaco"\n')
kernel_build.chmod(0o755)
(repo / 'kernels/tools/kernel_manifest.py').write_text(
'import pathlib, sys\npathlib.Path(sys.argv[1], "d4r-kernels.txt").write_text("layer 1234\\n")\n')
def fixture(path, data=b'fixture'):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(data)
return path
# A real minimal ELF lets the package's existing GLIBC checker run.
elf = inputs / 'library.so'
subprocess.run(['cc', '-shared', '-x', 'c', '-o', str(elf), '-'],
input='int fixture(void) { return 0; }\n', text=True, check=True)
fixture(repo / 'build/d4r_nvngx.dll')
fixture(repo / 'build/wine-nvcuda/x86_64-unix/nvcuda.dll.so', elf.read_bytes())
fixture(inputs / 'zluda/libnvcuda.so', elf.read_bytes())
fixture(inputs / 'rocm/lib/libamdhip64.so.7', elf.read_bytes())
fixture(inputs / 'rocm/licenses/runtime.txt')
for name in ('d3d12.dll', 'd3d12core.dll'):
fixture(inputs / 'vkd3d' / name)
fixture(inputs / 'opti/OptiScaler.dll')
fixture(inputs / 'opti/OptiScaler.ini', upstream_ini().replace('\n', '\r\n').encode())
dlss = fixture(inputs / 'nvngx_dlss.dll')
core = fixture(inputs / '_nvngx.dll')
license_path = fixture(inputs / 'license.txt')
for name in ('LICENSE-APACHE', 'LICENSE-MIT', 'ext/llvm-project/llvm/LICENSE.TXT', 'LICENSE', 'COPYING'):
fixture(inputs / 'source' / name)
# Prebuilt L texture names keep the full flow from calling an emitter.
names = ['rrlite_dec0_4x4']
for mv in ('mvhi', 'mvlo'):
for dynamic_range in ('hdr', 'ldr'):
names.append(f'rrlite_enc0_4x4_{mv}_{dynamic_range}')
names.extend(f'rrlite_post_{v}_{mv}_{dynamic_range}' for v in ('3_1', '3_2'))
for prefix in ('gfx1101', 'accuracy/gfx1101'):
for name in names:
fixture(inputs / 'tex' / prefix / (name + '.hsaco'))
fixture(inputs / 'tex' / prefix / 'd4r-accuracy.txt', b'1\n')
env = {k: v for k, v in os.environ.items() if not k.startswith('D4R_')}
env.update(D4R_SKIP_BUILD='1', D4R_GPU_ARCHS='gfx1101', SOURCE_DATE_EPOCH='1700000000',
D4R_OPTISCALER=str(inputs / 'opti'), D4R_DLSS_DLLS=str(dlss),
D4R_ZLUDA_DIR=str(inputs / 'zluda'), D4R_VKD3D_DIR=str(inputs / 'vkd3d'),
D4R_ROCM_RUNTIME=str(inputs / 'rocm'), D4R_OPTISCALER_LICENSE=str(license_path),
D4R_ZLUDA_SRC=str(inputs / 'source'), D4R_VKD3D_SRC=str(inputs / 'source'),
D4R_BUNDLE_DLSS=str(dlss), D4R_BUNDLE_NGX=str(core), D4R_BUNDLE_TEX=str(inputs / 'tex'))
version = (repo / 'packaging/VERSION').read_text().strip()
configs = []
for bundled in ('1', '0'):
with self.subTest(bundled=bundled):
env['D4R_BUNDLE_NVIDIA'] = bundled
result = subprocess.run(['bash', str(repo / 'scripts/package_release.sh'), str(repo / 'dist')],
env=env, text=True, capture_output=True)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
name = f'd4r-{version}' + ('-nonvidia' if bundled == '0' else '')
with zipfile.ZipFile(repo / 'dist' / (name + '.zip')) as archive:
self.assertIsNone(archive.testzip())
data = archive.read('OptiScaler.ini')
self.assert_routing(data)
configs.append(data)
self.assertEqual(data, (repo / 'dist' / name / 'OptiScaler.ini').read_bytes())
self.assertIn('d4r/nvngx.dll', archive.namelist())
self.assertNotIn('nvngx.dll', archive.namelist())
self.assertNotIn('d4r/_nvngx.dll', archive.namelist())
self.assertEqual('d4r/ngx/_nvngx.dll' in archive.namelist(), bundled == '1')
self.assertEqual('d4r/nvngx_dlss.dll' in archive.namelist(), bundled == '1')
self.assertEqual(archive.read('d4r/d4r-check.sh'), (ROOT / 'packaging/d4r-check.sh').read_bytes())
self.assertEqual(configs[0], configs[1])
class InstallCheckTests(unittest.TestCase):
def test_routing_separate_from_file_presence(self):
with tempfile.TemporaryDirectory() as temporary:
game = Path(temporary) / 'game with spaces'
for name in ('Game.exe', 'dxgi.dll', 'd3d12.dll', 'd3d12core.dll', 'd4r/nvngx.dll',
'd4r/nvcuda.dll', 'd4r/zluda/libcuda.so', 'd4r/d4r.ini', 'd4r/nvngx_dlss.dll',
'd4r/ngx/_nvngx.dll', 'd4r/rocm/lib/libamdhip64.so.7'):
path = game / name
path.parent.mkdir(parents=True, exist_ok=True)
path.touch()
for value, good in ((r'd4r\nvngx.dll', True), ('./d4r/nvngx.dll', True),
('Z:' + str(game / 'd4r/nvngx.dll').replace('/', '\\'), True),
('auto', False), ('d4r', False), (r'd4r\ngx\_nvngx.dll', False),
(r'C:\windows\system32\_nvngx.dll', False), ('', False)):
with self.subTest(value=value):
setting = f'NvngxPath={value}\n' if value else ''
(game / 'OptiScaler.ini').write_bytes(
('[Libraries]\nOptiDllPath=d4r\n' + setting).replace('\n', '\r\n').encode())
result = subprocess.run(['sh', str(ROOT / 'packaging/d4r-check.sh'), str(game)],
text=True, capture_output=True)
self.assertIn('ok d4r/nvngx.dll', result.stdout)
if good:
self.assertIn('OptiScaler NGX routing: NvngxPath=', result.stdout)
self.assertNotIn('CONFIG', result.stdout)
else:
self.assertIn('CONFIG', result.stdout)
self.assertIn('OptiDllPath alone can load system _nvngx.dll', result.stdout)
self.assertNotIn('checks passed', result.stdout)
self.assertNotEqual(result.returncode, 0)
def test_section_and_duplicate_keys(self):
for ini in ('[Other]\nNvngxPath=d4r\\nvngx.dll\n[Libraries]\nOptiDllPath=d4r\n',
'[Libraries]\nNvngxPath=d4r\\nvngx.dll\nnvngxpath=auto\n'):
with tempfile.TemporaryDirectory() as temporary:
game = Path(temporary)
(game / 'd4r').mkdir()
(game / 'OptiScaler.ini').write_text(ini)
result = subprocess.run(['sh', str(ROOT / 'packaging/d4r-check.sh'), temporary],
capture_output=True, text=True)
self.assertIn('CONFIG', result.stdout)
self.assertNotEqual(result.returncode, 0)
def test_correct_routing_does_not_hide_missing_shim(self):
with tempfile.TemporaryDirectory() as temporary:
game = Path(temporary)
(game / 'd4r').mkdir()
(game / 'OptiScaler.ini').write_text('[Libraries]\nNvngxPath=d4r\\nvngx.dll\n')
result = subprocess.run(['sh', str(ROOT / 'packaging/d4r-check.sh'), temporary],
capture_output=True, text=True)
self.assertIn('MISSING d4r/nvngx.dll', result.stdout)
self.assertIn('OptiScaler NGX routing: NvngxPath=', result.stdout)
self.assertNotIn('checks passed', result.stdout)
self.assertNotEqual(result.returncode, 0)
if __name__ == '__main__':
unittest.main()
+92
View File
@@ -0,0 +1,92 @@
"""Marker polling defaults and the shim's model-override diagnostics."""
import configparser
import os
from pathlib import Path
import re
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
SHIM = ROOT / 'tools/d4r_nvngx_shim.cpp'
class ShimConfigTests(unittest.TestCase):
def test_marker_poll_defaults_agree(self):
for name in ('packaging/d4r.ini', 'config/d4r.ini.default'):
ini = configparser.ConfigParser()
ini.read(ROOT / name)
self.assertEqual(ini.getint('Interop', 'MarkerPollUs'), 200, name)
source = SHIM.read_text()
portable = re.search(r'portable_set\("D4R_SHIM_MARKER_POLL_US", poll.empty\(\) \? "(\d+)" : poll\);', source)
runtime = re.search(r'env_uint\("D4R_SHIM_MARKER_POLL_US", (\d+)\)', source)
self.assertIsNotNone(portable, 'portable marker polling fallback missing')
self.assertIsNotNone(runtime, 'runtime marker polling fallback missing')
self.assertEqual(int(portable[1]), 200)
self.assertEqual(int(runtime[1]), 200)
def test_launcher_marker_poll_defaults_overrides_and_validation(self):
with tempfile.TemporaryDirectory() as temporary:
ini = Path(temporary) / 'd4r.ini'
env = {key: value for key, value in os.environ.items() if not key.startswith('D4R_')}
cmd = ['python3', str(ROOT / 'scripts/d4r_config.py'), '--config', str(ini)]
for value, expected in ((None, '200'), ('auto', '200'), ('200', '200'), ('0', '0'), ('75', '75')):
ini.write_text('[Interop]\n' + (f'MarkerPollUs = {value}\n' if value is not None else ''))
result = subprocess.run(cmd, env=env, text=True, capture_output=True, check=True)
self.assertIn(f'export D4R_SHIM_MARKER_POLL_US={expected}\n', result.stdout)
# An explicit environment variable keeps its existing precedence.
result = subprocess.run(cmd, env=dict(env, D4R_SHIM_MARKER_POLL_US='35'),
text=True, capture_output=True, check=True)
self.assertNotIn('export D4R_SHIM_MARKER_POLL_US=', result.stdout)
for value in ('-1', '0.5', 'invalid'):
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)
def test_production_model_override_logs_and_presets(self):
# Compile the actual feature-creation preset block with fake NGX inputs
# and a captured logger, so the test exercises the production message
# and override behavior without requiring Windows, NGX or a GPU.
source = SHIM.read_text()
start = source.index(' const char* presetNames[] =')
end = source.index(' feature->preset = presets[1];', start)
block = source[start:end]
runner_source = r'''
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <string>
static unsigned nextPreset = 21;
unsigned get_uint_or(void*, const char*, unsigned) { return nextPreset++; }
std::string env_string(const char* name) { const char* value = getenv(name); return value ? value : ""; }
void logf(const char* format, ...) {
va_list args; va_start(args, format); vprintf(format, args); va_end(args); puts("");
}
int main() {
void* parameters = nullptr;
''' + block + r'''
printf("presets:"); for (unsigned preset : presets) printf(" %u", preset); puts("");
}
'''
with tempfile.TemporaryDirectory() as temporary:
runner = Path(temporary) / 'model-override'
subprocess.run(['c++', '-std=c++17', '-Wall', '-Wextra', '-Werror', '-x', 'c++', '-', '-o', str(runner)],
input=runner_source, text=True, capture_output=True, check=True)
env = {key: value for key, value in os.environ.items() if key != 'D4R_DLSS_PRESET'}
for preset, model in ((5, 'E'), (11, 'K'), (12, 'L'), (13, 'M')):
with self.subTest(model=model):
output = subprocess.check_output([str(runner)], env=dict(env, D4R_DLSS_PRESET=str(preset)), text=True)
self.assertIn(f'D4R_DLSS_PRESET={preset} (model {model}) overrides game/OptiScaler presets', output)
self.assertIn('[DLAA=21 Quality=22 Balanced=23 Performance=24 UltraPerformance=25 UltraQuality=26]', output)
self.assertIn(f'using preset={preset} for all quality modes', output)
self.assertIn('presets:' + f' {preset}' * 6, output)
for value in (None, ''):
current = env if value is None else dict(env, D4R_DLSS_PRESET=value)
output = subprocess.check_output([str(runner)], env=current, text=True)
self.assertNotIn('model override', output)
self.assertEqual(output.strip(), 'presets: 21 22 23 24 25 26')
if __name__ == '__main__':
unittest.main()