Fix Windows numeric NGX feature discovery and quick-test launches
This commit is contained in:
1 parent
21ed0a8c88
commit
17121ccbf6
22 files changed
+473
-44
No files matched your search
@@ -13,7 +13,7 @@ transformer networks on Windows 11 / RX 9070 XT (gfx1201), using patched
|
|||||||
ZLUDA/HIP and VRAM buffers/shared fences directly. Inputs and output belong to
|
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 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`.
|
The Windows backend, command-list hooks and diagnostics live in `tools/windows`.
|
||||||
All sixteen Windows hardware gates pass, and queued-frame/feature-recreation K
|
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
|
outputs match synchronous controls exactly. A five-minute K/4K Silent Hill 2
|
||||||
run completes 16941 finite frames without backend errors. Performance remains
|
run completes 16941 finite frames without backend errors. Performance remains
|
||||||
under development; asynchronous interop is opt-in and requires one queue.
|
under development; asynchronous interop is opt-in and requires one queue.
|
||||||
@@ -37,6 +37,12 @@ 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
|
diagnostic ZIP after exiting. RESTORE-GAME.cmd restores replaced files. Read
|
||||||
[the short English instructions](docs/windows-quick-test.txt). Corresponding
|
[the short English instructions](docs/windows-quick-test.txt). Corresponding
|
||||||
sources are a separate release asset; the test requires no SDK installation.
|
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; other GPUs and the reported Cyberpunk game still need testing.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,15 @@ executing kernels. It rejects another architecture's package and a local
|
|||||||
D3D12 proxy identifying itself as vkd3d/Wine, producing one diagnostic ZIP.
|
D3D12 proxy identifying itself as vkd3d/Wine, producing one diagnostic ZIP.
|
||||||
RX 9060 XT needs gfx1200: the old gfx1201-only package fails before DLSS
|
RX 9060 XT needs gfx1200: the old gfx1201-only package fails before DLSS
|
||||||
initialization on it. Use native D3D12. On an untested GPU, start with
|
initialization on it. Use native D3D12. On an untested GPU, start with
|
||||||
synchronous K and output/exception diagnostics.
|
synchronous K and output diagnostics. The ordinary launcher does not attach
|
||||||
|
a debugger. `-CaptureExceptions` is an explicit developer option; games with
|
||||||
|
anti-debug protection can refuse it.
|
||||||
|
|
||||||
|
Numeric CUDA driver NGX initialization searches for `nvngx_dlss.dll` beside
|
||||||
|
the calling d4r shim. The installer stages your local feature DLL in `d4r/`
|
||||||
|
and the original NVIDIA core in `d4r/vendor/`. `Libraries.NvngxDlssPath` is
|
||||||
|
the feature directory. Keeping the feature DLL only in `vendor/` causes
|
||||||
|
`BAD00004` (FeatureNotFound) in numeric-ID games such as Cyberpunk.
|
||||||
|
|
||||||
Build the shim/diagnostics, corrected ZLUDA, K/M native objects and patched
|
Build the shim/diagnostics, corrected ZLUDA, K/M native objects and patched
|
||||||
OptiScaler using the scripts in `scripts/windows`, then run:
|
OptiScaler using the scripts in `scripts/windows`, then run:
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ IF SOMETHING FAILS:
|
|||||||
- Do not start a second test while the first game is running.
|
- Do not start a second test while the first game is running.
|
||||||
|
|
||||||
No HIP SDK installation is required; the isolated runtime is included.
|
No HIP SDK installation is required; the isolated runtime is included.
|
||||||
This uses synchronous interop, output checks and crash capture by default.
|
This uses synchronous interop and output checks. No debugger is attached by default.
|
||||||
|
Exit codes and loaded DLLs are logged. A debugger is only an explicit developer option.
|
||||||
|
Your local DLSS DLL is staged beside the d4r shim automatically.
|
||||||
It is a correctness diagnostic, NOT an FPS benchmark or an optimized daily-use build.
|
It is a correctness diagnostic, NOT an FPS benchmark or an optimized daily-use build.
|
||||||
Colour, depth, motion and output remain in VRAM in the runtime fast path.
|
Colour, depth, motion and output remain in VRAM in the runtime fast path.
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,64 @@ explicit limits; the validated package keeps conservative arithmetic.
|
|||||||
|
|
||||||
## Milestone and gates
|
## Milestone and gates
|
||||||
|
|
||||||
|
2026-10-02 issue #10 follow-up ([comment 5958769640](https://github.com/countervolts/d4r/issues/10#issuecomment-5958769640)):
|
||||||
|
four new logs confirm that RX 9060 XT / gfx1200 HIP discovery succeeds. The
|
||||||
|
Cyberpunk K/M runs never launch the transformer: numeric CUDA NGX capabilities
|
||||||
|
report `available=0, feature_init=BAD00004` (FeatureNotFound). The unmatched
|
||||||
|
adapter during enumeration is not the main Radeon: its runtime LUID matches.
|
||||||
|
GetFeatureRequirements now returns success with AdapterUnsupported for Intel /
|
||||||
|
WARP / another nonmatching adapter, while runtime initialization still requires
|
||||||
|
the exact HIP architecture and D3D12 LUID.
|
||||||
|
|
||||||
|
The feature discovery failure is reproduced on RX 9070 XT without a game,
|
||||||
|
using Cyberpunk's unchanged numeric application ID `100152211`. Keeping the
|
||||||
|
feature DLL only beside the official core in `d4r/vendor/` fails; placing it
|
||||||
|
beside the calling shim in `d4r/` succeeds. Putting it beside the EXE alone is
|
||||||
|
insufficient when the call originates in the shim. The installer now stages
|
||||||
|
the local feature DLL beside the shim and sets `Libraries.NvngxDlssPath` to
|
||||||
|
the directory, as required by OptiScaler's discovery logic. Project identity,
|
||||||
|
DLL contents, numeric driver ABI and capability checks remain unchanged.
|
||||||
|
|
||||||
|
The standalone reproduction also exposed concurrent/reentrant OptiScaler
|
||||||
|
device hook installation: Detours error `0x10dd` clears a live trampoline and
|
||||||
|
execution jumps to null. Source patch `0004` serializes installation/removal
|
||||||
|
and guards recursion; `0005` forwards numeric NGX init failures instead of
|
||||||
|
reporting success. The exact patched frontend source is
|
||||||
|
`86b21ea` (base `45a2001`), with pinned submodules verified directly before build.
|
||||||
|
|
||||||
|
The quick launcher no longer attaches a debugger by default: Assassin's Creed
|
||||||
|
Black Flag Resynced refused the previous debugger launch (`DEADC0DE`). Empty
|
||||||
|
stdout/stderr now parse correctly. A clean early process exit with zero DLSS
|
||||||
|
frames is inconclusive, as in the SM2 log; an external Steam restart is not
|
||||||
|
tracked and must not be reported as successful hardware validation.
|
||||||
|
|
||||||
|
Validation on the available RX 9070 XT: all eleven target builds pass; CTest
|
||||||
|
20/20; summary parser 9/9 including all four submitted logs. The layout
|
||||||
|
regression passes two expected FeatureNotFound cases (direct + OptiScaler),
|
||||||
|
then three finite frames each for direct K, OptiScaler K and OptiScaler M.
|
||||||
|
Every required native layer executes; GPU NaN/Inf checks pass, CPU frame copies
|
||||||
|
and frame age are zero. Direct/OptiScaler K RGB matches bit-for-bit for all
|
||||||
|
three frames (max absolute/relative error 0). Reports are under
|
||||||
|
`test-results/issue-10-5958769640/`, including `ctest.log`,
|
||||||
|
`summary-parser.json`, `layout-final/` and `build-all-targets.json`.
|
||||||
|
All five exported OptiScaler patches apply to the pinned upstream sources and
|
||||||
|
reproduce its exact committed files (`optiScaler-patches.json`). Reproduce the
|
||||||
|
standalone layout/error/coverage/RGB checks with:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\windows\test-ngx-feature-layout.ps1 -DiagnosticRoot .\dist\windows-gpu-coverage-gfx1201 -HipRoot .\.tools\therock-10.2.0a20260929\_rocm_sdk_core -ZludaRoot .\dist\zluda-windows-gpu-coverage -NativeRoot .\dist\windows-gpu-coverage-game-gfx1201\d4r\native -OptiScalerDll .\dist\optiscaler-windows-d4r\OptiScaler.dll -NgxCore .\_nvngx.dll -DlssDll .\nvngx_dlss.dll -OutputDirectory .\test-results\ngx-feature-layout
|
||||||
|
```
|
||||||
|
|
||||||
|
These tests do not validate the reporter's gfx1200 kernels or game image.
|
||||||
|
The local Cyberpunk EXE is `D:\Games\Cyberpunk 2077\bin\x64\Cyberpunk2077.exe`;
|
||||||
|
it is located but is not launched or modified while the user is away.
|
||||||
|
|
||||||
2026-10-02 quick-test packaging: one universal ZIP shares the identical
|
2026-10-02 quick-test packaging: one universal ZIP shares the identical
|
||||||
OptiScaler/ZLUDA/HIP runtime and selects among all eleven previously compiled
|
OptiScaler/ZLUDA/HIP runtime and selects among all eleven previously compiled
|
||||||
host/kernel targets using read-only HIP discovery. START-K.cmd / START-M.cmd
|
host/kernel targets using read-only HIP discovery. START-K.cmd / START-M.cmd
|
||||||
use file pickers, remember validated game/DLL paths, back up replaced files,
|
use file pickers, remember validated game/DLL paths, back up replaced files,
|
||||||
run synchronous output/crash diagnostics, and produce one report ZIP.
|
run synchronous output diagnostics, and produce one report ZIP. The initial
|
||||||
|
release attached a debugger; the issue #10 follow-up above removes that default.
|
||||||
RESTORE-GAME.cmd works without HIP discovery or NVIDIA DLL selection. No
|
RESTORE-GAME.cmd works without HIP discovery or NVIDIA DLL selection. No
|
||||||
runtime arithmetic changes or additional hardware-support claims are made.
|
runtime arithmetic changes or additional hardware-support claims are made.
|
||||||
The short English instructions are in `windows-quick-test.txt`; developer
|
The short English instructions are in `windows-quick-test.txt`; developer
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
diff --git a/OptiScaler/hooks/D3D12_Hooks.cpp b/OptiScaler/hooks/D3D12_Hooks.cpp
|
||||||
|
index 3b757be..05fc194 100644
|
||||||
|
--- a/OptiScaler/hooks/D3D12_Hooks.cpp
|
||||||
|
+++ b/OptiScaler/hooks/D3D12_Hooks.cpp
|
||||||
|
@@ -2217,11 +2217,20 @@ static HRESULT hkD3D12GetInterface(REFCLSID rclsid, REFIID riid, void** ppvDebug
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+// Device discovery and NGX initialization can overlap. Installing d4r's
|
||||||
|
+// command hooks can also create a device and re-enter this function. Never
|
||||||
|
+// overwrite live Detours trampolines from a second installation attempt.
|
||||||
|
+static std::recursive_mutex deviceHookMutex;
|
||||||
|
+static bool deviceHookInstalling = false;
|
||||||
|
static void HookToDevice(ID3D12Device* InDevice)
|
||||||
|
{
|
||||||
|
- if (o_CreateSampler != nullptr || InDevice == nullptr)
|
||||||
|
+ std::lock_guard<std::recursive_mutex> lock(deviceHookMutex);
|
||||||
|
+ if (o_CreateSampler != nullptr || InDevice == nullptr || deviceHookInstalling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ deviceHookInstalling = true;
|
||||||
|
+ struct InstallationGuard { ~InstallationGuard() { deviceHookInstalling = false; } } installationGuard;
|
||||||
|
+
|
||||||
|
LOG_DEBUG("Dx12");
|
||||||
|
|
||||||
|
// Get the vtable pointer
|
||||||
|
@@ -2334,6 +2343,7 @@ static void HookToDevice(ID3D12Device* InDevice)
|
||||||
|
|
||||||
|
static void UnhookDevice()
|
||||||
|
{
|
||||||
|
+ std::lock_guard<std::recursive_mutex> lock(deviceHookMutex);
|
||||||
|
LOG_FUNC();
|
||||||
|
|
||||||
|
DetourTransactionBegin();
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
diff --git a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
|
||||||
|
index 1f723f1..ef5ec77 100644
|
||||||
|
--- a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
|
||||||
|
+++ b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp
|
||||||
|
@@ -184,6 +184,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Init_Ext(unsigned long long InApp
|
||||||
|
|
||||||
|
if (result == NVSDK_NGX_Result_Success)
|
||||||
|
NVNGXProxy::SetDx12Inited(true);
|
||||||
|
+ else if (State::Instance().dlssExternalBackend)
|
||||||
|
+ return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@@ -254,6 +256,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Init(unsigned long long InApplica
|
||||||
|
|
||||||
|
if (result == NVSDK_NGX_Result_Success)
|
||||||
|
NVNGXProxy::SetDx12Inited(true);
|
||||||
|
+ else if (State::Instance().dlssExternalBackend)
|
||||||
|
+ return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
# Explicit Windows d4r backend
|
# Explicit Windows d4r backend
|
||||||
|
|
||||||
Base: OptiScaler `45a2001303ddff632e279f77aef85ceede5832cb` (2026-09-30).
|
Base: OptiScaler `45a2001303ddff632e279f77aef85ceede5832cb` (2026-09-30).
|
||||||
|
|
||||||
|
`0004` serializes D3D12 device hook installation/removal and guards recursive
|
||||||
|
device discovery while the d4r command backend installs. The previous frontend
|
||||||
|
can start two installations, fail a Detours transaction with `0x10dd`, clear
|
||||||
|
live original-function pointers and call null. This was reproduced in the
|
||||||
|
numeric-ID standalone harness; no game was required.
|
||||||
|
|
||||||
|
`0005` propagates numeric Init/Init_Ext failures for the explicitly selected
|
||||||
|
external backend, matching the existing ProjectID behavior. FeatureNotFound
|
||||||
|
must fail initialization instead of being hidden until repeated CreateFeature
|
||||||
|
attempts. `Libraries.NvngxDlssPath` takes a directory, not the DLL filename;
|
||||||
|
the Windows installer and standalone runner now use that directory.
|
||||||
The modifications to OptiScaler are GPL-3.0, matching its upstream license.
|
The modifications to OptiScaler are GPL-3.0, matching its upstream license.
|
||||||
No NVIDIA DLL is supplied or patched.
|
No NVIDIA DLL is supplied or patched.
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,23 @@ try {
|
|||||||
if ($LASTEXITCODE) { throw "Source patch failed: $($patch.Name)" }
|
if ($LASTEXITCODE) { throw "Source patch failed: $($patch.Name)" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& git -C $SourceRoot submodule update --init --depth 1
|
# Verify existing checkouts directly. A complete local checkout does not
|
||||||
if ($LASTEXITCODE) { throw 'Pinned OptiScaler submodules failed.' }
|
# need Git's shell-based submodule helper (or a network connection).
|
||||||
|
$submodulePaths=@(& git -C $SourceRoot config --file .gitmodules --get-regexp '\.path$' | ForEach-Object { ($_ -split ' ',2)[1] })
|
||||||
|
$submodules=@()
|
||||||
|
foreach ($path in $submodulePaths) {
|
||||||
|
$tree=(& git -C $SourceRoot ls-tree HEAD -- $path) -split '\s+',4
|
||||||
|
if ($tree.Count -lt 4 -or $tree[0] -ne '160000') { throw "Missing pinned submodule: $path" }
|
||||||
|
$checkout=Join-Path $SourceRoot $path
|
||||||
|
$actual=if (Test-Path -LiteralPath (Join-Path $checkout '.git')) { (& git -C $checkout rev-parse HEAD).Trim() } else { '' }
|
||||||
|
if ($actual -ne $tree[2]) {
|
||||||
|
& git -C $SourceRoot submodule update --init --depth 1 -- $path
|
||||||
|
if ($LASTEXITCODE) { throw "Pinned OptiScaler submodule failed: $path" }
|
||||||
|
$actual=(& git -C $checkout rev-parse HEAD).Trim()
|
||||||
|
if ($actual -ne $tree[2]) { throw "Wrong submodule revision: $path" }
|
||||||
|
}
|
||||||
|
$submodules+=(' '+$actual+' '+$path)
|
||||||
|
}
|
||||||
if (!$BuildToolsRoot -and (Test-Path -LiteralPath (Join-Path $repo '.tools/vs2022/MSBuild/Current/Bin/MSBuild.exe'))) {
|
if (!$BuildToolsRoot -and (Test-Path -LiteralPath (Join-Path $repo '.tools/vs2022/MSBuild/Current/Bin/MSBuild.exe'))) {
|
||||||
$BuildToolsRoot = Join-Path $repo '.tools/vs2022'
|
$BuildToolsRoot = Join-Path $repo '.tools/vs2022'
|
||||||
}
|
}
|
||||||
@@ -72,7 +87,7 @@ try {
|
|||||||
buildTools=$BuildToolsRoot; msbuildVersion=(& $msbuild -version -nologo | Select-Object -Last 1);
|
buildTools=$BuildToolsRoot; msbuildVersion=(& $msbuild -version -nologo | Select-Object -Last 1);
|
||||||
patches=@($patches | ForEach-Object { @{name=$_.Name; sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash} });
|
patches=@($patches | ForEach-Object { @{name=$_.Name; sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash} });
|
||||||
dllSha256=(Get-FileHash -LiteralPath (Join-Path $InstallRoot 'OptiScaler.dll') -Algorithm SHA256).Hash;
|
dllSha256=(Get-FileHash -LiteralPath (Join-Path $InstallRoot 'OptiScaler.dll') -Algorithm SHA256).Hash;
|
||||||
submodules=@(& git -C $SourceRoot submodule status)}
|
submodules=$submodules}
|
||||||
$metadata | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $InstallRoot 'build-info.json') -Encoding UTF8
|
$metadata | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $InstallRoot 'build-info.json') -Encoding UTF8
|
||||||
Write-Host "Built OptiScaler with external Windows d4r backend: $InstallRoot"
|
Write-Host "Built OptiScaler with external Windows d4r backend: $InstallRoot"
|
||||||
} finally { $env:PATH = $previousPath }
|
} finally { $env:PATH = $previousPath }
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Parse completed diagnostic records. Empty streams are valid, including games
|
||||||
|
# that refuse a debugger before initializing the upscaler.
|
||||||
|
function Get-D4RGameSummary {
|
||||||
|
param([AllowEmptyString()][string]$Stdout='', [AllowEmptyString()][string]$Stderr='',
|
||||||
|
[AllowEmptyString()][string]$Debugger='', [int]$Preset=11, [double]$RunSeconds=0,
|
||||||
|
[bool]$ValidateOutput=$false, $GameCrash=$null)
|
||||||
|
$gameExit=[regex]::Match($Debugger, 'EXIT code=0x([0-9a-f]+)')
|
||||||
|
$exitCode=if ($gameExit.Success) { '0x'+$gameExit.Groups[1].Value } else { 'diagnostic_timeout' }
|
||||||
|
$frames=[regex]::Matches($Stdout, '(?m)^D4R_FRAME cpu_frame_copies=([0-9]+) frame_age=([0-9]+) interop_ngx_ms=([0-9.]+)\r?$')
|
||||||
|
$checks=[regex]::Matches($Stdout, '(?m)^D4R_OUTPUT_VALIDATION elements=([0-9]+) nan=([0-9]+) inf=([0-9]+) diagnostics_cpu_bytes=8\r?$')
|
||||||
|
$launches=[regex]::Matches($Stderr, '\[d4r-launch\] kernel="([^"]+)" backend=(native|translated)')
|
||||||
|
$kernels=@($launches | ForEach-Object { $_.Groups[1].Value+' '+$_.Groups[2].Value } | Group-Object | ForEach-Object {
|
||||||
|
$parts=$_.Name.Split(' '); @{kernel=$parts[0]; backend=$parts[1]; launches=$_.Count}
|
||||||
|
})
|
||||||
|
$capabilities=@([regex]::Matches($Stdout, '(?m)^D4R_CAPABILITIES available=(-?[0-9]+) feature_init=(0x[0-9a-f]+) needs_driver=(-?[0-9]+)\r?$') |
|
||||||
|
ForEach-Object { $_.Groups[2].Value } | Select-Object -Unique)
|
||||||
|
$session=if ($frames.Count) { 'completed-dlss-frames' }
|
||||||
|
elseif ($capabilities -contains '0xbad00004') { 'ngx-feature-not-found' }
|
||||||
|
elseif ($capabilities.Count -and $capabilities -ne '0x00000001') { 'ngx-capability-failure' }
|
||||||
|
elseif ($exitCode -eq '0x0') { 'process-exited-without-dlss-frames' }
|
||||||
|
elseif ($exitCode -eq 'diagnostic_timeout') { 'diagnostic-timeout-without-dlss-frames' }
|
||||||
|
else { 'process-failed-before-dlss-frames' }
|
||||||
|
return [ordered]@{exitCode=$exitCode; session=$session; featureInitResults=$capabilities;
|
||||||
|
runSeconds=$RunSeconds; preset=$Preset; gameCrash=$GameCrash;
|
||||||
|
nativeLaunches=([regex]::Matches($Stderr, '\[d4r-launch\].*backend=native')).Count;
|
||||||
|
completedFrames=$frames.Count; outputValidationRequested=$ValidateOutput;
|
||||||
|
outputGpuChecks=$checks.Count; kernels=$kernels;
|
||||||
|
nonfiniteOutputs=@($checks | Where-Object { $_.Groups[2].Value -ne '0' -or $_.Groups[3].Value -ne '0' }).Count;
|
||||||
|
previousFrameOutputs=@($frames | Where-Object { $_.Groups[2].Value -ne '0' }).Count;
|
||||||
|
cpuImageCopyFrames=@($frames | Where-Object { $_.Groups[1].Value -ne '0' }).Count;
|
||||||
|
failures=([regex]::Matches($Stderr, 'D4R_[A-Z0-9_]*FAILURE\b')).Count}
|
||||||
|
}
|
||||||
@@ -66,6 +66,7 @@ if ($entries.Count -ne 16) { throw "Expected 11 K and 5 M native objects; found
|
|||||||
Set-Content -LiteralPath (Join-Path $PackageRoot 'd4r/native/d4r-kernels.txt') -Encoding ASCII
|
Set-Content -LiteralPath (Join-Path $PackageRoot 'd4r/native/d4r-kernels.txt') -Encoding ASCII
|
||||||
$stagedFiles.Add('d4r/native/d4r-kernels.txt')
|
$stagedFiles.Add('d4r/native/d4r-kernels.txt')
|
||||||
Stage (Join-Path $repo 'scripts/windows/windows-game.ps1') 'windows-game.ps1'
|
Stage (Join-Path $repo 'scripts/windows/windows-game.ps1') 'windows-game.ps1'
|
||||||
|
Stage (Join-Path $repo 'scripts/windows/game-summary.ps1') 'game-summary.ps1'
|
||||||
Stage (Join-Path $repo 'scripts/windows/gpu-target.ps1') 'gpu-target.ps1'
|
Stage (Join-Path $repo 'scripts/windows/gpu-target.ps1') 'gpu-target.ps1'
|
||||||
Stage (Join-Path $repo 'scripts/windows/gpu-preflight.ps1') 'gpu-preflight.ps1'
|
Stage (Join-Path $repo 'scripts/windows/gpu-preflight.ps1') 'gpu-preflight.ps1'
|
||||||
Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'gpu-targets.json'
|
Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'gpu-targets.json'
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ foreach ($gpu in Get-D4RGpuTargets) {
|
|||||||
if (!$baseline) { $baseline=$metadata }
|
if (!$baseline) { $baseline=$metadata }
|
||||||
if ($metadata.dlssSha256 -ne $baseline.dlssSha256 -or $metadata.zludaBuild.sourceCommit -ne $baseline.zludaBuild.sourceCommit) { throw 'Input packages do not use the same validated dependencies.' }
|
if ($metadata.dlssSha256 -ne $baseline.dlssSha256 -or $metadata.zludaBuild.sourceCommit -ne $baseline.zludaBuild.sourceCommit) { throw 'Input packages do not use the same validated dependencies.' }
|
||||||
}
|
}
|
||||||
foreach ($name in @('windows-game.ps1','gpu-target.ps1','gpu-preflight.ps1')) {
|
foreach ($name in @('windows-game.ps1','game-summary.ps1','gpu-target.ps1','gpu-preflight.ps1')) {
|
||||||
$entry=Stage (Join-Path $PSScriptRoot $name) "files/common/$name"
|
$entry=Stage (Join-Path $PSScriptRoot $name) "files/common/$name"
|
||||||
$common+=@{path=$name; sha256=$entry.sha256; version=$entry.version}
|
$common+=@{path=$name; sha256=$entry.sha256; version=$entry.version}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
param(
|
param(
|
||||||
[ValidateSet('run','install','restore')][string]$Action='run',
|
[ValidateSet('run','install','restore')][string]$Action='run',
|
||||||
[ValidateSet(11,13)][int]$Preset=11,
|
[ValidateSet(11,13)][int]$Preset=11,
|
||||||
[string]$GameExe, [string]$NgxCore, [string]$DlssDll
|
[string]$GameExe, [string]$NgxCore, [string]$DlssDll,
|
||||||
|
[switch]$CaptureExceptions
|
||||||
)
|
)
|
||||||
$ErrorActionPreference='Stop'
|
$ErrorActionPreference='Stop'
|
||||||
$root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
$root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
|
||||||
@@ -126,7 +127,7 @@ try {
|
|||||||
Write-Host 'In the game: select DLSS if available; otherwise select FSR/XeSS to let OptiScaler intercept it.'
|
Write-Host 'In the game: select DLSS if available; otherwise select FSR/XeSS to let OptiScaler intercept it.'
|
||||||
Write-Host 'The first launch compiles shaders and can take several minutes. Then play for 30 seconds and EXIT the game normally.'
|
Write-Host 'The first launch compiles shaders and can take several minutes. Then play for 30 seconds and EXIT the game normally.'
|
||||||
& (Join-Path $selectedPackage 'windows-game.ps1') -Action $Action -GameExe $GameExe -NgxCore $NgxCore -DlssDll $DlssDll `
|
& (Join-Path $selectedPackage 'windows-game.ps1') -Action $Action -GameExe $GameExe -NgxCore $NgxCore -DlssDll $DlssDll `
|
||||||
-Preset $Preset -ValidateOutput -CaptureExceptions -OutputDirectory $output
|
-Preset $Preset -ValidateOutput -CaptureExceptions:$CaptureExceptions -OutputDirectory $output
|
||||||
if ($Action -eq 'install') { $status.status='installed-only' }
|
if ($Action -eq 'install') { $status.status='installed-only' }
|
||||||
else {
|
else {
|
||||||
$summary=Get-Content -LiteralPath (Join-Path $output 'summary.json') -Raw | ConvertFrom-Json
|
$summary=Get-Content -LiteralPath (Join-Path $output 'summary.json') -Raw | ConvertFrom-Json
|
||||||
@@ -143,7 +144,13 @@ try {
|
|||||||
@($required).Count -eq $(if ($Preset -eq 11) { 11 } else { 5 }) -and
|
@($required).Count -eq $(if ($Preset -eq 11) { 11 } else { 5 }) -and
|
||||||
$status.missingNativeKernels.Count -eq 0 -and $status.translatedNativeKernels.Count -eq 0
|
$status.missingNativeKernels.Count -eq 0 -and $status.translatedNativeKernels.Count -eq 0
|
||||||
$status.hardwareValidationCompleted=[bool]$passed
|
$status.hardwareValidationCompleted=[bool]$passed
|
||||||
$status.status=if ($passed) { 'backend-checks-passed-image-still-needs-user-review' } else { 'backend-checks-failed-or-no-dlss-frames' }
|
$status.status=if ($passed) { 'backend-checks-passed-image-still-needs-user-review' }
|
||||||
|
elseif ($summary.completedFrames -eq 0 -and $summary.exitCode -eq '0x0' -and $summary.failures -eq 0) { 'inconclusive-process-exited-without-dlss-frames' }
|
||||||
|
else { 'backend-checks-failed-or-no-dlss-frames' }
|
||||||
|
$status.session=$summary.session
|
||||||
|
if ($status.status -eq 'inconclusive-process-exited-without-dlss-frames') {
|
||||||
|
Write-Host 'The launched process exited without a DLSS frame. A Steam/launcher restart is not tracked by this test. Keep Steam open and select the actual game executable. Send the ZIP if it restarts again.' -ForegroundColor Yellow
|
||||||
|
}
|
||||||
Write-Host $(if ($passed) { 'Backend checks PASSED. Please also report whether the image looked correct.' } else { 'Test did not pass. Send the diagnostic ZIP; do not guess from the FPS.' }) -ForegroundColor $(if ($passed) { 'Green' } else { 'Yellow' })
|
Write-Host $(if ($passed) { 'Backend checks PASSED. Please also report whether the image looked correct.' } else { 'Test did not pass. Send the diagnostic ZIP; do not guess from the FPS.' }) -ForegroundColor $(if ($passed) { 'Green' } else { 'Yellow' })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@@ -163,4 +170,4 @@ try {
|
|||||||
Write-Host 'Also tell us: GPU model, game name, K or M, and whether the image was correct.'
|
Write-Host 'Also tell us: GPU model, game name, K or M, and whether the image was correct.'
|
||||||
Write-Host 'Close the game before running RESTORE-GAME.cmd.'
|
Write-Host 'Close the game before running RESTORE-GAME.cmd.'
|
||||||
}
|
}
|
||||||
if ($status.status -eq 'failed' -or $status.status -eq 'backend-checks-failed-or-no-dlss-frames') { exit 1 }
|
if ($status.status -eq 'failed' -or $status.status -eq 'backend-checks-failed-or-no-dlss-frames' -or $status.status.StartsWith('inconclusive-')) { exit 1 }
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
[CmdletBinding()]
|
||||||
|
param([string]$LogRoot, [string]$OutputDirectory)
|
||||||
|
$ErrorActionPreference='Stop'
|
||||||
|
. (Join-Path $PSScriptRoot 'game-summary.ps1')
|
||||||
|
$cases=@(
|
||||||
|
@{name='empty-streams-debugger-refused'; stdout=''; stderr=''; debugger='EXIT code=0xdeadc0de'; session='process-failed-before-dlss-frames'},
|
||||||
|
@{name='launcher-exit'; stdout=''; stderr=''; debugger='EXIT code=0x0'; session='process-exited-without-dlss-frames'},
|
||||||
|
@{name='feature-not-found'; stdout='D4R_CAPABILITIES available=0 feature_init=0xbad00004 needs_driver=0'; stderr='D4R_WINDOWS_FAILURE unavailable'; debugger='EXIT code=0xc0000409'; session='ngx-feature-not-found'},
|
||||||
|
@{name='complete-frame'; stdout="D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms=12.4`nD4R_OUTPUT_VALIDATION elements=3 nan=0 inf=0 diagnostics_cpu_bytes=8";
|
||||||
|
stderr='[d4r-launch] kernel="dltss_pwin_enc0_layer" backend=native'; debugger='EXIT code=0x0'; session='completed-dlss-frames'},
|
||||||
|
@{name='truncated-frame'; stdout='D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms='; stderr=''; debugger=''; session='diagnostic-timeout-without-dlss-frames'}
|
||||||
|
)
|
||||||
|
$results=@()
|
||||||
|
foreach ($case in $cases) {
|
||||||
|
$summary=Get-D4RGameSummary -Stdout $case.stdout -Stderr $case.stderr -Debugger $case.debugger
|
||||||
|
if ($summary.session -ne $case.session) { throw "Wrong session classification: $($case.name)" }
|
||||||
|
if ($case.name -eq 'complete-frame') {
|
||||||
|
if ($summary.completedFrames -ne 1 -or $summary.outputGpuChecks -ne 1 -or $summary.nativeLaunches -ne 1 -or
|
||||||
|
$summary.nonfiniteOutputs -or $summary.previousFrameOutputs -or $summary.cpuImageCopyFrames) { throw 'Complete frame counters are wrong.' }
|
||||||
|
} elseif ($summary.completedFrames -ne 0) { throw 'A failed or incomplete run was counted as a frame.' }
|
||||||
|
$results+=@{case=$case.name; passed=$true; summary=$summary}
|
||||||
|
}
|
||||||
|
if ($LogRoot) {
|
||||||
|
foreach ($entry in @{ 'acbf-k'='process-failed-before-dlss-frames'; 'cyberpunk-k'='ngx-feature-not-found';
|
||||||
|
'cyberpunk-m'='ngx-feature-not-found'; 'sm2-k'='process-exited-without-dlss-frames' }.GetEnumerator()) {
|
||||||
|
$dir=Get-ChildItem -LiteralPath (Join-Path $LogRoot $entry.Key) -Directory | Select-Object -First 1
|
||||||
|
$summary=Get-D4RGameSummary -Stdout ([IO.File]::ReadAllText((Join-Path $dir.FullName 'd4r.stdout.log'))) `
|
||||||
|
-Stderr ([IO.File]::ReadAllText((Join-Path $dir.FullName 'd4r.stderr.log'))) `
|
||||||
|
-Debugger ([IO.File]::ReadAllText((Join-Path $dir.FullName 'debugger.log')))
|
||||||
|
if ($summary.session -ne $entry.Value -or $summary.completedFrames -ne 0 -or $summary.nativeLaunches -ne 0) { throw "Unexpected classification for actual report $($entry.Key)" }
|
||||||
|
$results+=@{case='issue-10-'+$entry.Key; passed=$true; summary=$summary}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($OutputDirectory) {
|
||||||
|
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
|
||||||
|
$results | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary-parser.json') -Encoding UTF8
|
||||||
|
}
|
||||||
|
Write-Host "PASS GAME_SUMMARY cases=$($results.Count)"
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
# Reproduce numeric NGX feature discovery without launching or modifying a game.
|
||||||
|
# The private NVIDIA DLL staging directory is deleted; reports contain logs only.
|
||||||
|
[CmdletBinding()]
|
||||||
|
param([Parameter(Mandatory=$true)][string]$DiagnosticRoot,
|
||||||
|
[Parameter(Mandatory=$true)][string]$HipRoot,
|
||||||
|
[Parameter(Mandatory=$true)][string]$ZludaRoot,
|
||||||
|
[Parameter(Mandatory=$true)][string]$NativeRoot,
|
||||||
|
[Parameter(Mandatory=$true)][string]$OptiScalerDll,
|
||||||
|
[Parameter(Mandatory=$true)][string]$NgxCore,
|
||||||
|
[Parameter(Mandatory=$true)][string]$DlssDll,
|
||||||
|
[Parameter(Mandatory=$true)][string]$OutputDirectory,
|
||||||
|
[UInt64]$ApplicationId=100152211)
|
||||||
|
$ErrorActionPreference='Stop'
|
||||||
|
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
|
||||||
|
foreach ($name in @('DiagnosticRoot','HipRoot','ZludaRoot','NativeRoot','OptiScalerDll','NgxCore','DlssDll')) {
|
||||||
|
Set-Variable -Name $name -Value ((Get-Item -LiteralPath (Get-Variable -Name $name -ValueOnly)).FullName)
|
||||||
|
}
|
||||||
|
$arch=Get-D4RGpuTarget $DiagnosticRoot
|
||||||
|
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
|
||||||
|
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
|
||||||
|
$runtime=Join-Path ([IO.Path]::GetTempPath()) ('d4r-feature-layout-'+[Guid]::NewGuid().ToString('N'))
|
||||||
|
$settings=@{HIP_PATH=$HipRoot; PATH="$HipRoot\bin;$ZludaRoot;$env:PATH";
|
||||||
|
D4R_NVAPI_BACKEND=(Join-Path $ZludaRoot 'nvapi64.dll'); ZLUDA_CUDA_LIB=(Join-Path $ZludaRoot 'nvcuda.dll');
|
||||||
|
D4R_ZLUDA_NATIVE_DIR=$NativeRoot; D4R_ZLUDA_VERBOSE='1';
|
||||||
|
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_F16_REFERENCE='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0';
|
||||||
|
D4R_VALIDATE_OUTPUT='1'; D4R_DIAG_DIR=$null; ZLUDA_LOG_DIR=$null; D4R_FORMAT_MODULE=$null;
|
||||||
|
D4R_ASYNC_INTEROP=$null; D4R_BATCH_INPUT_COPIES=$null; D4R_D3D12_COMMAND_BACKEND=$null}
|
||||||
|
$old=@{}; $results=@()
|
||||||
|
try {
|
||||||
|
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
|
||||||
|
foreach ($dir in @('app','d4r','d4r/vendor')) { New-Item -ItemType Directory -Force (Join-Path $runtime $dir) | Out-Null }
|
||||||
|
$exe=Join-Path $runtime 'app/d4r_d3d12_dlss_probe.exe'
|
||||||
|
$shim=Join-Path $runtime 'd4r/_nvngx.dll'
|
||||||
|
$core=Join-Path $runtime 'd4r/vendor/_nvngx.dll'
|
||||||
|
$feature=Join-Path $runtime 'd4r/vendor/nvngx_dlss.dll'
|
||||||
|
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot 'bin/d4r_d3d12_dlss_probe.exe') -Destination $exe
|
||||||
|
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot 'bin/d4r_nvngx.dll') -Destination $shim
|
||||||
|
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot "bin/pixel_convert_${arch}.hsaco") -Destination (Split-Path $shim)
|
||||||
|
Copy-Item -LiteralPath $NgxCore -Destination $core
|
||||||
|
Copy-Item -LiteralPath $DlssDll -Destination $feature
|
||||||
|
$opti=Join-Path $runtime 'app/OptiScaler.dll'
|
||||||
|
Copy-Item -LiteralPath $OptiScalerDll -Destination $opti
|
||||||
|
$cases=@(@{name='vendor-only-negative'; preset=11; frontend='d4r'; expectedExit=4},
|
||||||
|
@{name='optiscaler-vendor-only-negative'; preset=11; frontend='optiscaler'; expectedExit=4},
|
||||||
|
@{name='caller-dll-k'; preset=11; frontend='d4r'; expectedExit=0},
|
||||||
|
@{name='optiscaler-caller-k'; preset=11; frontend='optiscaler'; expectedExit=0},
|
||||||
|
@{name='optiscaler-caller-m'; preset=13; frontend='optiscaler'; expectedExit=0})
|
||||||
|
foreach ($case in $cases) {
|
||||||
|
$out=Join-Path $OutputDirectory $case.name
|
||||||
|
New-Item -ItemType Directory -Force $out | Out-Null
|
||||||
|
if ($case.expectedExit -eq 0) {
|
||||||
|
$feature=Join-Path $runtime 'd4r/nvngx_dlss.dll'
|
||||||
|
if (!(Test-Path -LiteralPath $feature)) { Copy-Item -LiteralPath $DlssDll -Destination $feature }
|
||||||
|
}
|
||||||
|
$env:D4R_DIAG_DIR=$out; $env:ZLUDA_LOG_DIR=Join-Path $out 'zluda-trace'
|
||||||
|
$env:D4R_FORMAT_MODULE=Join-Path $runtime "d4r/pixel_convert_${arch}.hsaco"
|
||||||
|
$module=if ($case.frontend -eq 'optiscaler') { $opti } else { $shim }
|
||||||
|
if ($case.frontend -eq 'optiscaler') {
|
||||||
|
@"
|
||||||
|
[Upscalers]
|
||||||
|
Dx12Upscaler=dlss
|
||||||
|
[FrameGen]
|
||||||
|
Enabled=false
|
||||||
|
FGInput=nofg
|
||||||
|
FGOutput=nofg
|
||||||
|
[DLSS]
|
||||||
|
Enabled=true
|
||||||
|
AllowExternalBackend=true
|
||||||
|
RenderPresetOverride=true
|
||||||
|
RenderPresetForAll=$($case.preset)
|
||||||
|
UseGenericAppIdWithDlss=false
|
||||||
|
[Libraries]
|
||||||
|
NvngxPath=$(Split-Path $shim)
|
||||||
|
NvngxDlssPath=$(Split-Path $feature)
|
||||||
|
NvngxFeaturePath=$(Split-Path $feature)
|
||||||
|
[Hotfix]
|
||||||
|
RestoreComputeSignature=false
|
||||||
|
RestoreGraphicSignature=false
|
||||||
|
ExtendedStateRestore=false
|
||||||
|
[Log]
|
||||||
|
LogToFile=true
|
||||||
|
LogLevel=0
|
||||||
|
[Menu]
|
||||||
|
DisableSplash=true
|
||||||
|
"@ | Set-Content -LiteralPath (Join-Path $runtime 'app/OptiScaler.ini') -Encoding UTF8
|
||||||
|
}
|
||||||
|
$arguments=@('--hip-root',$HipRoot,'--cuda-dll',(Join-Path $ZludaRoot 'nvcuda.dll'),
|
||||||
|
'--module',$module,'--ngx-core',$core,'--dlss-dll',$feature,
|
||||||
|
'--nvapi-dll',(Join-Path $DiagnosticRoot 'nvapi-compat/nvapi64.dll'),
|
||||||
|
'--ngx-app-id',"$ApplicationId",'--ngx-abi','driver','--ngx-frontend',$case.frontend,
|
||||||
|
'--interop-mode','command-list','--iterations','3','--preset',"$($case.preset)")
|
||||||
|
$info=New-Object Diagnostics.ProcessStartInfo
|
||||||
|
# Capture harness faults outside OptiScaler's loader hooks. Games use
|
||||||
|
# the no-debug launcher by default; this developer reproducer is separate.
|
||||||
|
$arguments=@('--output-directory',$out,'--',$exe)+$arguments
|
||||||
|
$info.FileName=Join-Path $DiagnosticRoot 'bin/d4r_debug_launcher.exe'; $info.WorkingDirectory=Split-Path $exe
|
||||||
|
$info.Arguments=(@($arguments | ForEach-Object { if ($_.Contains('"')) { throw 'Unsupported quote in test path.' }; '"'+$_+'"' }) -join ' ')
|
||||||
|
$info.UseShellExecute=$false; $info.CreateNoWindow=$true; $info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
|
||||||
|
foreach ($key in $settings.Keys) { if (![Environment]::GetEnvironmentVariable($key,'Process')) { $info.EnvironmentVariables.Remove($key) } }
|
||||||
|
$process=New-Object Diagnostics.Process; $process.StartInfo=$info
|
||||||
|
try {
|
||||||
|
[void]$process.Start(); $stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
|
||||||
|
if (!$process.WaitForExit(240000)) { $process.Kill(); $process.WaitForExit(); throw "NGX layout test timed out: $($case.name)" }
|
||||||
|
$log=$stdout.GetAwaiter().GetResult(); $errorLog=$stderr.GetAwaiter().GetResult()
|
||||||
|
[IO.File]::WriteAllText((Join-Path $out 'stdout.log'),$log)
|
||||||
|
[IO.File]::WriteAllText((Join-Path $out 'stderr.log'),$errorLog)
|
||||||
|
if ($process.ExitCode -ne $case.expectedExit) { throw "Unexpected exit $($process.ExitCode): $($case.name), see $out" }
|
||||||
|
if ($case.expectedExit) {
|
||||||
|
if ($log -notmatch 'D4R_CAPABILITIES available=0 feature_init=0xbad00004' -or $log -match 'D4R_FRAME ') { throw 'Old vendor-only layout did not reproduce FeatureNotFound.' }
|
||||||
|
if ($case.frontend -eq 'optiscaler' -and $errorLog -notmatch 'FAIL D3D12_DLSS D3D12 Init NGX=') { throw 'OptiScaler swallowed the numeric backend initialization failure.' }
|
||||||
|
} else {
|
||||||
|
if ($log -notmatch 'D4R_CAPABILITIES available=1 feature_init=0x00000001 needs_driver=0' -or
|
||||||
|
([regex]::Matches($log,'D3D12_OUTPUT preset=\d+ frame=\d+ finite=1')).Count -ne 3 -or
|
||||||
|
([regex]::Matches($log,'D4R_OUTPUT_VALIDATION elements=\d+ nan=0 inf=0 diagnostics_cpu_bytes=8')).Count -ne 3 -or
|
||||||
|
$log -notmatch 'PASS D3D12_DLSS .*fast_path_cpu_copies=0 frame_age=0' -or $errorLog -match 'D4R_WINDOWS_FAILURE') { throw 'Corrected feature layout did not complete finite zero-copy frames.' }
|
||||||
|
$required=@(Get-Content -LiteralPath (Join-Path $NativeRoot 'd4r-kernels.txt') | Where-Object {
|
||||||
|
if ($case.preset -eq 11) { $_ -match '^dltss_pwin_' } else { $_ -match '^rrlite_' }
|
||||||
|
} | ForEach-Object { $_.Split(' ')[0] })
|
||||||
|
if ($required.Count -ne $(if ($case.preset -eq 11) { 11 } else { 5 })) { throw 'Incomplete native manifest.' }
|
||||||
|
foreach ($kernel in $required) {
|
||||||
|
if ($errorLog -notmatch ('\[d4r-launch\] kernel="'+[regex]::Escape($kernel)+'" backend=native') -or
|
||||||
|
$errorLog -match ('\[d4r-launch\] kernel="'+[regex]::Escape($kernel)+'" backend=translated')) { throw "Missing native network execution: $kernel" }
|
||||||
|
}
|
||||||
|
if ($case.frontend -eq 'd4r' -and $log -notmatch 'D3D12_REQUIREMENTS warp_supported=0 enumeration_success=1') { throw 'WARP adapter enumeration regression failed.' }
|
||||||
|
}
|
||||||
|
$results+=@{case=$case.name; passed=$true; expectedExit=$case.expectedExit; application=$ApplicationId; preset=$case.preset; architecture=$arch}
|
||||||
|
Write-Host "PASS NGX_FEATURE_LAYOUT $($case.name)"
|
||||||
|
} finally {
|
||||||
|
if ($case.frontend -eq 'optiscaler') {
|
||||||
|
Get-ChildItem -LiteralPath (Split-Path $exe) -Filter '*.log' -File | ForEach-Object {
|
||||||
|
Copy-Item -LiteralPath $_.FullName -Destination $out -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$process.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ($frame=0; $frame -lt 3; $frame++) {
|
||||||
|
$direct=[IO.File]::ReadAllBytes((Join-Path $OutputDirectory "caller-dll-k/output-$frame.rgba16f"))
|
||||||
|
$frontend=[IO.File]::ReadAllBytes((Join-Path $OutputDirectory "optiscaler-caller-k/output-$frame.rgba16f"))
|
||||||
|
if ($direct.Length -ne $frontend.Length -or $direct.Length -ne 512*288*8) { throw 'RGB comparison dimensions differ.' }
|
||||||
|
for ($pixel=0; $pixel -lt $direct.Length; $pixel+=8) {
|
||||||
|
if (([BitConverter]::ToUInt64($direct,$pixel) -band [UInt64]0xffffffffffff) -ne
|
||||||
|
([BitConverter]::ToUInt64($frontend,$pixel) -band [UInt64]0xffffffffffff)) { throw "K frontend RGB mismatch: frame=$frame offset=$pixel" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$results+=@{case='k-direct-optiscaler-rgb'; passed=$true; frames=3; rgbByteExact=$true; maxAbsoluteError=0; maxRelativeError=0}
|
||||||
|
Write-Host 'PASS NGX_FEATURE_LAYOUT k_direct_optiscaler_rgb exact=1 max_abs=0 max_rel=0'
|
||||||
|
} finally {
|
||||||
|
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
|
||||||
|
$results | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'feature-layout.json') -Encoding UTF8
|
||||||
|
$resolved=[IO.Path]::GetFullPath($runtime)
|
||||||
|
$temp=[IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\')+'\'
|
||||||
|
if (!$resolved.StartsWith($temp,[StringComparison]::OrdinalIgnoreCase) -or [IO.Path]::GetFileName($resolved) -notmatch '^d4r-feature-layout-[0-9a-f]{32}$') { throw 'Refusing cleanup outside private NGX staging.' }
|
||||||
|
if (Test-Path -LiteralPath $resolved) {
|
||||||
|
foreach ($attempt in 1..10) {
|
||||||
|
try { Remove-Item -LiteralPath $resolved -Recurse -Force; break }
|
||||||
|
catch { if ($attempt -eq 10) { throw }; Start-Sleep -Milliseconds 300 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,11 +29,15 @@ $results=@()
|
|||||||
$exe=Fixture ('space GPU '+[char]0x03a9+' test')
|
$exe=Fixture ('space GPU '+[char]0x03a9+' test')
|
||||||
$game=Split-Path $exe
|
$game=Split-Path $exe
|
||||||
$before=@{}
|
$before=@{}
|
||||||
foreach ($name in @('dxgi.dll','OptiScaler.ini')) {
|
foreach ($name in @('dxgi.dll','OptiScaler.ini','nvngx_dlss.dll')) {
|
||||||
Set-Content -LiteralPath (Join-Path $game $name) "original $name" -Encoding ASCII
|
Set-Content -LiteralPath (Join-Path $game $name) "original $name" -Encoding ASCII
|
||||||
$before[$name]=(Get-FileHash -LiteralPath (Join-Path $game $name)).Hash
|
$before[$name]=(Get-FileHash -LiteralPath (Join-Path $game $name)).Hash
|
||||||
}
|
}
|
||||||
Invoke-Child 'install' @('-Action','install','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll)
|
Invoke-Child 'install' @('-Action','install','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll)
|
||||||
|
if ((Get-FileHash -LiteralPath (Join-Path $game 'd4r/nvngx_dlss.dll')).Hash -ne (Get-FileHash -LiteralPath $DlssDll).Hash) {
|
||||||
|
throw 'Numeric NGX driver feature DLL was not staged beside the shim.'
|
||||||
|
}
|
||||||
|
if ((Get-FileHash -LiteralPath (Join-Path $game 'nvngx_dlss.dll')).Hash -ne $before['nvngx_dlss.dll']) { throw 'Original application DLSS DLL was changed.' }
|
||||||
$saved=Get-Content -LiteralPath (Join-Path $PackageRoot 'work/settings.json') -Raw | ConvertFrom-Json
|
$saved=Get-Content -LiteralPath (Join-Path $PackageRoot 'work/settings.json') -Raw | ConvertFrom-Json
|
||||||
if ($saved.game -ne $exe -or $saved.architecture -ne 'gfx1201') { throw 'GPU detection or remembered selection failed on this RX9070XT fixture.' }
|
if ($saved.game -ne $exe -or $saved.architecture -ne 'gfx1201') { throw 'GPU detection or remembered selection failed on this RX9070XT fixture.' }
|
||||||
# Restore uses remembered game selection and needs neither HIP nor NVIDIA DLLs.
|
# Restore uses remembered game selection and needs neither HIP nor NVIDIA DLLs.
|
||||||
@@ -41,6 +45,29 @@ Invoke-Child 'restore' @('-Action','restore')
|
|||||||
foreach ($name in $before.Keys) { if ((Get-FileHash -LiteralPath (Join-Path $game $name)).Hash -ne $before[$name]) { throw 'Original game bytes not restored.' } }
|
foreach ($name in $before.Keys) { if ((Get-FileHash -LiteralPath (Join-Path $game $name)).Hash -ne $before[$name]) { throw 'Original game bytes not restored.' } }
|
||||||
if (Test-Path -LiteralPath (Join-Path $game 'd4r')) { throw 'Runtime directory remains after restore.' }
|
if (Test-Path -LiteralPath (Join-Path $game 'd4r')) { throw 'Runtime directory remains after restore.' }
|
||||||
$results+=@{case='auto-gfx1201-install-remember-restore'; passed=$true; gpuKernelsExecuted=$false}
|
$results+=@{case='auto-gfx1201-install-remember-restore'; passed=$true; gpuKernelsExecuted=$false}
|
||||||
|
# A harmless child refuses attached debuggers and produces an empty stderr.
|
||||||
|
# The default launcher must allow it to exit and must report no DLSS session.
|
||||||
|
$exe=Join-Path (Join-Path $OutputDirectory 'launcher-fixture') 'Fixture.exe'
|
||||||
|
New-Item -ItemType Directory -Force (Split-Path $exe) | Out-Null
|
||||||
|
Add-Type -TypeDefinition @'
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
public static class D4RLauncherFixture {
|
||||||
|
[DllImport("kernel32.dll")] private static extern bool IsDebuggerPresent();
|
||||||
|
public static int Main(string[] args) { return IsDebuggerPresent() ? 91 : 0; }
|
||||||
|
}
|
||||||
|
'@ -OutputAssembly $exe -OutputType ConsoleApplication
|
||||||
|
Invoke-Child 'run-no-debug' @('-Action','run','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll) 1
|
||||||
|
$report=Get-ChildItem -LiteralPath (Join-Path $PackageRoot 'results') -Directory | Sort-Object Name -Descending | Select-Object -First 1
|
||||||
|
$status=Get-Content -LiteralPath (Join-Path $report.FullName 'quick-test.json') -Raw | ConvertFrom-Json
|
||||||
|
$environment=Get-Content -LiteralPath (Join-Path $report.FullName 'environment.json') -Raw | ConvertFrom-Json
|
||||||
|
if ($environment.attachedDebugger -or $status.hardwareValidationCompleted -or
|
||||||
|
$status.status -ne 'inconclusive-process-exited-without-dlss-frames' -or $status.gameSummary.exitCode -ne '0x0' -or
|
||||||
|
(Get-Item -LiteralPath (Join-Path $report.FullName 'd4r.stderr.log')).Length -ne 0) {
|
||||||
|
throw 'Default launch attaches a debugger, mishandles empty stderr or falsely validates a launcher exit.'
|
||||||
|
}
|
||||||
|
Invoke-Child 'restore-launcher-fixture' @('-Action','restore','-GameExe',$exe)
|
||||||
|
$results+=@{case='run-no-debug-empty-stderr-no-false-pass'; passed=$true; gpuKernelsExecuted=$false}
|
||||||
foreach ($case in @('wrong-core','wrong-dlss','vkd3d')) {
|
foreach ($case in @('wrong-core','wrong-dlss','vkd3d')) {
|
||||||
$exe=Fixture $case; $game=Split-Path $exe
|
$exe=Fixture $case; $game=Split-Path $exe
|
||||||
$core=if ($case -eq 'wrong-core') { Join-Path $PackageRoot 'files/targets/gfx1201/d4r/_nvngx.dll' } else { $NgxCore }
|
$core=if ($case -eq 'wrong-core') { Join-Path $PackageRoot 'files/targets/gfx1201/d4r/_nvngx.dll' } else { $NgxCore }
|
||||||
@@ -64,4 +91,4 @@ try {
|
|||||||
$results+=@{case='tampered-package'; passed=$true; rejectedBeforeGameChanges=$true; gpuKernelsExecuted=$false}
|
$results+=@{case='tampered-package'; passed=$true; rejectedBeforeGameChanges=$true; gpuKernelsExecuted=$false}
|
||||||
} finally { [IO.File]::WriteAllBytes($readme,$original) }
|
} finally { [IO.File]::WriteAllBytes($readme,$original) }
|
||||||
$results | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
$results | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
||||||
Write-Host "PASS QUICK_TEST_FIXTURES positive=1 negative=4 real_game_untouched=1 Report: $OutputDirectory"
|
Write-Host "PASS QUICK_TEST_FIXTURES cases=$($results.Count) real_game_untouched=1 Report: $OutputDirectory"
|
||||||
@@ -314,7 +314,7 @@ RenderPresetForAll=$Preset
|
|||||||
UseGenericAppIdWithDlss=false
|
UseGenericAppIdWithDlss=false
|
||||||
[Libraries]
|
[Libraries]
|
||||||
NvngxPath=$bridgeDirectory
|
NvngxPath=$bridgeDirectory
|
||||||
NvngxDlssPath=$localDlss
|
NvngxDlssPath=$ngxRuntimeDirectory
|
||||||
NvngxFeaturePath=$ngxRuntimeDirectory
|
NvngxFeaturePath=$ngxRuntimeDirectory
|
||||||
[Hotfix]
|
[Hotfix]
|
||||||
RestoreComputeSignature=false
|
RestoreComputeSignature=false
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ param(
|
|||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
|
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
|
||||||
. (Join-Path $PSScriptRoot 'gpu-preflight.ps1')
|
. (Join-Path $PSScriptRoot 'gpu-preflight.ps1')
|
||||||
|
. (Join-Path $PSScriptRoot 'game-summary.ps1')
|
||||||
if ($ProfileGpuBoundary -and !$AsyncInterop) { throw '-ProfileGpuBoundary requires -AsyncInterop.' }
|
if ($ProfileGpuBoundary -and !$AsyncInterop) { throw '-ProfileGpuBoundary requires -AsyncInterop.' }
|
||||||
if ($ProfileKernels -and $ProfileKernelsDeferred) { throw 'Choose either serializing or deferred kernel profiling.' }
|
if ($ProfileKernels -and $ProfileKernelsDeferred) { throw 'Choose either serializing or deferred kernel profiling.' }
|
||||||
if ($ProfileLegacyStream -and !$ProfileKernelsDeferred) { throw '-ProfileLegacyStream requires -ProfileKernelsDeferred.' }
|
if ($ProfileLegacyStream -and !$ProfileKernelsDeferred) { throw '-ProfileLegacyStream requires -ProfileKernelsDeferred.' }
|
||||||
@@ -144,7 +145,10 @@ if ($LocalTextureKernels) {
|
|||||||
}
|
}
|
||||||
# Private local test copies only; these are never added to the public package.
|
# Private local test copies only; these are never added to the public package.
|
||||||
InstallFile $NgxCore 'd4r/vendor/_nvngx.dll'
|
InstallFile $NgxCore 'd4r/vendor/_nvngx.dll'
|
||||||
InstallFile $DlssDll 'd4r/vendor/nvngx_dlss.dll'
|
# The numeric driver Init ABI searches the calling module's directory; it does
|
||||||
|
# not accept FeatureCommonInfo. Keep the exact local feature DLL alongside the
|
||||||
|
# d4r shim. Putting it only beside the core in vendor/ produces FeatureNotFound.
|
||||||
|
InstallFile $DlssDll 'd4r/nvngx_dlss.dll'
|
||||||
$bridge = GamePath 'd4r'
|
$bridge = GamePath 'd4r'
|
||||||
$vendor = GamePath 'd4r/vendor'
|
$vendor = GamePath 'd4r/vendor'
|
||||||
$ini = @"
|
$ini = @"
|
||||||
@@ -162,8 +166,8 @@ RenderPresetForAll=$Preset
|
|||||||
UseGenericAppIdWithDlss=false
|
UseGenericAppIdWithDlss=false
|
||||||
[Libraries]
|
[Libraries]
|
||||||
NvngxPath=$bridge
|
NvngxPath=$bridge
|
||||||
NvngxDlssPath=$vendor\nvngx_dlss.dll
|
NvngxDlssPath=$bridge
|
||||||
NvngxFeaturePath=$vendor
|
NvngxFeaturePath=$bridge
|
||||||
[Hotfix]
|
[Hotfix]
|
||||||
RestoreComputeSignature=false
|
RestoreComputeSignature=false
|
||||||
RestoreGraphicSignature=false
|
RestoreGraphicSignature=false
|
||||||
@@ -187,7 +191,7 @@ $settings = @{
|
|||||||
D4R_HIP_ROOT=(GamePath 'd4r/hip'); HIP_PATH=(GamePath 'd4r/hip');
|
D4R_HIP_ROOT=(GamePath 'd4r/hip'); HIP_PATH=(GamePath 'd4r/hip');
|
||||||
D4R_NVCUDA_DLL=(GamePath 'd4r/zluda/nvcuda.dll'); ZLUDA_CUDA_LIB=(GamePath 'd4r/zluda/nvcuda.dll');
|
D4R_NVCUDA_DLL=(GamePath 'd4r/zluda/nvcuda.dll'); ZLUDA_CUDA_LIB=(GamePath 'd4r/zluda/nvcuda.dll');
|
||||||
D4R_NVAPI_DLL=(GamePath 'd4r/nvapi/nvapi64.dll'); D4R_NVAPI_BACKEND=(GamePath 'd4r/zluda/nvapi64.dll');
|
D4R_NVAPI_DLL=(GamePath 'd4r/nvapi/nvapi64.dll'); D4R_NVAPI_BACKEND=(GamePath 'd4r/zluda/nvapi64.dll');
|
||||||
D4R_NGX_CORE=(GamePath 'd4r/vendor/_nvngx.dll'); D4R_DLSS_DLL=(GamePath 'd4r/vendor/nvngx_dlss.dll');
|
D4R_NGX_CORE=(GamePath 'd4r/vendor/_nvngx.dll'); D4R_DLSS_DLL=(GamePath 'd4r/nvngx_dlss.dll');
|
||||||
D4R_FORMAT_MODULE=(GamePath "d4r/pixel_convert_${GpuArch}.hsaco");
|
D4R_FORMAT_MODULE=(GamePath "d4r/pixel_convert_${GpuArch}.hsaco");
|
||||||
D4R_ZLUDA_NATIVE_DIR=(GamePath 'd4r/native'); D4R_D3D12_COMMAND_BACKEND='1'; D4R_ZLUDA_VERBOSE='1';
|
D4R_ZLUDA_NATIVE_DIR=(GamePath 'd4r/native'); D4R_D3D12_COMMAND_BACKEND='1'; D4R_ZLUDA_VERBOSE='1';
|
||||||
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0'; D4R_ZLUDA_WMMA_F16_REFERENCE='1';
|
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0'; D4R_ZLUDA_WMMA_F16_REFERENCE='1';
|
||||||
@@ -288,9 +292,9 @@ try {
|
|||||||
[void]$outTask.GetAwaiter().GetResult(); [void]$errTask.GetAwaiter().GetResult()
|
[void]$outTask.GetAwaiter().GetResult(); [void]$errTask.GetAwaiter().GetResult()
|
||||||
$outFile.Dispose(); $outFile = $null; $errFile.Dispose(); $errFile = $null
|
$outFile.Dispose(); $outFile = $null; $errFile.Dispose(); $errFile = $null
|
||||||
foreach ($file in Get-ChildItem -LiteralPath $game -Filter 'OptiScaler*.log' -File) { Copy-Item -LiteralPath $file.FullName -Destination $OutputDirectory -Force }
|
foreach ($file in Get-ChildItem -LiteralPath $game -Filter 'OptiScaler*.log' -File) { Copy-Item -LiteralPath $file.FullName -Destination $OutputDirectory -Force }
|
||||||
$stderr = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stderr.log') -Raw
|
$stderr = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'd4r.stderr.log'))
|
||||||
$stdout = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stdout.log') -Raw
|
$stdout = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'd4r.stdout.log'))
|
||||||
$debugger = Get-Content -LiteralPath (Join-Path $OutputDirectory 'debugger.log') -Raw
|
$debugger = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'debugger.log'))
|
||||||
$gameExit = [regex]::Match($debugger, 'EXIT code=0x([0-9a-f]+)')
|
$gameExit = [regex]::Match($debugger, 'EXIT code=0x([0-9a-f]+)')
|
||||||
$gameCrash = $null
|
$gameCrash = $null
|
||||||
if ([IO.Path]::GetFileName($GameExe) -eq 'SHProto-Win64-Shipping.exe' -and $gameExit.Success -and $gameExit.Groups[1].Value -ne '0') {
|
if ([IO.Path]::GetFileName($GameExe) -eq 'SHProto-Win64-Shipping.exe' -and $gameExit.Success -and $gameExit.Groups[1].Value -ne '0') {
|
||||||
@@ -305,21 +309,8 @@ try {
|
|||||||
reason=[string]$context.FGenericCrashContext.RuntimeProperties.ErrorMessage}
|
reason=[string]$context.FGenericCrashContext.RuntimeProperties.ErrorMessage}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# A bounded stop can interrupt the last printf; count only complete records.
|
Get-D4RGameSummary -Stdout $stdout -Stderr $stderr -Debugger $debugger -Preset $Preset `
|
||||||
$frames = [regex]::Matches($stdout, '(?m)^D4R_FRAME cpu_frame_copies=([0-9]+) frame_age=([0-9]+) interop_ngx_ms=([0-9.]+)\r?$')
|
-RunSeconds $timer.Elapsed.TotalSeconds -ValidateOutput ([bool]$ValidateOutput) -GameCrash $gameCrash |
|
||||||
$checks = [regex]::Matches($stdout, '(?m)^D4R_OUTPUT_VALIDATION elements=([0-9]+) nan=([0-9]+) inf=([0-9]+) diagnostics_cpu_bytes=8\r?$')
|
|
||||||
$nonfinite = @($checks | Where-Object { $_.Groups[2].Value -ne '0' -or $_.Groups[3].Value -ne '0' }).Count
|
|
||||||
$launches = [regex]::Matches($stderr, '\[d4r-launch\] kernel="([^"]+)" backend=(native|translated)')
|
|
||||||
$kernels = @($launches | ForEach-Object { $_.Groups[1].Value + ' ' + $_.Groups[2].Value } | Group-Object | ForEach-Object {
|
|
||||||
$parts=$_.Name.Split(' '); @{kernel=$parts[0]; backend=$parts[1]; launches=$_.Count}
|
|
||||||
})
|
|
||||||
@{exitCode=$(if ($gameExit.Success) { '0x' + $gameExit.Groups[1].Value } else { 'diagnostic_timeout' }); runSeconds=$timer.Elapsed.TotalSeconds; preset=$Preset; gameCrash=$gameCrash;
|
|
||||||
nativeLaunches=([regex]::Matches($stderr, '\[d4r-launch\].*backend=native')).Count;
|
|
||||||
completedFrames=$frames.Count; outputValidationRequested=[bool]$ValidateOutput;
|
|
||||||
outputGpuChecks=$checks.Count; nonfiniteOutputs=$nonfinite; kernels=$kernels;
|
|
||||||
previousFrameOutputs=@($frames | Where-Object { $_.Groups[2].Value -ne '0' }).Count;
|
|
||||||
cpuImageCopyFrames=@($frames | Where-Object { $_.Groups[1].Value -ne '0' }).Count;
|
|
||||||
failures=([regex]::Matches($stderr, 'D4R_[A-Z0-9_]*FAILURE\b')).Count} |
|
|
||||||
ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
||||||
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath ($OutputDirectory + '.zip') -Force
|
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath ($OutputDirectory + '.zip') -Force
|
||||||
Write-Host "Game diagnostic bundle: $OutputDirectory.zip"
|
Write-Host "Game diagnostic bundle: $OutputDirectory.zip"
|
||||||
|
|||||||
@@ -218,13 +218,21 @@ int main(int argc, char** argv) {
|
|||||||
using Requirements = unsigned(*)(IDXGIAdapter*,const d4r::ngx::FeatureDiscoveryInfo*,d4r::ngx::FeatureRequirement*);
|
using Requirements = unsigned(*)(IDXGIAdapter*,const d4r::ngx::FeatureDiscoveryInfo*,d4r::ngx::FeatureRequirement*);
|
||||||
check(shim.symbol<Requirements>("NVSDK_NGX_D3D12_GetFeatureRequirements")(adapter.Get(),&discovery,&requirements),"D3D12 feature requirements");
|
check(shim.symbol<Requirements>("NVSDK_NGX_D3D12_GetFeatureRequirements")(adapter.Get(),&discovery,&requirements),"D3D12 feature requirements");
|
||||||
if (requirements.FeatureSupported != 0) throw std::runtime_error("D3D12 DLSS requirements unsupported");
|
if (requirements.FeatureSupported != 0) throw std::runtime_error("D3D12 DLSS requirements unsupported");
|
||||||
|
if (args.ngx_frontend != "optiscaler") {
|
||||||
|
ComPtr<IDXGIAdapter> warp;
|
||||||
|
dx(factory->EnumWarpAdapter(IID_PPV_ARGS(warp.GetAddressOf())), "Requirements WARP adapter");
|
||||||
|
d4r::ngx::FeatureRequirement unsupported{};
|
||||||
|
check(shim.symbol<Requirements>("NVSDK_NGX_D3D12_GetFeatureRequirements")(warp.Get(),&discovery,&unsupported),"WARP feature requirements");
|
||||||
|
if (unsupported.FeatureSupported != 4) throw std::runtime_error("WARP must report AdapterUnsupported without an initialization failure");
|
||||||
|
std::printf("D3D12_REQUIREMENTS warp_supported=0 enumeration_success=1\n");
|
||||||
|
}
|
||||||
if (args.ngx_abi == "project-legacy") {
|
if (args.ngx_abi == "project-legacy") {
|
||||||
using ProjectInit = unsigned(*)(const char*,int,const char*,const wchar_t*,ID3D12Device*,const void*,unsigned);
|
using ProjectInit = unsigned(*)(const char*,int,const char*,const wchar_t*,ID3D12Device*,const void*,unsigned);
|
||||||
check(shim.symbol<ProjectInit>("NVSDK_NGX_D3D12_Init_with_ProjectID")("24480451-f00d-face-1304-0308dabad187",0,"1.0",directory.c_str(),device.Get(),nullptr,0x15),"D3D12 legacy project Init");
|
check(shim.symbol<ProjectInit>("NVSDK_NGX_D3D12_Init_with_ProjectID")("24480451-f00d-face-1304-0308dabad187",0,"1.0",directory.c_str(),device.Get(),nullptr,0x15),"D3D12 legacy project Init");
|
||||||
} else if (args.ngx_abi == "project") {
|
} else if (args.ngx_abi == "project") {
|
||||||
using ProjectInit = unsigned(*)(const char*,int,const char*,const wchar_t*,ID3D12Device*,unsigned,const void*);
|
using ProjectInit = unsigned(*)(const char*,int,const char*,const wchar_t*,ID3D12Device*,unsigned,const void*);
|
||||||
check(shim.symbol<ProjectInit>("NVSDK_NGX_D3D12_Init_ProjectID")("24480451-f00d-face-1304-0308dabad187",0,"1.0",directory.c_str(),device.Get(),0x15,nullptr),"D3D12 project Init");
|
check(shim.symbol<ProjectInit>("NVSDK_NGX_D3D12_Init_ProjectID")("24480451-f00d-face-1304-0308dabad187",0,"1.0",directory.c_str(),device.Get(),0x15,nullptr),"D3D12 project Init");
|
||||||
} else check(shim.symbol<Init>("NVSDK_NGX_D3D12_Init_Ext")(241534723ull, directory.c_str(), device.Get(), 0x15, nullptr), "D3D12 Init");
|
} else check(shim.symbol<Init>("NVSDK_NGX_D3D12_Init_Ext")(args.ngx_app_id, directory.c_str(), device.Get(), 0x15, nullptr), "D3D12 Init");
|
||||||
auto shutdown = shim.symbol<Shutdown>("NVSDK_NGX_D3D12_Shutdown");
|
auto shutdown = shim.symbol<Shutdown>("NVSDK_NGX_D3D12_Shutdown");
|
||||||
struct ShutdownCleanup { Shutdown fn; ~ShutdownCleanup() { (void)fn(); } } shutdownCleanup{shutdown};
|
struct ShutdownCleanup { Shutdown fn; ~ShutdownCleanup() { (void)fn(); } } shutdownCleanup{shutdown};
|
||||||
void* parameters = nullptr; check(shim.symbol<Allocate>("NVSDK_NGX_D3D12_AllocateParameters")(¶meters), "AllocateParameters");
|
void* parameters = nullptr; check(shim.symbol<Allocate>("NVSDK_NGX_D3D12_AllocateParameters")(¶meters), "AllocateParameters");
|
||||||
|
|||||||
@@ -87,10 +87,13 @@ API unsigned NVSDK_NGX_D3D12_GetFeatureRequirements(IDXGIAdapter* adapter, const
|
|||||||
DXGI_ADAPTER_DESC desc{}; d4r::win::dx(adapter->GetDesc(&desc), "NGX requirements adapter");
|
DXGI_ADAPTER_DESC desc{}; d4r::win::dx(adapter->GetDesc(&desc), "NGX requirements adapter");
|
||||||
// OptiScaler can override the DXGI vendor ID. The physical HIP
|
// OptiScaler can override the DXGI vendor ID. The physical HIP
|
||||||
// architecture and full adapter LUID are the authoritative identity.
|
// architecture and full adapter LUID are the authoritative identity.
|
||||||
d4r::diag::HipApi hip(d4r::win::env_path("D4R_HIP_ROOT")); hipDeviceProp_t props{}; hip.select_architecture(-1,props,&desc.AdapterLuid);
|
d4r::diag::HipApi hip(d4r::win::env_path("D4R_HIP_ROOT")); hipDeviceProp_t props{};
|
||||||
requirements->FeatureSupported = std::memcmp(&desc.AdapterLuid,props.luid,sizeof(LUID)) ? 4u : 0u;
|
const int ordinal = hip.select_architecture(-1,props,&desc.AdapterLuid,true);
|
||||||
|
requirements->FeatureSupported = ordinal < 0 ? 4u : 0u;
|
||||||
std::strcpy(requirements->MinOSVersion,"10.0.22000.0");
|
std::strcpy(requirements->MinOSVersion,"10.0.22000.0");
|
||||||
std::printf("D4R_REQUIREMENTS feature=%u support=%u architecture=%s\n",info->FeatureID,requirements->FeatureSupported,d4r::diag::HipApi::target_arch());
|
std::printf("D4R_REQUIREMENTS feature=%u support=%u architecture=%s adapter_luid=%08lx:%08lx hip_ordinal=%d\n",
|
||||||
|
info->FeatureID,requirements->FeatureSupported,d4r::diag::HipApi::target_arch(),
|
||||||
|
static_cast<unsigned long>(desc.AdapterLuid.HighPart),static_cast<unsigned long>(desc.AdapterLuid.LowPart),ordinal);
|
||||||
return 1u;
|
return 1u;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ struct Args {
|
|||||||
std::string ngx_core, dlss_dll;
|
std::string ngx_core, dlss_dll;
|
||||||
std::string nvapi_dll;
|
std::string nvapi_dll;
|
||||||
std::string ngx_abi = "driver";
|
std::string ngx_abi = "driver";
|
||||||
|
unsigned long long ngx_app_id = 241534723ull;
|
||||||
std::string ngx_frontend = "d4r";
|
std::string ngx_frontend = "d4r";
|
||||||
std::string ngx_mode = "init";
|
std::string ngx_mode = "init";
|
||||||
unsigned preset = 11;
|
unsigned preset = 11;
|
||||||
@@ -160,6 +161,12 @@ struct Args {
|
|||||||
else if (key == "--dlss-dll") dlss_dll = value;
|
else if (key == "--dlss-dll") dlss_dll = value;
|
||||||
else if (key == "--nvapi-dll") nvapi_dll = value;
|
else if (key == "--nvapi-dll") nvapi_dll = value;
|
||||||
else if (key == "--ngx-abi") ngx_abi = value;
|
else if (key == "--ngx-abi") ngx_abi = value;
|
||||||
|
else if (key == "--ngx-app-id") {
|
||||||
|
size_t end = 0;
|
||||||
|
if (value.empty() || value[0] == '-') throw std::runtime_error("Invalid NGX application ID");
|
||||||
|
ngx_app_id = std::stoull(value, &end);
|
||||||
|
if (end != value.size()) throw std::runtime_error("Invalid NGX application ID");
|
||||||
|
}
|
||||||
else if (key == "--ngx-frontend") {
|
else if (key == "--ngx-frontend") {
|
||||||
if (value != "d4r" && value != "optiscaler") throw std::runtime_error("ngx-frontend must be d4r or optiscaler");
|
if (value != "d4r" && value != "optiscaler") throw std::runtime_error("ngx-frontend must be d4r or optiscaler");
|
||||||
ngx_frontend = value;
|
ngx_frontend = value;
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ struct HipApi {
|
|||||||
if (result != hipSuccess) throw std::runtime_error(std::string(call) + ": " + hipGetErrorString(result));
|
if (result != hipSuccess) throw std::runtime_error(std::string(call) + ": " + hipGetErrorString(result));
|
||||||
}
|
}
|
||||||
static const char* target_arch() { return D4R_TARGET_ARCH; }
|
static const char* target_arch() { return D4R_TARGET_ARCH; }
|
||||||
int select_architecture(int requested, hipDeviceProp_t& selected, const void* required_luid = nullptr) const {
|
int select_architecture(int requested, hipDeviceProp_t& selected, const void* required_luid = nullptr,
|
||||||
|
bool allow_no_match = false) const {
|
||||||
// Architecture spoofing invalidates a gfx12 correctness test.
|
// Architecture spoofing invalidates a gfx12 correctness test.
|
||||||
for (const char* name : {"HSA_OVERRIDE_GFX_VERSION", "HSA_OVERRIDE_GFX_VERSION_0"})
|
for (const char* name : {"HSA_OVERRIDE_GFX_VERSION", "HSA_OVERRIDE_GFX_VERSION_0"})
|
||||||
if (std::getenv(name)) throw std::runtime_error(std::string("Unset architecture override ") + name);
|
if (std::getenv(name)) throw std::runtime_error(std::string("Unset architecture override ") + name);
|
||||||
@@ -67,6 +68,7 @@ struct HipApi {
|
|||||||
selected = props;
|
selected = props;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (found < 0 && allow_no_match) return -1; // Capability enumeration can include Intel/WARP adapters.
|
||||||
if (found < 0) throw std::runtime_error(std::string("No selected ") + target_arch() +
|
if (found < 0) throw std::runtime_error(std::string("No selected ") + target_arch() +
|
||||||
" device for this adapter; use the package matching the actual HIP architecture (see GPU log)");
|
" device for this adapter; use the package matching the actual HIP architecture (see GPU log)");
|
||||||
require_gpu_target(selected.gcnArchName, target_arch());
|
require_gpu_target(selected.gcnArchName, target_arch());
|
||||||
|
|||||||
@@ -88,8 +88,9 @@ int main(int argc, char** argv)
|
|||||||
common.LoggingInfo = {reinterpret_cast<void*>(&ngx_log), 2, false};
|
common.LoggingInfo = {reinterpret_cast<void*>(&ngx_log), 2, false};
|
||||||
loaded_modules();
|
loaded_modules();
|
||||||
std::printf("STAGE NVSDK_NGX_CUDA_Init sdk=0x15 core=%s dlss=%s\n", args.ngx_core.c_str(), args.dlss_dll.c_str());
|
std::printf("STAGE NVSDK_NGX_CUDA_Init sdk=0x15 core=%s dlss=%s\n", args.ngx_core.c_str(), args.dlss_dll.c_str());
|
||||||
if (args.ngx_abi == "driver") check(driver_init(241534723ull, data_path.c_str(), 0x15), "NVSDK_NGX_CUDA_Init(driver ABI)");
|
std::printf("NGX_APPLICATION id=%llu\n", args.ngx_app_id);
|
||||||
else if (args.ngx_abi == "sdk") check(init(241534723ull, data_path.c_str(), &common, 0x15), "NVSDK_NGX_CUDA_Init(SDK ABI)");
|
if (args.ngx_abi == "driver") check(driver_init(args.ngx_app_id, data_path.c_str(), 0x15), "NVSDK_NGX_CUDA_Init(driver ABI)");
|
||||||
|
else if (args.ngx_abi == "sdk") check(init(args.ngx_app_id, data_path.c_str(), &common, 0x15), "NVSDK_NGX_CUDA_Init(SDK ABI)");
|
||||||
else if (args.ngx_abi == "project") check(core.symbol<ProjectInit>("NVSDK_NGX_CUDA_Init_ProjectID")(
|
else if (args.ngx_abi == "project") check(core.symbol<ProjectInit>("NVSDK_NGX_CUDA_Init_ProjectID")(
|
||||||
"24480451-f00d-face-1304-0308dabad187", 0, "1.0", data_path.c_str(), 0x15, &common), "NVSDK_NGX_CUDA_Init_ProjectID");
|
"24480451-f00d-face-1304-0308dabad187", 0, "1.0", data_path.c_str(), 0x15, &common), "NVSDK_NGX_CUDA_Init_ProjectID");
|
||||||
else throw std::runtime_error("--ngx-abi must be driver, sdk or project");
|
else throw std::runtime_error("--ngx-abi must be driver, sdk or project");
|
||||||
|
|||||||
Reference in new issue
Block a user