Enable experimental native Windows RDNA3 and RDNA4 targets

Share explicit target metadata across build/runtime/package guards, preserve native gfx11 WMMA with a Windows LDS lane exchange, select HIP devices by D3D12 LUID, and reject wrong-target/vkd3d installations before changing game files. Review all issue #10 logs and document compile-only coverage plus RX9070XT regressions.

Co-authored-by: realdody <[email protected]>
This commit is contained in:
xdfnx-devandrealdody committed 2026-10-02 17:10:42 +03:00
1 parent 98de8e3a3e
commit 3fa963fd1b
32 files changed
+494 -162

No files matched your search

+3 -1
View File
@@ -5,10 +5,12 @@ param(
[string]$HipRoot = 'C:\Program Files\AMD\ROCm\7.2',
[string]$ZludaRoot,
[ValidateSet('cu','wgp')][string]$ShaderMode='cu',
[ValidateSet('gfx1200','gfx1201')][string]$GpuArch='gfx1201',
[string]$GpuArch='gfx1201',
[string]$OutputDirectory
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
[void](Get-D4RGpuTargetInfo $GpuArch)
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo "build/private-textures-$GpuArch" }
@@ -0,0 +1,44 @@
[CmdletBinding()]
param(
[string[]]$GpuArchitectures,
[ValidateSet('stable','therock')][string]$RuntimeProfile='therock',
[string]$ZludaRoot, [string]$DlssDll,
[switch]$PackageGames,
[string]$BuildRoot, [string]$OutputRoot, [string]$ArchiveDirectory
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$GpuArchitectures) { $GpuArchitectures=@(Get-D4RGpuTargets | ForEach-Object { $_.architecture }) }
foreach ($arch in $GpuArchitectures) { [void](Get-D4RGpuTargetInfo $arch) }
if (@($GpuArchitectures | Select-Object -Unique).Count -ne $GpuArchitectures.Count) { throw 'Duplicate GPU target.' }
if (!$BuildRoot) { $BuildRoot=Join-Path $repo 'build/windows-gpu-coverage' }
if (!$OutputRoot) { $OutputRoot=Join-Path $repo 'dist/windows-gpu-coverage' }
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if ($ArchiveDirectory -and !$PackageGames) { throw 'ArchiveDirectory requires PackageGames.' }
if ($PackageGames -and (!$DlssDll -or ![IO.Path]::IsPathRooted($DlssDll) -or !(Test-Path -LiteralPath $DlssDll))) {
throw 'PackageGames requires an absolute path to your local nvngx_dlss.dll; it will not be redistributed.'
}
New-Item -ItemType Directory -Force $BuildRoot | Out-Null
if ($ArchiveDirectory) { New-Item -ItemType Directory -Force $ArchiveDirectory | Out-Null }
$results=[Collections.Generic.List[object]]::new()
foreach ($arch in $GpuArchitectures) {
$build="$BuildRoot-$arch"; $diag="$OutputRoot-$arch"
$log=Join-Path $BuildRoot "$arch-build.log"
Write-Host "Building $arch (compile/package only; no GPU workloads). Log: $log"
& (Join-Path $PSScriptRoot 'build-windows-rdna4.ps1') -RuntimeProfile $RuntimeProfile -GpuArch $arch `
-ZludaRoot $ZludaRoot -BuildDirectory $build -InstallDirectory $diag *> $log
$row=[ordered]@{architecture=$arch; compiled=$true; hardwareTestExecuted=$false; buildDirectory=$build; diagnosticRoot=$diag; log=$log}
if ($PackageGames) {
$k="$BuildRoot-native-k-$arch"; $m="$BuildRoot-native-m-$arch"; $game="$OutputRoot-game-$arch"
& (Join-Path $PSScriptRoot 'stage-native-k.ps1') -DlssDll $DlssDll -PackageRoot $diag -GpuArch $arch -OutputDirectory $k
& (Join-Path $PSScriptRoot 'stage-native-m.ps1') -DlssDll $DlssDll -PackageRoot $diag -GpuArch $arch -OutputDirectory $m
$packageArgs=@{DiagnosticRoot=$diag; GpuArch=$arch; PackageRoot=$game; ZludaRoot=$ZludaRoot; KernelKRoot=$k; KernelMRoot=$m}
if ($ArchiveDirectory) { $packageArgs.ArchivePath=Join-Path $ArchiveDirectory "d4r-windows-$arch.zip" }
& (Join-Path $PSScriptRoot 'package-windows-game.ps1') @packageArgs
$row.gamePackage=$game
}
$results.Add($row)
$results | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $BuildRoot 'matrix-build.json') -Encoding UTF8
Write-Host "Compiled $arch; hardware validation remains separate."
}
+3 -1
View File
@@ -2,13 +2,15 @@
param(
[string]$HipRoot = $env:HIP_PATH,
[ValidateSet('stable', 'therock')][string]$RuntimeProfile = 'stable',
[ValidateSet('gfx1200','gfx1201')][string]$GpuArch = 'gfx1201',
[string]$GpuArch = 'gfx1201',
[string]$ZludaRoot,
[string]$ToolchainRoot,
[string]$BuildDirectory,
[string]$InstallDirectory
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
[void](Get-D4RGpuTargetInfo $GpuArch)
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if ($RuntimeProfile -eq 'therock') {
if (!$PSBoundParameters.ContainsKey('HipRoot')) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
+58
View File
@@ -0,0 +1,58 @@
# Read-only inventory before touching game files. It allocates no GPU memory
# and executes no kernels; successful discovery is not hardware validation.
function Invoke-D4RGpuPreflight([string]$PackageRoot, [string]$GameDirectory, [string]$Target, [string]$OutputDirectory) {
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$result=[ordered]@{passed=$false; target=$Target; gpuWorkExecuted=$false; failure=$null}
try {
$proxy=Join-Path $GameDirectory 'd3d12.dll'
if (Test-Path -LiteralPath $proxy) {
$item=Get-Item -LiteralPath $proxy
$result.localD3D12=@{path=$proxy; sha256=(Get-FileHash -LiteralPath $proxy).Hash; product=$item.VersionInfo.ProductName}
# Identify known Vulkan/Wine proxies by their own strings. Do not
# load, remove or replace a third-party game DLL.
if ($item.Length -le 64MB -and [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($proxy)) -match '(?i)vkd3d|wined3d') {
throw 'Local d3d12.dll identifies as vkd3d/Wine. Restore the game native D3D12 installation before using this Windows backend.'
}
}
$info=[Diagnostics.ProcessStartInfo]::new()
$info.FileName=Join-Path $PackageRoot 'd4r/d4r_gpu_inventory.exe'
$hip=Join-Path $PackageRoot 'd4r/hip'
foreach ($value in @($hip,$OutputDirectory)) { if ($value.Contains('"')) { throw 'Unsupported quote in inventory path.' } }
$info.Arguments='--hip-root "' + $hip + '" --output-dir "' + $OutputDirectory + '"'
$info.UseShellExecute=$false; $info.CreateNoWindow=$true
$info.EnvironmentVariables['D4R_DIAG_DIR']=$OutputDirectory
$info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
$process=[Diagnostics.Process]::new(); $process.StartInfo=$info
try {
if (!$process.Start()) { throw 'Cannot start GPU inventory.' }
$stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
$timedOut=!$process.WaitForExit(30000)
if ($timedOut) { $process.Kill(); $process.WaitForExit() }
$stdout.GetAwaiter().GetResult() | Set-Content (Join-Path $OutputDirectory 'gpu-inventory.stdout.log') -Encoding UTF8
$stderr.GetAwaiter().GetResult() | Set-Content (Join-Path $OutputDirectory 'gpu-inventory.stderr.log') -Encoding UTF8
$result.exitCode=$process.ExitCode
$result.exceptionOrExitHex='0x{0:X8}' -f [BitConverter]::ToUInt32([BitConverter]::GetBytes([int]$process.ExitCode),0)
if ($timedOut) { $result.timedOut=$true; throw 'HIP inventory timed out after 30 seconds.' }
if ($process.ExitCode) { throw "HIP inventory failed (exit $($process.ExitCode))." }
} finally { $process.Dispose() }
$inventory=Get-Content (Join-Path $OutputDirectory 'gpu-inventory.json') -Raw | ConvertFrom-Json
$result.inventory=$inventory
if ($inventory.compiledTarget -ne $Target) { throw "Inventory executable targets $($inventory.compiledTarget); package requires $Target." }
$matching=@($inventory.devices | Where-Object { $_.architecture -eq $Target -and $_.wavefrontSize -eq 32 })
if (!$matching.Count) {
$actual=@($inventory.devices | ForEach-Object { "$($_.architecture) ($($_.name))" }) -join ', '
throw "GPU target mismatch: detected $actual; package requires $Target. Use the package for the actual HIP architecture; do not rename code objects."
}
$result.passed=$true
Write-Host "D4R_PREFLIGHT target=$Target devices=$($matching.Count) gpu_work_executed=0"
} catch {
$result.failure=$_.Exception.Message
$result | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $OutputDirectory 'preflight.json') -Encoding UTF8
try { Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion,DriverDate | ConvertTo-Json |
Set-Content (Join-Path $OutputDirectory 'driver.json') -Encoding UTF8 } catch {}
$bundle=$OutputDirectory+'.zip'
Compress-Archive -Path (Join-Path $OutputDirectory '*') -DestinationPath $bundle -Force
throw "$($result.failure) Diagnostic bundle: $bundle"
}
$result | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $OutputDirectory 'preflight.json') -Encoding UTF8
}
+17 -5
View File
@@ -1,19 +1,31 @@
# Shared by the build, diagnostics, staging and game package scripts.
function Get-D4RGpuTargets {
$registry=Join-Path $PSScriptRoot 'gpu-targets.json'
if (!(Test-Path -LiteralPath $registry)) { $registry=Join-Path $PSScriptRoot '../../tools/windows/gpu-targets.json' }
$data=Get-Content -LiteralPath $registry -Raw | ConvertFrom-Json
if ($data.schema -ne 1) { throw 'Unsupported GPU target registry schema.' }
return $data.targets
}
function Get-D4RGpuTargetInfo([string]$Target) {
$info=@(Get-D4RGpuTargets | Where-Object { $_.architecture -eq $Target })
if ($info.Count -ne 1) { throw "Unsupported GPU target: $Target" }
return $info[0]
}
function Get-D4RGpuTarget([string]$Root, [string]$Requested) {
$configured=$null
$targetFile=Join-Path $Root 'gpu-target.json'
if (Test-Path -LiteralPath $targetFile) {
$configured=(Get-Content -LiteralPath $targetFile -Raw | ConvertFrom-Json).architecture
if ($configured -notin @('gfx1200','gfx1201')) { throw "Unsupported package GPU target: $configured" }
[void](Get-D4RGpuTargetInfo $configured)
}
$target=if ($Requested) { $Requested } elseif ($configured) { $configured } else { 'gfx1201' }
if ($target -notin @('gfx1200','gfx1201')) { throw "Unsupported GPU target: $target" }
if (!$configured -and $target -ne 'gfx1201') { throw 'A gfx1200 build requires gpu-target.json; rebuild with -GpuArch gfx1200.' }
[void](Get-D4RGpuTargetInfo $target)
if (!$configured -and $target -ne 'gfx1201') { throw "A $target build requires gpu-target.json; rebuild with -GpuArch $target." }
if ($configured -and $target -ne $configured) { throw "Requested $target differs from package target $configured" }
return $target
}
function Assert-D4RCodeObjectTarget([string]$Path, [string]$Target) {
if ($Target -notin @('gfx1200','gfx1201')) { throw "Unsupported GPU target: $Target" }
$info=Get-D4RGpuTargetInfo $Target
$reader=[IO.BinaryReader]::new([IO.File]::OpenRead($Path))
try { $header=$reader.ReadBytes(64) } finally { $reader.Dispose() }
if ($header.Length -ne 64 -or $header[0] -ne 127 -or $header[1] -ne 69 -or $header[2] -ne 76 -or $header[3] -ne 70 -or
@@ -21,6 +33,6 @@ function Assert-D4RCodeObjectTarget([string]$Path, [string]$Target) {
throw "Invalid AMDGPU ELF64 code object: $Path"
}
# LLVM AMDGPU e_flags machine IDs; inspect, never patch or spoof them.
$expected=if ($Target -eq 'gfx1200') { 0x48 } else { 0x4e }
$expected=$info.elfMachine
if ($header[48] -ne $expected) { throw "Code object does not target ${Target}: $Path (ELF machine=$($header[48]))" }
}
+5 -2
View File
@@ -2,7 +2,7 @@
param(
[string]$PackageRoot, [string]$DiagnosticRoot, [string]$OptiScalerRoot,
[string]$ZludaRoot, [string]$HipRoot, [string]$KernelKRoot, [string]$KernelMRoot,
[ValidateSet('gfx1200','gfx1201')][string]$GpuArch,
[string]$GpuArch,
[string]$ArchivePath
)
$ErrorActionPreference = 'Stop'
@@ -15,7 +15,7 @@ foreach ($name in $defaults.Keys) {
if (!(Get-Variable -Name $name -ValueOnly)) { Set-Variable -Name $name -Value (Join-Path $repo $defaults[$name]) }
}
$GpuArch=Get-D4RGpuTarget $DiagnosticRoot $GpuArch
if ($GpuArch -eq 'gfx1200' -and !$PSBoundParameters.ContainsKey('PackageRoot')) { $PackageRoot += '-gfx1200' }
if ($GpuArch -ne 'gfx1201' -and !$PSBoundParameters.ContainsKey('PackageRoot')) { $PackageRoot += "-$GpuArch" }
if (!$KernelKRoot) { $KernelKRoot=Join-Path $repo "build/native-k-$GpuArch" }
if (!$KernelMRoot) { $KernelMRoot=Join-Path $repo "build/native-m-$GpuArch" }
foreach ($directory in @($KernelKRoot,$KernelMRoot)) {
@@ -46,6 +46,7 @@ Stage (Join-Path $DiagnosticRoot 'bin/d4r_nvngx.dll') 'd4r/_nvngx.dll'
Stage (Join-Path $DiagnosticRoot "bin/pixel_convert_${GpuArch}.hsaco") "d4r/pixel_convert_${GpuArch}.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'
Stage (Join-Path $DiagnosticRoot 'bin/d4r_gpu_inventory.exe') 'd4r/d4r_gpu_inventory.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"
@@ -66,6 +67,8 @@ if ($entries.Count -ne 16) { throw "Expected 11 K and 5 M native objects; found
$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/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'
if (Test-Path -LiteralPath (Join-Path $DiagnosticRoot 'gpu-target.json')) {
Stage (Join-Path $DiagnosticRoot 'gpu-target.json') 'gpu-target.json'
} else {
+1 -1
View File
@@ -1,5 +1,5 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [ValidateSet('gfx1200','gfx1201')][string]$GpuArch)
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [string]$GpuArch)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
+1 -1
View File
@@ -1,5 +1,5 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [ValidateSet('gfx1200','gfx1201')][string]$GpuArch)
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [string]$GpuArch)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
+1 -1
View File
@@ -4,7 +4,7 @@ param(
[ValidateSet('stable', 'therock')][string]$RuntimeProfile = 'stable',
[string]$ZludaRoot,
[string]$PackageRoot,
[ValidateSet('gfx1200','gfx1201')][string]$GpuArch,
[string]$GpuArch,
[string]$OutputDirectory,
[string]$NgxCore = $env:D4R_NGX_CORE,
[string]$DlssDll = $env:D4R_DLSS_DLL,
+3
View File
@@ -27,6 +27,7 @@ param(
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
. (Join-Path $PSScriptRoot 'gpu-preflight.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.' }
@@ -74,6 +75,7 @@ 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.' }
Invoke-D4RGpuPreflight $package $game $GpuArch (Join-Path $package ('results/preflight-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')))
$textureFiles=@(); $textureManifest=@()
if ($LocalTextureKernels) {
$LocalTextureKernels=(Get-Item -LiteralPath $LocalTextureKernels -ErrorAction Stop).FullName
@@ -193,6 +195,7 @@ $settings = @{
# false have the same numerical effect; unset reuses the validated cache.
D4R_ZLUDA_IGNORE_DENORMAL=$null; D4R_ZLUDA_FAST_MATH=$null;
D4R_ZLUDA_WMMA_F32ACC=$null; D4R_ZLUDA_WAVE64=$null;
D4R_ZLUDA_WMMA_LAYOUT=$null;
D4R_QUIET_API=$(if ($VerboseRuntime) { $null } else { '1' });
D4R_VALIDATE_OUTPUT=$(if ($ValidateOutput) { '1' } else { $null });
D4R_PROFILE_STAGES=$(if ($ProfileStages) { '1' } else { $null });