Fix game startup resource lifetime and D32S8 depth-plane interop
This commit is contained in:
1 parent
19d859e43d
commit
5d33bddcd0
17 files changed
+539
-11
No files matched your search
@@ -0,0 +1,46 @@
|
||||
[CmdletBinding()]
|
||||
param([Parameter(Mandatory=$true)][int]$GameProcessId, [Parameter(Mandatory=$true)][string]$OutputPath)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
if (!('D4RWindowCapture' -as [type])) {
|
||||
Add-Type @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
public static class D4RWindowCapture {
|
||||
public delegate bool Callback(IntPtr window, IntPtr data);
|
||||
[StructLayout(LayoutKind.Sequential)] public struct Rect { public int Left, Top, Right, Bottom; }
|
||||
[DllImport("user32.dll")] public static extern bool EnumWindows(Callback callback, IntPtr data);
|
||||
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr window, out uint process);
|
||||
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr window, out Rect rect);
|
||||
[DllImport("user32.dll",CharSet=CharSet.Unicode)] public static extern int GetWindowText(IntPtr window, StringBuilder text, int count);
|
||||
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr window);
|
||||
}
|
||||
'@
|
||||
}
|
||||
$windows = [Collections.Generic.List[object]]::new()
|
||||
$callback = [D4RWindowCapture+Callback]{ param($window,$data)
|
||||
[uint32]$owner = 0
|
||||
[void][D4RWindowCapture]::GetWindowThreadProcessId($window,[ref]$owner)
|
||||
if ($owner -eq $GameProcessId) {
|
||||
$rect = [D4RWindowCapture+Rect]::new()
|
||||
[void][D4RWindowCapture]::GetWindowRect($window,[ref]$rect)
|
||||
$title = [Text.StringBuilder]::new(512)
|
||||
[void][D4RWindowCapture]::GetWindowText($window,$title,512)
|
||||
$windows.Add([pscustomobject]@{handle=$window; title=$title.ToString(); visible=[D4RWindowCapture]::IsWindowVisible($window); rect=$rect;
|
||||
area=($rect.Right-$rect.Left)*($rect.Bottom-$rect.Top)})
|
||||
}
|
||||
return $true
|
||||
}
|
||||
[void][D4RWindowCapture]::EnumWindows($callback,[IntPtr]::Zero)
|
||||
$windows | Select-Object handle,title,visible,area | Format-Table
|
||||
$chosen = $windows | Where-Object { $_.visible -and $_.area -gt 4096 } | Sort-Object area -Descending | Select-Object -First 1
|
||||
if (!$chosen) { throw "No visible game window for PID $GameProcessId" }
|
||||
$rect = $chosen.rect
|
||||
$bitmap = [Drawing.Bitmap]::new($rect.Right-$rect.Left,$rect.Bottom-$rect.Top)
|
||||
$graphics = [Drawing.Graphics]::FromImage($bitmap)
|
||||
try {
|
||||
$graphics.CopyFromScreen($rect.Left,$rect.Top,0,0,$bitmap.Size)
|
||||
$bitmap.Save([IO.Path]::GetFullPath($OutputPath),[Drawing.Imaging.ImageFormat]::Png)
|
||||
} finally { $graphics.Dispose(); $bitmap.Dispose() }
|
||||
Write-Host "Captured game window: $OutputPath"
|
||||
@@ -0,0 +1,76 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$PackageRoot, [string]$DiagnosticRoot, [string]$OptiScalerRoot,
|
||||
[string]$ZludaRoot, [string]$HipRoot, [string]$KernelKRoot, [string]$KernelMRoot
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
|
||||
$defaults = @{PackageRoot='dist/windows-rdna4-game'; DiagnosticRoot='dist/windows-rdna4-command-list';
|
||||
OptiScalerRoot='dist/optiscaler-windows-d4r'; ZludaRoot='dist/zluda-windows-f16-reference';
|
||||
HipRoot='.tools/therock-10.2.0a20260929/_rocm_sdk_core';
|
||||
KernelKRoot='build/native-k-gfx1201'; KernelMRoot='build/native-m-gfx1201'}
|
||||
foreach ($name in $defaults.Keys) {
|
||||
if (!(Get-Variable -Name $name -ValueOnly)) { Set-Variable -Name $name -Value (Join-Path $repo $defaults[$name]) }
|
||||
}
|
||||
$PackageRoot = [IO.Path]::GetFullPath($PackageRoot)
|
||||
New-Item -ItemType Directory -Force $PackageRoot | Out-Null
|
||||
$stagedFiles = [Collections.Generic.List[string]]::new()
|
||||
function Stage([string]$source, [string]$relative) {
|
||||
if (!(Test-Path -LiteralPath $source -PathType Leaf)) { throw "Required file missing: $source" }
|
||||
$destination = Join-Path $PackageRoot $relative
|
||||
New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null
|
||||
Copy-Item -LiteralPath $source -Destination $destination -Force
|
||||
$stagedFiles.Add($relative)
|
||||
}
|
||||
Stage (Join-Path $OptiScalerRoot 'OptiScaler.dll') 'OptiScaler.dll'
|
||||
Stage (Join-Path $DiagnosticRoot 'bin/d4r_nvngx.dll') 'd4r/_nvngx.dll'
|
||||
Stage (Join-Path $DiagnosticRoot 'bin/pixel_convert_gfx1201.hsaco') 'd4r/pixel_convert_gfx1201.hsaco'
|
||||
Stage (Join-Path $DiagnosticRoot 'nvapi-compat/nvapi64.dll') 'd4r/nvapi/nvapi64.dll'
|
||||
Stage (Join-Path $DiagnosticRoot 'bin/d4r_debug_launcher.exe') 'd4r/d4r_debug_launcher.exe'
|
||||
foreach ($file in @('nvcuda.dll','nvapi64.dll','libc++.dll','libunwind.dll')) { Stage (Join-Path $ZludaRoot $file) "d4r/zluda/$file" }
|
||||
foreach ($file in @('amdhip64_7.dll','amd_comgr.dll','hiprtc0717.dll','hiprtc-builtins0717.dll','rocm_kpack.dll','AMD.ROCM.Comgr.MANIFEST','.hipVersion')) {
|
||||
Stage (Join-Path $HipRoot "bin/$file") "d4r/hip/bin/$file"
|
||||
}
|
||||
$entries = @{}
|
||||
foreach ($directory in @($KernelKRoot, $KernelMRoot)) {
|
||||
foreach ($line in Get-Content -LiteralPath (Join-Path $directory 'd4r-kernels.txt')) {
|
||||
if (!$line.Trim() -or $line.StartsWith('#')) { continue }
|
||||
if ($line -notmatch '^([A-Za-z0-9_]+) ([0-9a-f]{16})$') { throw "Invalid native manifest entry: $line" }
|
||||
if ($entries.ContainsKey($Matches[1])) { throw "Duplicate native kernel: $($Matches[1])" }
|
||||
$entries[$Matches[1]] = $line
|
||||
Stage (Join-Path $directory ($Matches[1] + '.hsaco')) ('d4r/native/' + $Matches[1] + '.hsaco')
|
||||
}
|
||||
}
|
||||
if ($entries.Count -ne 16) { throw "Expected 11 K and 5 M native objects; found $($entries.Count)" }
|
||||
@('# Audited DLSS 310.9.1: K + M gfx1201 native kernels', '# Generated by package-windows-game.ps1') + @($entries.Values | Sort-Object) |
|
||||
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/capture-game-window.ps1') 'capture-game-window.ps1'
|
||||
Stage (Join-Path $repo 'scripts/windows/send-game-key.ps1') 'send-game-key.ps1'
|
||||
Stage (Join-Path $repo 'docs/windows-game.md') 'README.md'
|
||||
Stage (Join-Path $repo 'LICENSE') 'licenses/d4r.txt'
|
||||
Stage (Join-Path $OptiScalerRoot 'GPL-3.0.txt') 'licenses/OptiScaler.txt'
|
||||
Stage (Join-Path $repo 'external/ZLUDA/LICENSE-MIT') 'licenses/ZLUDA-MIT.txt'
|
||||
Stage (Join-Path $repo 'external/ZLUDA/LICENSE-APACHE') 'licenses/ZLUDA-APACHE.txt'
|
||||
Stage (Join-Path $repo 'external/ZLUDA/ext/llvm-project/LICENSE.TXT') 'licenses/LLVM.txt'
|
||||
Stage (Join-Path $repo 'external/MinHook/LICENSE.txt') 'licenses/MinHook.txt'
|
||||
Stage (Join-Path $HipRoot 'share/doc/amd_comgr/LICENSE.txt') 'licenses/amd_comgr.txt'
|
||||
Stage (Join-Path $repo 'external/clr/LICENSE.md') 'licenses/HIP-CLR.txt'
|
||||
foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/optiscaler') -Filter '*.patch') { Stage $patch.FullName ('source-patches/optiscaler/' + $patch.Name) }
|
||||
foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda') -Filter '*.patch') { Stage $patch.FullName ('source-patches/zluda/' + $patch.Name) }
|
||||
$metadata = [ordered]@{
|
||||
architecture='gfx1201'; nativeKernels=16; dlssSha256='3975567b8943c53acce397f2b72380092f84f162d00b0d2c7d08a1025c563983';
|
||||
d4rCommit=(& git -C $repo rev-parse HEAD).Trim();
|
||||
optiScaler=(Get-Content -LiteralPath (Join-Path $OptiScalerRoot 'build-info.json') -Raw | ConvertFrom-Json);
|
||||
zludaCommit=(& git -C (Join-Path $repo 'external/ZLUDA') rev-parse HEAD).Trim();
|
||||
hipRuntime='TheRock 10.2.0a20260929 / HIP 7.17.26386';
|
||||
files=@($stagedFiles | ForEach-Object { Get-Item -LiteralPath (Join-Path $PackageRoot $_) } | ForEach-Object {
|
||||
@{path=$_.FullName.Substring($PackageRoot.Length+1); sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash; version=$_.VersionInfo.FileVersion}
|
||||
})
|
||||
}
|
||||
$metadata | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath (Join-Path $PackageRoot 'package.json') -Encoding UTF8
|
||||
if (Get-ChildItem -LiteralPath $PackageRoot -Recurse -File | Where-Object { $_.Name -eq 'nvngx_dlss.dll' -or ($_.Name -eq '_nvngx.dll' -and $_.DirectoryName -ne (Join-Path $PackageRoot 'd4r')) }) {
|
||||
throw 'Proprietary NVIDIA binaries must not be in the package.'
|
||||
}
|
||||
Write-Host "Windows game development package: $PackageRoot (NVIDIA DLLs excluded)"
|
||||
@@ -0,0 +1,25 @@
|
||||
[CmdletBinding()]
|
||||
param([Parameter(Mandatory=$true)][int]$GameProcessId,
|
||||
[ValidateSet('Enter','Escape','Up','Down','Tab')][string]$Key='Enter')
|
||||
$ErrorActionPreference='Stop'
|
||||
$process=Get-Process -Id $GameProcessId -ErrorAction Stop
|
||||
if ($process.ProcessName -ne 'SHProto-Win64-Shipping') { throw 'This helper is scoped to the authorized Silent Hill 2 diagnostic.' }
|
||||
if (!('D4RGameKeys' -as [type])) {
|
||||
Add-Type @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class D4RGameKeys {
|
||||
[DllImport("user32.dll")] public static extern bool PostMessage(IntPtr window, uint message, IntPtr key, IntPtr flags);
|
||||
[DllImport("user32.dll")] public static extern uint MapVirtualKey(uint code, uint kind);
|
||||
}
|
||||
'@
|
||||
}
|
||||
$window=$process.MainWindowHandle
|
||||
if ($window -eq [IntPtr]::Zero) { throw 'Game window missing on this desktop.' }
|
||||
$codes=@{Enter=13; Escape=27; Up=38; Down=40; Tab=9}
|
||||
$code=$codes[$Key]; $scan=[D4RGameKeys]::MapVirtualKey($code,0)
|
||||
$flags=[long](1 -bor ($scan -shl 16))
|
||||
if ($Key -in @('Up','Down')) { $flags=$flags -bor 0x01000000 }
|
||||
if (![D4RGameKeys]::PostMessage($window,0x100,[IntPtr]$code,[IntPtr]$flags)) { throw 'Game key-down post failed.' }
|
||||
if (![D4RGameKeys]::PostMessage($window,0x101,[IntPtr]$code,[IntPtr]($flags -bor 0xc0000000L))) { throw 'Game key-up post failed.' }
|
||||
Write-Host "Sent $Key only to diagnostic game PID $GameProcessId."
|
||||
@@ -8,7 +8,7 @@ param(
|
||||
[string]$NgxCore = $env:D4R_NGX_CORE,
|
||||
[string]$DlssDll = $env:D4R_DLSS_DLL,
|
||||
[ValidateSet('init', 'evaluate', 'd3d12')][string]$NgxMode = 'init',
|
||||
[ValidateSet('driver','sdk','project')][string]$NgxAbi = 'driver',
|
||||
[ValidateSet('driver','sdk','project','project-legacy')][string]$NgxAbi = 'driver',
|
||||
[string]$OptiScalerDll,
|
||||
[ValidateSet(5, 11, 13)][int]$Preset = 11,
|
||||
[switch]$NgxOnly,
|
||||
@@ -17,7 +17,7 @@ param(
|
||||
[switch]$CommandListBackend,
|
||||
[switch]$CaptureExceptions,
|
||||
[switch]$EarlyIndirectProbe,
|
||||
[ValidateSet('baseline','packed','unorm')][string]$PixelProfile = 'baseline',
|
||||
[ValidateSet('baseline','packed','unorm','depth-stencil')][string]$PixelProfile = 'baseline',
|
||||
[ValidateSet('legacy','enhanced','inherited-legacy','inherited-enhanced')][string]$BarrierMode = 'legacy',
|
||||
[int]$Iterations = 32,
|
||||
[int]$TimeoutSeconds = 180
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('install','restore','run')][string]$Action = 'run',
|
||||
[Parameter(Mandatory=$true)][string]$GameExe,
|
||||
[string]$NgxCore, [string]$DlssDll,
|
||||
[ValidateSet(11,13)][int]$Preset = 11,
|
||||
[int]$RunSeconds = 0,
|
||||
[string]$DiagnosticResolution,
|
||||
[string]$CacheDirectory = $env:ZLUDA_CACHE_DIR,
|
||||
[string[]]$GameArguments = @('-dx12','-windowed','-ResX=1280','-ResY=720'),
|
||||
[string]$OutputDirectory
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$package = [IO.Path]::GetFullPath($PSScriptRoot)
|
||||
$GameExe = (Get-Item -LiteralPath $GameExe -ErrorAction Stop).FullName
|
||||
$game = Split-Path $GameExe
|
||||
$backup = Join-Path $game '.d4r-backup'
|
||||
$manifestPath = Join-Path $backup 'manifest.json'
|
||||
function GamePath([string]$relative) {
|
||||
$path = [IO.Path]::GetFullPath((Join-Path $game $relative))
|
||||
if (!$path.StartsWith($game + '\', [StringComparison]::OrdinalIgnoreCase)) { throw "Path escapes game directory: $relative" }
|
||||
return $path
|
||||
}
|
||||
if (Get-Process -Name ([IO.Path]::GetFileNameWithoutExtension($GameExe)) -ErrorAction SilentlyContinue) { throw 'Close the game before installing, restoring or running this diagnostic.' }
|
||||
if ($Action -eq 'restore') {
|
||||
if (!(Test-Path -LiteralPath $manifestPath)) { throw 'No d4r installation manifest exists.' }
|
||||
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
|
||||
foreach ($entry in $manifest.files) {
|
||||
$path = GamePath $entry.path
|
||||
if ((Test-Path -LiteralPath $path) -and (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $entry.installedHash) { throw "File changed since installation; preserved: $path" }
|
||||
}
|
||||
foreach ($entry in $manifest.files) {
|
||||
$path = GamePath $entry.path
|
||||
if ($entry.existed) { Copy-Item -LiteralPath (Join-Path $backup ('original/' + $entry.path)) -Destination $path -Force }
|
||||
elseif (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Force }
|
||||
}
|
||||
# Remove only empty directories; preserve user files and diagnostic logs.
|
||||
if (Test-Path -LiteralPath (GamePath 'd4r')) {
|
||||
Get-ChildItem -LiteralPath (GamePath 'd4r') -Directory -Recurse | Sort-Object { $_.FullName.Length } -Descending | ForEach-Object {
|
||||
if (!(Get-ChildItem -LiteralPath $_.FullName -Force)) { Remove-Item -LiteralPath $_.FullName }
|
||||
}
|
||||
if (!(Get-ChildItem -LiteralPath (GamePath 'd4r') -Force)) { Remove-Item -LiteralPath (GamePath 'd4r') }
|
||||
}
|
||||
Move-Item -LiteralPath $manifestPath -Destination (Join-Path $backup ('restored-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff') + '.json'))
|
||||
Write-Host "Original game files restored. Backups retained: $backup"
|
||||
return
|
||||
}
|
||||
if (!$NgxCore -or !$DlssDll) { throw 'Pass both local NVIDIA DLL paths with -NgxCore and -DlssDll.' }
|
||||
$NgxCore = (Get-Item -LiteralPath $NgxCore).FullName
|
||||
$DlssDll = (Get-Item -LiteralPath $DlssDll).FullName
|
||||
$metadata = Get-Content -LiteralPath (Join-Path $package 'package.json') -Raw | ConvertFrom-Json
|
||||
foreach ($file in $metadata.files) {
|
||||
if ((Get-FileHash -LiteralPath (Join-Path $package $file.path) -Algorithm SHA256).Hash -ne $file.sha256) { throw "Package file changed; rebuild package: $($file.path)" }
|
||||
}
|
||||
if ((Get-FileHash -LiteralPath $DlssDll -Algorithm SHA256).Hash -ne $metadata.dlssSha256) { throw 'DLSS DLL does not match the validated 310.9.1 native manifest. Rebuild and validate native manifests for this DLL first.' }
|
||||
$manifest = if (Test-Path -LiteralPath $manifestPath) { Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json } else { [pscustomobject]@{game=$GameExe; files=@()} }
|
||||
if ($manifest.game -ne $GameExe) { throw 'Backup manifest belongs to another executable.' }
|
||||
if (!(Test-Path -LiteralPath $manifestPath) -and (Test-Path -LiteralPath (GamePath 'd4r'))) { throw 'An existing d4r directory has no installation manifest; preserved.' }
|
||||
New-Item -ItemType Directory -Force $backup | Out-Null
|
||||
function InstallFile([string]$source, [string]$relative) {
|
||||
$path = GamePath $relative
|
||||
$entry = @($manifest.files | Where-Object path -eq $relative) | Select-Object -First 1
|
||||
if ($entry) {
|
||||
if ((Test-Path -LiteralPath $path) -and (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $entry.installedHash) { throw "Installed file changed; preserved: $path" }
|
||||
} else {
|
||||
$existed = Test-Path -LiteralPath $path
|
||||
if ($existed) {
|
||||
$original = Join-Path $backup ('original/' + $relative)
|
||||
New-Item -ItemType Directory -Force (Split-Path $original) | Out-Null
|
||||
Copy-Item -LiteralPath $path -Destination $original
|
||||
}
|
||||
$entry = [pscustomobject]@{path=$relative; existed=[bool]$existed; installedHash=''}
|
||||
$manifest.files = @($manifest.files) + @($entry)
|
||||
}
|
||||
New-Item -ItemType Directory -Force (Split-Path $path) | Out-Null
|
||||
Copy-Item -LiteralPath $source -Destination $path -Force
|
||||
$entry.installedHash = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash
|
||||
$manifest | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $manifestPath -Encoding UTF8
|
||||
}
|
||||
InstallFile (Join-Path $package 'OptiScaler.dll') 'dxgi.dll'
|
||||
foreach ($file in Get-ChildItem -LiteralPath (Join-Path $package 'd4r') -Recurse -File) { InstallFile $file.FullName $file.FullName.Substring($package.Length+1) }
|
||||
# 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'
|
||||
$bridge = GamePath 'd4r'
|
||||
$vendor = GamePath 'd4r/vendor'
|
||||
$ini = @"
|
||||
[Upscalers]
|
||||
Dx12Upscaler=dlss
|
||||
[FrameGen]
|
||||
Enabled=false
|
||||
FGInput=nofg
|
||||
FGOutput=nofg
|
||||
[DLSS]
|
||||
Enabled=true
|
||||
AllowExternalBackend=true
|
||||
RenderPresetOverride=true
|
||||
RenderPresetForAll=$Preset
|
||||
UseGenericAppIdWithDlss=false
|
||||
[Libraries]
|
||||
NvngxPath=$bridge
|
||||
NvngxDlssPath=$vendor\nvngx_dlss.dll
|
||||
NvngxFeaturePath=$vendor
|
||||
[Hotfix]
|
||||
RestoreComputeSignature=false
|
||||
RestoreGraphicSignature=false
|
||||
ExtendedStateRestore=false
|
||||
[Log]
|
||||
LogToFile=true
|
||||
LogLevel=0
|
||||
[Menu]
|
||||
DisableSplash=true
|
||||
"@
|
||||
$tempIni = Join-Path $backup 'generated-OptiScaler.ini'
|
||||
$ini | Set-Content -LiteralPath $tempIni -Encoding UTF8
|
||||
InstallFile $tempIni 'OptiScaler.ini'
|
||||
if ($Action -eq 'install') { Write-Host "Installed development backend for preset $Preset. Use -Action restore to revert."; return }
|
||||
if (!$OutputDirectory) { $OutputDirectory = Join-Path $package ('results/game-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
|
||||
$OutputDirectory = [IO.Path]::GetFullPath($OutputDirectory)
|
||||
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
|
||||
if (!$CacheDirectory) { $CacheDirectory = Join-Path $package 'cache' }
|
||||
$CacheDirectory = [IO.Path]::GetFullPath($CacheDirectory)
|
||||
$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_FORMAT_MODULE=(GamePath 'd4r/pixel_convert_gfx1201.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';
|
||||
D4R_DIAG_DIR=$OutputDirectory; ZLUDA_LOG_DIR=(Join-Path $OutputDirectory 'zluda-trace');
|
||||
ZLUDA_CACHE_DIR=$CacheDirectory; PATH=((GamePath 'd4r/hip/bin') + ';' + (GamePath 'd4r/zluda') + ';' + $env:PATH)
|
||||
}
|
||||
$old = @{}; $process = $null; $originalSettings = @()
|
||||
try {
|
||||
if ($DiagnosticResolution) {
|
||||
if ([IO.Path]::GetFileName($GameExe) -ne 'SHProto-Win64-Shipping.exe' -or $DiagnosticResolution -notmatch '^([0-9]{3,4})x([0-9]{3,4})$') { throw 'DiagnosticResolution currently supports Silent Hill 2 only; use e.g. 1280x720.' }
|
||||
$renderWidth=[int]$Matches[1]; $renderHeight=[int]$Matches[2]
|
||||
if ($renderWidth -gt 4096 -or $renderHeight -gt 2160) { throw 'Diagnostic resolution is too large.' }
|
||||
$userRoot=Join-Path $env:LOCALAPPDATA 'SilentHill2/Saved'
|
||||
foreach ($relative in @('Config/Windows/GameUserSettings.ini','SaveGames/GFXSettings.SHProto-Win64-Shipping.xml')) {
|
||||
$path=Join-Path $userRoot $relative
|
||||
$saved=Join-Path $OutputDirectory ('original-settings/' + $relative)
|
||||
New-Item -ItemType Directory -Force (Split-Path $saved) | Out-Null
|
||||
Copy-Item -LiteralPath $path -Destination $saved
|
||||
$originalSettings += @{path=$path; saved=$saved}
|
||||
if ($relative.EndsWith('.ini')) {
|
||||
$text=[IO.File]::ReadAllText($path)
|
||||
$text=$text -replace 'Resolution=\(X=[0-9]+,Y=[0-9]+\)', "Resolution=(X=$renderWidth,Y=$renderHeight)"
|
||||
$text=$text -replace 'ScreenMode=Borderless', 'ScreenMode=Windowed'
|
||||
$text=$text -replace '(?m)^ResolutionSizeX=[0-9]+', "ResolutionSizeX=$renderWidth"
|
||||
$text=$text -replace '(?m)^ResolutionSizeY=[0-9]+', "ResolutionSizeY=$renderHeight"
|
||||
$text=$text -replace '(?m)^FullscreenMode=[0-9]+', 'FullscreenMode=2'
|
||||
[IO.File]::WriteAllText($path,$text,[Text.UTF8Encoding]::new($false))
|
||||
} else {
|
||||
$xml=[xml](Get-Content -LiteralPath $path -Raw -Encoding Unicode)
|
||||
$xml.GSA_SDK.GAMESETTINGS.RESOLUTION.Width="$renderWidth"
|
||||
$xml.GSA_SDK.GAMESETTINGS.RESOLUTION.Height="$renderHeight"
|
||||
$xml.Save($path)
|
||||
}
|
||||
}
|
||||
Write-Host "Temporary diagnostic resolution: $DiagnosticResolution; original settings restore at exit."
|
||||
}
|
||||
foreach ($key in $settings.Keys) { $old[$key] = [Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
|
||||
@{preset=$Preset; game=$GameExe; package=$metadata; driver=@(Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion,DriverDate); arguments=$GameArguments} |
|
||||
ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'environment.json') -Encoding UTF8
|
||||
function Quote([string]$value) { if ($value.Contains('"')) { throw 'A command argument contains an unsupported quote.' }; return '"' + $value + '"' }
|
||||
$arguments = @('--output-directory', (Quote $OutputDirectory), '--', (Quote $GameExe)) + @($GameArguments | ForEach-Object { Quote $_ })
|
||||
$process = Start-Process -FilePath (GamePath 'd4r/d4r_debug_launcher.exe') -ArgumentList $arguments -WorkingDirectory $game -WindowStyle Hidden -PassThru `
|
||||
-RedirectStandardOutput (Join-Path $OutputDirectory 'd4r.stdout.log') -RedirectStandardError (Join-Path $OutputDirectory 'd4r.stderr.log')
|
||||
Write-Host "Game diagnostic started (preset $Preset). Logs: $OutputDirectory"
|
||||
$timer = [Diagnostics.Stopwatch]::StartNew()
|
||||
while (!$process.WaitForExit(1000)) {
|
||||
if ($RunSeconds -gt 0 -and $timer.Elapsed.TotalSeconds -ge $RunSeconds) { $process.Kill(); $process.WaitForExit(); break }
|
||||
}
|
||||
$process.WaitForExit()
|
||||
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
|
||||
$gameExit = [regex]::Match($debugger, 'EXIT code=0x([0-9a-f]+)')
|
||||
@{exitCode=$(if ($gameExit.Success) { '0x' + $gameExit.Groups[1].Value } else { 'diagnostic_timeout' }); runSeconds=$timer.Elapsed.TotalSeconds; preset=$Preset;
|
||||
nativeLaunches=([regex]::Matches($stderr, '\[d4r-launch\].*backend=native')).Count;
|
||||
completedFrames=([regex]::Matches($stdout, 'D4R_FRAME ')).Count;
|
||||
failures=([regex]::Matches($stderr, 'D4R_WINDOWS_FAILURE|D4R_COMMAND_FAILURE')).Count} |
|
||||
ConvertTo-Json | 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"
|
||||
} finally {
|
||||
if ($process -and !$process.HasExited) { $process.Kill(); $process.WaitForExit() }
|
||||
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
|
||||
foreach ($entry in $originalSettings) { Copy-Item -LiteralPath $entry.saved -Destination $entry.path -Force }
|
||||
}
|
||||
Reference in new issue
Block a user