Windows: DLSS watermark off, check script, 310.7.0 pair, shorter docs
- Set Disable.Watermark on the game path (the Linux shim already does); [DLSS] ShowWatermark = true keeps NVIDIA's stamp. - Always write d4r\d4r_nvngx.log in player mode. It was skipped when the launcher gave the game a valid stderr pipe, e.g. Steam. - Accept NVIDIA's 310.7.0 + _nvngx 32.0.15.9636 as "less tested" pins. Native kernels are still gated by PTX identity, so a different DLL falls back to translated kernels. - Add d4r-check.ps1 (ok/MISSING/note lines with a fix for each; -Report writes a bug-report ZIP) with 15 fixture tests. - package-windows-release.ps1: -Architectures subset, ships the check script, GPU registry and one GPU-query tool. - Add a shorter WINDOWS_README.txt; trim README's Windows section and merge in the RX 9060 XT / distributor-DLL notes. - Diagnostic probe accepts preset 12 (L). Tested on RX 7700 XT without a game: loader and shim start-up, K and M synthetic NGX frames with both DLL pairs (finite output, native kernels used). Not tested in a game.
This commit is contained in:
1 parent
df415ec828
commit
774efac524
12 files changed
+519
-70
No files matched your search
@@ -8,54 +8,11 @@ Preset L is NVIDIA's DLSS 4.5 model for Ultra Performance, especially at 4K. Set
|
|||||||
|
|
||||||
**Proof of concept:** d4r shows that DLSS can run on an AMD GPU, but it is not really that practical for everyday use yet. It has been tested on one GPU in a handful of games and depends on unreleased patches to ZLUDA and vkd3d-proton.
|
**Proof of concept:** d4r shows that DLSS can run on an AMD GPU, but it is not really that practical for everyday use yet. It has been tested on one GPU in a handful of games and depends on unreleased patches to ZLUDA and vkd3d-proton.
|
||||||
|
|
||||||
**Native Windows development:** an experimental D3D12 backend runs K and M
|
**Windows (experimental):** d4r also runs natively on Windows 11, in D3D12 games, with no Wine or Proton. It supports the DLSS 4 (K) and DLSS 4.5 (M) models. Installing works like the Linux release: extract the ZIP into the game folder, copy in two NVIDIA files, and edit `d4r\d4r.ini`. See [the Windows guide](packaging/windows/WINDOWS_README.txt); `d4r\d4r-check.ps1` checks an install and writes a bug-report ZIP.
|
||||||
transformer networks on Windows 11 / RX 9070 XT (gfx1201), using patched
|
|
||||||
ZLUDA/HIP and VRAM buffers/shared fences directly. Inputs and output belong to
|
|
||||||
the current frame; this path does not use Wine, Proton or CPU image staging.
|
|
||||||
The Windows backend, command-list hooks and diagnostics live in `tools/windows`.
|
|
||||||
All twenty Windows diagnostic gates pass, and queued-frame/feature-recreation K
|
|
||||||
outputs match synchronous controls exactly. A five-minute K/4K Silent Hill 2
|
|
||||||
run completes 16941 finite frames without backend errors. Performance remains
|
|
||||||
under development; asynchronous interop is opt-in and requires one queue.
|
|
||||||
M retains the FP16-equivalent baseline; native FP8 has not established a
|
|
||||||
full-network speedup. Windows preset L is not validated. See
|
|
||||||
[Windows build and validation](docs/windows-rdna4-port.md),
|
|
||||||
[OptiScaler installation](docs/windows-game.md) and
|
|
||||||
[Windows measurements](docs/windows-performance.md). NVIDIA DLLs are supplied
|
|
||||||
locally and excluded from packages.
|
|
||||||
|
|
||||||
Experimental Windows builds also cover RDNA3 `gfx1100..gfx1103`, RDNA3.5
|
Only the Radeon RX 9070 XT (gfx1201) has been tested on real hardware here. Its backend checks pass for K and M in Silent Hill 2 and Cyberpunk 2077 at 4K; those runs are correctness checks, not FPS benchmarks, and Windows performance is still under development. Community logs from an RX 9060 XT (gfx1200) show native K/M execution and finite output in Cyberpunk and Dawnwalker, but texture/LOD and motion artifacts are still reported, so that is backend coverage and not completed image-quality validation. The other targets (RDNA3 `gfx1100..gfx1103`, RDNA3.5 `gfx1150..gfx1154`) are compile-tested only. Windows preset E and L are not available. NVIDIA DLLs are supplied by you and are never part of the repository; the quick launcher can use a distributor-supplied DLL pair, but that packaging support does not establish redistribution permission.
|
||||||
`gfx1150..gfx1154` and RDNA4 `gfx1200/gfx1201`, with separate guarded packages.
|
|
||||||
Only RX 9070 XT has physical validation here; other targets are compile-tested.
|
|
||||||
Community RX 9060 XT / gfx1200 logs now show native K/M execution and finite
|
|
||||||
output in Cyberpunk and Dawnwalker. Visual issues are still reported, so this
|
|
||||||
is backend coverage rather than completed image-quality validation.
|
|
||||||
The installer checks the real HIP target before changing game files. See
|
|
||||||
[Windows GPU coverage and issue #10 diagnostics](docs/windows-gpu-support.md).
|
|
||||||
|
|
||||||
For a short Windows hardware test, the fork's
|
More: [Windows GPU coverage](docs/windows-gpu-support.md), [measurements](docs/windows-performance.md), [build and validation notes](docs/windows-rdna4-port.md), and the [diagnostic launcher](docs/windows-game.md) and [quick test](docs/windows-quick-test.txt) used for bug reports.
|
||||||
[quick-test prereleases](https://github.com/xdfnx-dev/d4r/releases) provide one
|
|
||||||
ZIP that detects the GPU automatically. Extract it and double-click START-K.cmd
|
|
||||||
or START-M.cmd, select your game and local NVIDIA DLLs, then send the single
|
|
||||||
diagnostic ZIP after exiting. RESTORE-GAME.cmd restores replaced files. Read
|
|
||||||
[the short English instructions](docs/windows-quick-test.txt). Corresponding
|
|
||||||
sources are a separate release asset; the test requires no SDK installation.
|
|
||||||
The updated quick test launches without an attached debugger, stages the
|
|
||||||
locally supplied DLSS DLL beside the shim for numeric CUDA NGX initialization,
|
|
||||||
and reports a launcher exit with zero frames as inconclusive. Source fixes
|
|
||||||
also serialize OptiScaler device-hook installation and forward numeric init
|
|
||||||
errors. These fixes pass standalone direct/OptiScaler K and OptiScaler M on
|
|
||||||
RX 9070 XT. Cyberpunk 2077 2.31 also reaches saved 4K gameplay with K and M:
|
|
||||||
13,145 K session frames and 5,268 M frames pass GPU output checks, every
|
|
||||||
required native transformer layer executes, and no backend failures,
|
|
||||||
previous-frame outputs or CPU image copies occur. Sessions include menus and
|
|
||||||
loading; this synchronous diagnostic is not an FPS benchmark. Other GPUs,
|
|
||||||
including the reporter's RX 9060 XT / gfx1200, required further testing at that point.
|
|
||||||
The subsequent RX 9060 XT retest passes all required native-layer/output
|
|
||||||
checks in Cyberpunk and Dawnwalker; texture/LOD and motion artifacts remain
|
|
||||||
open. Distributor-supplied DLL pairs can now be selected automatically by the
|
|
||||||
quick launcher. The public fork ZIP still uses locally supplied NVIDIA files;
|
|
||||||
packaging support does not establish redistribution permission.
|
|
||||||
|
|
||||||
See [supported games](SUPPORTED_GAMES.md) for the tested games and DLSS models.
|
See [supported games](SUPPORTED_GAMES.md) for the tested games and DLSS models.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
d4r for Windows: NVIDIA DLSS on AMD Radeon RDNA3 and RDNA4
|
||||||
|
===========================================================
|
||||||
|
|
||||||
|
d4r runs NVIDIA's own DLSS (DLSS 4 by default) on a Radeon GPU in DirectX 12 games. OptiScaler
|
||||||
|
(included) catches the game's upscaler calls and hands them to d4r.
|
||||||
|
|
||||||
|
This is an early release. Only the Radeon RX 9070 XT has been tested on real hardware; every other
|
||||||
|
GPU in this release is compile-tested. SUPPORTED_GAMES.md in the source repository lists the
|
||||||
|
tested games. Expect problems.
|
||||||
|
|
||||||
|
What you need
|
||||||
|
-------------
|
||||||
|
- Windows 11, a Radeon RX 7000 or RX 9000 series GPU, a current AMD Adrenalin driver.
|
||||||
|
- A DirectX 12 game without anti-cheat (OptiScaler injects a DLL; it can get an account banned).
|
||||||
|
- Two files from NVIDIA, which this ZIP does not include:
|
||||||
|
nvngx_dlss.dll version 310.9.1 (tested) or 310.7.0. Many games ship one in their folder;
|
||||||
|
right-click > Properties > Details shows the version.
|
||||||
|
_nvngx.dll version 32.0.16.1714 (tested) or 32.0.15.9636. It is part of an NVIDIA display
|
||||||
|
driver package: extract the installer with 7-Zip and search for _nvngx.dll.
|
||||||
|
|
||||||
|
Install
|
||||||
|
-------
|
||||||
|
1. Extract this ZIP into the folder that holds the game's main .exe. For Unreal Engine games that
|
||||||
|
is <game>\<Project>\Binaries\Win64, next to <Project>-Win64-Shipping.exe.
|
||||||
|
If the folder already has a dxgi.dll or OptiScaler.ini (another OptiScaler install), or a
|
||||||
|
d3d12.dll from a Linux install, move those out first.
|
||||||
|
2. Copy nvngx_dlss.dll into the d4r folder and _nvngx.dll into d4r\ngx.
|
||||||
|
3. Optional: check the install. In the game folder, open PowerShell and run
|
||||||
|
powershell -ExecutionPolicy Bypass -File d4r\d4r-check.ps1
|
||||||
|
4. Start the game from Steam, Epic or a shortcut as usual. In its graphics settings choose DLSS
|
||||||
|
(or FSR 3.1/XeSS if DLSS is hidden; OptiScaler then feeds DLSS). Keep frame generation off.
|
||||||
|
Press Insert in game for OptiScaler's menu.
|
||||||
|
|
||||||
|
The first time DLSS starts, the game can freeze for several minutes while DLSS's GPU kernels are
|
||||||
|
compiled. They are cached in %LOCALAPPDATA%\d4r\cache, so later starts are quick.
|
||||||
|
|
||||||
|
Settings
|
||||||
|
--------
|
||||||
|
Edit d4r\d4r.ini (it is commented) and restart the game. Each game has its own copy.
|
||||||
|
- Model: K (DLSS 4, default) or M (DLSS 4.5, heavier). Select the quality mode in the game.
|
||||||
|
- AsyncInterop, ValidateOutput, Log: for testing and bug reports; the defaults are the tested setting.
|
||||||
|
OptiScaler's own settings (overlay, render ratios) are in OptiScaler.ini.
|
||||||
|
|
||||||
|
If something goes wrong
|
||||||
|
-----------------------
|
||||||
|
- Run d4r\d4r-check.ps1: it prints ok / MISSING / note lines with the fix for each problem.
|
||||||
|
- d4r\d4r_nvngx.log is rewritten at every launch. A line "d4r: DLSS disabled: ..." says why.
|
||||||
|
- DLSS missing in the menu and no d4r_nvngx.log: the files are not next to the game's main .exe.
|
||||||
|
- For a bug report run d4r\d4r-check.ps1 -Report and send the ZIP it puts on your Desktop,
|
||||||
|
with your GPU, the game, the model and what the image looked like. Logs can contain folder names.
|
||||||
|
- Not supported: frame generation, ray reconstruction, DirectX 11, Vulkan, models E and L.
|
||||||
|
|
||||||
|
Uninstall
|
||||||
|
---------
|
||||||
|
Delete dxgi.dll, OptiScaler.ini, OptiScaler.log (if present), WINDOWS_README.txt and the d4r folder
|
||||||
|
from the game folder. The cache in %LOCALAPPDATA%\d4r can be deleted too. Nothing else was changed.
|
||||||
|
|
||||||
|
Licenses
|
||||||
|
--------
|
||||||
|
d4r is Apache License 2.0. This ZIP also contains ZLUDA (Apache 2.0 or MIT), OptiScaler (GPL 3.0,
|
||||||
|
patched; the patches are in the source repository), and AMD's HIP runtime. d4r\licenses has the
|
||||||
|
texts. d4r is not affiliated with NVIDIA, AMD or the OptiScaler project. NVIDIA's files are yours
|
||||||
|
to supply, under NVIDIA's terms.
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
; Select the quality mode (Quality, Performance, ...) in the game or the OptiScaler menu (Insert).
|
; Select the quality mode (Quality, Performance, ...) in the game or the OptiScaler menu (Insert).
|
||||||
; Models E and L are not available on Windows.
|
; Models E and L are not available on Windows.
|
||||||
Model = K
|
Model = K
|
||||||
|
; NVIDIA's library stamps "DLSS SDK - DO NOT DISTRIBUTE" over the image; d4r turns that off.
|
||||||
|
; true shows it.
|
||||||
|
ShowWatermark = false
|
||||||
|
|
||||||
[Interop]
|
[Interop]
|
||||||
; Experimental: lets the game continue while DLSS runs on the GPU instead of waiting for it.
|
; Experimental: lets the game continue while DLSS runs on the GPU instead of waiting for it.
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
# Checks a d4r install on Windows. It only reads files and prints what it finds.
|
||||||
|
# Run it from the game folder (the one holding the game's .exe and d4r\), or give that folder:
|
||||||
|
# powershell -ExecutionPolicy Bypass -File d4r\d4r-check.ps1 [GAME_FOLDER]
|
||||||
|
# Add -Report to also write one ZIP (logs, this output, GPU and driver) to send with a bug report.
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$GameFolder,
|
||||||
|
[switch]$Report,
|
||||||
|
[string]$InventoryFile, # tests: a gpu-inventory.json to use instead of running the GPU query
|
||||||
|
[string]$ReportDirectory # tests: where -Report writes its ZIP (default: your Desktop)
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
if (!$GameFolder) {
|
||||||
|
$GameFolder = if ((Split-Path $PSScriptRoot -Leaf) -eq 'd4r') { Split-Path $PSScriptRoot -Parent } else { (Get-Location).Path }
|
||||||
|
}
|
||||||
|
$game = [IO.Path]::GetFullPath($GameFolder).TrimEnd('\')
|
||||||
|
$d4r = Join-Path $game 'd4r'
|
||||||
|
$problems = 0
|
||||||
|
$lines = [Collections.Generic.List[string]]::new()
|
||||||
|
function Say([string]$text) { $lines.Add($text); Write-Host $text }
|
||||||
|
function Ok([string]$text) { Say (' ok ' + $text) }
|
||||||
|
function Bad([string]$text) { Say (' MISSING ' + $text); $script:problems++ }
|
||||||
|
function Note([string]$text) { Say (' note ' + $text) }
|
||||||
|
function Hash([string]$path) { (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash }
|
||||||
|
function Version([string]$path) {
|
||||||
|
try { $v = (Get-Item -LiteralPath $path).VersionInfo; if ($v.FileVersion) { return ($v.FileVersion -replace ',\s*', '.') } } catch {}
|
||||||
|
return 'unknown'
|
||||||
|
}
|
||||||
|
function Read-TextFile([string]$path) { [IO.File]::ReadAllText($path) }
|
||||||
|
|
||||||
|
Say "d4r install in $game"
|
||||||
|
if (!(Test-Path -LiteralPath $d4r -PathType Container)) {
|
||||||
|
Say 'no d4r folder here; run this from the folder with the game .exe (extract the d4r ZIP there first)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (@(Get-ChildItem -LiteralPath $game -Filter '*.exe' -File -ErrorAction SilentlyContinue).Count) { Ok 'game executable next to d4r\' }
|
||||||
|
else { Note 'no .exe next to d4r\ (the d4r files must sit in the folder of the game''s main .exe; for Unreal Engine games that is <game>\<Project>\Binaries\Win64)' }
|
||||||
|
|
||||||
|
# --- the install's own file list ---------------------------------------------------------------
|
||||||
|
$manifest = $null
|
||||||
|
$manifestPath = Join-Path $d4r 'package.json'
|
||||||
|
if (Test-Path -LiteralPath $manifestPath) {
|
||||||
|
try { $manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json } catch { $manifest = $null }
|
||||||
|
}
|
||||||
|
if (!$manifest) { Bad 'd4r\package.json is missing or damaged (extract the d4r ZIP again)' }
|
||||||
|
|
||||||
|
# --- files --------------------------------------------------------------------------------------
|
||||||
|
$required = @('dxgi.dll', 'OptiScaler.ini', 'd4r\_nvngx.dll', 'd4r\d4r.ini', 'd4r\dll-pins.txt',
|
||||||
|
'd4r\hip\bin\amdhip64_7.dll', 'd4r\zluda\nvcuda.dll', 'd4r\zluda\nvapi64.dll')
|
||||||
|
foreach ($file in $required) {
|
||||||
|
if (Test-Path -LiteralPath (Join-Path $game $file) -PathType Leaf) { Ok $file }
|
||||||
|
else { Bad "$file (extract the d4r ZIP again over the game folder)" }
|
||||||
|
}
|
||||||
|
if ($manifest) {
|
||||||
|
$edited = @('OptiScaler.ini', 'd4r/d4r.ini') # players are meant to edit these
|
||||||
|
$damaged = 0
|
||||||
|
foreach ($entry in $manifest.files) {
|
||||||
|
$path = Join-Path $game ($entry.path -replace '/', '\')
|
||||||
|
if (!(Test-Path -LiteralPath $path -PathType Leaf)) {
|
||||||
|
if ($required -notcontains ($entry.path -replace '/', '\')) { Bad "$($entry.path) (extract the d4r ZIP again)" }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ((Hash $path) -ne $entry.sha256) {
|
||||||
|
if ($entry.path -eq 'dxgi.dll') { Note 'dxgi.dll is not the one that came with d4r (another OptiScaler or ReShade?). Move it away and extract the d4r ZIP again' }
|
||||||
|
elseif ($edited -contains $entry.path) { Note "$($entry.path) has been edited (fine if you did it)" }
|
||||||
|
else { Bad "$($entry.path) differs from the release (damaged or replaced; extract the d4r ZIP again)"; $damaged++ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$damaged) { Ok 'every other d4r file matches the release' }
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- OptiScaler.ini ---------------------------------------------------------------------------
|
||||||
|
$optiIni = Join-Path $game 'OptiScaler.ini'
|
||||||
|
if (Test-Path -LiteralPath $optiIni) {
|
||||||
|
$text = Read-TextFile $optiIni
|
||||||
|
if ($text -notmatch '(?im)^\s*AllowExternalBackend\s*=\s*true') { Bad 'OptiScaler.ini: [DLSS] AllowExternalBackend must be true (this is not the d4r OptiScaler.ini)' }
|
||||||
|
if ($text -notmatch '(?im)^\s*Dx12Upscaler\s*=\s*dlss') { Note 'OptiScaler.ini: [Upscalers] Dx12Upscaler is not dlss; the game will not use d4r' }
|
||||||
|
$m = [regex]::Match($text, '(?im)^\s*NvngxPath\s*=\s*(\S+)')
|
||||||
|
if (!$m.Success) { Bad 'OptiScaler.ini: [Libraries] NvngxPath is missing (it must name the d4r folder)' }
|
||||||
|
else {
|
||||||
|
$folder = $m.Groups[1].Value
|
||||||
|
$resolved = if ([IO.Path]::IsPathRooted($folder)) { $folder } else { Join-Path $game $folder }
|
||||||
|
if (Test-Path -LiteralPath (Join-Path $resolved '_nvngx.dll')) { Ok "OptiScaler.ini NvngxPath = $folder" }
|
||||||
|
else { Bad "OptiScaler.ini NvngxPath = $folder does not hold _nvngx.dll (use NvngxPath=d4r, or the full path of the d4r folder)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- NVIDIA DLLs (never shipped; the exact versions come from dll-pins.txt) -----------------------
|
||||||
|
$pins = @()
|
||||||
|
$pinsPath = Join-Path $d4r 'dll-pins.txt'
|
||||||
|
if (Test-Path -LiteralPath $pinsPath) {
|
||||||
|
foreach ($line in Get-Content -LiteralPath $pinsPath) {
|
||||||
|
$line = $line.Trim()
|
||||||
|
if (!$line -or $line.StartsWith('#')) { continue }
|
||||||
|
$f = $line -split '\s+'
|
||||||
|
if ($f.Count -ge 4 -and $f[1].Length -eq 64) { $pins += [pscustomobject]@{ kind = $f[0]; sha = $f[1].ToUpperInvariant(); version = $f[2]; status = $f[3] } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Check-Nvidia([string]$kind, [string]$relative, [string]$label, [string]$source) {
|
||||||
|
$path = Join-Path $game $relative
|
||||||
|
$wanted = @($pins | Where-Object { $_.kind -eq $kind } | ForEach-Object { $_.version }) -join ' or '
|
||||||
|
if (!$wanted) { Note "$label cannot be checked (d4r\dll-pins.txt is missing or damaged)"; return }
|
||||||
|
if (!(Test-Path -LiteralPath $path -PathType Leaf)) { Bad "${relative}: copy NVIDIA's $label here (version $wanted; $source)"; return }
|
||||||
|
$hash = Hash $path
|
||||||
|
$pin = @($pins | Where-Object { $_.kind -eq $kind -and $_.sha -eq $hash }) | Select-Object -First 1
|
||||||
|
if (!$pin) { Bad "$relative is version $(Version $path), which d4r does not accept. d4r on Windows needs exactly $wanted ($source)"; return }
|
||||||
|
if ($pin.status -eq 'validated') { Ok "$relative ($label $($pin.version), tested on Windows)" }
|
||||||
|
else { Ok "$relative ($label $($pin.version))"; Note "$label $($pin.version) is accepted but has had less Windows testing" }
|
||||||
|
}
|
||||||
|
Check-Nvidia 'dlss' 'd4r\nvngx_dlss.dll' 'nvngx_dlss.dll' 'many games ship one in their folder; see WINDOWS_README.txt'
|
||||||
|
Check-Nvidia 'ngx' 'd4r\ngx\_nvngx.dll' '_nvngx.dll' 'it is part of NVIDIA''s display driver package; see WINDOWS_README.txt'
|
||||||
|
|
||||||
|
# --- GPU and the build for it --------------------------------------------------------------------
|
||||||
|
$registryPath = Join-Path $d4r 'gpu-targets.json'
|
||||||
|
$registry = @()
|
||||||
|
if (Test-Path -LiteralPath $registryPath) { $registry = @((Get-Content -LiteralPath $registryPath -Raw | ConvertFrom-Json).targets) }
|
||||||
|
$inventory = $null
|
||||||
|
if ($InventoryFile) { $inventory = Get-Content -LiteralPath $InventoryFile -Raw | ConvertFrom-Json }
|
||||||
|
elseif (Test-Path -LiteralPath (Join-Path $d4r 'd4r_gpu_inventory.exe')) {
|
||||||
|
$work = Join-Path ([IO.Path]::GetTempPath()) ('d4r-check-' + [Guid]::NewGuid().ToString('N'))
|
||||||
|
New-Item -ItemType Directory -Path $work | Out-Null
|
||||||
|
try {
|
||||||
|
$info = New-Object Diagnostics.ProcessStartInfo
|
||||||
|
$info.FileName = Join-Path $d4r 'd4r_gpu_inventory.exe'
|
||||||
|
$info.Arguments = '--hip-root "' + (Join-Path $d4r 'hip') + '" --output-dir "' + $work + '"'
|
||||||
|
$info.UseShellExecute = $false; $info.CreateNoWindow = $true
|
||||||
|
$info.RedirectStandardOutput = $true; $info.RedirectStandardError = $true
|
||||||
|
$info.EnvironmentVariables['D4R_DIAG_DIR'] = $work
|
||||||
|
$process = New-Object Diagnostics.Process; $process.StartInfo = $info
|
||||||
|
[void]$process.Start()
|
||||||
|
$null = $process.StandardOutput.ReadToEndAsync(); $null = $process.StandardError.ReadToEndAsync()
|
||||||
|
if (!$process.WaitForExit(30000)) { $process.Kill(); $process.WaitForExit() }
|
||||||
|
if (Test-Path -LiteralPath (Join-Path $work 'gpu-inventory.json')) { $inventory = Get-Content -LiteralPath (Join-Path $work 'gpu-inventory.json') -Raw | ConvertFrom-Json }
|
||||||
|
} catch {} finally {
|
||||||
|
$process.Dispose()
|
||||||
|
Get-ChildItem -LiteralPath $work -File -ErrorAction SilentlyContinue | ForEach-Object { Remove-Item -LiteralPath $_.FullName }
|
||||||
|
Remove-Item -LiteralPath $work -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$arch = $null
|
||||||
|
if (!$inventory) { Note 'could not ask the AMD runtime about your GPU (d4r_gpu_inventory.exe is missing, or the AMD graphics driver is not installed or is too old)' }
|
||||||
|
else {
|
||||||
|
$supported = @($registry | ForEach-Object { $_.architecture })
|
||||||
|
$devices = @($inventory.devices | Where-Object { $_.wavefrontSize -eq 32 -and ($supported -contains $_.architecture -or !$supported.Count) })
|
||||||
|
if (!$devices.Count) {
|
||||||
|
$seen = @($inventory.devices | ForEach-Object { "$($_.name) ($($_.architecture))" }) -join ', '
|
||||||
|
Bad ("no supported RDNA3/RDNA4 GPU found by the AMD runtime. It sees: " + $(if ($seen) { $seen } else { 'nothing' }) + '. Update the AMD Adrenalin driver; RDNA2 and older are not supported')
|
||||||
|
} else {
|
||||||
|
foreach ($device in $devices) {
|
||||||
|
$a = $device.architecture
|
||||||
|
$missing = @()
|
||||||
|
foreach ($rel in @("d4r\_nvngx_$a.dll", "d4r\pixel_convert_$a.hsaco", "d4r\nvapi\$a\nvapi64.dll", "d4r\native\$a\d4r-kernels.txt")) {
|
||||||
|
if (!(Test-Path -LiteralPath (Join-Path $game $rel))) { $missing += $rel }
|
||||||
|
}
|
||||||
|
$native = @(Get-ChildItem -LiteralPath (Join-Path $d4r "native\$a") -Filter '*.hsaco' -ErrorAction SilentlyContinue).Count
|
||||||
|
if ($missing.Count) { Bad "GPU $($device.name) ($a): this release has no complete build for it (missing: $($missing -join ', '))" }
|
||||||
|
else {
|
||||||
|
Ok "GPU $($device.name) ($a): build present, $native native kernels"
|
||||||
|
if (!$arch) { $arch = $a }
|
||||||
|
}
|
||||||
|
if ($a -ne 'gfx1201') { Note "only the RX 9070 XT (gfx1201) has been tested on real hardware; $a is compile-tested" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (@($inventory.devices | Where-Object { $_.wavefrontSize -eq 32 }).Count -gt 1) { Note 'several GPUs found; d4r uses the one the game renders on' }
|
||||||
|
}
|
||||||
|
if ($arch -and $registry.Count) {
|
||||||
|
$info = @($registry | Where-Object { $_.architecture -eq $arch }) | Select-Object -First 1
|
||||||
|
$bad = 0
|
||||||
|
$objects = @(Get-Item -LiteralPath (Join-Path $d4r "pixel_convert_$arch.hsaco") -ErrorAction SilentlyContinue) +
|
||||||
|
@(Get-ChildItem -LiteralPath (Join-Path $d4r "native\$arch") -Filter '*.hsaco' -ErrorAction SilentlyContinue)
|
||||||
|
foreach ($object in $objects) {
|
||||||
|
$stream = [IO.File]::OpenRead($object.FullName)
|
||||||
|
try { $header = New-Object byte[] 64; [void]$stream.Read($header, 0, 64) } finally { $stream.Dispose() }
|
||||||
|
if ($header[0] -ne 127 -or $header[1] -ne 69 -or $header[2] -ne 76 -or $header[3] -ne 70 -or $header[48] -ne $info.elfMachine) {
|
||||||
|
Bad "$($object.Name) is not built for $arch (do not rename or mix files from other GPUs; extract the d4r ZIP again)"; $bad++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($objects.Count -and !$bad) { Ok "all $($objects.Count) GPU code objects are built for $arch" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Linux / Wine leftovers ------------------------------------------------------------------------
|
||||||
|
$proxyFound = $false
|
||||||
|
foreach ($name in @('d3d12.dll', 'd3d12core.dll')) {
|
||||||
|
$proxy = Join-Path $game $name
|
||||||
|
if (Test-Path -LiteralPath $proxy -PathType Leaf) {
|
||||||
|
$item = Get-Item -LiteralPath $proxy
|
||||||
|
if ($item.Length -le 64MB -and [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($proxy)) -match '(?i)vkd3d|wined3d') {
|
||||||
|
Bad "$name in the game folder is vkd3d-proton/Wine (left over from a Linux install?). Move it out; d4r on Windows uses native D3D12"
|
||||||
|
$proxyFound = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$proxyFound) { Ok 'no vkd3d/Wine d3d12.dll in the game folder' }
|
||||||
|
|
||||||
|
# --- d4r.ini ---------------------------------------------------------------------------------------
|
||||||
|
$iniPath = Join-Path $d4r 'd4r.ini'
|
||||||
|
$model = 'K'
|
||||||
|
if (Test-Path -LiteralPath $iniPath) {
|
||||||
|
$section = ''; $iniProblems = 0
|
||||||
|
$known = @{ 'dlss.model' = 1; 'dlss.showwatermark' = 1; 'interop.asyncinterop' = 1; 'debug.validateoutput' = 1; 'debug.log' = 1; 'paths.cachedir' = 1 }
|
||||||
|
$boolean = @('dlss.showwatermark', 'interop.asyncinterop', 'debug.validateoutput')
|
||||||
|
foreach ($raw in (Read-TextFile $iniPath).TrimStart([char]0xFEFF) -split "`n") {
|
||||||
|
$line = $raw.Trim()
|
||||||
|
if (!$line -or $line.StartsWith(';') -or $line.StartsWith('#')) { continue }
|
||||||
|
if ($line.StartsWith('[')) { $section = $line.Trim('[', ']').Trim(); continue }
|
||||||
|
$eq = $line.IndexOf('='); if ($eq -lt 0) { continue }
|
||||||
|
$key = $line.Substring(0, $eq).Trim()
|
||||||
|
$value = ($line.Substring($eq + 1) -replace '\s[;#].*$', '').Trim()
|
||||||
|
$name = ("$section.$key").ToLowerInvariant()
|
||||||
|
$v = $value.ToLowerInvariant()
|
||||||
|
if (!$known.ContainsKey($name)) { Note "d4r.ini: [$section] $key is not a Windows setting; ignored"; $iniProblems++ }
|
||||||
|
elseif ($name -eq 'dlss.model') {
|
||||||
|
if (@('', 'auto', 'k', 'dlss4', '11') -contains $v) { $model = 'K' }
|
||||||
|
elseif (@('m', 'dlss4.5', '13') -contains $v) { $model = 'M' }
|
||||||
|
else { Note "d4r.ini: [DLSS] Model '$value' is not available on Windows (use K or M); K will be used"; $iniProblems++ }
|
||||||
|
}
|
||||||
|
elseif ($boolean -contains $name) {
|
||||||
|
if (@('', 'auto', '1', 'true', 'yes', 'on', '0', 'false', 'no', 'off') -notcontains $v) { Note "d4r.ini: [$section] $key must be true or false, not '$value'; the default will be used"; $iniProblems++ }
|
||||||
|
}
|
||||||
|
elseif ($name -eq 'debug.log' -and @('', 'auto', 'normal', 'verbose') -notcontains $v) { Note "d4r.ini: [Debug] Log must be normal or verbose, not '$value'; normal will be used"; $iniProblems++ }
|
||||||
|
}
|
||||||
|
if (!$iniProblems) { Ok "d4r.ini is valid (model $model)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- what the last game start said -----------------------------------------------------------------
|
||||||
|
$log = Join-Path $d4r 'd4r_nvngx.log'
|
||||||
|
if (Test-Path -LiteralPath $log) {
|
||||||
|
$messages = @(Get-Content -LiteralPath $log | Where-Object { $_ -match '^d4r: ' })
|
||||||
|
$failed = @($messages | Where-Object { $_ -match 'DLSS disabled' })
|
||||||
|
if ($failed.Count) { foreach ($m in $failed | Select-Object -First 3) { Bad ('last game start: ' + $m.Substring(5)) } }
|
||||||
|
elseif ($messages.Count) { Ok ('last game start: ' + $messages[0].Substring(5)) }
|
||||||
|
else { Note 'd4r\d4r_nvngx.log has no d4r summary line yet (the game may not have chosen DLSS)' }
|
||||||
|
foreach ($m in $messages | Where-Object { $_ -notmatch 'DLSS disabled|player mode' } | Select-Object -First 5) { Note ('last game start: ' + $m.Substring(5)) }
|
||||||
|
} else { Note 'no d4r\d4r_nvngx.log yet: start the game once and choose DLSS (or FSR/XeSS) in its graphics settings' }
|
||||||
|
if (Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Path -and $_.Path.StartsWith($game + '\', [StringComparison]::OrdinalIgnoreCase) -and $_.ProcessName -notmatch '^(powershell|pwsh)$' }) {
|
||||||
|
Note 'the game is running; its log is rewritten at every start'
|
||||||
|
}
|
||||||
|
|
||||||
|
Say ''
|
||||||
|
if ($problems -eq 0) { Say 'Everything d4r needs is in place.' } else { Say "$problems thing(s) to fix above." }
|
||||||
|
|
||||||
|
# --- bug-report ZIP ------------------------------------------------------------------------------
|
||||||
|
if ($Report) {
|
||||||
|
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||||
|
$destination = if ($ReportDirectory) { $ReportDirectory } else { [Environment]::GetFolderPath('Desktop') }
|
||||||
|
$staging = Join-Path ([IO.Path]::GetTempPath()) ("d4r-report-$stamp")
|
||||||
|
New-Item -ItemType Directory -Force -Path $staging | Out-Null
|
||||||
|
try {
|
||||||
|
$lines | Set-Content -LiteralPath (Join-Path $staging 'check.txt') -Encoding UTF8
|
||||||
|
foreach ($file in @('d4r\d4r_nvngx.log', 'd4r\d4r.ini', 'OptiScaler.ini', 'OptiScaler.log')) {
|
||||||
|
$source = Join-Path $game $file
|
||||||
|
if (Test-Path -LiteralPath $source) { Copy-Item -LiteralPath $source -Destination (Join-Path $staging (Split-Path $file -Leaf)) }
|
||||||
|
}
|
||||||
|
Get-ChildItem -LiteralPath $game -Filter 'OptiScaler*.log' -File | ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination $staging -Force }
|
||||||
|
try { Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion, DriverDate | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $staging 'driver.json') -Encoding UTF8 } catch {}
|
||||||
|
if ($inventory) { $inventory | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $staging 'gpu-inventory.json') -Encoding UTF8 }
|
||||||
|
Get-ChildItem -LiteralPath $game -Recurse -File -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.FullName.StartsWith($d4r + '\') -or $_.Name -in @('dxgi.dll', 'OptiScaler.ini') } |
|
||||||
|
ForEach-Object { '{0} {1,12} {2}' -f (Hash $_.FullName), $_.Length, $_.FullName.Substring($game.Length + 1) } |
|
||||||
|
Set-Content -LiteralPath (Join-Path $staging 'files.sha256.txt') -Encoding UTF8
|
||||||
|
$zip = Join-Path $destination "d4r-report-$stamp.zip"
|
||||||
|
Compress-Archive -Path (Join-Path $staging '*') -DestinationPath $zip -Force
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host "Bug report written: $zip" -ForegroundColor Cyan
|
||||||
|
Write-Host 'Also tell us: GPU, game, K or M, and what the image looked like. The logs can contain local folder names; look before posting publicly.'
|
||||||
|
} finally {
|
||||||
|
Get-ChildItem -LiteralPath $staging -File -ErrorAction SilentlyContinue | ForEach-Object { Remove-Item -LiteralPath $_.FullName }
|
||||||
|
Remove-Item -LiteralPath $staging -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($problems) { exit 1 }
|
||||||
@@ -7,6 +7,7 @@ param(
|
|||||||
[string]$GamePackagePrefix,
|
[string]$GamePackagePrefix,
|
||||||
[Parameter(Mandatory=$true)][string]$LoaderDll,
|
[Parameter(Mandatory=$true)][string]$LoaderDll,
|
||||||
[Parameter(Mandatory=$true)][string]$PackageRoot,
|
[Parameter(Mandatory=$true)][string]$PackageRoot,
|
||||||
|
[string[]]$Architectures, # default: every target in gpu-targets.json; a subset makes a smaller release
|
||||||
[string]$ArchivePath
|
[string]$ArchivePath
|
||||||
)
|
)
|
||||||
$ErrorActionPreference='Stop'
|
$ErrorActionPreference='Stop'
|
||||||
@@ -28,8 +29,10 @@ function Stage([string]$Source,[string]$Relative) {
|
|||||||
$item=Get-Item -LiteralPath $destination
|
$item=Get-Item -LiteralPath $destination
|
||||||
$files.Add(@{path=$Relative.Replace('\','/'); sha256=(Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash; version=$item.VersionInfo.FileVersion})
|
$files.Add(@{path=$Relative.Replace('\','/'); sha256=(Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash; version=$item.VersionInfo.FileVersion})
|
||||||
}
|
}
|
||||||
$targets=[ordered]@{}; $baseline=$null; $commonStaged=$false
|
$targets=[ordered]@{}; $baseline=$null; $commonStaged=$false; $inventoryStaged=$false
|
||||||
foreach ($gpu in Get-D4RGpuTargets) {
|
$selected=@(Get-D4RGpuTargets | Where-Object { !$Architectures -or $Architectures -contains $_.architecture })
|
||||||
|
if (!$selected.Count -or ($Architectures -and $selected.Count -ne @($Architectures | Select-Object -Unique).Count)) { throw "Unknown GPU target in -Architectures: $($Architectures -join ', ')" }
|
||||||
|
foreach ($gpu in $selected) {
|
||||||
$arch=$gpu.architecture; $source="$GamePackagePrefix-$arch"
|
$arch=$gpu.architecture; $source="$GamePackagePrefix-$arch"
|
||||||
$metadata=Get-Content -LiteralPath (Join-Path $source 'package.json') -Raw | ConvertFrom-Json
|
$metadata=Get-Content -LiteralPath (Join-Path $source 'package.json') -Raw | ConvertFrom-Json
|
||||||
if ($metadata.architecture -ne $arch -or $metadata.d4rWorkingTreeDirty) { throw "Uncommitted or wrong-target input: $source" }
|
if ($metadata.architecture -ne $arch -or $metadata.d4rWorkingTreeDirty) { throw "Uncommitted or wrong-target input: $source" }
|
||||||
@@ -41,7 +44,9 @@ foreach ($gpu in Get-D4RGpuTargets) {
|
|||||||
if ((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $file.sha256) { throw "Input file changed: $source/$relative" }
|
if ((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $file.sha256) { throw "Input file changed: $source/$relative" }
|
||||||
if ($relative.EndsWith('.hsaco')) { Assert-D4RCodeObjectTarget $path $arch; $objects++ }
|
if ($relative.EndsWith('.hsaco')) { Assert-D4RCodeObjectTarget $path $arch; $objects++ }
|
||||||
# Per-target files get target-specific names so one folder serves every GPU.
|
# Per-target files get target-specific names so one folder serves every GPU.
|
||||||
if ($relative -eq 'd4r/_nvngx.dll') { Stage $path "d4r/_nvngx_$arch.dll" }
|
# One GPU-query tool serves every target: it reports each device's real architecture.
|
||||||
|
if ($relative -eq 'd4r/d4r_gpu_inventory.exe') { if (!$inventoryStaged) { Stage $path 'd4r/d4r_gpu_inventory.exe'; $inventoryStaged=$true } }
|
||||||
|
elseif ($relative -eq 'd4r/_nvngx.dll') { Stage $path "d4r/_nvngx_$arch.dll" }
|
||||||
elseif ($relative -eq 'd4r/nvapi/nvapi64.dll') { Stage $path "d4r/nvapi/$arch/nvapi64.dll" }
|
elseif ($relative -eq 'd4r/nvapi/nvapi64.dll') { Stage $path "d4r/nvapi/$arch/nvapi64.dll" }
|
||||||
elseif ($relative -like 'd4r/pixel_convert_*.hsaco') { Stage $path $relative }
|
elseif ($relative -like 'd4r/pixel_convert_*.hsaco') { Stage $path $relative }
|
||||||
elseif ($relative.StartsWith('d4r/native/')) { Stage $path ("d4r/native/$arch/" + $relative.Substring('d4r/native/'.Length)) }
|
elseif ($relative.StartsWith('d4r/native/')) { Stage $path ("d4r/native/$arch/" + $relative.Substring('d4r/native/'.Length)) }
|
||||||
@@ -51,7 +56,7 @@ foreach ($gpu in Get-D4RGpuTargets) {
|
|||||||
if (!$commonStaged) { Stage $path $public }
|
if (!$commonStaged) { Stage $path $public }
|
||||||
elseif ((Get-FileHash -LiteralPath (Join-Path $PackageRoot $public) -Algorithm SHA256).Hash -ne $file.sha256) { throw "Shared runtime differs in $arch : $relative" }
|
elseif ((Get-FileHash -LiteralPath (Join-Path $PackageRoot $public) -Algorithm SHA256).Hash -ne $file.sha256) { throw "Shared runtime differs in $arch : $relative" }
|
||||||
}
|
}
|
||||||
# Installer-only files (launcher, inventory, PowerShell, docs) are not part of a drag-in install.
|
# Installer-only files (launcher, PowerShell installer, docs) are not part of a drag-in install.
|
||||||
}
|
}
|
||||||
if ($objects -ne 17) { throw "Expected 17 code objects for $arch" }
|
if ($objects -ne 17) { throw "Expected 17 code objects for $arch" }
|
||||||
$commonStaged=$true
|
$commonStaged=$true
|
||||||
@@ -63,6 +68,8 @@ Stage $loader 'd4r/_nvngx.dll'
|
|||||||
Stage (Join-Path $repo 'packaging/windows/OptiScaler.ini') 'OptiScaler.ini'
|
Stage (Join-Path $repo 'packaging/windows/OptiScaler.ini') 'OptiScaler.ini'
|
||||||
Stage (Join-Path $repo 'packaging/windows/d4r.ini') 'd4r/d4r.ini'
|
Stage (Join-Path $repo 'packaging/windows/d4r.ini') 'd4r/d4r.ini'
|
||||||
Stage (Join-Path $repo 'tools/windows/dll-pins.txt') 'd4r/dll-pins.txt'
|
Stage (Join-Path $repo 'tools/windows/dll-pins.txt') 'd4r/dll-pins.txt'
|
||||||
|
Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'd4r/gpu-targets.json'
|
||||||
|
if (!$inventoryStaged) { throw 'No d4r/d4r_gpu_inventory.exe in the inputs; d4r-check.ps1 needs it to query the GPU.' }
|
||||||
foreach ($optional in @(@{source='packaging/windows/WINDOWS_README.txt'; path='WINDOWS_README.txt'},
|
foreach ($optional in @(@{source='packaging/windows/WINDOWS_README.txt'; path='WINDOWS_README.txt'},
|
||||||
@{source='scripts/windows/d4r-check.ps1'; path='d4r/d4r-check.ps1'})) {
|
@{source='scripts/windows/d4r-check.ps1'; path='d4r/d4r-check.ps1'})) {
|
||||||
$path=Join-Path $repo $optional.source
|
$path=Join-Path $repo $optional.source
|
||||||
@@ -95,4 +102,4 @@ if ($ArchivePath) {
|
|||||||
}
|
}
|
||||||
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
|
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
|
||||||
}
|
}
|
||||||
Write-Host "Windows drag-in release: $PackageRoot ($($targets.Count) GPU targets, no NVIDIA DLLs)"
|
Write-Host "Windows drag-in release: $PackageRoot ($($targets.Count) GPU target(s): $($targets.Keys -join ', '); no NVIDIA DLLs)"
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# d4r-check.ps1 against fixture installs. No GPU, no NVIDIA binaries: the packaging test's
|
||||||
|
# synthetic release is the install, a fake inventory file stands in for the GPU query, and
|
||||||
|
# fixture text files stand in for the NVIDIA DLLs (pinned in a fixture dll-pins.txt).
|
||||||
|
[CmdletBinding()]
|
||||||
|
param([string]$OutputDirectory)
|
||||||
|
$ErrorActionPreference='Stop'
|
||||||
|
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
|
||||||
|
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/d4r-check/'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
|
||||||
|
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
|
||||||
|
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
|
||||||
|
& (Join-Path $PSScriptRoot 'test-windows-release-package.ps1') -OutputDirectory (Join-Path $OutputDirectory 'package') | Out-Null
|
||||||
|
$release=Join-Path $OutputDirectory 'package/release'
|
||||||
|
$check=Join-Path $repo 'scripts/windows/d4r-check.ps1'
|
||||||
|
$powershell="$env:SystemRoot/System32/WindowsPowerShell/v1.0/powershell.exe"
|
||||||
|
$results=@()
|
||||||
|
function Sha([string]$path) { (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash }
|
||||||
|
function Set-ManifestHash([string]$game,[string]$relative) {
|
||||||
|
$path=Join-Path $game 'd4r/package.json'
|
||||||
|
$manifest=Get-Content -LiteralPath $path -Raw | ConvertFrom-Json
|
||||||
|
foreach ($entry in $manifest.files) { if ($entry.path -eq $relative) { $entry.sha256=Sha (Join-Path $game ($relative -replace '/','\')) } }
|
||||||
|
$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $path -Encoding UTF8
|
||||||
|
}
|
||||||
|
function New-Install([string]$name) {
|
||||||
|
$game=Join-Path $OutputDirectory "cases/$name"
|
||||||
|
New-Item -ItemType Directory -Force (Split-Path $game) | Out-Null
|
||||||
|
Copy-Item -LiteralPath $release -Destination $game -Recurse
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'Game.exe') 'fixture' -Encoding ASCII
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/nvngx_dlss.dll') 'fixture dlss' -Encoding ASCII
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/ngx/_nvngx.dll') 'fixture core' -Encoding ASCII
|
||||||
|
$unrelated=('B'*64)
|
||||||
|
@('# fixture pins',
|
||||||
|
"dlss $(Sha (Join-Path $game 'd4r/nvngx_dlss.dll')) 310.9.1 validated",
|
||||||
|
"dlss $unrelated 310.7.0 unvalidated",
|
||||||
|
"ngx $(Sha (Join-Path $game 'd4r/ngx/_nvngx.dll')) 32.0.16.1714 validated") |
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/dll-pins.txt') -Encoding ASCII
|
||||||
|
Set-ManifestHash $game 'd4r/dll-pins.txt'
|
||||||
|
return $game
|
||||||
|
}
|
||||||
|
function Write-Inventory([string]$name,[string]$arch,[string]$gpu='AMD Radeon RX 7700 XT') {
|
||||||
|
$path=Join-Path $OutputDirectory "inventory-$name.json"
|
||||||
|
@{devices=@(@{name=$gpu; architecture=$arch; wavefrontSize=32})} | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $path -Encoding UTF8
|
||||||
|
return $path
|
||||||
|
}
|
||||||
|
function Run-Check([string]$game,[string]$inventory,[string[]]$More=@()) {
|
||||||
|
$ErrorActionPreference='Continue' # native stderr must not become a terminating error
|
||||||
|
$text=& $powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $game 'd4r/d4r-check.ps1') -GameFolder $game -InventoryFile $inventory @More 2>&1 | Out-String
|
||||||
|
return @{exit=$LASTEXITCODE; text=$text}
|
||||||
|
}
|
||||||
|
function Expect([string]$case,$run,[int]$exit,[string[]]$patterns) {
|
||||||
|
if ($run.exit -ne $exit) { throw "$case : exit $($run.exit), expected $exit`n$($run.text)" }
|
||||||
|
foreach ($pattern in $patterns) { if ($run.text -notmatch $pattern) { throw "$case : output lacks /$pattern/`n$($run.text)" } }
|
||||||
|
$script:results+=@{case=$case; passed=$true; gpuKernelsExecuted=$false}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Healthy install.
|
||||||
|
$game=New-Install 'healthy'; $inv=Write-Inventory 'a' 'gfx1101'
|
||||||
|
Expect 'healthy-install' (Run-Check $game $inv) 0 @('ok\s+d4r\\nvngx_dlss\.dll \(nvngx_dlss\.dll 310\.9\.1, tested on Windows\)','ok\s+d4r\\ngx\\_nvngx\.dll',
|
||||||
|
'ok\s+GPU AMD Radeon RX 7700 XT \(gfx1101\): build present, 16 native kernels','ok\s+all 17 GPU code objects are built for gfx1101',
|
||||||
|
'ok\s+no vkd3d/Wine d3d12\.dll','ok\s+d4r\.ini is valid \(model K\)','compile-tested','Everything d4r needs is in place')
|
||||||
|
|
||||||
|
# 2. NVIDIA DLL problems, each with the fix.
|
||||||
|
$game=New-Install 'dll-missing'; Remove-Item -LiteralPath (Join-Path $game 'd4r/nvngx_dlss.dll')
|
||||||
|
Expect 'dll-missing' (Run-Check $game $inv) 1 @("MISSING\s+d4r\\nvngx_dlss\.dll: copy NVIDIA's nvngx_dlss\.dll here \(version 310\.9\.1 or 310\.7\.0","1 thing\(s\) to fix")
|
||||||
|
$game=New-Install 'dll-wrong'; Set-Content -LiteralPath (Join-Path $game 'd4r/nvngx_dlss.dll') 'some other version' -Encoding ASCII
|
||||||
|
Expect 'dll-wrong-version' (Run-Check $game $inv) 1 @('MISSING\s+d4r\\nvngx_dlss\.dll is version \S+, which d4r does not accept\. d4r on Windows needs exactly 310\.9\.1 or 310\.7\.0')
|
||||||
|
$game=New-Install 'dll-less-tested'; Set-Content -LiteralPath (Join-Path $game 'd4r/nvngx_dlss.dll') 'fixture dlss 310.7' -Encoding ASCII
|
||||||
|
@('dlss '+(Sha (Join-Path $game 'd4r/nvngx_dlss.dll'))+' 310.7.0 unvalidated','ngx '+(Sha (Join-Path $game 'd4r/ngx/_nvngx.dll'))+' 32.0.16.1714 validated') | Set-Content -LiteralPath (Join-Path $game 'd4r/dll-pins.txt') -Encoding ASCII
|
||||||
|
Set-ManifestHash $game 'd4r/dll-pins.txt'
|
||||||
|
Expect 'dll-less-tested-accepted' (Run-Check $game $inv) 0 @('ok\s+d4r\\nvngx_dlss\.dll \(nvngx_dlss\.dll 310\.7\.0\)','note\s+nvngx_dlss\.dll 310\.7\.0 is accepted but has had less Windows testing')
|
||||||
|
|
||||||
|
# 3. Leftovers, edited files, a replaced dxgi.dll, and a broken OptiScaler.ini.
|
||||||
|
$game=New-Install 'vkd3d'; Set-Content -LiteralPath (Join-Path $game 'd3d12.dll') 'vkd3d-proton fixture' -Encoding ASCII
|
||||||
|
Expect 'vkd3d-proxy' (Run-Check $game $inv) 1 @('MISSING\s+d3d12\.dll in the game folder is vkd3d-proton/Wine')
|
||||||
|
$game=New-Install 'dxgi-replaced'; Set-Content -LiteralPath (Join-Path $game 'dxgi.dll') 'another dxgi' -Encoding ASCII
|
||||||
|
Expect 'foreign-dxgi' (Run-Check $game $inv) 0 @('note\s+dxgi\.dll is not the one that came with d4r')
|
||||||
|
$game=New-Install 'opti-path'; (Get-Content -LiteralPath (Join-Path $game 'OptiScaler.ini')) -replace '^NvngxPath=.*$','NvngxPath=nowhere' | Set-Content -LiteralPath (Join-Path $game 'OptiScaler.ini') -Encoding ASCII
|
||||||
|
Expect 'optiscaler-ini-path' (Run-Check $game $inv) 1 @('MISSING\s+OptiScaler\.ini NvngxPath = nowhere does not hold _nvngx\.dll')
|
||||||
|
|
||||||
|
# 4. d4r.ini mistakes are notes with what will happen instead.
|
||||||
|
$game=New-Install 'ini'; Set-Content -LiteralPath (Join-Path $game 'd4r/d4r.ini') "[DLSS]`nModel = E`nShowWatermark = sometimes`n[Latency]`nFrameAge = 1`n[Debug]`nLog = loud`n" -Encoding ASCII
|
||||||
|
Expect 'ini-mistakes' (Run-Check $game $inv) 0 @("note\s+d4r\.ini: \[DLSS\] Model 'E' is not available on Windows",'must be true or false, not ''sometimes''','\[Latency\] FrameAge is not a Windows setting','Log must be normal or verbose')
|
||||||
|
|
||||||
|
# 5. GPU cases.
|
||||||
|
$game=New-Install 'gpu-no-build'; Remove-Item -LiteralPath (Join-Path $game 'd4r/_nvngx_gfx1103.dll')
|
||||||
|
Expect 'gpu-without-build' (Run-Check $game (Write-Inventory 'b' 'gfx1103' 'AMD Radeon 780M')) 1 @('MISSING\s+GPU AMD Radeon 780M \(gfx1103\): this release has no complete build for it \(missing: d4r\\_nvngx_gfx1103\.dll\)')
|
||||||
|
$game=New-Install 'gpu-rdna2'
|
||||||
|
Expect 'gpu-unsupported' (Run-Check $game (Write-Inventory 'c' 'gfx1030' 'AMD Radeon RX 6800')) 1 @('MISSING\s+no supported RDNA3/RDNA4 GPU found by the AMD runtime\. It sees: AMD Radeon RX 6800 \(gfx1030\)')
|
||||||
|
$game=New-Install 'gpu-wrong-object'
|
||||||
|
$other=@(Get-ChildItem -LiteralPath (Join-Path $game 'd4r/native/gfx1100') -Filter '*.hsaco')[0].FullName
|
||||||
|
Copy-Item -LiteralPath $other -Destination (Join-Path $game 'd4r/native/gfx1101/kernel3.hsaco') -Force
|
||||||
|
Expect 'code-object-for-another-gpu' (Run-Check $game $inv) 1 @('MISSING\s+kernel3\.hsaco is not built for gfx1101','differs from the release')
|
||||||
|
|
||||||
|
# 6. What the last game start said, and the bug-report ZIP.
|
||||||
|
$game=New-Install 'log-failure'
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: DLSS disabled: Wrong nvngx_dlss.dll: you have version 1.2.3.4" -Encoding ASCII
|
||||||
|
Expect 'log-reports-failure' (Run-Check $game $inv) 1 @('MISSING\s+last game start: DLSS disabled: Wrong nvngx_dlss\.dll')
|
||||||
|
$game=New-Install 'log-ok'
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: player mode, model=K validate=0 async=0 log=normal, architecture=gfx1101" -Encoding ASCII
|
||||||
|
Expect 'log-reports-ok' (Run-Check $game $inv) 0 @('ok\s+last game start: player mode, model=K')
|
||||||
|
$game=New-Install 'report'; $reportDir=Join-Path $OutputDirectory 'reports'; New-Item -ItemType Directory -Force $reportDir | Out-Null
|
||||||
|
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: DLSS disabled: test failure" -Encoding ASCII
|
||||||
|
$run=Run-Check $game $inv @('-Report','-ReportDirectory',$reportDir)
|
||||||
|
$zip=@(Get-ChildItem -LiteralPath $reportDir -Filter 'd4r-report-*.zip')
|
||||||
|
if ($zip.Count -ne 1) { throw "Expected one report ZIP.`n$($run.text)" }
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
$archive=[IO.Compression.ZipFile]::OpenRead($zip[0].FullName)
|
||||||
|
try { $names=@($archive.Entries | ForEach-Object { $_.Name }) } finally { $archive.Dispose() }
|
||||||
|
foreach ($required in @('check.txt','d4r_nvngx.log','d4r.ini','OptiScaler.ini','files.sha256.txt','gpu-inventory.json')) { if ($names -notcontains $required) { throw "Report lacks $required (has: $($names -join ', '))" } }
|
||||||
|
if ($names -contains 'nvngx_dlss.dll' -or $names -contains '_nvngx.dll') { throw 'The report must never contain NVIDIA DLLs.' }
|
||||||
|
if ($run.text -notmatch 'Bug report written') { throw 'Report location was not printed.' }
|
||||||
|
$results+=@{case='bug-report-zip'; passed=$true; entries=$names}
|
||||||
|
|
||||||
|
# 7. No d4r folder at all.
|
||||||
|
$empty=Join-Path $OutputDirectory 'cases/empty'; New-Item -ItemType Directory -Force $empty | Out-Null
|
||||||
|
$ErrorActionPreference='Continue'
|
||||||
|
$text=& $powershell -NoProfile -ExecutionPolicy Bypass -File $check -GameFolder $empty 2>&1 | Out-String
|
||||||
|
$exitEmpty=$LASTEXITCODE; $ErrorActionPreference='Stop'
|
||||||
|
if ($exitEmpty -ne 1 -or $text -notmatch 'no d4r folder here') { throw "A folder without d4r must be reported.`n$text" }
|
||||||
|
$results+=@{case='no-d4r-folder'; passed=$true}
|
||||||
|
|
||||||
|
$results | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
||||||
|
Write-Host "PASS D4R_CHECK cases=$($results.Count) Report: $OutputDirectory"
|
||||||
@@ -20,7 +20,7 @@ function New-Inputs([string]$Prefix,[scriptblock]$Mutate) {
|
|||||||
foreach ($target in $targets) {
|
foreach ($target in $targets) {
|
||||||
$arch=$target.architecture; $root="$Prefix-$arch"
|
$arch=$target.architecture; $root="$Prefix-$arch"
|
||||||
$text=@{'OptiScaler.dll'='optiscaler'; 'd4r/_nvngx.dll'="shim $arch"; 'd4r/nvapi/nvapi64.dll'="nvapi $arch";
|
$text=@{'OptiScaler.dll'='optiscaler'; 'd4r/_nvngx.dll'="shim $arch"; 'd4r/nvapi/nvapi64.dll'="nvapi $arch";
|
||||||
'd4r/hip/bin/amdhip64_7.dll'='hip'; 'd4r/zluda/nvcuda.dll'='zluda'; 'licenses/d4r.txt'='license';
|
'd4r/hip/bin/amdhip64_7.dll'='hip'; 'd4r/zluda/nvcuda.dll'='zluda'; 'd4r/zluda/nvapi64.dll'='zluda nvapi'; 'licenses/d4r.txt'='license';
|
||||||
'd4r/d4r_gpu_inventory.exe'='inventory'; 'd4r/d4r_debug_launcher.exe'='launcher'; 'windows-game.ps1'='installer';
|
'd4r/d4r_gpu_inventory.exe'='inventory'; 'd4r/d4r_debug_launcher.exe'='launcher'; 'windows-game.ps1'='installer';
|
||||||
'd4r/native/d4r-kernels.txt'='manifest'}
|
'd4r/native/d4r-kernels.txt'='manifest'}
|
||||||
foreach ($entry in $text.GetEnumerator()) {
|
foreach ($entry in $text.GetEnumerator()) {
|
||||||
@@ -53,7 +53,8 @@ New-Inputs $prefix
|
|||||||
$release=Join-Path $OutputDirectory 'release'
|
$release=Join-Path $OutputDirectory 'release'
|
||||||
Invoke-Package $prefix $release
|
Invoke-Package $prefix $release
|
||||||
foreach ($path in @('dxgi.dll','OptiScaler.ini','d4r/_nvngx.dll','d4r/d4r.ini','d4r/dll-pins.txt','d4r/package.json',
|
foreach ($path in @('dxgi.dll','OptiScaler.ini','d4r/_nvngx.dll','d4r/d4r.ini','d4r/dll-pins.txt','d4r/package.json',
|
||||||
'd4r/hip/bin/amdhip64_7.dll','d4r/zluda/nvcuda.dll','d4r/licenses/d4r.txt','d4r/ngx/PUT _nvngx.dll HERE.txt')) {
|
'd4r/hip/bin/amdhip64_7.dll','d4r/zluda/nvcuda.dll','d4r/licenses/d4r.txt','d4r/ngx/PUT _nvngx.dll HERE.txt',
|
||||||
|
'd4r/gpu-targets.json','d4r/d4r_gpu_inventory.exe','d4r/d4r-check.ps1','WINDOWS_README.txt')) {
|
||||||
if (!(Test-Path -LiteralPath (Join-Path $release $path))) { throw "Release lacks $path" }
|
if (!(Test-Path -LiteralPath (Join-Path $release $path))) { throw "Release lacks $path" }
|
||||||
}
|
}
|
||||||
if ((Get-Content -LiteralPath (Join-Path $release 'd4r/_nvngx.dll') -Raw).Trim() -ne 'loader fixture') { throw 'd4r/_nvngx.dll is not the loader.' }
|
if ((Get-Content -LiteralPath (Join-Path $release 'd4r/_nvngx.dll') -Raw).Trim() -ne 'loader fixture') { throw 'd4r/_nvngx.dll is not the loader.' }
|
||||||
@@ -66,7 +67,8 @@ foreach ($target in $targets) {
|
|||||||
if ($native.Count -ne 16 -or !(Test-Path -LiteralPath (Join-Path $release "d4r/native/$arch/d4r-kernels.txt"))) { throw "Native folder for $arch is incomplete" }
|
if ($native.Count -ne 16 -or !(Test-Path -LiteralPath (Join-Path $release "d4r/native/$arch/d4r-kernels.txt"))) { throw "Native folder for $arch is incomplete" }
|
||||||
foreach ($object in $native) { Assert-D4RCodeObjectTarget $object.FullName $arch }
|
foreach ($object in $native) { Assert-D4RCodeObjectTarget $object.FullName $arch }
|
||||||
}
|
}
|
||||||
foreach ($excluded in @('d4r/d4r_gpu_inventory.exe','d4r/d4r_debug_launcher.exe','windows-game.ps1','d4r/native/kernel1.hsaco','d4r/nvapi/nvapi64.dll')) {
|
if (@(Get-ChildItem -LiteralPath $release -Recurse -Filter 'd4r_gpu_inventory.exe').Count -ne 1) { throw 'The GPU query tool must ship exactly once.' }
|
||||||
|
foreach ($excluded in @('d4r/d4r_debug_launcher.exe','windows-game.ps1','d4r/native/kernel1.hsaco','d4r/nvapi/nvapi64.dll')) {
|
||||||
if (Test-Path -LiteralPath (Join-Path $release $excluded)) { throw "Installer-only or untargeted file shipped: $excluded" }
|
if (Test-Path -LiteralPath (Join-Path $release $excluded)) { throw "Installer-only or untargeted file shipped: $excluded" }
|
||||||
}
|
}
|
||||||
$manifest=Get-Content -LiteralPath (Join-Path $release 'd4r/package.json') -Raw | ConvertFrom-Json
|
$manifest=Get-Content -LiteralPath (Join-Path $release 'd4r/package.json') -Raw | ConvertFrom-Json
|
||||||
@@ -77,6 +79,16 @@ $shipped=@(Get-ChildItem -LiteralPath $release -Recurse -File | ForEach-Object {
|
|||||||
if (Compare-Object $shipped @($manifest.files.path)) { throw 'Manifest and shipped files differ.' }
|
if (Compare-Object $shipped @($manifest.files.path)) { throw 'Manifest and shipped files differ.' }
|
||||||
$results+=@{case='drag-in-layout'; passed=$true; targets=$targets.Count; files=$shipped.Count}
|
$results+=@{case='drag-in-layout'; passed=$true; targets=$targets.Count; files=$shipped.Count}
|
||||||
|
|
||||||
|
# 1b. A subset release carries only the requested targets.
|
||||||
|
$subset=Join-Path $OutputDirectory 'release-subset'
|
||||||
|
& (Join-Path $PSScriptRoot 'package-windows-release.ps1') -GamePackagePrefix $prefix -LoaderDll $loader -PackageRoot $subset -Architectures gfx1101,gfx1201 | Out-Null
|
||||||
|
$kept=@(Get-ChildItem -LiteralPath (Join-Path $subset 'd4r') -Filter '_nvngx_gfx*.dll' | ForEach-Object { $_.Name })
|
||||||
|
if (($kept | Sort-Object) -join ',' -ne '_nvngx_gfx1101.dll,_nvngx_gfx1201.dll') { throw "Subset shipped the wrong shims: $($kept -join ',')" }
|
||||||
|
$rejected=$false
|
||||||
|
try { & (Join-Path $PSScriptRoot 'package-windows-release.ps1') -GamePackagePrefix $prefix -LoaderDll $loader -PackageRoot (Join-Path $OutputDirectory 'release-unknown') -Architectures gfx9999 | Out-Null } catch { $rejected=$_.Exception.Message -match 'Unknown GPU target' }
|
||||||
|
if (!$rejected) { throw 'An unknown architecture was not rejected.' }
|
||||||
|
$results+=@{case='architecture-subset'; passed=$true; shipped=$kept}
|
||||||
|
|
||||||
# 2. A code object for another GPU in a target's input is rejected.
|
# 2. A code object for another GPU in a target's input is rejected.
|
||||||
$prefix=Join-Path $OutputDirectory 'inputs/mixed/game'
|
$prefix=Join-Path $OutputDirectory 'inputs/mixed/game'
|
||||||
New-Inputs $prefix { param($root,$arch) if ($arch -eq 'gfx1101') { Write-CodeObject (Join-Path $root 'd4r/native/kernel3.hsaco') 65 } }
|
New-Inputs $prefix { param($root,$arch) if ($arch -eq 'gfx1101') { Write-CodeObject (Join-Path $root 'd4r/native/kernel3.hsaco') 65 } }
|
||||||
|
|||||||
@@ -148,6 +148,11 @@ API unsigned NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCommandList* list, co
|
|||||||
if (!snapshot->parameters) return failure;
|
if (!snapshot->parameters) return failure;
|
||||||
d4r::win::player::apply_preset(p);
|
d4r::win::player::apply_preset(p);
|
||||||
d4r::ngx::copy_create(p, snapshot->parameters); d4r::ngx::copy_frame(p, snapshot->parameters);
|
d4r::ngx::copy_create(p, snapshot->parameters); d4r::ngx::copy_frame(p, snapshot->parameters);
|
||||||
|
// NVIDIA's library stamps "DLSS SDK - DO NOT DISTRIBUTE" over its output unless the SDK's
|
||||||
|
// Disable.Watermark parameter is set (the Linux shim sets it too). The game's own value is
|
||||||
|
// not used. [DLSS] ShowWatermark = true (D4R_SHIM_WATERMARK=1) keeps the stamp.
|
||||||
|
static const bool watermark = [] { const char* v = std::getenv("D4R_SHIM_WATERMARK"); return v && v[0] == '1'; }();
|
||||||
|
d4r_ngx_set_int(snapshot->parameters, "Disable.Watermark", watermark ? 0 : 1);
|
||||||
const char* names[] = {"Color", "Depth", "MotionVectors", "Output", "ExposureTexture"};
|
const char* names[] = {"Color", "Depth", "MotionVectors", "Output", "ExposureTexture"};
|
||||||
const char* states[] = {"D4R.Color.State", "D4R.Depth.State", "D4R.Motion.State", "D4R.Output.State", "D4R.Exposure.State"};
|
const char* states[] = {"D4R.Color.State", "D4R.Depth.State", "D4R.Motion.State", "D4R.Output.State", "D4R.Exposure.State"};
|
||||||
for (unsigned i = 0; i < 5; ++i) {
|
for (unsigned i = 0; i < 5; ++i) {
|
||||||
|
|||||||
@@ -202,8 +202,8 @@ struct Args {
|
|||||||
else if (key == "--preset") {
|
else if (key == "--preset") {
|
||||||
size_t end = 0;
|
size_t end = 0;
|
||||||
preset = static_cast<unsigned>(std::stoul(value, &end));
|
preset = static_cast<unsigned>(std::stoul(value, &end));
|
||||||
if (end != value.size() || (preset != 5 && preset != 11 && preset != 13))
|
if (end != value.size() || (preset != 5 && preset != 11 && preset != 12 && preset != 13))
|
||||||
throw std::runtime_error("preset must be 5 (E), 11 (K) or 13 (M)");
|
throw std::runtime_error("preset must be 5 (E), 11 (K), 12 (L) or 13 (M)");
|
||||||
}
|
}
|
||||||
else if (key == "--fixture-dir") fixture_dir = value;
|
else if (key == "--fixture-dir") fixture_dir = value;
|
||||||
else if (key == "--benchmark-module") benchmark_module = value;
|
else if (key == "--benchmark-module") benchmark_module = value;
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
# never shipped or committed; players copy their own.
|
# never shipped or committed; players copy their own.
|
||||||
# dlss = nvngx_dlss.dll (d4r\nvngx_dlss.dll)
|
# dlss = nvngx_dlss.dll (d4r\nvngx_dlss.dll)
|
||||||
# ngx = _nvngx.dll, NVIDIA's NGX core from a display driver (d4r\ngx\_nvngx.dll)
|
# ngx = _nvngx.dll, NVIDIA's NGX core from a display driver (d4r\ngx\_nvngx.dll)
|
||||||
# status: validated = tested on Windows hardware; anything else is accepted
|
# status: validated = tested on Windows hardware by the project; anything else is
|
||||||
# but reported as unvalidated in d4r\d4r_nvngx.log.
|
# accepted but reported as having had less testing in d4r\d4r_nvngx.log and d4r-check.ps1.
|
||||||
|
# Native kernels only replace DLSS code whose PTX identity matches; anything else
|
||||||
|
# falls back to ZLUDA's translated kernels, so an accepted DLL is never run with a
|
||||||
|
# wrong native kernel.
|
||||||
# kind sha256 version status
|
# kind sha256 version status
|
||||||
dlss 3975567B8943C53ACCE397F2B72380092F84F162D00B0D2C7D08A1025C563983 310.9.1 validated
|
dlss 3975567B8943C53ACCE397F2B72380092F84F162D00B0D2C7D08A1025C563983 310.9.1 validated
|
||||||
|
dlss 1CDFDC957CB7FC9805500CA6793F607EF2D4DBD7C967FEAC70ACA9CAF382D0C0 310.7.0 unvalidated
|
||||||
ngx 66767018C36B3BAB46398DADE3ADF173DAA3730FDA75965689EA848C9BC4E79B 32.0.16.1714 validated
|
ngx 66767018C36B3BAB46398DADE3ADF173DAA3730FDA75965689EA848C9BC4E79B 32.0.16.1714 validated
|
||||||
|
ngx 0765FB7FB2B8BE28EE1F0226679D7B2636A69CACCE5A23891984978F690D81A4 32.0.15.9636 unvalidated
|
||||||
@@ -22,7 +22,7 @@ struct IniEntry { std::string section, key, value; };
|
|||||||
struct Pin { std::string kind, sha256, version, status; };
|
struct Pin { std::string kind, sha256, version, status; };
|
||||||
struct Settings {
|
struct Settings {
|
||||||
unsigned preset = 11; // K
|
unsigned preset = 11; // K
|
||||||
bool asyncInterop = false, validateOutput = false, verbose = false;
|
bool asyncInterop = false, validateOutput = false, verbose = false, showWatermark = false;
|
||||||
std::wstring cacheDir;
|
std::wstring cacheDir;
|
||||||
};
|
};
|
||||||
struct State {
|
struct State {
|
||||||
@@ -102,7 +102,8 @@ inline Settings read_settings(const std::vector<IniEntry>& ini, std::vector<std:
|
|||||||
if (value.empty() || value == "AUTO" || value == "K" || value == "DLSS4" || value == "11") settings.preset = 11;
|
if (value.empty() || value == "AUTO" || value == "K" || value == "DLSS4" || value == "11") settings.preset = 11;
|
||||||
else if (value == "M" || value == "DLSS4.5" || value == "13") settings.preset = 13;
|
else if (value == "M" || value == "DLSS4.5" || value == "13") settings.preset = 13;
|
||||||
else notes.push_back("d4r.ini: [DLSS] Model '" + entry.value + "' is not available on Windows (use K or M); using K");
|
else notes.push_back("d4r.ini: [DLSS] Model '" + entry.value + "' is not available on Windows (use K or M); using K");
|
||||||
} else if (name == "interop.asyncinterop") settings.asyncInterop = flag(entry, false);
|
} else if (name == "dlss.showwatermark") settings.showWatermark = flag(entry, false);
|
||||||
|
else if (name == "interop.asyncinterop") settings.asyncInterop = flag(entry, false);
|
||||||
else if (name == "debug.validateoutput") settings.validateOutput = flag(entry, false);
|
else if (name == "debug.validateoutput") settings.validateOutput = flag(entry, false);
|
||||||
else if (name == "debug.log") {
|
else if (name == "debug.log") {
|
||||||
const auto value = lower(entry.value);
|
const auto value = lower(entry.value);
|
||||||
@@ -213,11 +214,9 @@ inline void set_variable(const wchar_t* name, const std::optional<std::wstring>&
|
|||||||
SetEnvironmentVariableW(name, value ? value->c_str() : nullptr);
|
SetEnvironmentVariableW(name, value ? value->c_str() : nullptr);
|
||||||
_wputenv_s(name, value ? value->c_str() : L"");
|
_wputenv_s(name, value ? value->c_str() : L"");
|
||||||
}
|
}
|
||||||
// Only when the game has no console/pipe: never steal a launcher's streams.
|
// Player mode only runs when no launcher set up the environment, so no launcher is
|
||||||
inline bool unattached(DWORD stream) {
|
// reading these streams. A game started from Steam can have a valid but unread pipe
|
||||||
const HANDLE current = GetStdHandle(stream);
|
// as stderr; always writing to the log keeps errors visible.
|
||||||
return !current || current == INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
inline void redirect(FILE* crt, DWORD stream, const std::filesystem::path& path) {
|
inline void redirect(FILE* crt, DWORD stream, const std::filesystem::path& path) {
|
||||||
FILE* reopened = nullptr;
|
FILE* reopened = nullptr;
|
||||||
if (_wfreopen_s(&reopened, path.c_str(), L"a", crt) || !reopened) return;
|
if (_wfreopen_s(&reopened, path.c_str(), L"a", crt) || !reopened) return;
|
||||||
@@ -253,6 +252,7 @@ inline void apply(const std::filesystem::path& dir, const Settings& settings) {
|
|||||||
{L"D4R_QUIET_API", settings.verbose ? unset : on},
|
{L"D4R_QUIET_API", settings.verbose ? unset : on},
|
||||||
{L"D4R_VALIDATE_OUTPUT", settings.validateOutput ? on : unset},
|
{L"D4R_VALIDATE_OUTPUT", settings.validateOutput ? on : unset},
|
||||||
{L"D4R_ASYNC_INTEROP", settings.asyncInterop ? on : unset},
|
{L"D4R_ASYNC_INTEROP", settings.asyncInterop ? on : unset},
|
||||||
|
{L"D4R_SHIM_WATERMARK", settings.showWatermark ? on : unset},
|
||||||
{L"D4R_PROFILE_STAGES", unset}, {L"D4R_ZLUDA_PROFILE", unset}, {L"D4R_ZLUDA_PROFILE_DEFERRED", unset},
|
{L"D4R_PROFILE_STAGES", unset}, {L"D4R_ZLUDA_PROFILE", unset}, {L"D4R_ZLUDA_PROFILE_DEFERRED", unset},
|
||||||
{L"D4R_ZLUDA_PROFILE_ALLOW_LEGACY", unset}, {L"D4R_ZLUDA_PROFILE_EVERY", unset},
|
{L"D4R_ZLUDA_PROFILE_ALLOW_LEGACY", unset}, {L"D4R_ZLUDA_PROFILE_EVERY", unset},
|
||||||
{L"D4R_PROFILE_COMMAND_HOOKS", unset}, {L"D4R_ZLUDA_PROFILE_API", unset}, {L"D4R_PROFILE_GPU_BOUNDARY", unset},
|
{L"D4R_PROFILE_COMMAND_HOOKS", unset}, {L"D4R_ZLUDA_PROFILE_API", unset}, {L"D4R_PROFILE_GPU_BOUNDARY", unset},
|
||||||
@@ -278,12 +278,10 @@ inline void ensure_environment() {
|
|||||||
if (!std::filesystem::exists(dir / L"d4r.ini")) return; // Developer layout: keep the original requirement.
|
if (!std::filesystem::exists(dir / L"d4r.ini")) return; // Developer layout: keep the original requirement.
|
||||||
auto& current = state(); current.dir = dir;
|
auto& current = state(); current.dir = dir;
|
||||||
const auto log = dir / L"d4r_nvngx.log";
|
const auto log = dir / L"d4r_nvngx.log";
|
||||||
if (unattached(STD_ERROR_HANDLE)) {
|
{ std::ofstream truncate(log, std::ios::trunc); } // Rewritten at every launch, as on Linux.
|
||||||
{ std::ofstream truncate(log, std::ios::trunc); } // Rewritten at every launch, as on Linux.
|
redirect(stderr, STD_ERROR_HANDLE, log);
|
||||||
redirect(stderr, STD_ERROR_HANDLE, log);
|
|
||||||
}
|
|
||||||
const auto settings = read_settings(parse_ini(read_text(dir / L"d4r.ini")), current.notes);
|
const auto settings = read_settings(parse_ini(read_text(dir / L"d4r.ini")), current.notes);
|
||||||
if (settings.verbose && unattached(STD_OUTPUT_HANDLE)) redirect(stdout, STD_OUTPUT_HANDLE, log);
|
if (settings.verbose) redirect(stdout, STD_OUTPUT_HANDLE, log);
|
||||||
const auto pins = parse_pins(read_text(dir / L"dll-pins.txt"));
|
const auto pins = parse_pins(read_text(dir / L"dll-pins.txt"));
|
||||||
verify_dll(dir, pins, "dlss", L"nvngx_dlss.dll", "nvngx_dlss.dll", current.notes);
|
verify_dll(dir, pins, "dlss", L"nvngx_dlss.dll", "nvngx_dlss.dll", current.notes);
|
||||||
verify_dll(dir, pins, "ngx", L"ngx\\_nvngx.dll", "_nvngx.dll", current.notes);
|
verify_dll(dir, pins, "ngx", L"ngx\\_nvngx.dll", "_nvngx.dll", current.notes);
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ int wmain(int argc, wchar_t** argv) {
|
|||||||
s = settings("[Kernels]\nNativeFp8 = on\n[Latency]\nFrameAge = 1\n", notes);
|
s = settings("[Kernels]\nNativeFp8 = on\n[Latency]\nFrameAge = 1\n", notes);
|
||||||
expect(has_note(notes, "[Kernels] NativeFp8 is not a Windows setting") && has_note(notes, "[Latency] FrameAge"),
|
expect(has_note(notes, "[Kernels] NativeFp8 is not a Windows setting") && has_note(notes, "[Latency] FrameAge"),
|
||||||
"Linux-only settings are reported as ignored");
|
"Linux-only settings are reported as ignored");
|
||||||
|
s = settings("", notes);
|
||||||
|
expect(!s.showWatermark, "watermark is hidden by default");
|
||||||
|
s = settings("[DLSS]\nShowWatermark = true\n", notes);
|
||||||
|
expect(s.showWatermark && notes.empty(), "[DLSS] ShowWatermark = true keeps NVIDIA's stamp");
|
||||||
|
s = settings("[DLSS]\nShowWatermark = sometimes\n", notes);
|
||||||
|
expect(!s.showWatermark && has_note(notes, "ShowWatermark must be true or false"), "invalid ShowWatermark falls back to hidden with a note");
|
||||||
s = settings("[Paths]\nCacheDir = D:\\d4r-cache\n", notes);
|
s = settings("[Paths]\nCacheDir = D:\\d4r-cache\n", notes);
|
||||||
expect(s.cacheDir == L"D:\\d4r-cache" && notes.empty(), "CacheDir path");
|
expect(s.cacheDir == L"D:\\d4r-cache" && notes.empty(), "CacheDir path");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user