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
@@ -41,8 +41,23 @@ try {
|
||||
if ($LASTEXITCODE) { throw "Source patch failed: $($patch.Name)" }
|
||||
}
|
||||
}
|
||||
& git -C $SourceRoot submodule update --init --depth 1
|
||||
if ($LASTEXITCODE) { throw 'Pinned OptiScaler submodules failed.' }
|
||||
# Verify existing checkouts directly. A complete local checkout does not
|
||||
# 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'))) {
|
||||
$BuildToolsRoot = Join-Path $repo '.tools/vs2022'
|
||||
}
|
||||
@@ -72,7 +87,7 @@ try {
|
||||
buildTools=$BuildToolsRoot; msbuildVersion=(& $msbuild -version -nologo | Select-Object -Last 1);
|
||||
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;
|
||||
submodules=@(& git -C $SourceRoot submodule status)}
|
||||
submodules=$submodules}
|
||||
$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"
|
||||
} 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
|
||||
$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/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-preflight.ps1') 'gpu-preflight.ps1'
|
||||
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 ($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"
|
||||
$common+=@{path=$name; sha256=$entry.sha256; version=$entry.version}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
param(
|
||||
[ValidateSet('run','install','restore')][string]$Action='run',
|
||||
[ValidateSet(11,13)][int]$Preset=11,
|
||||
[string]$GameExe, [string]$NgxCore, [string]$DlssDll
|
||||
[string]$GameExe, [string]$NgxCore, [string]$DlssDll,
|
||||
[switch]$CaptureExceptions
|
||||
)
|
||||
$ErrorActionPreference='Stop'
|
||||
$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 '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 `
|
||||
-Preset $Preset -ValidateOutput -CaptureExceptions -OutputDirectory $output
|
||||
-Preset $Preset -ValidateOutput -CaptureExceptions:$CaptureExceptions -OutputDirectory $output
|
||||
if ($Action -eq 'install') { $status.status='installed-only' }
|
||||
else {
|
||||
$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
|
||||
$status.missingNativeKernels.Count -eq 0 -and $status.translatedNativeKernels.Count -eq 0
|
||||
$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' })
|
||||
}
|
||||
} 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 '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')
|
||||
$game=Split-Path $exe
|
||||
$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
|
||||
$before[$name]=(Get-FileHash -LiteralPath (Join-Path $game $name)).Hash
|
||||
}
|
||||
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
|
||||
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.
|
||||
@@ -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.' } }
|
||||
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}
|
||||
# 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')) {
|
||||
$exe=Fixture $case; $game=Split-Path $exe
|
||||
$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}
|
||||
} finally { [IO.File]::WriteAllBytes($readme,$original) }
|
||||
$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
|
||||
[Libraries]
|
||||
NvngxPath=$bridgeDirectory
|
||||
NvngxDlssPath=$localDlss
|
||||
NvngxDlssPath=$ngxRuntimeDirectory
|
||||
NvngxFeaturePath=$ngxRuntimeDirectory
|
||||
[Hotfix]
|
||||
RestoreComputeSignature=false
|
||||
|
||||
@@ -28,6 +28,7 @@ param(
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
|
||||
. (Join-Path $PSScriptRoot 'gpu-preflight.ps1')
|
||||
. (Join-Path $PSScriptRoot 'game-summary.ps1')
|
||||
if ($ProfileGpuBoundary -and !$AsyncInterop) { throw '-ProfileGpuBoundary requires -AsyncInterop.' }
|
||||
if ($ProfileKernels -and $ProfileKernelsDeferred) { throw 'Choose either serializing or deferred kernel profiling.' }
|
||||
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.
|
||||
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'
|
||||
$vendor = GamePath 'd4r/vendor'
|
||||
$ini = @"
|
||||
@@ -162,8 +166,8 @@ RenderPresetForAll=$Preset
|
||||
UseGenericAppIdWithDlss=false
|
||||
[Libraries]
|
||||
NvngxPath=$bridge
|
||||
NvngxDlssPath=$vendor\nvngx_dlss.dll
|
||||
NvngxFeaturePath=$vendor
|
||||
NvngxDlssPath=$bridge
|
||||
NvngxFeaturePath=$bridge
|
||||
[Hotfix]
|
||||
RestoreComputeSignature=false
|
||||
RestoreGraphicSignature=false
|
||||
@@ -187,7 +191,7 @@ $settings = @{
|
||||
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_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_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';
|
||||
@@ -288,9 +292,9 @@ try {
|
||||
[void]$outTask.GetAwaiter().GetResult(); [void]$errTask.GetAwaiter().GetResult()
|
||||
$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 }
|
||||
$stderr = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stderr.log') -Raw
|
||||
$stdout = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stdout.log') -Raw
|
||||
$debugger = Get-Content -LiteralPath (Join-Path $OutputDirectory 'debugger.log') -Raw
|
||||
$stderr = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'd4r.stderr.log'))
|
||||
$stdout = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'd4r.stdout.log'))
|
||||
$debugger = [IO.File]::ReadAllText((Join-Path $OutputDirectory 'debugger.log'))
|
||||
$gameExit = [regex]::Match($debugger, 'EXIT code=0x([0-9a-f]+)')
|
||||
$gameCrash = $null
|
||||
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}
|
||||
}
|
||||
}
|
||||
# A bounded stop can interrupt the last printf; count only complete records.
|
||||
$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?$')
|
||||
$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} |
|
||||
Get-D4RGameSummary -Stdout $stdout -Stderr $stderr -Debugger $debugger -Preset $Preset `
|
||||
-RunSeconds $timer.Elapsed.TotalSeconds -ValidateOutput ([bool]$ValidateOutput) -GameCrash $gameCrash |
|
||||
ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
|
||||
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath ($OutputDirectory + '.zip') -Force
|
||||
Write-Host "Game diagnostic bundle: $OutputDirectory.zip"
|
||||
|
||||
Reference in new issue
Block a user