Build native Windows packages for both RDNA4 targets

Add explicit gfx1200/gfx1201 builds, runtime selection and per-target
code objects. Guard staging, packaging and installation against mixed
architectures; retain gfx1201 compatibility and strict K/M arithmetic.

Adapt realdody's target configuration and MSVC binary16/BOOL portability
fixes from ae530b0. Do not import its forced gfx12 layout on RDNA3.
Add exhaustive binary16 and C++/PowerShell target contract regressions.

Validation: 20 CTest gates on RX 9070 XT; four software-only gfx1200 gates;
MSVC portability compile checks; exact 4K K async and M control outputs;
isolated package install/restore and mixed-target rejection tests.
No physical gfx1200 validation is claimed.

Co-authored-by: realdody <[email protected]>
This commit is contained in:
xdfnx-devandrealdody committed 2026-10-02 16:18:18 +03:00
1 parent 8f7058d2ba
commit 98de8e3a3e
51 files changed
+636 -127

No files matched your search

+51
View File
@@ -0,0 +1,51 @@
#pragma once
// Adapted from realdody/d4r ae530b0 (MIT), realdody <[email protected]>.
#include <cstdint>
#include <cstring>
#include <cmath>
#include <limits>
namespace d4r::diag::binary16 {
// MSVC has no _Float16 extension. Convert double<->IEEE binary16 explicitly with
// round-to-nearest-even, matching a native _Float16 cast. This probe compares the
// f16-accumulator MMA against a double sum rounded once to half, so the rounding
// must match IEEE 754 binary16 exactly.
inline uint16_t half_bits(double value) {
uint64_t bits;
std::memcpy(&bits, &value, sizeof(bits));
const uint16_t sign = static_cast<uint16_t>((bits >> 63) << 15);
int32_t exponent = static_cast<int32_t>((bits >> 52) & 0x7ff);
uint64_t mantissa = bits & 0x000fffffffffffffULL;
if (exponent == 0x7ff) return static_cast<uint16_t>(sign | (mantissa ? 0x7e00 : 0x7c00));
if (exponent == 0) return sign; // double subnormal rounds to half zero
int32_t unbiased = exponent - 1023;
if (unbiased > 15) return static_cast<uint16_t>(sign | 0x7c00);
mantissa |= 0x0010000000000000ULL; // implicit leading one (53-bit significand)
const int shift = unbiased >= -14 ? 42 : 28 - unbiased;
uint64_t rounded = shift >= 64 ? 0 : (mantissa >> shift);
if (shift < 64) {
const uint64_t remainder = mantissa & ((1ULL << shift) - 1);
const uint64_t halfway = 1ULL << (shift - 1);
if (remainder > halfway || (remainder == halfway && (rounded & 1))) ++rounded;
}
if (unbiased >= -14) {
if (rounded >= 0x800) { // rounding overflowed into the exponent
rounded = 0x400;
if (++unbiased > 15) return static_cast<uint16_t>(sign | 0x7c00);
}
return static_cast<uint16_t>(sign | ((unbiased + 15) << 10) | static_cast<uint16_t>(rounded & 0x3ff));
}
if (rounded >= 0x400) return static_cast<uint16_t>(sign | 0x0400); // smallest normal half
return static_cast<uint16_t>(sign | static_cast<uint16_t>(rounded));
}
inline double half_value(uint16_t bits) {
const bool negative = (bits & 0x8000u) != 0;
const uint32_t exponent = (bits >> 10) & 0x1fu;
const uint32_t mantissa = bits & 0x3ffu;
double magnitude;
if (exponent == 0) magnitude = std::ldexp(static_cast<double>(mantissa), -24);
else if (exponent == 0x1fu) magnitude = mantissa ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::infinity();
else magnitude = std::ldexp(static_cast<double>(mantissa) / 1024.0 + 1.0, static_cast<int>(exponent) - 15);
return negative ? -magnitude : magnitude;
}
}
+45
View File
@@ -0,0 +1,45 @@
#include "binary16.h"
#include <cstdio>
#include <initializer_list>
#include <stdexcept>
static void check(double value, uint16_t expected) {
const auto actual = d4r::diag::binary16::half_bits(value);
if (actual != expected) throw std::runtime_error("binary16 rounding mismatch");
}
int main() {
using namespace d4r::diag::binary16;
try {
unsigned encodings = 0, boundaries = 0;
for (unsigned bits = 0; bits < 65536; ++bits) {
if ((bits & 0x7c00) == 0x7c00 && (bits & 0x3ff)) continue;
check(half_value(uint16_t(bits)), uint16_t(bits));
++encodings;
}
for (unsigned bits = 0; bits < 0x7bff; ++bits) {
const double low = half_value(uint16_t(bits)), high = half_value(uint16_t(bits + 1));
const double midpoint = (low + high) * 0.5;
const uint16_t tie = uint16_t(bits + (bits & 1));
check(midpoint, tie); check(-midpoint, uint16_t(tie | 0x8000));
check(std::nextafter(midpoint, low), uint16_t(bits));
check(std::nextafter(midpoint, high), uint16_t(bits + 1));
#if !defined(_MSC_VER)
for (double value : {midpoint, -midpoint, std::nextafter(midpoint, low), std::nextafter(midpoint, high)}) {
const _Float16 native = static_cast<_Float16>(value);
uint16_t expected; std::memcpy(&expected, &native, sizeof(expected));
check(value, expected);
}
#endif
++boundaries;
}
check(65519.0, 0x7bff); check(65520.0, 0x7c00);
check(-65520.0, 0xfc00);
check(std::numeric_limits<double>::denorm_min(), 0);
check(-std::numeric_limits<double>::denorm_min(), 0x8000);
check(std::numeric_limits<double>::quiet_NaN(), 0x7e00);
std::printf("PASS BINARY16 encodings=%u rounding_boundaries=%u\n", encodings, boundaries);
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL BINARY16 %s\n", e.what()); return 5;
}
}
+18 -6
View File
@@ -1,4 +1,4 @@
"""Build a private gfx1201 texture override from the user's local DLSS DLL.
"""Build a private RDNA4 texture override from the user's local DLSS DLL.
The resulting PTX/code object contains NVIDIA code and must remain local.
No Wine, shell script, GPU, CUDA SDK or system installation is required.
@@ -15,6 +15,14 @@ import subprocess
import sys
def require_code_object_target(path, target):
with path.open('rb') as file:
header = file.read(64)
if (len(header) != 64 or header[:6] != b'\x7fELF\x02\x01' or
header[18:20] != b'\xe0\x00' or header[48] != {'gfx1200': 0x48, 'gfx1201': 0x4e}[target]):
raise RuntimeError(f'Code object does not target {target}: {path}')
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--dlss-dll', type=pathlib.Path, required=True)
@@ -22,6 +30,7 @@ def main():
parser.add_argument('--zluda-root', type=pathlib.Path, required=True)
parser.add_argument('--kernel', required=True)
parser.add_argument('--output-directory', type=pathlib.Path, required=True)
parser.add_argument('--gpu-arch', choices=['gfx1200', 'gfx1201'], default='gfx1201')
parser.add_argument('--shader-mode', choices=['cu', 'wgp'], default='cu')
args = parser.parse_args()
if not re.fullmatch(r'hiluma_engine_(?:output_depth(?:inv|reg)_mv(?:hi|lo)_(?:hdr|ldr)(?:_max)?|'
@@ -30,6 +39,8 @@ def main():
repo = pathlib.Path(__file__).resolve().parents[2]
output = args.output_directory.resolve()
output.mkdir(parents=True, exist_ok=True)
for existing in output.glob('*.hsaco'):
require_code_object_target(existing, args.gpu_arch)
work = output / ('work-' + args.kernel)
work.mkdir(exist_ok=True)
hip = args.hip_root.resolve()
@@ -70,7 +81,7 @@ def main():
raise RuntimeError('PTX recipe made no changes; refuse a no-op override')
raw, ir, extra = work / 'raw.bc', work / 'raw.ll', work / 'extra.bc'
run('compile-helper', [tools['clang++'], '-x', 'hip', '-std=c++20', '-nogpuinc', '-nogpulib', '-O3',
'-mno-wavefrontsize64', '--offload-device-only', '--offload-arch=gfx1201',
'-mno-wavefrontsize64', '--offload-device-only', '--offload-arch=' + args.gpu_arch,
'-fgpu-rdc', '-emit-llvm', '-c', '-Xclang', '-fdenormal-fp-math=dynamic',
'-DD4R_ACCURACY', '-DD4R_KERNEL_NAME=' + args.kernel,
'-o', raw, repo / 'kernels/tex/sust_only.hip'])
@@ -79,12 +90,12 @@ def main():
for line in ir.read_text().splitlines():
if re.search(r'@llvm.used|wchar_size|llvm.module.flags|__hip_cuid', line):
continue
line = line.replace('optnone', '').replace('"target-cpu"="gfx1201"', '')
line = line.replace('optnone', '').replace(f'"target-cpu"="{args.gpu_arch}"', '')
lines.append(re.sub(r'"target-features"="[^"]+"', '', line))
ir.write_text('\n'.join(lines) + '\n')
run('assemble', [tools['llvm-as'], ir, '-o', extra])
env['D4R_ZLUDA_EXTRA_BC'] = str(extra)
run('emit', [emitter, edited, work / 'emitted', 'gfx1201'])
run('emit', [emitter, edited, work / 'emitted', args.gpu_arch])
optimized = (work / 'emitted/opt.ll').read_text()
definition = re.search(r'^define amdgpu_kernel .*@' + re.escape(args.kernel) + r'\(.*#(\d+)\s*\{', optimized, re.M)
if not definition:
@@ -93,9 +104,10 @@ def main():
expected_mode = '-cumode' if args.shader_mode == 'wgp' else '+cumode'
if not attributes or expected_mode not in attributes[1]:
raise RuntimeError(f'Emitter did not honor {args.shader_mode} mode; build the corresponding ZLUDA patch first')
require_code_object_target(work / 'emitted/module.hsaco', args.gpu_arch)
shutil.copyfile(work / 'emitted/module.hsaco', output / (args.kernel + '.hsaco'))
run('manifest', [sys.executable, repo / 'kernels/tools/kernel_manifest.py', output, args.dlss_dll])
metadata = dict(architecture='gfx1201', accuracy=True, nativeFP8=False, shaderMode=args.shader_mode,
metadata = dict(architecture=args.gpu_arch, accuracy=True, nativeFP8=False, shaderMode=args.shader_mode,
lastBuiltKernel=args.kernel, lastRecipeRewrites=rewrite_counts,
privateNvidiaDerivedCode=True, validation='not yet validated; do not install before comparison',
dlssSha256=hashlib.sha256(args.dlss_dll.read_bytes()).hexdigest(),
@@ -103,7 +115,7 @@ def main():
compiler=subprocess.check_output([str(tools['clang++']), '--version'], env=env).decode(errors='replace'),
objects={p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in output.glob('*.hsaco')})
(output / 'build-info.json').write_text(json.dumps(metadata, indent=2) + '\n')
print(f'Built PRIVATE gfx1201 texture override: {output}; validation required before use')
print(f'Built PRIVATE {args.gpu_arch} texture override: {output}; validation required before use')
if __name__ == '__main__':
+2 -2
View File
@@ -46,7 +46,7 @@ int main(int argc, char** argv)
// Require the real HIP architecture, then match the CUDA device by PCI identity.
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
CudaApi api(args.cuda_dll);
loaded_modules();
std::printf("STAGE cuInit\n");
@@ -130,7 +130,7 @@ int main(int argc, char** argv)
if (primary) api.check(api.cuDevicePrimaryCtxRelease_v2(device), "cuDevicePrimaryCtxRelease_v2");
else api.check(api.cuCtxDestroy_v2(context), "cuCtxDestroy_v2");
cleanup.context = nullptr;
std::printf("PASS CUDA architecture=gfx1201 context=%s iterations=%u guard_verified=1 queued=%u\n",
std::printf("PASS CUDA architecture=%s context=%s iterations=%u guard_verified=1 queued=%u\n", d4r::diag::HipApi::target_arch(),
args.context.c_str(), args.iterations, unsigned(queued));
return 0;
} catch (const std::exception& e) {
+2 -2
View File
@@ -8,7 +8,7 @@ int main(int argc, char** argv) {
Args args(argc, argv);
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
SearchDirectory search(std::filesystem::path(wide(args.cuda_dll)).parent_path());
CudaApi cuda(args.cuda_dll);
cuda.check(cuda.cuInit(0), "cuInit");
@@ -64,7 +64,7 @@ int main(int argc, char** argv) {
}
}
cuda.check(cuda.cuCtxSynchronize(), "cuCtxSynchronize");
std::printf("PASS CUDA_IMAGES architecture=gfx1201 iterations=%u descriptor_and_storage=1 pitched_device_copies=1 fp16_fp32=1 async_array_copy=%u\n",
std::printf("PASS CUDA_IMAGES architecture=%s iterations=%u descriptor_and_storage=1 pitched_device_copies=1 fp16_fp32=1 async_array_copy=%u\n", d4r::diag::HipApi::target_arch(),
args.iterations, unsigned(std::getenv("D4R_DIAG_ASYNC_ARRAY_COPY") != nullptr));
return 0;
} catch (const std::exception& e) {
+8 -2
View File
@@ -1,5 +1,6 @@
#include "hip_api.h"
#include "cuda_api.h"
#include "binary16.h"
#include <array>
#include <cmath>
#include <cstring>
@@ -60,6 +61,10 @@ static constexpr char source[] = R"PTX(
}
)PTX";
#if defined(_MSC_VER)
using d4r::diag::binary16::half_bits;
using d4r::diag::binary16::half_value;
#else
static uint16_t half_bits(double value) {
_Float16 half = static_cast<_Float16>(value);
uint16_t bits;
@@ -71,6 +76,7 @@ static double half_value(uint16_t bits) {
std::memcpy(&half, &bits, sizeof(bits));
return static_cast<double>(half);
}
#endif
int main(int argc, char** argv) {
using namespace d4r::diag;
@@ -79,7 +85,7 @@ int main(int argc, char** argv) {
Args args(argc, argv);
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
CudaApi cuda(args.cuda_dll);
cuda.check(cuda.cuInit(0), "cuInit");
CUdevice device = -1;
@@ -155,7 +161,7 @@ int main(int argc, char** argv) {
}
std::printf("MMA_REFERENCE cases=%zu elements=%zu differing=%zu\n", cases, d.size(), mismatch);
if (mismatch) return 5;
std::printf("PASS CUDA_F16_MMA architecture=gfx1201 cases=%zu exact_f16=1\n", cases);
std::printf("PASS CUDA_F16_MMA architecture=%s cases=%zu exact_f16=1\n", d4r::diag::HipApi::target_arch(), cases);
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "FAIL CUDA_F16_MMA %s\n", error.what());
@@ -360,9 +360,9 @@ static void STDMETHODCALLTYPE hook_SOSetTargets(ID3D12GraphicsCommandList* self,
return original_SOSetTargets(access.target(), start_slot, view_count, views);
}
using Fn_OMSetRenderTargets = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, WINBOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
using Fn_OMSetRenderTargets = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
static Fn_OMSetRenderTargets original_OMSetRenderTargets = nullptr;
static void STDMETHODCALLTYPE hook_OMSetRenderTargets(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, WINBOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
static void STDMETHODCALLTYPE hook_OMSetRenderTargets(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
Access access(self);
auto saved_render_target_descriptors = copy_values(render_target_descriptors, (single_descriptor_handle ? 1 : render_target_descriptor_count));
auto saved_depth_stencil_descriptor = copy_values(depth_stencil_descriptor, 1);
+2 -2
View File
@@ -123,7 +123,7 @@ int main(int argc, char** argv) {
std::unique_ptr<HipApi> hip;
hipDeviceProp_t props{};
const bool no_hip = std::getenv("D4R_COMMAND_PROBE_NO_HIP") != nullptr;
if (!no_hip) { hip = std::make_unique<HipApi>(args.hip_root); hip->select_gfx1201(args.device, props); }
if (!no_hip) { hip = std::make_unique<HipApi>(args.hip_root); hip->select_architecture(args.device, props); }
ComPtr<IDXGIFactory4> factory; dx(CreateDXGIFactory1(IID_PPV_ARGS(factory.GetAddressOf())), "Probe DXGI");
ComPtr<IDXGIAdapter1> adapter;
for (UINT i = 0; ; ++i) {
@@ -295,7 +295,7 @@ int main(int argc, char** argv) {
}
const bool warp = std::getenv("D4R_COMMAND_PROBE_WARP") != nullptr;
std::printf("PASS D3D12_COMMAND_BACKEND adapter=%s architecture=%s backend=%u iterations=%u batch_order=1 root_state=1 deep_copy=1 indirect=%u indirect_reset=%u reset_reuse=%u live_recordings=0 frame_age=0\n",
warp ? "WARP" : "AMD", warp ? "software" : no_hip ? "not_queried" : "gfx1201", !no_hooks,
warp ? "WARP" : "AMD", warp ? "software" : no_hip ? "not_queried" : HipApi::target_arch(), !no_hooks,
args.iterations, indirect_enabled, root_indirect, no_hooks ? 0 : 2 * args.iterations);
return 0;
} catch (const std::exception& failure) {
+3 -3
View File
@@ -30,7 +30,7 @@ int main(int argc, char** argv) {
std::make_pair("D4R_NVCUDA_DLL", args.cuda_dll), std::make_pair("D4R_NVAPI_DLL", args.nvapi_dll),
std::make_pair("D4R_NGX_CORE", args.ngx_core), std::make_pair("D4R_DLSS_DLL", args.dlss_dll)})
if (_putenv_s(pair.first, pair.second.c_str())) throw std::runtime_error("Cannot set runtime environment");
HipApi hip(args.hip_root); hipDeviceProp_t props{}; hip.select_gfx1201(args.device, props);
HipApi hip(args.hip_root); hipDeviceProp_t props{}; hip.select_architecture(args.device, props);
ComPtr<IDXGIFactory4> factory; dx(CreateDXGIFactory1(IID_PPV_ARGS(factory.GetAddressOf())), "CreateDXGIFactory1");
ComPtr<IDXGIAdapter1> adapter;
bool found = false;
@@ -169,7 +169,7 @@ int main(int argc, char** argv) {
if (!matches) throw std::runtime_error("Imported D3D12 VRAM to CUDA array mismatch on plane " + std::to_string(i));
timeline.drain(queue.Get());
}
std::printf("PASS D3D12_ARRAY_COPY architecture=gfx1201 planes=5 cpu_copies_between_apis=0\n");
std::printf("PASS D3D12_ARRAY_COPY architecture=%s planes=5 cpu_copies_between_apis=0\n", d4r::diag::HipApi::target_arch());
return 0;
}
Library shim(wide(args.module));
@@ -398,7 +398,7 @@ int main(int argc, char** argv) {
std::printf("D4R_BURST_VALIDATION frames=%zu cpu_readback_after_all_submissions=1\n", submitted.size());
}
loaded_modules();
std::printf("PASS D3D12_DLSS architecture=gfx1201 preset=%u frames=%u fast_path_cpu_copies=0 frame_age=0 enhanced=%u queue_integration=%s\n",
std::printf("PASS D3D12_DLSS architecture=%s preset=%u frames=%u fast_path_cpu_copies=0 frame_age=0 enhanced=%u queue_integration=%s\n", d4r::diag::HipApi::target_arch(),
args.preset, args.iterations, enhanced, commandBackend ? "recorded_command_list" : "explicit_harness");
return 0;
} catch (const std::exception& error) { std::fprintf(stderr, "FAIL D3D12_DLSS %s\n", error.what()); loaded_modules(); return 4; }
+2 -2
View File
@@ -137,7 +137,7 @@ int main(int argc, char** argv)
throw std::runtime_error("--stream-lifetime must be persistent or cycle");
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
ExternalApi external{hip};
ComPtr<IDXGIFactory4> factory;
dx(CreateDXGIFactory1(IID_PPV_ARGS(factory.GetAddressOf())), "CreateDXGIFactory1");
@@ -336,7 +336,7 @@ int main(int argc, char** argv)
DWORD handles_after = 0; GetProcessHandleCount(GetCurrentProcess(), &handles_after);
std::printf("HANDLES before=%lu after=%lu\n", handles_before, handles_after);
if (final_cycle_handles > warmed_handles + 4) throw std::runtime_error("Handle count grew after first-cycle warmup");
std::printf("PASS INTEROP architecture=gfx1201 iterations=%u texture=R32_UINT external_fence=1\n", args.iterations);
std::printf("PASS INTEROP architecture=%s iterations=%u texture=R32_UINT external_fence=1\n", d4r::diag::HipApi::target_arch(), args.iterations);
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL INTEROP %s\n", e.what());
+2 -2
View File
@@ -170,7 +170,7 @@ std::vector<uint32_t> read_reference(ID3D12Device* device, ID3D12CommandQueue* q
int main(int argc, char** argv) {
start();
try {
Args args(argc, argv); HipApi hip(args.hip_root); hipDeviceProp_t props{}; hip.select_gfx1201(args.device, props);
Args args(argc, argv); HipApi hip(args.hip_root); hipDeviceProp_t props{}; hip.select_architecture(args.device, props);
ExternalApi external{hip}; PixelProgram program(hip, wide(args.module));
{
PixelAllocation diagnostic(hip,3,1,8);
@@ -259,6 +259,6 @@ int main(int argc, char** argv) {
}
++verified; std::printf("PASS PIXEL_FORMAT name=%s plane=%u pixels=%u decode_max_abs=%.9g encode=%u\n", item.name,item.plane,count,maxAbs,item.plane==0);
}
std::printf("PASS D3D12_GPU_FORMATS architecture=gfx1201 cases=%u iterations=%u width=%u height=%u enhanced=%u typed_srv_reference=1 typed_uav_reference=1\n", verified,args.iterations,width,height,enhanced); return 0;
std::printf("PASS D3D12_GPU_FORMATS architecture=%s cases=%u iterations=%u width=%u height=%u enhanced=%u typed_srv_reference=1 typed_uav_reference=1\n", d4r::diag::HipApi::target_arch(), verified,args.iterations,width,height,enhanced); return 0;
} catch (const std::exception& error) { std::fprintf(stderr,"FAIL D3D12_GPU_FORMATS %s\n",error.what()); loaded_modules(); return 1; }
}
+2 -2
View File
@@ -87,10 +87,10 @@ API unsigned NVSDK_NGX_D3D12_GetFeatureRequirements(IDXGIAdapter* adapter, const
DXGI_ADAPTER_DESC desc{}; d4r::win::dx(adapter->GetDesc(&desc), "NGX requirements adapter");
// OptiScaler can override the DXGI vendor ID. The physical HIP
// 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_gfx1201(-1,props);
d4r::diag::HipApi hip(d4r::win::env_path("D4R_HIP_ROOT")); hipDeviceProp_t props{}; hip.select_architecture(-1,props);
requirements->FeatureSupported = std::memcmp(&desc.AdapterLuid,props.luid,sizeof(LUID)) ? 4u : 0u;
std::strcpy(requirements->MinOSVersion,"10.0.22000.0");
std::printf("D4R_REQUIREMENTS feature=%u support=%u architecture=gfx1201\n",info->FeatureID,requirements->FeatureSupported);
std::printf("D4R_REQUIREMENTS feature=%u support=%u architecture=%s\n",info->FeatureID,requirements->FeatureSupported,d4r::diag::HipApi::target_arch());
return 1u;
});
}
+3 -2
View File
@@ -52,8 +52,9 @@ def generate(source):
slot = 9 # IUnknown(3), ID3D12Object(4), DeviceChild(1), CommandList(1).
for version, interface, methods in sorted(classes):
for result, name, arguments in methods:
result = ' '.join(result.split())
arguments = ' '.join(arguments.split())
# MinGW WINBOOL and Microsoft SDK BOOL have the same ABI.
result = ' '.join(result.split()).replace('WINBOOL', 'BOOL')
arguments = ' '.join(arguments.split()).replace('WINBOOL', 'BOOL')
declarations = [arg.strip() for arg in arguments.split(',')] if arguments else []
names = []
for declaration in declarations:
+2 -2
View File
@@ -30,7 +30,7 @@ int main(int argc, char** argv)
if (args.module.empty()) throw std::runtime_error("--module is required");
HipApi hip(args.hip_root);
hipDeviceProp_t properties{};
hip.select_gfx1201(args.device, properties);
hip.select_architecture(args.device, properties);
hipModule_t module = nullptr;
hip.check(hip.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(WMMA)");
struct ModuleCleanup {
@@ -120,7 +120,7 @@ int main(int argc, char** argv)
}
}
}
std::printf("PASS GFX12_WMMA architecture=gfx1201 modes=raw,legacy_adapter,upstream_layout iterations=%u max_abs=%.9g max_rel=%.9g\n",
std::printf("PASS GFX12_WMMA architecture=%s modes=raw,legacy_adapter,upstream_layout iterations=%u max_abs=%.9g max_rel=%.9g\n", d4r::diag::HipApi::target_arch(),
args.iterations, max_absolute_error, max_relative_error);
return 0;
} catch (const std::exception& error) {
+6
View File
@@ -0,0 +1,6 @@
{
"schema": 1,
"architecture": "@D4R_GPU_ARCH@",
"wavefrontSize": 32,
"validation": "Compilation is not hardware validation; run the GPU diagnostics."
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <array>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <string>
#ifndef D4R_TARGET_ARCH
#define D4R_TARGET_ARCH "gfx1201"
#endif
namespace d4r::diag {
inline bool supported_gpu_target(const std::string& target) {
return target == "gfx1200" || target == "gfx1201";
}
inline std::string gpu_architecture(const std::string& name) {
return name.substr(0, name.find(':'));
}
inline void require_gpu_target(const std::string& actual, const std::string& expected) {
if (!supported_gpu_target(expected) || gpu_architecture(actual) != expected)
throw std::runtime_error("GPU architecture mismatch: detected " + actual + ", package requires " + expected);
}
inline std::string code_object_target(const std::filesystem::path& path) {
// AMDGPU ELF e_flags machine IDs from LLVM's documented code-object ABI.
// Never infer compatibility from a filename or rewrite the ELF target.
std::ifstream file(path, std::ios::binary);
std::array<unsigned char, 64> header{};
if (!file.read(reinterpret_cast<char*>(header.data()), header.size()) ||
header[0] != 0x7f || header[1] != 'E' || header[2] != 'L' || header[3] != 'F' ||
header[4] != 2 || header[5] != 1 || header[18] != 0xe0 || header[19] != 0)
throw std::runtime_error("Invalid AMDGPU ELF64 code object: " + path.string());
switch (header[48]) {
case 0x48: return "gfx1200";
case 0x4e: return "gfx1201";
default: throw std::runtime_error("Unsupported AMDGPU code-object target: " + path.string());
}
}
inline void require_code_object_target(const std::filesystem::path& path, const std::string& expected) {
require_gpu_target(code_object_target(path), expected);
}
}
+31
View File
@@ -0,0 +1,31 @@
#include "gpu_target.h"
#include <cstdio>
int main(int argc, char** argv) {
using namespace d4r::diag;
try {
unsigned rejected = 0, objects = 0;
for (const char* target : {"gfx1200", "gfx1201"}) {
require_gpu_target(target, target);
require_gpu_target(std::string(target) + ":xnack-:sramecc-", target);
for (const char* invalid : {"gfx1101", "gfx12000", "gfx1202", "gfx1250", ""}) {
try { require_gpu_target(invalid, target); }
catch (const std::exception&) { ++rejected; continue; }
throw std::runtime_error("Invalid GPU target accepted");
}
}
for (int i = 1; i < argc; ++i) {
require_code_object_target(argv[i], D4R_TARGET_ARCH);
const auto other = std::string(D4R_TARGET_ARCH) == "gfx1201" ? "gfx1200" : "gfx1201";
try { require_code_object_target(argv[i], other); }
catch (const std::exception&) { ++rejected; ++objects; continue; }
throw std::runtime_error("Wrong code-object target accepted");
}
if (!objects) throw std::runtime_error("Supply actual compiled code objects");
std::printf("PASS GPU_TARGET_CONTRACT target=%s objects=%u rejected=%u hardware_executed=0\n",
D4R_TARGET_ARCH, objects, rejected);
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL GPU_TARGET_CONTRACT %s\n", e.what()); return 5;
}
}
+8 -4
View File
@@ -1,5 +1,6 @@
#pragma once
#include "diagnostic.h"
#include "gpu_target.h"
#include <hip/hip_runtime_api.h>
namespace d4r::diag {
@@ -40,7 +41,8 @@ struct HipApi {
if (verbose || result != hipSuccess) std::printf("HIP %s -> %d (%s)\n", call, static_cast<int>(result), hipGetErrorName(result));
if (result != hipSuccess) throw std::runtime_error(std::string(call) + ": " + hipGetErrorString(result));
}
int select_gfx1201(int requested, hipDeviceProp_t& selected) const {
static const char* target_arch() { return D4R_TARGET_ARCH; }
int select_architecture(int requested, hipDeviceProp_t& selected) const {
// Architecture spoofing invalidates a gfx12 correctness test.
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);
@@ -59,14 +61,16 @@ struct HipApi {
i, props.name, props.gcnArchName, props.warpSize, props.totalGlobalMem,
props.pciDomainID, props.pciBusID, props.pciDeviceID);
const std::string arch = props.gcnArchName;
if (arch.substr(0, arch.find(':')) == "gfx1201" && (requested < 0 || requested == i) && found < 0) {
if (gpu_architecture(arch) == target_arch() && (requested < 0 || requested == i) && found < 0) {
found = i;
selected = props;
}
}
if (found < 0) throw std::runtime_error("No selected gfx1201 device; never substitute gfx110x");
if (found < 0) throw std::runtime_error(std::string("No selected ") + target_arch() + " device; refusing architecture substitution");
require_gpu_target(selected.gcnArchName, target_arch());
check(hipSetDevice(found), "hipSetDevice");
std::printf("SELECTED HIP ordinal=%d architecture=gfx1201\n", found);
std::printf("SELECTED HIP ordinal=%d architecture=%s validation=%s\n", found, target_arch(),
std::string(target_arch()) == "gfx1201" ? "previously_tested_target" : "hardware_unverified_target");
return found;
}
};
+3 -3
View File
@@ -9,13 +9,13 @@ int main(int argc, char** argv)
if (args.module.empty()) throw std::runtime_error("--module is required");
HipApi api(args.hip_root);
hipDeviceProp_t props{};
api.select_gfx1201(args.device, props);
api.select_architecture(args.device, props);
loaded_modules();
size_t free = 0, total = 0;
api.check(api.hipMemGetInfo(&free, &total), "hipMemGetInfo");
std::printf("VRAM free=%zu total=%zu\n", free, total);
hipModule_t module = nullptr;
api.check(api.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(gfx1201)");
api.check(api.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(target)");
struct ModuleCleanup { HipApi& api; hipModule_t m; ~ModuleCleanup() { if (m) (void)api.hipModuleUnload(m); } } cleanup{api, module};
hipFunction_t kernel = nullptr;
api.check(api.hipModuleGetFunction(&kernel, module, "d4r_probe_pattern"), "hipModuleGetFunction");
@@ -41,7 +41,7 @@ int main(int argc, char** argv)
allocation_cleanup.p = nullptr;
api.check(api.hipModuleUnload(module), "hipModuleUnload");
cleanup.m = nullptr;
std::printf("PASS HIP architecture=gfx1201 iterations=%u guard_verified=1\n", args.iterations);
std::printf("PASS HIP architecture=%s iterations=%u guard_verified=1\n", d4r::diag::HipApi::target_arch(), args.iterations);
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL HIP %s\n", e.what());
+1 -1
View File
@@ -9,7 +9,7 @@ int main(int argc, char** argv)
Args args(argc, argv);
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
hipModule_t module = nullptr;
hipFunction_t kernel = nullptr;
void* output = nullptr;
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Compare real gfx1201 K enc1/enc2 launches with the existing numpy reference."""
"""Compare RDNA4 K enc1/enc2 launches with the existing numpy reference."""
import argparse
import math
import pathlib
@@ -73,7 +73,7 @@ def main():
# after each K stage has been compared on captured DLSS weights/activations.
if full_abs > 0.001 or full_psnr < 60.0 or merged_abs > 0.001 or merged_psnr < 60.0:
raise RuntimeError(f"K {args.kernel_name} numerical mismatch against pwin_model.py")
print(f"PASS K_REFERENCE architecture=gfx1201 kernel={args.kernel_name} "
print(f"PASS K_REFERENCE reference_layout=gfx12 kernel={args.kernel_name} "
"nonzero_weights=1 transformer_executed=1 nan_inf=0")
+3 -3
View File
@@ -42,7 +42,7 @@ int main(int argc, char** argv)
if (args.module.empty()) throw std::runtime_error("--module is required");
HipApi hip(args.hip_root);
hipDeviceProp_t properties{};
hip.select_gfx1201(args.device, properties);
hip.select_architecture(args.device, properties);
if (args.kernel_name != "enc1" && args.kernel_name != "enc2")
throw std::runtime_error("--kernel-name must be enc1 or enc2");
const bool enc2 = args.kernel_name == "enc2";
@@ -124,7 +124,7 @@ int main(int argc, char** argv)
return 5;
}
}
std::printf("PASS K_IDENTITY architecture=gfx1201 kernel=%s iterations=%u full_elements=%zu merged_elements=%zu transformer_executed=1 nonzero_weights=0\n",
std::printf("PASS K_IDENTITY architecture=%s kernel=%s iterations=%u full_elements=%zu merged_elements=%zu transformer_executed=1 nonzero_weights=0\n", d4r::diag::HipApi::target_arch(),
args.kernel_name.c_str(), args.iterations, full_elements, merged_elements);
// Exercise nonzero V projection, position-only attention and Wo GEMMs.
@@ -213,7 +213,7 @@ int main(int argc, char** argv)
save("full.bin", full.data(), full.size() * sizeof(uint16_t));
save("merged.bin", merged.data(), merged.size() * sizeof(uint16_t));
}
std::printf("PASS K_NONZERO architecture=gfx1201 kernel=%s changed_elements=%zu full_elements=%zu merged_elements=%zu fixture_saved=%d numerical_reference_pending=1\n",
std::printf("PASS K_NONZERO architecture=%s kernel=%s changed_elements=%zu full_elements=%zu merged_elements=%zu fixture_saved=%d numerical_reference_pending=1\n", d4r::diag::HipApi::target_arch(),
args.kernel_name.c_str(), changed, full.size(), merged.size(), !args.fixture_dir.empty());
return 0;
} catch (const std::exception& error) {
+1 -1
View File
@@ -139,7 +139,7 @@ def validate(layer, directory, output, window_count=1, real_capture=False):
if maximum > absolute_limit or psnr < 60:
worst = int(difference.argmax())
raise RuntimeError(f'K mismatch at {worst}: reference={expected[worst]}, gpu={actual[worst]}')
print(f'PASS K_REPLAY_REFERENCE kernel={layer} architecture=gfx1201 nan_inf=0')
print(f'PASS K_REPLAY_REFERENCE kernel={layer} reference_layout=gfx12 nan_inf=0')
if __name__ == '__main__':
+1 -1
View File
@@ -153,7 +153,7 @@ def validate(layer, directory, output, block_count, real_capture, exact=False):
maximum, peak, psnr, steps = metrics(expected, actual, f'M_REPLAY_REFERENCE kernel={layer}')
if ((exact or not real_capture) and maximum != 0) or (real_capture and (steps.max() > 1 or psnr < 50)):
raise RuntimeError(f'M mismatch: exact synthetic / <=1 FP8 step and >=50 dB real gate; peak={peak}')
print(f'PASS M_REPLAY_REFERENCE kernel={layer} blocks={len(pairs)} architecture=gfx1201 nan_inf=0')
print(f'PASS M_REPLAY_REFERENCE kernel={layer} blocks={len(pairs)} reference_layout=gfx12 nan_inf=0')
if __name__ == '__main__':
+3 -3
View File
@@ -37,7 +37,7 @@ int main(int argc, char** argv) {
throw std::runtime_error("--module, --fixture-dir and --output-dir are required");
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
const std::filesystem::path input(wide(args.fixture_dir)), output(wide(args.output_dir));
auto parameters = read_file(input / L"args.bin");
if (parameters.empty() || parameters.size() > 4096) throw std::runtime_error("Invalid replay parameter size");
@@ -84,7 +84,7 @@ int main(int argc, char** argv) {
std::memcpy(parameters.data() + offset, &pointer, 8);
}
hipModule_t module = nullptr;
hip.check(hip.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(replay gfx1201)");
hip.check(hip.hipModuleLoad(&module, args.module.c_str()), "hipModuleLoad(replay)");
struct Cleanup { HipApi& hip; hipModule_t module; ~Cleanup() { (void)hip.hipModuleUnload(module); } } cleanup{hip, module};
if (const char* debugBlock = std::getenv("D4R_SWIN_DEBUG_BLOCK")) {
int coordinates[2]{};
@@ -240,7 +240,7 @@ int main(int argc, char** argv) {
file.write(reinterpret_cast<const char*>(bytes.data()), std::streamsize(bytes.size()));
if (!file) throw std::runtime_error("Cannot save replay allocation");
}
std::printf("PASS NATIVE_REPLAY architecture=gfx1201 kernel=%s iterations=%u benchmark_pairs=%u numerical_reference=pending\n",
std::printf("PASS NATIVE_REPLAY architecture=%s kernel=%s iterations=%u benchmark_pairs=%u numerical_reference=pending\n", d4r::diag::HipApi::target_arch(),
kernel.c_str(), args.benchmark_module.empty() ? args.iterations : 1, args.benchmark_module.empty() ? 0 : args.iterations);
return 0;
} catch (const std::exception& error) {
+2 -2
View File
@@ -34,7 +34,7 @@ int main(int argc, char** argv)
if (dlss_path.filename() != L"nvngx_dlss.dll") throw std::runtime_error("DLSS file must be named nvngx_dlss.dll");
HipApi hip(args.hip_root);
hipDeviceProp_t props{};
hip.select_gfx1201(args.device, props);
hip.select_architecture(args.device, props);
SearchDirectory cuda_search(std::filesystem::path(wide(args.cuda_dll)).parent_path());
CudaApi cuda(args.cuda_dll);
cuda.check(cuda.cuInit(0), "cuInit");
@@ -124,7 +124,7 @@ int main(int argc, char** argv)
cuda.check(cuda.cuCtxSynchronize(), "cuCtxSynchronize");
cuda.check(cuda.cuCtxSetCurrent(nullptr), "cuCtxSetCurrent(NULL)");
cuda.check(cuda.cuDevicePrimaryCtxRelease_v2(device), "cuDevicePrimaryCtxRelease_v2"); context = nullptr;
std::printf("PASS NGX_INIT architecture=gfx1201 sr_available=1 transformer_validation=pending\n");
std::printf("PASS NGX_INIT architecture=%s sr_available=1 transformer_validation=pending\n", d4r::diag::HipApi::target_arch());
return 0;
} catch (const std::exception& e) {
std::fprintf(stderr, "FAIL NGX_INIT %s\n", e.what());
+3 -3
View File
@@ -42,7 +42,7 @@ inline std::filesystem::path pixel_module_path() {
reinterpret_cast<LPCWSTR>(&pixel_module_path), &module)) throw std::runtime_error("Locate GPU conversion module directory");
wchar_t path[32768]{}; const DWORD length = GetModuleFileNameW(module, path, 32768);
if (!length || length == 32768) throw std::runtime_error("GPU conversion module path is invalid");
return std::filesystem::path(path).parent_path() / L"pixel_convert_gfx1201.hsaco";
return std::filesystem::path(path).parent_path() / diag::wide(std::string("pixel_convert_") + diag::HipApi::target_arch() + ".hsaco");
}
struct Runtime {
@@ -94,7 +94,7 @@ struct Runtime {
if (!d3d) throw std::runtime_error("Null D3D12 device");
try {
hipDeviceProp_t props{};
hip.select_gfx1201(-1, props);
hip.select_architecture(-1, props);
hip.verbose = cuda.verbose = !std::getenv("D4R_QUIET_API");
const auto luid = adapter_luid(d3d);
if (std::memcmp(&luid, props.luid, sizeof(luid))) throw std::runtime_error("D3D12/HIP LUID mismatch");
@@ -155,7 +155,7 @@ struct Runtime {
ngx_check(destroy(caps), "Destroy capability parameters");
if (available != 1 || initResult != 1 || needsDriver != 0)
throw std::runtime_error("CUDA DLSS is unavailable after capability initialization");
std::printf("D4R_RUNTIME platform=Windows architecture=gfx1201 cpu_frame_copies=0 frame_age=0\n");
std::printf("D4R_RUNTIME platform=Windows architecture=%s cpu_frame_copies=0 frame_age=0\n", d4r::diag::HipApi::target_arch());
} catch (...) { cleanup(); throw; }
}
Runtime(const Runtime&) = delete;
+3 -3
View File
@@ -27,11 +27,11 @@ int __cdecl initialize()
const char* root = std::getenv("HIP_PATH");
if (!root) return -5;
auto runtime = std::make_unique<d4r::diag::HipApi>(root);
device_ordinal = runtime->select_gfx1201(-1, properties);
device_ordinal = runtime->select_architecture(-1, properties);
hip = std::move(runtime);
runtime_ready.store(true, std::memory_order_release);
}
std::printf("NVAPI_COMPAT initialize physical=gfx1201 CUDA_model_profile=AD100\n");
std::printf("NVAPI_COMPAT initialize physical=%s CUDA_model_profile=AD100\n", properties.gcnArchName);
return 0;
} catch (const std::exception& e) { std::fprintf(stderr, "NVAPI_COMPAT init failed: %s\n", e.what()); return -1; }
}
@@ -48,7 +48,7 @@ int __cdecl architecture(void* handle, ArchInfo* info)
if (!valid(handle) || !info) return -5;
if (info->version != (sizeof(ArchInfo) | 1u << 16) && info->version != (sizeof(ArchInfo) | 2u << 16)) return -9;
info->architecture = 0x190; info->implementation = 2; info->revision = 0x11;
std::printf("NVAPI_COMPAT GetArchInfo profile=AD102 physical=gfx1201\n");
std::printf("NVAPI_COMPAT GetArchInfo profile=AD102 physical=%s\n", properties.gcnArchName);
return 0;
}
int __cdecl adapter_id(void* handle, void* luid)
+1
View File
@@ -58,6 +58,7 @@ class PixelProgram {
public:
PixelProgram(diag::HipApi& hip, const std::filesystem::path& module) : hip_(hip) {
try {
diag::require_code_object_target(module, diag::HipApi::target_arch());
hip.check(hip.hipModuleLoad(&module_, diag::utf8(module.c_str()).c_str()), "Load native GPU format conversion");
hip.check(hip.hipModuleGetFunction(&decode_, module_, "d4r_pixel_decode"), "Resolve GPU pixel decode");
hip.check(hip.hipModuleGetFunction(&encode_, module_, "d4r_pixel_encode"), "Resolve GPU pixel encode");