#include "d3d12_external.h" #include "ngx_parameters.h" #include "ngx_cuda_evaluate.h" #include #include #include int main(int argc, char** argv) { using namespace d4r::diag; using namespace d4r::win; start(); try { Args args(argc, argv); if (args.cuda_dll.empty() || (args.interop_mode != "images" && (args.module.empty() || args.ngx_core.empty() || args.dlss_dll.empty()))) throw std::runtime_error("--module shim DLL, --cuda-dll, --ngx-core and --dlss-dll required"); const char* diagDir = std::getenv("D4R_DIAG_DIR"); if (!diagDir && args.interop_mode != "images") throw std::runtime_error("Set D4R_DIAG_DIR"); const std::filesystem::path directory(diagDir ? wide(diagDir) : std::filesystem::current_path().wstring()); std::filesystem::create_directories(directory); const bool commandBackend = args.interop_mode == "command-list"; if (args.interop_mode == "images" && args.pixel_profile != "baseline") throw std::runtime_error("Raw CUDA image diagnostic requires baseline formats"); std::printf("D3D12_PIXEL_PROFILE %s\n", args.pixel_profile.c_str()); if (commandBackend && _putenv_s("D4R_D3D12_COMMAND_BACKEND", "1")) throw std::runtime_error("Cannot enable command backend"); for (const auto& pair : {std::make_pair("D4R_HIP_ROOT", args.hip_root), 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); ComPtr factory; dx(CreateDXGIFactory1(IID_PPV_ARGS(factory.GetAddressOf())), "CreateDXGIFactory1"); ComPtr adapter; bool found = false; for (UINT i = 0; ; ++i) { const HRESULT result = factory->EnumAdapters1(i, adapter.ReleaseAndGetAddressOf()); if (result == DXGI_ERROR_NOT_FOUND) break; dx(result, "EnumAdapters"); DXGI_ADAPTER_DESC1 desc{}; dx(adapter->GetDesc1(&desc), "GetDesc1"); if (!std::memcmp(&desc.AdapterLuid, props.luid, sizeof(LUID))) { found = true; break; } } if (!found) throw std::runtime_error("HIP adapter missing from DXGI"); ComPtr device; dx(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(device.GetAddressOf())), "D3D12CreateDevice"); ComPtr queue; D3D12_COMMAND_QUEUE_DESC qd{}; qd.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; dx(device->CreateCommandQueue(&qd, IID_PPV_ARGS(queue.GetAddressOf())), "CreateCommandQueue"); ComPtr completion; dx(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(completion.GetAddressOf())), "CreateFence(harness)"); Handle event; event.value = CreateEventW(nullptr, FALSE, FALSE, nullptr); if (!event.value) throw std::runtime_error("CreateEvent(harness)"); uint64_t fenceValue = 0; auto drain = [&] { dx(queue->Signal(completion.Get(), ++fenceValue), "Queue Signal(harness)"); if (completion->GetCompletedValue() < fenceValue) { dx(completion->SetEventOnCompletion(fenceValue, event.value), "SetEventOnCompletion(harness)"); if (WaitForSingleObject(event.value, 30000) != WAIT_OBJECT_0) throw std::runtime_error("Harness GPU timeout"); } }; ComPtr allocator; ComPtr list; dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(allocator.GetAddressOf())), "CreateCommandAllocator"); dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator.Get(), nullptr, IID_PPV_ARGS(list.GetAddressOf())), "CreateCommandList"); constexpr unsigned width = 256, height = 144, outWidth = 512, outHeight = 288; struct Texture { ComPtr image, upload; D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint{}; UINT64 bytes; } textures[5]; for (unsigned i = 0; i < 5; ++i) { auto& texture = textures[i]; D3D12_RESOURCE_DESC desc{}; desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Width = i == 4 ? 1 : i == 3 ? outWidth : width; desc.Height = i == 4 ? 1 : i == 3 ? outHeight : height; desc.DepthOrArraySize = desc.MipLevels = desc.SampleDesc.Count = 1; desc.Format = i == 0 || i == 3 ? DXGI_FORMAT_R16G16B16A16_FLOAT : i == 2 ? DXGI_FORMAT_R16G16_FLOAT : DXGI_FORMAT_R32_FLOAT; if (args.pixel_profile == "packed") desc.Format = i == 0 || i == 3 ? DXGI_FORMAT_R11G11B10_FLOAT : i == 2 ? DXGI_FORMAT_R32G32B32A32_FLOAT : i == 4 ? DXGI_FORMAT_R16_FLOAT : DXGI_FORMAT_R32_FLOAT; if (args.pixel_profile == "unorm") desc.Format = i == 3 ? DXGI_FORMAT_B8G8R8A8_UNORM : i == 2 ? DXGI_FORMAT_R16G16_SNORM : i == 4 ? DXGI_FORMAT_R32G32B32A32_FLOAT : desc.Format; if (i == 3) desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; D3D12_HEAP_PROPERTIES heap{}; heap.Type = D3D12_HEAP_TYPE_DEFAULT; heap.CreationNodeMask = heap.VisibleNodeMask = 1; dx(device->CreateCommittedResource(&heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(texture.image.GetAddressOf())), "CreateCommittedResource(texture)"); UINT rows; UINT64 rowBytes; device->GetCopyableFootprints(&desc, 0, 1, 0, &texture.footprint, &rows, &rowBytes, &texture.bytes); texture.upload = make_buffer(device.Get(), texture.bytes, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ); void* raw = nullptr; D3D12_RANGE noRead{}; dx(texture.upload->Map(0, &noRead, &raw), "Map(synthetic initialization)"); std::memset(raw, 0, size_t(texture.bytes)); for (unsigned y = 0; y < desc.Height; ++y) for (unsigned x = 0; x < desc.Width; ++x) { auto* row = static_cast(raw) + y * texture.footprint.Footprint.RowPitch; if (i == 0) { uint16_t pixel[] = {uint16_t(((x / 16 + y / 16) & 1) ? 0x3a00 : 0x3400), uint16_t((x & 32) ? 0x3800 : 0x3400), uint16_t((y & 32) ? 0x3a00 : 0x3800), 0x3c00}; if (desc.Format == DXGI_FORMAT_R11G11B10_FLOAT) { const uint32_t packed = uint32_t(pixel[0] >> 4) | (uint32_t(pixel[1] >> 4) << 11) | (uint32_t(pixel[2] >> 5) << 22); std::memcpy(row + x * 4, &packed, 4); } else std::memcpy(row + x * 8, pixel, sizeof(pixel)); } else if (i == 1 || i == 4) { if (desc.Format == DXGI_FORMAT_R16_FLOAT) { const uint16_t one = 0x3c00; std::memcpy(row + x * 2, &one, 2); } else { const float value = i == 1 ? .5f : 1.f; std::memcpy(row + x * 4, &value, 4); } } else if (i == 3) { if (desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT) { const uint16_t pixel[] = {0x7e00, 0x7e00, 0x7e00, 0x7e00}; std::memcpy(row + x * 8, pixel, 8); } else { const uint32_t sentinel = 0xffffffff; std::memcpy(row + x * 4, &sentinel, 4); } } } texture.upload->Unmap(0, nullptr); D3D12_TEXTURE_COPY_LOCATION src{}, dst{}; src.pResource = texture.upload.Get(); src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; src.PlacedFootprint = texture.footprint; dst.pResource = texture.image.Get(); dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); transition(list.Get(), texture.image.Get(), D3D12_RESOURCE_STATE_COPY_DEST, i == 3 ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); } dx(list->Close(), "Close(synthetic producers)"); ID3D12CommandList* producer[] = {list.Get()}; if (!commandBackend) { queue->ExecuteCommandLists(1, producer); drain(); } if (args.interop_mode == "images") { CudaApi cuda(args.cuda_dll); cuda.check(cuda.cuInit(0), "cuInit(image interop)"); CUdevice ordinal = 0; CUcontext context = nullptr; cuda.check(cuda.cuDeviceGet(&ordinal, 0), "cuDeviceGet(image interop)"); cuda.check(cuda.cuDevicePrimaryCtxRetain(&context, ordinal), "cuDevicePrimaryCtxRetain(image interop)"); struct ContextCleanup { CudaApi& cuda; CUdevice ordinal; ~ContextCleanup() { (void)cuda.cuCtxSetCurrent(nullptr); (void)cuda.cuDevicePrimaryCtxRelease_v2(ordinal); } } contextCleanup{cuda, ordinal}; cuda.check(cuda.cuCtxSetCurrent(context), "cuCtxSetCurrent(image interop)"); ExternalApi external{hip}; SharedTimeline timeline(external, device.Get()); d4r::cuda::ImageApi images(cuda); std::unique_ptr planes[5]; std::unique_ptr arrays[5]; dx(allocator->Reset(), "Reset(image interop allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(image interop list)"); for (unsigned i = 0; i < 5; ++i) { const auto desc = resource_desc(textures[i].image.Get()); const unsigned channels = i == 0 || i == 3 ? 4 : i == 2 ? 2 : 1; const bool half = i == 0 || i == 2 || i == 3; planes[i] = std::make_unique(external, device.Get(), desc); arrays[i] = std::make_unique(images, unsigned(desc.Width), desc.Height, half ? 16 : 32, channels, i == 3, i == 0 ? 1 : 0); planes[i]->copy_input(list.Get(), textures[i].image.Get(), i == 3 ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); } dx(list->Close(), "Close(image interop input)"); ID3D12CommandList* copies[] = {list.Get()}; queue->ExecuteCommandLists(1, copies); timeline.wait_input(queue.Get()); for (unsigned i = 0; i < 5; ++i) arrays[i]->upload_device(reinterpret_cast(planes[i]->mapped), planes[i]->footprint.Footprint.RowPitch); for (unsigned i = 0; i < 5; ++i) { const auto desc = resource_desc(textures[i].image.Get()); const unsigned channels = i == 0 || i == 3 ? 4 : i == 2 ? 2 : 1; const bool half = i == 0 || i == 2 || i == 3; const size_t rowBytes = size_t(desc.Width) * channels * (half ? 2 : 4); std::vector actual(rowBytes * desc.Height); arrays[i]->download(actual.data()); void* expected = nullptr; D3D12_RANGE read{0, size_t(textures[i].bytes)}; dx(textures[i].upload->Map(0, &read, &expected), "Map(expected diagnostic image)"); bool matches = true; for (unsigned y = 0; y < desc.Height; ++y) if (std::memcmp(actual.data() + y * rowBytes, static_cast(expected) + y * textures[i].footprint.Footprint.RowPitch, rowBytes)) { matches = false; break; } D3D12_RANGE noWrite{}; textures[i].upload->Unmap(0, &noWrite); std::printf("D3D12_ARRAY_COPY plane=%u format=%u matches=%u first=%02x%02x%02x%02x\n", i, desc.Format, matches, actual[0], actual[1], actual[2], actual[3]); 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"); return 0; } Library shim(wide(args.module)); using Init = unsigned(*)(unsigned long long, const wchar_t*, ID3D12Device*, unsigned, const void*); using Allocate = unsigned(*)(void**); using Destroy = unsigned(*)(void*); using Create = unsigned(*)(ID3D12GraphicsCommandList*, unsigned, void*, void**); using Evaluate = unsigned(*)(ID3D12CommandQueue*, void*, void*); using Release = unsigned(*)(void*); using Shutdown = unsigned(*)(); auto check = [](unsigned result, const char* call) { if (result != 1) throw std::runtime_error(std::string(call) + " NGX=" + std::to_string(result)); }; check(shim.symbol("NVSDK_NGX_D3D12_Init_Ext")(241534723ull, directory.c_str(), device.Get(), 0x15, nullptr), "D3D12 Init"); auto shutdown = shim.symbol("NVSDK_NGX_D3D12_Shutdown"); struct ShutdownCleanup { Shutdown fn; ~ShutdownCleanup() { (void)fn(); } } shutdownCleanup{shutdown}; void* parameters = nullptr; check(shim.symbol("NVSDK_NGX_D3D12_AllocateParameters")(¶meters), "AllocateParameters"); auto destroy = shim.symbol("NVSDK_NGX_D3D12_DestroyParameters"); struct ParameterCleanup { Destroy fn; void* p; ~ParameterCleanup() { (void)fn(p); } } parameterCleanup{destroy, parameters}; for (const auto& pair : {std::make_pair("Width", width), std::make_pair("Height", height), std::make_pair("OutWidth", outWidth), std::make_pair("OutHeight", outHeight), std::make_pair("CreationNodeMask", 1u), std::make_pair("VisibilityNodeMask", 1u)}) d4r_ngx_set_uint(parameters, pair.first, pair.second); d4r_ngx_set_int(parameters, "PerfQualityValue", 2); d4r_ngx_set_int(parameters, "DLSS.Feature.Create.Flags", 0); for (const char* name : {"DLSS.Hint.Render.Preset.DLAA", "DLSS.Hint.Render.Preset.Quality", "DLSS.Hint.Render.Preset.Balanced", "DLSS.Hint.Render.Preset.Performance", "DLSS.Hint.Render.Preset.UltraPerformance", "DLSS.Hint.Render.Preset.UltraQuality"}) d4r_ngx_set_uint(parameters, name, args.preset); void* handle = nullptr; check(shim.symbol("NVSDK_NGX_D3D12_CreateFeature")(nullptr, 1, parameters, &handle), "D3D12 CreateFeature"); auto release = shim.symbol("NVSDK_NGX_D3D12_ReleaseFeature"); struct FeatureCleanup { Release fn; void* h; ~FeatureCleanup() { (void)fn(h); } } featureCleanup{release, handle}; static const char* names[] = {"Color", "Depth", "MotionVectors", "Output", "ExposureTexture"}; for (unsigned i = 0; i < 5; ++i) d4r_ngx_set_d3d12_resource(parameters, names[i], textures[i].image.Get()); d4r_ngx_set_int(parameters, "Disable.Watermark", 1); auto readback = make_buffer(device.Get(), textures[3].bytes, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST); ComPtr predecessor; ComPtr predecessorAllocator; if (commandBackend) { // Keep initial synthetic producers unsubmitted until the first // batch, before the list which contains the NGX evaluation. predecessor = list; predecessorAllocator = allocator; dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(allocator.ReleaseAndGetAddressOf())), "Create game-style allocator"); dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator.Get(), nullptr, IID_PPV_ARGS(list.ReleaseAndGetAddressOf())), "Create game-style command list"); dx(list->Close(), "Close initial game-style list"); } for (unsigned frame = 0; frame < args.iterations; ++frame) { d4r_ngx_set_int(parameters, "Reset", frame == 0 ? 1 : 0); if (commandBackend) { dx(allocator->Reset(), "Reset(game-style allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(game-style list)"); using RecordedEvaluate = unsigned(*)(ID3D12GraphicsCommandList*, void*, void*, void*); check(shim.symbol("NVSDK_NGX_D3D12_EvaluateFeature")(list.Get(), handle, parameters, nullptr), "D3D12 recorded same-frame Evaluate"); // The caller may reuse/mutate its parameter object as soon as // Evaluate returns. The queued snapshot must remain immutable. d4r_ngx_set_d3d12_resource(parameters, "Color", nullptr); d4r_ngx_set_int(parameters, "Reset", 0); } else { check(shim.symbol("d4r_D3D12_EvaluateAtBoundary")(queue.Get(), handle, parameters), "D3D12 same-frame Evaluate"); dx(allocator->Reset(), "Reset(harness allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(harness list)"); } transition(list.Get(), textures[3].image.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); D3D12_TEXTURE_COPY_LOCATION src{}, dst{}; src.pResource = textures[3].image.Get(); src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dst.pResource = readback.Get(); dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst.PlacedFootprint = textures[3].footprint; list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); transition(list.Get(), textures[3].image.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); dx(list->Close(), "Close(verification)"); if (commandBackend && frame == 0) { ID3D12CommandList* batch[] = {predecessor.Get(), list.Get()}; queue->ExecuteCommandLists(2, batch); } else { ID3D12CommandList* verify[] = {list.Get()}; queue->ExecuteCommandLists(1, verify); } drain(); if (commandBackend) d4r_ngx_set_d3d12_resource(parameters, "Color", textures[0].image.Get()); void* raw = nullptr; D3D12_RANGE range{0, size_t(textures[3].bytes)}; dx(readback->Map(0, &range, &raw), "Map(verification only)"); std::vector pixels(size_t(outWidth) * outHeight * 4); const auto format = resource_desc(textures[3].image.Get()).Format; if (format == DXGI_FORMAT_R16G16B16A16_FLOAT) { for (unsigned y = 0; y < outHeight; ++y) std::memcpy(pixels.data() + size_t(y) * outWidth * 4, static_cast(raw) + y * textures[3].footprint.Footprint.RowPitch, outWidth * 8); } else { std::ofstream native(directory / ("output-" + std::to_string(frame) + (args.pixel_profile == "packed" ? ".r11g11b10f" : ".bgra8")), std::ios::binary); // Independently decode the diagnostic readback for previews and // frame comparisons. No CPU image copies are in the backend. static const auto unormHalf = [] { std::array lut{}; for (unsigned b = 0; b < 256; ++b) { double best = INFINITY; for (unsigned h = 0; h <= 0x3c00; ++h) { double error = std::abs(double(half_value(uint16_t(h))) - double(b)/255.); if (error < best || (error == best && !(h & 1))) { best = error; lut[b] = uint16_t(h); } } } return lut; }(); for (unsigned y = 0; y < outHeight; ++y) { const auto* row = static_cast(raw) + y * textures[3].footprint.Footprint.RowPitch; native.write(reinterpret_cast(row), outWidth * 4); for (unsigned x = 0; x < outWidth; ++x) { auto* p = pixels.data() + (size_t(y) * outWidth + x) * 4; if (format == DXGI_FORMAT_R11G11B10_FLOAT) { uint32_t value = 0; std::memcpy(&value,row + x * 4,4); p[0] = uint16_t((value & 2047) << 4); p[1] = uint16_t(((value >> 11) & 2047) << 4); p[2] = uint16_t((value >> 22) << 5); p[3] = 0x3c00; } else for (unsigned c = 0; c < 4; ++c) p[c] = unormHalf[row[x * 4 + (c == 0 ? 2 : c == 2 ? 0 : c)]]; } } if (!native) throw std::runtime_error("Saving native output format failed"); } D3D12_RANGE noWrite{}; readback->Unmap(0, &noWrite); double sum = 0, square = 0; for (size_t i = 0; i < pixels.size(); ++i) { const float value = half_value(pixels[i]); if (!std::isfinite(value)) throw std::runtime_error("D3D12 output contains NaN/Inf or unwritten pixels"); if ((i & 3) < 3) { sum += value; square += double(value) * value; } } const double count = outWidth * outHeight * 3, variance = square / count - (sum / count) * (sum / count); save_output(directory, pixels, outWidth, outHeight, frame); std::printf("D3D12_OUTPUT preset=%u frame=%u finite=1 mean=%.9g variance=%.9g frame_age=0\n", args.preset, frame, sum/count, variance); if (variance < 1e-6) throw std::runtime_error("D3D12 output lost the synthetic pattern"); } loaded_modules(); std::printf("PASS D3D12_DLSS architecture=gfx1201 preset=%u frames=%u fast_path_cpu_copies=0 frame_age=0 queue_integration=%s\n", args.preset, args.iterations, 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; } }