From 6cb6843870cd5dc071c618f1e203361cb5d186ae Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Fri, 25 Apr 2025 06:43:32 +0200 Subject: [PATCH 01/13] [SER] Basic execution tests - All trivial scalar/vector/matrix getters - HitObject::FromRayQuery with procedural hit - HitObject::GetAttributes with custom attributes and procedural hit SER implementation tracker: #7214 --- tools/clang/unittests/HLSLExec/DXRUtil.h | 226 +++ .../unittests/HLSLExec/ExecutionTest.cpp | 718 +++++++ .../unittests/HLSLExec/ExecutionTest_SER.h | 1703 +++++++++++++++++ 3 files changed, 2647 insertions(+) create mode 100644 tools/clang/unittests/HLSLExec/DXRUtil.h create mode 100644 tools/clang/unittests/HLSLExec/ExecutionTest_SER.h diff --git a/tools/clang/unittests/HLSLExec/DXRUtil.h b/tools/clang/unittests/HLSLExec/DXRUtil.h new file mode 100644 index 0000000000..1f008885cf --- /dev/null +++ b/tools/clang/unittests/HLSLExec/DXRUtil.h @@ -0,0 +1,226 @@ +//===------------ DXRUtil.h - DXR Utility Functions ------------*- C++ -*-===// +/////////////////////////////////////////////////////////////////////////////// +// // +// DXRUtil.h // +// Copyright (C) Nvidia Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// This file contains the utility functions for DXR execution tests. // +// // +/////////////////////////////////////////////////////////////////////////////// + +//= DXR Utility +//============================================================================ +#define SHADER_ID_SIZE_IN_BYTES 32 + +#ifndef ROUND_UP +#define ROUND_UP(v, powerOf2Alignment) \ + (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1)) +#endif +struct SceneConsts { + DirectX::XMFLOAT4 eye; + DirectX::XMFLOAT4 U; + DirectX::XMFLOAT4 V; + DirectX::XMFLOAT4 W; + float sceneScale; + unsigned windowSize[2]; + int rayFlags; +}; + +struct Instance { + D3D12_RAYTRACING_GEOMETRY_TYPE type; + DirectX::XMFLOAT4X4 matrix; + UINT geometryCount; + UINT bottomASIdx; + UINT instanceID; + UINT mask; + UINT flags; +}; + +class ShaderTable { +public: + void Init(ID3D12Device *device, int raygenCount, int missCount, + int hitGroupCount, int rayTypeCount, int rootTableDwords) { + m_rayTypeCount = rayTypeCount; + m_raygenCount = raygenCount; + m_missCount = missCount * rayTypeCount; + m_hitGroupCount = hitGroupCount * rayTypeCount; + m_rootTableSizeInBytes = rootTableDwords * 4; + m_shaderRecordSizeInBytes = + ROUND_UP(m_rootTableSizeInBytes + SHADER_ID_SIZE_IN_BYTES, + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT); + m_missStartIdx = m_raygenCount; + m_hitGroupStartIdx = m_missStartIdx + m_missCount; + + const int m_totalSizeInBytes = + (m_raygenCount + m_missCount + m_hitGroupCount) * + m_shaderRecordSizeInBytes; + + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer( + m_totalSizeInBytes, D3D12_RESOURCE_FLAG_NONE, + std::max(D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT, + D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)); + CD3DX12_HEAP_PROPERTIES heap = + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + VERIFY_SUCCEEDED(device->CreateCommittedResource( + &heap, D3D12_HEAP_FLAG_NONE, &desc, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, nullptr, + IID_PPV_ARGS(&m_sbtResource))); + m_sbtResource->SetName(L"SBT Resource Heap"); + CD3DX12_HEAP_PROPERTIES upload = + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + VERIFY_SUCCEEDED(device->CreateCommittedResource( + &upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, IID_PPV_ARGS(&m_sbtUploadResource))); + m_sbtUploadResource->SetName(L"SBT Upload Heap"); + + VERIFY_SUCCEEDED(m_sbtUploadResource->Map(0, nullptr, (void **)&m_hostPtr)); + } + + void Upload(ID3D12GraphicsCommandList *cmdlist) { + CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( + m_sbtResource, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_COPY_DEST); + cmdlist->ResourceBarrier(1, &barrier); + cmdlist->CopyResource(m_sbtResource, m_sbtUploadResource); + CD3DX12_RESOURCE_BARRIER barrier2 = CD3DX12_RESOURCE_BARRIER::Transition( + m_sbtResource, D3D12_RESOURCE_STATE_COPY_DEST, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + cmdlist->ResourceBarrier(1, &barrier2); + } + + int GetShaderRecordSizeInBytes() { return m_shaderRecordSizeInBytes; } + + int GetRaygenShaderRecordIdx(int idx) { return idx; } + int GetMissShaderRecordIdx(int idx, int rayType) { + return m_missStartIdx + idx * m_rayTypeCount + rayType; + } + int GetHitGroupShaderRecordIdx(int idx, int rayType) { + return m_hitGroupStartIdx + idx * m_rayTypeCount + rayType; + } + + void *GetRaygenShaderIdPtr(int idx) { + return m_hostPtr + + GetRaygenShaderRecordIdx(idx) * m_shaderRecordSizeInBytes; + } + void *GetMissShaderIdPtr(int idx, int rayType) { + return m_hostPtr + + GetMissShaderRecordIdx(idx, rayType) * m_shaderRecordSizeInBytes; + } + void *GetHitGroupShaderIdPtr(int idx, int rayType) { + return m_hostPtr + + GetHitGroupShaderRecordIdx(idx, rayType) * m_shaderRecordSizeInBytes; + } + + void *GetRaygenRootTablePtr(int idx) { + return (char *)GetRaygenShaderIdPtr(idx) + SHADER_ID_SIZE_IN_BYTES; + } + void *GetMissRootTablePtr(int idx, int rayType) { + return (char *)GetMissShaderIdPtr(idx, rayType) + SHADER_ID_SIZE_IN_BYTES; + } + void *GetHitGroupRootTablePtr(int idx, int rayType) { + return (char *)GetHitGroupShaderIdPtr(idx, rayType) + + SHADER_ID_SIZE_IN_BYTES; + } + + int GetRaygenRangeInBytes() { + return m_raygenCount * m_shaderRecordSizeInBytes; + } + int GetMissRangeInBytes() { return m_missCount * m_shaderRecordSizeInBytes; } + int GetHitGroupRangeInBytes() { + return m_hitGroupCount * m_shaderRecordSizeInBytes; + } + + D3D12_GPU_VIRTUAL_ADDRESS GetRaygenStartGpuVA() { + return m_sbtResource->GetGPUVirtualAddress() + + GetRaygenShaderRecordIdx(0) * m_shaderRecordSizeInBytes; + } + D3D12_GPU_VIRTUAL_ADDRESS GetMissStartGpuVA() { + return m_sbtResource->GetGPUVirtualAddress() + + GetMissShaderRecordIdx(0, 0) * m_shaderRecordSizeInBytes; + } + D3D12_GPU_VIRTUAL_ADDRESS GetHitGroupStartGpuVA() { + return m_sbtResource->GetGPUVirtualAddress() + + GetHitGroupShaderRecordIdx(0, 0) * m_shaderRecordSizeInBytes; + } + +private: + CComPtr m_sbtResource; + CComPtr m_sbtUploadResource; + char *m_hostPtr = nullptr; + int m_rayTypeCount = 0; + int m_raygenCount = 0; + int m_missCount = 0; + int m_hitGroupCount = 0; + int m_rootTableSizeInBytes = 0; + int m_shaderRecordSizeInBytes = 0; + int m_missStartIdx = 0; + int m_hitGroupStartIdx = 0; +}; + +//----------------------------------------------------------------------------- +void AllocateBuffer( + ID3D12Device *pDevice, UINT64 bufferSize, ID3D12Resource **ppResource, + bool allowUAV = false, + D3D12_RESOURCE_STATES initialResourceState = D3D12_RESOURCE_STATE_COMMON, + const wchar_t *resourceName = nullptr) { + auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + auto bufferDesc = CD3DX12_RESOURCE_DESC::Buffer( + bufferSize, allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + : D3D12_RESOURCE_FLAG_NONE); + VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( + &uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, + initialResourceState, nullptr, IID_PPV_ARGS(ppResource))); + if (resourceName) { + (*ppResource)->SetName(resourceName); + } +} + +//----------------------------------------------------------------------------- +void ReallocScratchResource(ID3D12Device *pDevice, ID3D12Resource **ppResource, + UINT64 nbytes) { + + if (!(*ppResource) || (*ppResource)->GetDesc().Width < nbytes) { + AllocateBuffer(pDevice, nbytes, ppResource, true, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, L"scratchResource"); + } +} + +//----------------------------------------------------------------------------- +void AllocateUploadBuffer(ID3D12Device *pDevice, const void *pData, + UINT64 datasize, ID3D12Resource **ppResource, + const wchar_t *resourceName = nullptr) { + auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + auto bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(datasize); + VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( + &uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(ppResource))); + if (resourceName) { + (*ppResource)->SetName(resourceName); + } + void *pMappedData; + VERIFY_SUCCEEDED((*ppResource)->Map(0, nullptr, &pMappedData)); + memcpy(pMappedData, pData, datasize); + (*ppResource)->Unmap(0, nullptr); +} + +//----------------------------------------------------------------------------- +void AllocateBufferFromUpload(ID3D12Device *pDevice, + ID3D12GraphicsCommandList *pCommandList, + ID3D12Resource *uploadSource, + ID3D12Resource **ppResource, + D3D12_RESOURCE_STATES targetResourceState, + const wchar_t *resourceName = nullptr) { + const bool allowUAV = + targetResourceState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + AllocateBuffer(pDevice, uploadSource->GetDesc().Width, ppResource, allowUAV, + D3D12_RESOURCE_STATE_COPY_DEST, resourceName); + pCommandList->CopyResource(*ppResource, uploadSource); + CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( + *ppResource, D3D12_RESOURCE_STATE_COPY_DEST, targetResourceState); + pCommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&barrier); +} + +//= DXR Utility +//============================================================================ \ No newline at end of file diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index 6db27d7a41..403b261df1 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -60,6 +60,8 @@ #include "ShaderOpTest.h" #include #include + +#include "DXRUtil.h" // clang-format on #pragma comment(lib, "d3dcompiler.lib") @@ -292,6 +294,15 @@ class ExecutionTest { TEST_METHOD(SaturateTest); TEST_METHOD(SignTest); TEST_METHOD(Int64Test); + TEST_METHOD(SERBasicTest); + TEST_METHOD(SERScalarGetterTest); + TEST_METHOD(SERVectorGetterTest); + TEST_METHOD(SERMatrixGetterTest); + TEST_METHOD(SERRayQueryTest); + TEST_METHOD(SERIntersectionTest); + TEST_METHOD(SERGetAttributesTest); + TEST_METHOD(SERTraceHitMissNopTest); + TEST_METHOD(SERIsMissTest); TEST_METHOD(LifetimeIntrinsicTest) TEST_METHOD(WaveIntrinsicsTest); TEST_METHOD(WaveIntrinsicsDDITest); @@ -1917,6 +1928,12 @@ class ExecutionTest { CComPtr &pRootSignature, LPCWSTR pTargetProfile, LPCWSTR *pOptions, int numOptions); + CComPtr + RunDXRTest(ID3D12Device *pDevice0, LPCSTR shader, + D3D_SHADER_MODEL shaderModel, LPCWSTR *pOptions, int numOptions, + std::vector &testData, int windowWidth, int windowHeight, + bool useMesh, bool useProceduralGeometry, bool useIS, + int payloadCount = 1, int attributeCount = 2); void SetDescriptorHeap(ID3D12GraphicsCommandList *pCommandList, ID3D12DescriptorHeap *pHeap) { @@ -2078,6 +2095,707 @@ void ExecutionTest::RunRWByteBufferComputeTest(ID3D12Device *pDevice, WaitForSignal(pCommandQueue, FO); } +CComPtr ExecutionTest::RunDXRTest( + ID3D12Device *pDevice0, LPCSTR shader, D3D_SHADER_MODEL shaderModel, + LPCWSTR *pOptions, int numOptions, std::vector &testData, + int windowWidth, int windowHeight, bool useMesh, bool useProceduralGeometry, + bool useIS, int payloadCount, int attributeCount) { + CComPtr pDevice; + VERIFY_SUCCEEDED(pDevice0->QueryInterface(IID_PPV_ARGS(&pDevice))); + + LPCWSTR pTargetProfile; + switch (shaderModel) { + case D3D_SHADER_MODEL_6_9: + pTargetProfile = L"lib_6_9"; + break; + case D3D_SHADER_MODEL_6_8: + pTargetProfile = L"lib_6_8"; + break; + case D3D_SHADER_MODEL_6_7: + pTargetProfile = L"lib_6_7"; + break; + case D3D_SHADER_MODEL_6_6: + pTargetProfile = L"lib_6_6"; + break; + case D3D_SHADER_MODEL_6_5: + pTargetProfile = L"lib_6_5"; + break; + case D3D_SHADER_MODEL_6_4: + pTargetProfile = L"lib_6_4"; + break; + case D3D_SHADER_MODEL_6_3: + pTargetProfile = L"lib_6_3"; + break; + default: + // DXR capable shader model not found. + LogErrorFmt(L"DXR capable shader model not found."); + return nullptr; + } + + FenceObj FO; + InitFenceObj(pDevice, &FO); + + // Setup Resources + CComPtr pTestBuffer; + CComPtr pTestBufferRead; + CComPtr pSceneConstantBuffer; + + // Descriptor heap + CComPtr pDescriptorHeap; + { + // + // UAV descriptor heap layout: + // 0 - test buffer UAV + // 1 - vertex buffer SRV + // 2 - index buffer SRV + // + D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; + descriptorHeapDesc.NumDescriptors = 3; + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + pDevice->CreateDescriptorHeap(&descriptorHeapDesc, + IID_PPV_ARGS(&pDescriptorHeap)); + pDescriptorHeap->SetName(L"Descriptor Heap"); + } + int descriptorSize = pDevice->GetDescriptorHandleIncrementSize( + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + // Testbuffer + { + auto resDesc = CD3DX12_RESOURCE_DESC::Buffer( + testData.size() * sizeof(int), + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + auto defaultHeapProperties = + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( + &defaultHeapProperties, D3D12_HEAP_FLAG_NONE, &resDesc, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, + IID_PPV_ARGS(&pTestBuffer))); + pTestBuffer->SetName(L"Test Buffer"); + + const int descriptorIndex = 0; + D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + CD3DX12_CPU_DESCRIPTOR_HANDLE( + pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + descriptorIndex, descriptorSize); + D3D12_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {}; + UAVDesc.Format = DXGI_FORMAT_UNKNOWN; + UAVDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + UAVDesc.Buffer.FirstElement = 0; + UAVDesc.Buffer.NumElements = (UINT)testData.size(); + UAVDesc.Buffer.StructureByteStride = sizeof(int); + UAVDesc.Buffer.CounterOffsetInBytes = 0; + UAVDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + pDevice->CreateUnorderedAccessView(pTestBuffer, nullptr, &UAVDesc, + cpuDescriptorHandle); + } + + // Testbuffer Readback + { + CD3DX12_HEAP_PROPERTIES readHeap(D3D12_HEAP_TYPE_READBACK); + CD3DX12_RESOURCE_DESC readDesc( + CD3DX12_RESOURCE_DESC::Buffer(testData.size() * sizeof(int))); + pDevice->CreateCommittedResource(&readHeap, D3D12_HEAP_FLAG_NONE, &readDesc, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&pTestBufferRead)); + } + + // Create CBV resource (sceneConstantBuffer), index 1 + { + const int descriptorIndex = 1; + const UINT constantBufferSize = + (sizeof(SceneConsts) + + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) & + ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - + 1); // must be a multiple 256 bytes + D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + CD3DX12_CPU_DESCRIPTOR_HANDLE( + pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + descriptorIndex, descriptorSize); + auto resDesc = CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize); + auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + pDevice->CreateCommittedResource(&uploadHeapProperties, + D3D12_HEAP_FLAG_NONE, &resDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + IID_PPV_ARGS(&pSceneConstantBuffer)); + + UINT8 *sceneConstantBufferWO; + CD3DX12_RANGE readRange( + 0, 0); // We do not intend to read from this resource on the CPU. + pSceneConstantBuffer->Map( + 0, &readRange, reinterpret_cast(&sceneConstantBufferWO)); + + // Setup Scene Constants + SceneConsts sceneConsts = { + {25.f, -25.f, 700.f, 0.f}, + {536.f, 0.f, 0.f, 0.f}, + {0.f, 301.f, 0.f, 0.f}, + {0.f, 0., -699.f, 0.f}, + 100.f, + {(unsigned int)windowWidth, (unsigned int)windowHeight}, + 0x00}; + + memcpy(sceneConstantBufferWO, &sceneConsts, sizeof(SceneConsts)); + pSceneConstantBuffer->Unmap(0, nullptr); + + D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {}; + desc.SizeInBytes = constantBufferSize; + desc.BufferLocation = pSceneConstantBuffer->GetGPUVirtualAddress(); + pDevice->CreateConstantBufferView(&desc, cpuDescriptorHandle); + } + + // Local (SBT) root signature + CComPtr pLocalRootSignature; + { + CD3DX12_DESCRIPTOR_RANGE bufferRanges[1]; + CD3DX12_ROOT_PARAMETER rootParameters[1]; + bufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1, 0, + 2); // vertexBuffer(t1), indexBuffer(t2) + rootParameters[0].InitAsDescriptorTable( + _countof(bufferRanges), bufferRanges, D3D12_SHADER_VISIBILITY_ALL); + + CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; + rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, + D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE); + CComPtr signature; + CComPtr error; + VERIFY_SUCCEEDED(D3D12SerializeRootSignature( + &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); + VERIFY_SUCCEEDED(pDevice->CreateRootSignature( + 0, signature->GetBufferPointer(), signature->GetBufferSize(), + IID_PPV_ARGS(&pLocalRootSignature))); + pLocalRootSignature->SetName(L"Local Root Signature"); + } + + // Global root signature + CComPtr pGlobalRootSignature; + { + CD3DX12_DESCRIPTOR_RANGE bufferRanges[1]; + CD3DX12_ROOT_PARAMETER rootParameters[3]; + bufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, + 0); // testBuffer(u0) + rootParameters[0].InitAsShaderResourceView( + 0, 0, D3D12_SHADER_VISIBILITY_ALL); // accelStruct(t0) + rootParameters[1].InitAsConstantBufferView(0); // sceneConstants(b0) + rootParameters[2].InitAsDescriptorTable( + _countof(bufferRanges), bufferRanges, D3D12_SHADER_VISIBILITY_ALL); + + CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; + rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, + D3D12_ROOT_SIGNATURE_FLAG_NONE); + CComPtr signature; + CComPtr error; + VERIFY_SUCCEEDED(D3D12SerializeRootSignature( + &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); + VERIFY_SUCCEEDED(pDevice->CreateRootSignature( + 0, signature->GetBufferPointer(), signature->GetBufferSize(), + IID_PPV_ARGS(&pGlobalRootSignature))); + pGlobalRootSignature->SetName(L"Global Root Signature"); + } + + // Create command queue. + CComPtr pCommandQueue; + CreateCommandQueue(pDevice, L"RunDXRTest Command Queue", &pCommandQueue, + D3D12_COMMAND_LIST_TYPE_DIRECT); + + // Compile raygen shader. + CComPtr pShaderLib; + CompileFromText(shader, L"raygen", pTargetProfile, &pShaderLib, pOptions, + numOptions); + + // Describe and create the RT pipeline state object (RTPSO). + CD3DX12_STATE_OBJECT_DESC stateObjectDesc( + D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE); + auto lib = stateObjectDesc.CreateSubobject(); + CD3DX12_SHADER_BYTECODE byteCode(pShaderLib); + lib->SetDXILLibrary(&byteCode); + lib->DefineExport(L"raygen"); + lib->DefineExport(L"closesthit"); + lib->DefineExport(L"anyhit"); + lib->DefineExport(L"miss"); + if (useIS) { + lib->DefineExport(L"intersection"); + } + + const int maxRecursion = 1; + stateObjectDesc.CreateSubobject() + ->Config(payloadCount * sizeof(float), attributeCount * sizeof(float)); + stateObjectDesc + .CreateSubobject() + ->Config(maxRecursion); + + // Set Global Root Signature subobject. + auto globalRootSigSubObj = + stateObjectDesc + .CreateSubobject(); + globalRootSigSubObj->SetRootSignature(pGlobalRootSignature); + auto exports = stateObjectDesc.CreateSubobject< + CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT>(); + exports->SetSubobjectToAssociate(*globalRootSigSubObj); + exports->AddExport(L"raygen"); + exports->AddExport(L"closesthit"); + exports->AddExport(L"anyhit"); + exports->AddExport(L"miss"); + if (useIS) { + exports->AddExport(L"intersection"); + } + + auto hitGroup = + stateObjectDesc.CreateSubobject(); + hitGroup->SetClosestHitShaderImport(L"closesthit"); + hitGroup->SetAnyHitShaderImport(L"anyhit"); + if (useIS) { + hitGroup->SetIntersectionShaderImport(L"intersection"); + hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); + } + hitGroup->SetHitGroupExport(L"HitGroup"); + + CComPtr pStateObject; + CComPtr pStateObjectProperties; + VERIFY_SUCCEEDED( + pDevice->CreateStateObject(stateObjectDesc, IID_PPV_ARGS(&pStateObject))); + VERIFY_SUCCEEDED(pStateObject->QueryInterface(&pStateObjectProperties)); + stateObjectDesc.CreateSubobject() + ->SetRootSignature(pLocalRootSignature); + stateObjectDesc.CreateSubobject() + ->SetRootSignature(pGlobalRootSignature); + + // Create SBT + ShaderTable shaderTable; + shaderTable.Init(pDevice, + 1, // raygen count + 1, // miss count + useMesh && useProceduralGeometry ? 2 : 1, // hit group count + 1, // ray type count + 2 // dwords per root table + ); + + memcpy(shaderTable.GetRaygenShaderIdPtr(0), + pStateObjectProperties->GetShaderIdentifier(L"raygen"), + SHADER_ID_SIZE_IN_BYTES); + memcpy(shaderTable.GetMissShaderIdPtr(0, 0), + pStateObjectProperties->GetShaderIdentifier(L"miss"), + SHADER_ID_SIZE_IN_BYTES); + memcpy(shaderTable.GetHitGroupShaderIdPtr(0, 0), + pStateObjectProperties->GetShaderIdentifier(L"HitGroup"), + SHADER_ID_SIZE_IN_BYTES); + + auto tbl = pDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr; + memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), &tbl, 8); + + // Create a command allocator and list. + CComPtr pCommandAllocator; + CComPtr pCommandList; + VERIFY_SUCCEEDED(pDevice->CreateCommandAllocator( + D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCommandAllocator))); + VERIFY_SUCCEEDED(pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, + pCommandAllocator, nullptr, + IID_PPV_ARGS(&pCommandList))); + pCommandList->SetName(L"ExecutionTest::RunDXRTest Command List"); + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + VERIFY_SUCCEEDED(pCommandAllocator->Reset()); + VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + + // Create scene geometry. + CComPtr tlasResource; + CComPtr blasMeshResource; + CComPtr blasProceduralGeometryResource; + CComPtr instanceDescs; + CComPtr scratchResource; + + if (useMesh) { + CComPtr vertexBuffer; + CComPtr vertexBufferUpload; + CComPtr indexBuffer; + CComPtr indexBufferUpload; + + // Define a Quad + const float verts[] = { + -50.5f, 50.5f, 0.5f, // top left + 50.5f, -50.5f, 0.5f, // bottom right + -50.5f, -50.5f, 0.5f, // bottom left + 50.5f, 50.5f, 0.5f // top right + }; + const int indices[] = { + 0, 1, 2, // first triangle + 0, 3, 1 // second triangle + }; + + const UINT64 vertexDataSize = sizeof(verts); + const UINT64 indexDataSize = sizeof(indices); + + AllocateUploadBuffer(pDevice, verts, vertexDataSize, &vertexBufferUpload, + L"vertexBufferUpload"); + AllocateUploadBuffer(pDevice, indices, indexDataSize, &indexBufferUpload, + L"indexBufferUpload"); + + AllocateBufferFromUpload( + pDevice, pCommandList, vertexBufferUpload, &vertexBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"vertexBuffer"); + AllocateBufferFromUpload( + pDevice, pCommandList, indexBufferUpload, &indexBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"indexBuffer"); + + { + const int descriptorIndex = 1; + D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + CD3DX12_CPU_DESCRIPTOR_HANDLE( + pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + descriptorIndex, descriptorSize); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Shader4ComponentMapping = + D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Buffer.NumElements = + UINT(vertexDataSize / sizeof(DirectX::XMFLOAT3)); + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + srvDesc.Buffer.StructureByteStride = sizeof(DirectX::XMFLOAT3); + pDevice->CreateShaderResourceView(vertexBuffer, &srvDesc, + cpuDescriptorHandle); + } + { + const int descriptorIndex = 2; + D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + CD3DX12_CPU_DESCRIPTOR_HANDLE( + pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + descriptorIndex, descriptorSize); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Shader4ComponentMapping = + D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Buffer.NumElements = UINT(indexDataSize / sizeof(int)); + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + srvDesc.Buffer.StructureByteStride = sizeof(int); + pDevice->CreateShaderResourceView(indexBuffer, &srvDesc, + cpuDescriptorHandle); + } + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + VERIFY_SUCCEEDED(pCommandAllocator->Reset()); + VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + + if (!useIS) { + // Build BLAS. + { + D3D12_RAYTRACING_GEOMETRY_DESC geometryDesc = {}; + geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + geometryDesc.Triangles.IndexBuffer = + indexBuffer->GetGPUVirtualAddress(); + geometryDesc.Triangles.IndexCount = + static_cast(indexBuffer->GetDesc().Width) / sizeof(int); + geometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + geometryDesc.Triangles.Transform3x4 = 0; + geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + geometryDesc.Triangles.VertexCount = + static_cast(vertexBuffer->GetDesc().Width) / + sizeof(DirectX::XMFLOAT3); + geometryDesc.Triangles.VertexBuffer.StartAddress = + vertexBuffer->GetGPUVirtualAddress(); + geometryDesc.Triangles.VertexBuffer.StrideInBytes = + sizeof(DirectX::XMFLOAT3); + geometryDesc.Flags = + D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; // Non-opaque to trigger + // anyhit. + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; + accelInputs.Type = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + accelInputs.pGeometryDescs = &geometryDesc; + accelInputs.NumDescs = 1; + accelInputs.Flags = buildFlags; + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, + &prebuildInfo); + + ReallocScratchResource(pDevice, &scratchResource, + prebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, + &blasMeshResource, true, + D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, + L"blasMesh"); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; + buildDesc.Inputs = accelInputs; + buildDesc.ScratchAccelerationStructureData = + scratchResource->GetGPUVirtualAddress(); + buildDesc.DestAccelerationStructureData = + blasMeshResource->GetGPUVirtualAddress(); + + pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, + nullptr); + CD3DX12_RESOURCE_BARRIER barrier = + CD3DX12_RESOURCE_BARRIER::UAV(blasMeshResource); + pCommandList->ResourceBarrier(1, + (const D3D12_RESOURCE_BARRIER *)&barrier); + } + } + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + VERIFY_SUCCEEDED(pCommandAllocator->Reset()); + VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + } + + if (useProceduralGeometry) { + // Define procedural geometry AABB for a plane + CComPtr aabbBuffer; + CComPtr aabbBufferUpload; + + // Define the AABB for the plane, matching the size of the quad defined by + // verts[] + const D3D12_RAYTRACING_AABB aabb = { + -150.5f, -500.5f, -1000.0f, // Min corner (x, y, z) + 150.5f, -150.5f, 1000.0f // Max corner (x, y, z) + }; + const UINT64 aabbDataSize = sizeof(aabb); + + // Create an upload buffer for the AABB + AllocateUploadBuffer(pDevice, &aabb, aabbDataSize, &aabbBufferUpload, + L"aabbBufferUpload"); + + // Create a GPU buffer for the AABB + AllocateBufferFromUpload( + pDevice, pCommandList, aabbBufferUpload, &aabbBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"aabbBuffer"); + + // Describe the procedural geometry + D3D12_RAYTRACING_GEOMETRY_DESC procGeometryDesc = {}; + procGeometryDesc.Type = + D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + procGeometryDesc.AABBs.AABBs.StartAddress = + aabbBuffer->GetGPUVirtualAddress(); + procGeometryDesc.AABBs.AABBs.StrideInBytes = sizeof(D3D12_RAYTRACING_AABB); + procGeometryDesc.AABBs.AABBCount = 1; + + // Build the BLAS for the procedural geometry + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS blasInputs = {}; + blasInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + blasInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + blasInputs.NumDescs = 1; + blasInputs.pGeometryDescs = &procGeometryDesc; + blasInputs.Flags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&blasInputs, + &prebuildInfo); + + // Allocate scratch and result buffers for the BLAS + ReallocScratchResource(pDevice, &scratchResource, + prebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, + &blasProceduralGeometryResource, true, + D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, + L"blasProceduralGeometry"); + + // Build the BLAS + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC blasDesc = {}; + blasDesc.Inputs = blasInputs; + blasDesc.ScratchAccelerationStructureData = + scratchResource->GetGPUVirtualAddress(); + blasDesc.DestAccelerationStructureData = + blasProceduralGeometryResource->GetGPUVirtualAddress(); + + pCommandList->BuildRaytracingAccelerationStructure(&blasDesc, 0, nullptr); + + // Add a UAV barrier to ensure the BLAS is built before using it + CD3DX12_RESOURCE_BARRIER barrier = + CD3DX12_RESOURCE_BARRIER::UAV(blasProceduralGeometryResource); + pCommandList->ResourceBarrier(1, &barrier); + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + VERIFY_SUCCEEDED(pCommandAllocator->Reset()); + VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + } + + // Build TLAS. + { + if (useMesh) { + D3D12_RAYTRACING_INSTANCE_DESC instanceDesc = {}; + instanceDesc.Transform[0][0] = instanceDesc.Transform[1][1] = + instanceDesc.Transform[2][2] = 1; + instanceDesc.InstanceMask = 1; + instanceDesc.AccelerationStructure = + blasMeshResource->GetGPUVirtualAddress(); + + AllocateUploadBuffer(pDevice, &instanceDesc, sizeof(instanceDesc), + &instanceDescs, L"instanceDescs"); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; + accelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + accelInputs.NumDescs = 1; + accelInputs.Flags = buildFlags; + accelInputs.InstanceDescs = instanceDescs->GetGPUVirtualAddress(); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, + &prebuildInfo); + + AllocateBuffer( + pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, + D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; + buildDesc.Inputs = accelInputs; + buildDesc.ScratchAccelerationStructureData = + scratchResource->GetGPUVirtualAddress(); + buildDesc.DestAccelerationStructureData = + tlasResource->GetGPUVirtualAddress(); + + pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, 0); + } else { + D3D12_RAYTRACING_INSTANCE_DESC instanceDesc = {}; + instanceDesc.Transform[0][0] = instanceDesc.Transform[1][1] = + instanceDesc.Transform[2][2] = 1; + instanceDesc.InstanceMask = 1; + instanceDesc.AccelerationStructure = + blasProceduralGeometryResource->GetGPUVirtualAddress(); + + AllocateUploadBuffer(pDevice, &instanceDesc, sizeof(instanceDesc), + &instanceDescs, L"instanceDescs"); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; + accelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + accelInputs.NumDescs = 1; + accelInputs.Flags = buildFlags; + accelInputs.InstanceDescs = instanceDescs->GetGPUVirtualAddress(); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, + &prebuildInfo); + + AllocateBuffer( + pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, + D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; + buildDesc.Inputs = accelInputs; + buildDesc.ScratchAccelerationStructureData = + scratchResource->GetGPUVirtualAddress(); + buildDesc.DestAccelerationStructureData = + tlasResource->GetGPUVirtualAddress(); + + pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, 0); + } + + CD3DX12_RESOURCE_BARRIER barrier = + CD3DX12_RESOURCE_BARRIER::UAV(tlasResource); + pCommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&barrier); + } + + shaderTable.Upload(pCommandList); + + ID3D12DescriptorHeap *const pHeaps[1] = {pDescriptorHeap}; + pCommandList->SetDescriptorHeaps(1, pHeaps); + pCommandList->SetComputeRootSignature(pGlobalRootSignature); + pCommandList->SetComputeRootShaderResourceView( + 0, tlasResource->GetGPUVirtualAddress()); + pCommandList->SetComputeRootConstantBufferView( + 1, pSceneConstantBuffer->GetGPUVirtualAddress()); + pCommandList->SetComputeRootDescriptorTable( + 2, pDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); + + D3D12_DISPATCH_RAYS_DESC dispatchDesc = {}; + dispatchDesc.RayGenerationShaderRecord.StartAddress = + shaderTable.GetRaygenStartGpuVA(); + dispatchDesc.RayGenerationShaderRecord.SizeInBytes = + shaderTable.GetRaygenRangeInBytes(); + dispatchDesc.MissShaderTable.StartAddress = shaderTable.GetMissStartGpuVA(); + dispatchDesc.MissShaderTable.SizeInBytes = shaderTable.GetMissRangeInBytes(); + dispatchDesc.MissShaderTable.StrideInBytes = + shaderTable.GetShaderRecordSizeInBytes(); + dispatchDesc.HitGroupTable.StartAddress = shaderTable.GetHitGroupStartGpuVA(); + dispatchDesc.HitGroupTable.SizeInBytes = + shaderTable.GetHitGroupRangeInBytes(); + dispatchDesc.HitGroupTable.StrideInBytes = + shaderTable.GetShaderRecordSizeInBytes(); + dispatchDesc.Width = windowWidth; + dispatchDesc.Height = windowHeight; + dispatchDesc.Depth = 1; + pCommandList->SetPipelineState1(pStateObject); + pCommandList->DispatchRays(&dispatchDesc); + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + VERIFY_SUCCEEDED(pCommandAllocator->Reset()); + VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + + // Copy the testBuffer contents to CPU + D3D12_RESOURCE_BARRIER barriers[1]; + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + pTestBuffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COPY_SOURCE); + pCommandList->ResourceBarrier(1, barriers); + pCommandList->CopyResource(pTestBufferRead, pTestBuffer); + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + pTestBuffer, D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + pCommandList->ResourceBarrier(1, barriers); + + pCommandList->Close(); + ExecuteCommandList(pCommandQueue, pCommandList); + WaitForSignal(pCommandQueue, FO); + + // Copy the shader test data into 'testData'. + MappedData data(pTestBufferRead, (UINT32)testData.size() * sizeof(int)); + const int *pData = (int *)data.data(); + + for (int i = 0; i < testData.size(); i++) { + testData[i] = *pData++; + } + + // Cleanup resources + pTestBuffer.Release(); + pTestBufferRead.Release(); + pSceneConstantBuffer.Release(); + pDescriptorHeap.Release(); + pCommandQueue.Release(); + pCommandAllocator.Release(); + pCommandList.Release(); + pStateObject.Release(); + pStateObjectProperties.Release(); + tlasResource.Release(); + blasMeshResource.Release(); + blasProceduralGeometryResource.Release(); + instanceDescs.Release(); + scratchResource.Release(); + + return pTestBufferRead; +} + +// SER TESTS +#include "ExecutionTest_SER.h" +// + void ExecutionTest::RunLifetimeIntrinsicComputeTest( ID3D12Device *pDevice, LPCSTR pShader, CComPtr &pUavHeap, diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h new file mode 100644 index 0000000000..a99d55e79c --- /dev/null +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -0,0 +1,1703 @@ +//===--------- ExecutionTest_SER.h - SER Execution Tests -------*- C++ -*-===// +/////////////////////////////////////////////////////////////////////////////// +// // +// ExecutionTest_SER.h // +// Copyright (C) Nvidia Corporation. All rights reserved. // +// This file is distributed under the University of Illinois Open Source // +// License. See LICENSE.TXT for details. // +// // +// This file contains the execution tests for SER. // +// // +/////////////////////////////////////////////////////////////////////////////// + +TEST_F(ExecutionTest, SERScalarGetterTest) { + // SER: Test basic function of HitObject getters. + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + VALTYPE value : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + int id = 2 * (launchIndex.x + launchIndex.y * launchDim.x); + + RayDesc ray = ComputeRay(); + + // Fetch reference value + PerRayData refPayload; + TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, refPayload); + testBuffer[id] = refPayload.value; + + PerRayData serPayload; + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, serPayload); + dx::MaybeReorderThread(hitObject); + VALTYPE serVal = hitObject.SER_GET_SCALAR(); + testBuffer[id + 1] = serVal; +} + +float getFloatZero() { return 0.0f; } +int getIntZero() { return 0; } + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.value = MISS_GET_SCALAR(); +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + // UNUSED +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.value = HIT_GET_SCALAR(); +} +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + + if (!bDXRSupported) + return; + + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + + // RayTMin + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=float", + L"-DHIT_GET_SCALAR=RayTMin", + L"-DMISS_GET_SCALAR=RayTMin", + L"-DSER_GET_SCALAR=GetRayTMin"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + float *resArray = (float *)(testData.data() + id); + float refVal = resArray[0]; + float serVal = resArray[1]; + const bool passRayTMin = CompareFloatEpsilon(serVal, refVal, 0.0008f); + if (!passRayTMin) { + VERIFY_IS_TRUE(passRayTMin); + WEX::Logging::Log::Comment(L"HitObject::GetRayTMin() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetRayTMin() PASSED"); + } + + // RayTCurrent + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=float", + L"-DHIT_GET_SCALAR=RayTCurrent", + L"-DMISS_GET_SCALAR=RayTCurrent", + L"-DSER_GET_SCALAR=GetRayTCurrent"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + float *resArray = (float *)(testData.data() + id); + float refVal = resArray[0]; + float serVal = resArray[1]; + const bool passRayTCurrent = CompareFloatEpsilon(serVal, refVal, 0.0008f); + if (!passRayTCurrent) { + VERIFY_IS_TRUE(passRayTCurrent); + WEX::Logging::Log::Comment(L"HitObject::GetRayTCurrent() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetRayTCurrent() PASSED"); + } + + // RayFlags + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=RayFlags", + L"-DMISS_GET_SCALAR=RayFlags", + L"-DSER_GET_SCALAR=GetRayFlags"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetRayFlags() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetRayFlags() PASSED"); + } + + // HitKind + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=HitKind", + L"-DMISS_GET_SCALAR=getIntZero", + L"-DSER_GET_SCALAR=GetHitKind"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetHitKind() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetHitKind() PASSED"); + } + + // GeometryIndex + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=GeometryIndex", + L"-DMISS_GET_SCALAR=getIntZero", + L"-DSER_GET_SCALAR=GetGeometryIndex"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetGeometryIndex() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetGeometryIndex() PASSED"); + } + + // InstanceIndex + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=InstanceIndex", + L"-DMISS_GET_SCALAR=getIntZero", + L"-DSER_GET_SCALAR=GetInstanceIndex"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetInstanceIndex() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetInstanceIndex() PASSED"); + } + + // InstanceID + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=InstanceID", + L"-DMISS_GET_SCALAR=getIntZero", + L"-DSER_GET_SCALAR=GetInstanceID"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetInstanceID() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetInstanceID() PASSED"); + } + + // PrimitiveIndex + { + std::vector testData(windowSize * windowSize * 2, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DVALTYPE=uint", + L"-DHIT_GET_SCALAR=PrimitiveIndex", + L"-DMISS_GET_SCALAR=getIntZero", + L"-DSER_GET_SCALAR=GetPrimitiveIndex"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + for (int id = 0; id < testData.size(); id += 2) { + const int refVal = testData[id]; + const int serVal = testData[id + 1]; + if (refVal != serVal) { + VERIFY_ARE_EQUAL(refVal, serVal); + WEX::Logging::Log::Comment(L"HitObject::GetPrimitiveIndex() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetPrimitiveIndex() PASSED"); + } +} + +TEST_F(ExecutionTest, SERVectorGetterTest) { + // SER: Test basic function of HitObject getters. + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + float3 value : read(caller) : write(miss,closesthit); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + int id = 6 * (launchIndex.x + launchIndex.y * launchDim.x); + + RayDesc ray = ComputeRay(); + + // Fetch reference value + PerRayData refPayload; + TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, refPayload); + testBuffer[id] = refPayload.value.x; + testBuffer[id + 2] = refPayload.value.y; + testBuffer[id + 4] = refPayload.value.z; + + PerRayData serPayload; + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, serPayload); + dx::MaybeReorderThread(hitObject); + float3 serVal = hitObject.SER_GET_VECTOR(); + testBuffer[id + 1] = serVal.x; + testBuffer[id + 3] = serVal.y; + testBuffer[id + 5] = serVal.z; +} + +float3 getVecZero() { return 0.0f; } + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.value = MISS_GET_VECTOR(); +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + // UNUSED +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.value = HIT_GET_VECTOR(); +} +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + + if (!bDXRSupported) + return; + + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + + // WorldRayOrigin + { + std::vector testData(windowSize * windowSize * 6, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=WorldRayOrigin", + L"-DMISS_GET_VECTOR=WorldRayOrigin", + L"-DSER_GET_VECTOR=GetWorldRayOrigin"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 3 /*payloadCount*/); + for (int id = 0; id < testData.size(); id += 6) { + float *resArray = (float *)(testData.data() + id); + float refX = resArray[0]; + float serX = resArray[1]; + float refY = resArray[2]; + float serY = resArray[3]; + float refZ = resArray[4]; + float serZ = resArray[5]; + const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); + const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); + const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); + if (!passX || !passY || !passZ) { + VERIFY_ARE_EQUAL(serX, refX); + VERIFY_ARE_EQUAL(serY, refY); + VERIFY_ARE_EQUAL(serZ, refZ); + WEX::Logging::Log::Comment(L"HitObject::GetWorldRayOrigin() FAILED"); + break; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetWorldRayOrigin() PASSED"); + } + + // WorldRayDirection + { + std::vector testData(windowSize * windowSize * 6, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd", + L"-DHIT_GET_VECTOR=WorldRayDirection", + L"-DMISS_GET_VECTOR=WorldRayDirection", + L"-DSER_GET_VECTOR=GetWorldRayDirection"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 3 /*payloadCount*/); + for (int id = 0; id < testData.size(); id += 6) { + float *resArray = (float *)(testData.data() + id); + float refX = resArray[0]; + float serX = resArray[1]; + float refY = resArray[2]; + float serY = resArray[3]; + float refZ = resArray[4]; + float serZ = resArray[5]; + const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); + const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); + const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); + if (!passX || !passY || !passZ) { + VERIFY_ARE_EQUAL(serX, refX); + VERIFY_ARE_EQUAL(serY, refY); + VERIFY_ARE_EQUAL(serZ, refZ); + WEX::Logging::Log::Comment(L"HitObject::GetWorldRayDirection() FAILED"); + return; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetWorldRayDirection() PASSED"); + } + + // ObjectRayOrigin + { + std::vector testData(windowSize * windowSize * 6, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=ObjectRayOrigin", + L"-DMISS_GET_VECTOR=WorldRayOrigin", + L"-DSER_GET_VECTOR=GetObjectRayOrigin"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 3 /*payloadCount*/); + for (int id = 0; id < testData.size(); id += 6) { + float *resArray = (float *)(testData.data() + id); + float refX = resArray[0]; + float serX = resArray[1]; + float refY = resArray[2]; + float serY = resArray[3]; + float refZ = resArray[4]; + float serZ = resArray[5]; + const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); + const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); + const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); + if (!passX || !passY || !passZ) { + VERIFY_ARE_EQUAL(serX, refX); + VERIFY_ARE_EQUAL(serY, refY); + VERIFY_ARE_EQUAL(serZ, refZ); + WEX::Logging::Log::Comment(L"HitObject::GetObjectRayOrigin() FAILED"); + break; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetObjectRayOrigin() PASSED"); + } + + // ObjectRayDirection + { + std::vector testData(windowSize * windowSize * 6, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd", + L"-DHIT_GET_VECTOR=ObjectRayDirection", + L"-DMISS_GET_VECTOR=WorldRayDirection", + L"-DSER_GET_VECTOR=GetObjectRayDirection"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 3 /*payloadCount*/); + for (int id = 0; id < testData.size(); id += 6) { + float *resArray = (float *)(testData.data() + id); + float refX = resArray[0]; + float serX = resArray[1]; + float refY = resArray[2]; + float serY = resArray[3]; + float refZ = resArray[4]; + float serZ = resArray[5]; + const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); + const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); + const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); + if (!passX || !passY || !passZ) { + VERIFY_ARE_EQUAL(serX, refX); + VERIFY_ARE_EQUAL(serY, refY); + VERIFY_ARE_EQUAL(serZ, refZ); + WEX::Logging::Log::Comment( + L"HitObject::GetObjectRayDirection() FAILED"); + break; + } + } + WEX::Logging::Log::Comment(L"HitObject::GetObjectRayDirection() PASSED"); + } +} + +TEST_F(ExecutionTest, SERMatrixGetterTest) { + // SER: Test basic function of HitObject getters. + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + matrix value : read(caller) : write(miss,closesthit); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + int id = 2 * ROWS * COLS * (launchIndex.x + launchIndex.y * launchDim.x); + + RayDesc ray = ComputeRay(); + + // Fetch reference value + PerRayData refPayload; + TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, refPayload); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + testBuffer[id + 2 * (r * COLS + c)] = refPayload.value[r][c]; + } + } + + PerRayData serPayload; + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, serPayload); + dx::MaybeReorderThread(hitObject); + matrix serVal = hitObject.SER_GET_MATRIX(); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + testBuffer[1 + id + 2 * (r * COLS + c)] = serVal[r][c]; + } + } +} + +matrix getMatIdentity() { + matrix mat = 0; + mat[0][0] = 1.f; + mat[1][1] = 1.f; + mat[2][2] = 1.f; + return mat; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.value = MISS_GET_MATRIX(); +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + // UNUSED +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.value = HIT_GET_MATRIX(); +} +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + + if (!bDXRSupported) + return; + + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + + // WorldToObject3x4 + { + std::vector testData(windowSize * windowSize * 24, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DHIT_GET_MATRIX=WorldToObject3x4", + L"-DMISS_GET_MATRIX=getMatIdentity", + L"-DSER_GET_MATRIX=GetWorldToObject3x4", + L"-DROWS=3", + L"-DCOLS=4"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 12 /*payloadCount*/); + const int ROWS = 3; + const int COLS = 4; + for (int id = 0; id < testData.size(); id += 24) { + float *resArray = (float *)(testData.data() + id); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int refIdx = 2 * (r * COLS + c); + float ref = resArray[refIdx]; + float ser = resArray[1 + refIdx]; + if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { + VERIFY_ARE_EQUAL(ser, ref); + } + } + } + } + WEX::Logging::Log::Comment(L"HitObject::GetWorldToObject3x4() PASSED"); + } + + // WorldToObject4x3 + { + const int ROWS = 4; + const int COLS = 3; + std::vector testData(windowSize * windowSize * 2 * ROWS * COLS, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DHIT_GET_MATRIX=WorldToObject4x3", + L"-DMISS_GET_MATRIX=getMatIdentity", + L"-DSER_GET_MATRIX=GetWorldToObject4x3", + L"-DROWS=4", + L"-DCOLS=3"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 12 /*payloadCount*/); + for (int id = 0; id < testData.size(); id += 2 * ROWS * COLS) { + float *resArray = (float *)(testData.data() + id); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int refIdx = 2 * (r * COLS + c); + float ref = resArray[refIdx]; + float ser = resArray[1 + refIdx]; + if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { + VERIFY_ARE_EQUAL(ser, ref); + } + } + } + } + WEX::Logging::Log::Comment(L"HitObject::GetWorldToObject4x3() PASSED"); + } + + // ObjectToWorld3x4 + { + std::vector testData(windowSize * windowSize * 24, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DHIT_GET_MATRIX=ObjectToWorld3x4", + L"-DMISS_GET_MATRIX=getMatIdentity", + L"-DSER_GET_MATRIX=GetObjectToWorld3x4", + L"-DROWS=3", + L"-DCOLS=4"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 12 /*payloadCount*/); + const int ROWS = 3; + const int COLS = 4; + for (int id = 0; id < testData.size(); id += 24) { + float *resArray = (float *)(testData.data() + id); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int refIdx = 2 * (r * COLS + c); + float ref = resArray[refIdx]; + float ser = resArray[1 + refIdx]; + if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { + VERIFY_ARE_EQUAL(ser, ref); + } + } + } + } + WEX::Logging::Log::Comment(L"HitObject::GetObjectToWorld3x4() PASSED"); + } + + // ObjectToWorld4x3 + { + std::vector testData(windowSize * windowSize * 24, 0); + LPCWSTR args[] = {L"-HV 2021", + L"-Vd", + L"-DHIT_GET_MATRIX=ObjectToWorld4x3", + L"-DMISS_GET_MATRIX=getMatIdentity", + L"-DSER_GET_MATRIX=GetObjectToWorld4x3", + L"-DROWS=4", + L"-DCOLS=3"}; + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/, + 12 /*payloadCount*/); + const int ROWS = 4; + const int COLS = 3; + for (int id = 0; id < testData.size(); id += 24) { + float *resArray = (float *)(testData.data() + id); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int refIdx = 2 * (r * COLS + c); + float ref = resArray[refIdx]; + float ser = resArray[1 + refIdx]; + if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { + VERIFY_ARE_EQUAL(ser, ref); + WEX::Logging::Log::Comment( + L"HitObject::GetObjectToWorld4x3() FAILED"); + break; + } + } + } + } + WEX::Logging::Log::Comment(L"HitObject::GetObjectToWorld4x3() PASSED"); + } +} + +TEST_F(ExecutionTest, SERBasicTest) { + // SER: Test basic functionality. + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // SER Test + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + dx::HitObject::Invoke(hitObject, payload); + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 2); + VERIFY_ARE_EQUAL(histo[2], 4030); + VERIFY_ARE_EQUAL(histo[5], 66); + } +} + +TEST_F(ExecutionTest, SERRayQueryTest) { + // Test SER RayQuery + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // Template parameter set at runtime before compilation + RayQuery rayQ; + + // Funtion parameter set at runtime before compilation + rayQ.TraceRayInline(topObject, RAY_FLAG_NONE, 0xFF, ray); + + // Storage for procedural primitive hit attributes + Attrs attrs; + attrs.barycentrics = float2(1, 1); + + while (rayQ.Proceed()) + { + switch (rayQ.CandidateType()) + { + + case CANDIDATE_NON_OPAQUE_TRIANGLE: + { + // The system has already determined that the candidate would be the closest + // hit so far in the ray extents + rayQ.CommitNonOpaqueTriangleHit(); + } + } + } + +#if 0 + switch (rayQ.CommittedStatus()) + { + case COMMITTED_TRIANGLE_HIT: + { + if (rayQ.CommittedTriangleFrontFace()) + { + // Hit + payload.visited |= 4U; + } + break; + } + case COMMITTED_PROCEDURAL_PRIMITIVE_HIT: + { + // Unused + break; + } + case COMMITTED_NOTHING: + { + // Miss + payload.visited |= 2U; + break; + } + } +#else + dx::HitObject hit; + if (rayQ.CommittedStatus() == COMMITTED_NOTHING) + { + hit = dx::HitObject::MakeMiss(RAY_FLAG_NONE, 0, ray); + } + else + { + hit = dx::HitObject::FromRayQuery(rayQ); + } + dx::MaybeReorderThread(hit); + dx::HitObject::Invoke(hit, payload); +#endif + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERRayQueryTest requires shader model 6.9+ " + L"but no supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SERRayQueryTest skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SERRayQueryTest skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 2); + VERIFY_ARE_EQUAL(histo[0], 66); + VERIFY_ARE_EQUAL(histo[2], 4030); + } +} + +TEST_F(ExecutionTest, SERIntersectionTest) { + // Test SER with Intersection and procedural geometry + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit, closesthit, miss, caller) : write(anyhit, miss, closesthit, caller); +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x * sceneConstants.U.xyz + d.y * sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + +#if 0 + dx::HitObject hitObject; + TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); +#else + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + dx::HitObject::Invoke(hitObject, payload); +#endif + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +[shader("intersection")] +void intersection() +{ + Attrs attrs; + + ReportHit(0.1, 0, attrs); +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, false /*mesh*/, + true /*procedural geometry*/, true /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 2); + VERIFY_ARE_EQUAL(histo[2], 3400); + VERIFY_ARE_EQUAL(histo[5], 696); + } +} + +TEST_F(ExecutionTest, SERGetAttributesTest) { + // Test SER with HitObject::GetAttributes + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct CustomAttrs +{ + float dist; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit, closesthit, miss, caller) : write(anyhit, miss, closesthit, caller); +}; + +// reordercoherent // Requires #7250 +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x * sceneConstants.U.xyz + d.y * sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + + // Check Attributes for hit detection. + CustomAttrs customAttrs = hitObject.GetAttributes(); + bool isHit = hitObject.IsHit(); + + int testVal = 0; + if (isHit) { + if (int(floor(customAttrs.dist)) % 2 == 0) + testVal = hitObject.GetHitKind(); + } + else + { + // Use 255 to keep outside the HitKind range [0, 127] we passthru for hits. + testVal = 255; + } + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = testVal; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + // UNUSED +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in CustomAttrs attrs) +{ + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in CustomAttrs attrs) +{ + // UNUSED +} + +[shader("intersection")] +void intersection() +{ + // hitPos is intersection point with plane (base, n) + float3 base = {0.0f,0.0f,0.5f}; + float3 n = normalize(float3(0.0f,0.5f,0.5f)); + float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); + if (t > RayTCurrent() || t < RayTMin()) { + return; + } + float3 hitPos = ObjectRayOrigin() + t * ObjectRayDirection(); + float3 relHitPos = hitPos - base; + // Encode some hit information in hitKind + int hitKind = 0; + if (relHitPos.y >= 0.0f) + hitKind = 1; + hitKind *= 2; + if (relHitPos.x >= 0.0f) + hitKind += 1; + hitKind *= 2; + if (relHitPos.z >= 0.0f) + hitKind += 1; + + CustomAttrs attrs; + attrs.dist = length(relHitPos); + ReportHit(t, hitKind, attrs); +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, false /*mesh*/, + true /*procedural geometry*/, true /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 4); + VERIFY_ARE_EQUAL(histo[0], 328); + VERIFY_ARE_EQUAL(histo[1], 186); + VERIFY_ARE_EQUAL(histo[3], 182); + VERIFY_ARE_EQUAL(histo[255], 3400); + } +} + +TEST_F(ExecutionTest, SERTraceHitMissNopTest) { + // Test SER with conditional HitObject::TraceRay, HitObject::IsHit, + // HitObject::IsMiss, HitObject::IsNop + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // SER Test + dx::HitObject hitObject; + if (launchIndex.x % 2 == 0) { + hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + } + dx::MaybeReorderThread(hitObject); + + // Check hitObject for hit detection. + if (hitObject.IsHit()) + payload.visited |= 4U; + if (hitObject.IsMiss()) + payload.visited |= 2U; + if (hitObject.IsNop()) + payload.visited |= 1U; + + dx::HitObject::Invoke(hitObject, payload); + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 16U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 8U; +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 32U; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*mesh*/, + false /*procedural geometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 3); + VERIFY_ARE_EQUAL( + histo[1], + 2048); // isNop && !isMiss && !isHit && !anyhit && !closesthit && !miss + VERIFY_ARE_EQUAL( + histo[18], + 2015); // !isNop && isMiss && !isHit && !anyhit && !closesthit && miss + VERIFY_ARE_EQUAL( + histo[44], + 33); // !isNop && !isMiss && isHit && anyhit && closesthit && !miss + } +} + +TEST_F(ExecutionTest, SERIsMissTest) { + // Test SER with HitObject::IsMiss + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // SER Test + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + dx::HitObject::Invoke(hitObject, payload); + + // Check hitObject for hit detection. + if (hitObject.IsMiss()) + payload.visited |= 2U; + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + // UNUSED +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*mesh*/, + false /*procedural geometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 2); + VERIFY_ARE_EQUAL(histo[2], 4030); + VERIFY_ARE_EQUAL(histo[5], 66); + } +} From 6bcb1515d475448e0d93c2762ac059a2da521588 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 28 Apr 2025 10:17:47 +0200 Subject: [PATCH 02/13] Add SetShaderTableIndex+LoadLocalRootConstant tests / host code for local constants / simplifications --- .../unittests/HLSLExec/ExecutionTest.cpp | 64 +++- .../unittests/HLSLExec/ExecutionTest_SER.h | 303 +++++++++++++++++- 2 files changed, 353 insertions(+), 14 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index 403b261df1..d921c54489 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -303,6 +303,8 @@ class ExecutionTest { TEST_METHOD(SERGetAttributesTest); TEST_METHOD(SERTraceHitMissNopTest); TEST_METHOD(SERIsMissTest); + TEST_METHOD(SERShaderTableIndexTest); + TEST_METHOD(SERLoadLocalRootTableConstantTest); TEST_METHOD(LifetimeIntrinsicTest) TEST_METHOD(WaveIntrinsicsTest); TEST_METHOD(WaveIntrinsicsDDITest); @@ -2248,11 +2250,12 @@ CComPtr ExecutionTest::RunDXRTest( CComPtr pLocalRootSignature; { CD3DX12_DESCRIPTOR_RANGE bufferRanges[1]; - CD3DX12_ROOT_PARAMETER rootParameters[1]; + CD3DX12_ROOT_PARAMETER rootParameters[2]; bufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1, 0, 2); // vertexBuffer(t1), indexBuffer(t2) rootParameters[0].InitAsDescriptorTable( _countof(bufferRanges), bufferRanges, D3D12_SHADER_VISIBILITY_ALL); + rootParameters[1].InitAsConstants(4, 1, 0, D3D12_SHADER_VISIBILITY_ALL); CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, @@ -2316,6 +2319,9 @@ CComPtr ExecutionTest::RunDXRTest( if (useIS) { lib->DefineExport(L"intersection"); } + if (useMesh && useProceduralGeometry) { + lib->DefineExport(L"chAABB"); + } const int maxRecursion = 1; stateObjectDesc.CreateSubobject() @@ -2329,6 +2335,10 @@ CComPtr ExecutionTest::RunDXRTest( stateObjectDesc .CreateSubobject(); globalRootSigSubObj->SetRootSignature(pGlobalRootSignature); + // Set Local Root Signature subobject. + stateObjectDesc.CreateSubobject() + ->SetRootSignature(pLocalRootSignature); + auto exports = stateObjectDesc.CreateSubobject< CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT>(); exports->SetSubobjectToAssociate(*globalRootSigSubObj); @@ -2339,6 +2349,9 @@ CComPtr ExecutionTest::RunDXRTest( if (useIS) { exports->AddExport(L"intersection"); } + if (useMesh && useProceduralGeometry) { + exports->AddExport(L"chAABB"); + } auto hitGroup = stateObjectDesc.CreateSubobject(); @@ -2350,15 +2363,23 @@ CComPtr ExecutionTest::RunDXRTest( } hitGroup->SetHitGroupExport(L"HitGroup"); + if (useMesh && useProceduralGeometry) { + auto hitGroupAABB = + stateObjectDesc.CreateSubobject(); + hitGroupAABB->SetClosestHitShaderImport(L"chAABB"); + hitGroupAABB->SetAnyHitShaderImport(L"anyhit"); + if (useIS) { + hitGroup->SetIntersectionShaderImport(L"intersection"); + hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); + } + hitGroupAABB->SetHitGroupExport(L"HitGroupAABB"); + } + CComPtr pStateObject; CComPtr pStateObjectProperties; VERIFY_SUCCEEDED( pDevice->CreateStateObject(stateObjectDesc, IID_PPV_ARGS(&pStateObject))); VERIFY_SUCCEEDED(pStateObject->QueryInterface(&pStateObjectProperties)); - stateObjectDesc.CreateSubobject() - ->SetRootSignature(pLocalRootSignature); - stateObjectDesc.CreateSubobject() - ->SetRootSignature(pGlobalRootSignature); // Create SBT ShaderTable shaderTable; @@ -2367,21 +2388,33 @@ CComPtr ExecutionTest::RunDXRTest( 1, // miss count useMesh && useProceduralGeometry ? 2 : 1, // hit group count 1, // ray type count - 2 // dwords per root table + 4 // dwords per root table ); + int localRootConsts[4] = {12, 34, 56, 78}; memcpy(shaderTable.GetRaygenShaderIdPtr(0), pStateObjectProperties->GetShaderIdentifier(L"raygen"), SHADER_ID_SIZE_IN_BYTES); + memcpy(shaderTable.GetRaygenRootTablePtr(0), localRootConsts, + sizeof(localRootConsts)); memcpy(shaderTable.GetMissShaderIdPtr(0, 0), pStateObjectProperties->GetShaderIdentifier(L"miss"), SHADER_ID_SIZE_IN_BYTES); + memcpy(shaderTable.GetMissRootTablePtr(0, 0), localRootConsts, + sizeof(localRootConsts)); memcpy(shaderTable.GetHitGroupShaderIdPtr(0, 0), pStateObjectProperties->GetShaderIdentifier(L"HitGroup"), SHADER_ID_SIZE_IN_BYTES); + memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), localRootConsts, + sizeof(localRootConsts)); + if (useMesh && useProceduralGeometry) { + memcpy(shaderTable.GetHitGroupShaderIdPtr(0, 1), + pStateObjectProperties->GetShaderIdentifier(L"HitGroupAABB"), + SHADER_ID_SIZE_IN_BYTES); + } - auto tbl = pDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr; - memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), &tbl, 8); + // auto tbl = pDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr; + // memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), &tbl, 8); // Create a command allocator and list. CComPtr pCommandAllocator; @@ -2521,6 +2554,7 @@ CComPtr ExecutionTest::RunDXRTest( pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, &prebuildInfo); + scratchResource.Release(); ReallocScratchResource(pDevice, &scratchResource, prebuildInfo.ScratchDataSizeInBytes); AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, @@ -2597,6 +2631,7 @@ CComPtr ExecutionTest::RunDXRTest( &prebuildInfo); // Allocate scratch and result buffers for the BLAS + scratchResource.Release(); ReallocScratchResource(pDevice, &scratchResource, prebuildInfo.ScratchDataSizeInBytes); AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, @@ -2654,6 +2689,9 @@ CComPtr ExecutionTest::RunDXRTest( pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, &prebuildInfo); + scratchResource.Release(); + ReallocScratchResource(pDevice, &scratchResource, + prebuildInfo.ScratchDataSizeInBytes); AllocateBuffer( pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); @@ -2691,6 +2729,9 @@ CComPtr ExecutionTest::RunDXRTest( pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, &prebuildInfo); + scratchResource.Release(); + ReallocScratchResource(pDevice, &scratchResource, + prebuildInfo.ScratchDataSizeInBytes); AllocateBuffer( pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); @@ -2710,6 +2751,13 @@ CComPtr ExecutionTest::RunDXRTest( pCommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&barrier); } + // Set the local root constants. + pCommandList->SetComputeRootSignature(pLocalRootSignature); + pCommandList->SetComputeRoot32BitConstant(1, 12, 0); + pCommandList->SetComputeRoot32BitConstant(1, 34, 1); + pCommandList->SetComputeRoot32BitConstant(1, 56, 2); + pCommandList->SetComputeRoot32BitConstant(1, 78, 3); + shaderTable.Upload(pCommandList); ID3D12DescriptorHeap *const pHeaps[1] = {pDescriptorHeap}; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index a99d55e79c..1c24795a0c 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -586,7 +586,7 @@ struct SceneConstants struct[raypayload] PerRayData { - matrix value : read(caller) : write(miss,closesthit); + float elems[ROWS*COLS] : read(caller) : write(miss,closesthit); }; struct Attrs @@ -627,7 +627,7 @@ void raygen() TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, refPayload); for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { - testBuffer[id + 2 * (r * COLS + c)] = refPayload.value[r][c]; + testBuffer[id + 2 * (r * COLS + c)] = refPayload.elems[r*COLS + c]; } } @@ -642,8 +642,8 @@ void raygen() } } -matrix getMatIdentity() { - matrix mat = 0; +matrix getMatIdentity() { + matrix mat = 0; mat[0][0] = 1.f; mat[1][1] = 1.f; mat[2][2] = 1.f; @@ -653,7 +653,12 @@ matrix getMatIdentity() { [shader("miss")] void miss(inout PerRayData payload) { - payload.value = MISS_GET_MATRIX(); + matrix mat = MISS_GET_MATRIX(); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + payload.elems[r*COLS + c] = mat[r][c]; + } + } } [shader("anyhit")] @@ -665,7 +670,12 @@ void anyhit(inout PerRayData payload, in Attrs attrs) [shader("closesthit")] void closesthit(inout PerRayData payload, in Attrs attrs) { - payload.value = HIT_GET_MATRIX(); + matrix mat = HIT_GET_MATRIX(); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + payload.elems[r*COLS + c] = mat[r][c]; + } + } } )"; @@ -952,6 +962,287 @@ void closesthit(inout PerRayData payload, in Attrs attrs) } } +TEST_F(ExecutionTest, SERShaderTableIndexTest) { + // Test SER with HitObject::SetShaderTableIndex and + // HitObject::GetShaderTableIndex + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // SER Test + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + dx::HitObject::Invoke(hitObject, payload); + + if (hitObject.IsHit()) + { + // Alter the hit object to point to a new shader index to hit chAABB. + hitObject.SetShaderTableIndex( 1 ); + dx::HitObject::Invoke( hitObject, payload ); + // Poison the test data if GetShaderTableIndex does not match SetShaderTableIndex. + if (hitObject.GetShaderTableIndex() != 1) + payload.visited = 0; + } + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +[shader("closesthit")] +void chAABB(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 8U; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (bDXRSupported) { + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*mesh*/, + true /*procedural geometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 2); + VERIFY_ARE_EQUAL(histo[2], 4030); + VERIFY_ARE_EQUAL(histo[13], 66); + } +} + +TEST_F(ExecutionTest, SERLoadLocalRootTableConstantTest) { + // Test SER with HitObject::LoadLocalRootTableConstant + static const char *pShader = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint res : read(caller) : write(miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +struct LocalConstants +{ + int c0; + int c1; + int c2; + int c3; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); +ConstantBuffer localConstants : register(b1); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.res = 0; + + // SER Test +#if 1 + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::MaybeReorderThread(hitObject); + int c0 = hitObject.LoadLocalRootTableConstant(0); + int c1 = hitObject.LoadLocalRootTableConstant(4); + int c2 = hitObject.LoadLocalRootTableConstant(8); + int c3 = hitObject.LoadLocalRootTableConstant(12); + int res = c0 | c1 | c2 | c3; +#else + TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + int res = payload.res; +#endif + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = res; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.res = localConstants.c0 | localConstants.c1 | localConstants.c2 | localConstants.c3; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + // UNUSED +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.res = localConstants.c0 | localConstants.c1 | localConstants.c2 | localConstants.c3; +} + +)"; + + CComPtr pDevice; + bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " + L"supported device was found."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + return; + } + bool bDXRSupported = + bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); + + if (!bSM_6_9_Supported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support SM 6.9."); + } + if (!bDXRSupported) { + WEX::Logging::Log::Comment( + L"SER tests skipped, device does not support DXR."); + } + + // Initialize test data. + const int windowSize = 64; + std::vector testData(windowSize * windowSize, 0); + LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + + if (!bDXRSupported) + return; + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), + testData, windowSize, windowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map histo; + for (int val : testData) { + ++histo[val]; + } + VERIFY_ARE_EQUAL(histo.size(), 1); + VERIFY_ARE_EQUAL(histo[126], 4096); +} + TEST_F(ExecutionTest, SERRayQueryTest) { // Test SER RayQuery static const char *pShader = R"( From 144a083d9f112f26cec31811f304d2971d2fb039 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Wed, 30 Apr 2025 12:51:13 +0200 Subject: [PATCH 03/13] Uppercased vars for coding standards / added CreateDXRDevice helper / simplified tests/ added SERInvokeNoSBTTest --- tools/clang/unittests/HLSLExec/DXRUtil.h | 271 ++-- .../unittests/HLSLExec/ExecutionTest.cpp | 1069 ++++++++-------- .../unittests/HLSLExec/ExecutionTest_SER.h | 1108 ++++++++--------- 3 files changed, 1169 insertions(+), 1279 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/DXRUtil.h b/tools/clang/unittests/HLSLExec/DXRUtil.h index 1f008885cf..54828f4857 100644 --- a/tools/clang/unittests/HLSLExec/DXRUtil.h +++ b/tools/clang/unittests/HLSLExec/DXRUtil.h @@ -10,216 +10,213 @@ // // /////////////////////////////////////////////////////////////////////////////// +#pragma once + //= DXR Utility //============================================================================ #define SHADER_ID_SIZE_IN_BYTES 32 #ifndef ROUND_UP -#define ROUND_UP(v, powerOf2Alignment) \ - (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1)) +#define ROUND_UP(v, PowerOf2Alignment) \ + (((v) + (PowerOf2Alignment)-1) & ~((PowerOf2Alignment)-1)) #endif struct SceneConsts { - DirectX::XMFLOAT4 eye; + DirectX::XMFLOAT4 Eye; DirectX::XMFLOAT4 U; DirectX::XMFLOAT4 V; DirectX::XMFLOAT4 W; - float sceneScale; - unsigned windowSize[2]; - int rayFlags; + float SceneScale; + unsigned WindowSize[2]; + int RayFlags; }; struct Instance { - D3D12_RAYTRACING_GEOMETRY_TYPE type; - DirectX::XMFLOAT4X4 matrix; - UINT geometryCount; - UINT bottomASIdx; - UINT instanceID; - UINT mask; - UINT flags; + D3D12_RAYTRACING_GEOMETRY_TYPE Type; + DirectX::XMFLOAT4X4 Matrix; + UINT GeometryCount; + UINT BottomASIdx; + UINT InstanceID; + UINT Mask; + UINT Flags; }; class ShaderTable { public: - void Init(ID3D12Device *device, int raygenCount, int missCount, - int hitGroupCount, int rayTypeCount, int rootTableDwords) { - m_rayTypeCount = rayTypeCount; - m_raygenCount = raygenCount; - m_missCount = missCount * rayTypeCount; - m_hitGroupCount = hitGroupCount * rayTypeCount; - m_rootTableSizeInBytes = rootTableDwords * 4; - m_shaderRecordSizeInBytes = - ROUND_UP(m_rootTableSizeInBytes + SHADER_ID_SIZE_IN_BYTES, + void Init(ID3D12Device *Device, int RaygenCount, int MissCount, + int HitGroupCount, int RayTypeCount, int RootTableDwords) { + RayTypeCount = RayTypeCount; + RaygenCount = RaygenCount; + MissCount = MissCount * RayTypeCount; + HitGroupCount = HitGroupCount * RayTypeCount; + RootTableSizeInBytes = RootTableDwords * 4; + ShaderRecordSizeInBytes = + ROUND_UP(RootTableSizeInBytes + SHADER_ID_SIZE_IN_BYTES, D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT); - m_missStartIdx = m_raygenCount; - m_hitGroupStartIdx = m_missStartIdx + m_missCount; + MissStartIdx = RaygenCount; + HitGroupStartIdx = MissStartIdx + MissCount; - const int m_totalSizeInBytes = - (m_raygenCount + m_missCount + m_hitGroupCount) * - m_shaderRecordSizeInBytes; + const int TotalSizeInBytes = + (RaygenCount + MissCount + HitGroupCount) * ShaderRecordSizeInBytes; - D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer( - m_totalSizeInBytes, D3D12_RESOURCE_FLAG_NONE, + D3D12_RESOURCE_DESC Desc = CD3DX12_RESOURCE_DESC::Buffer( + TotalSizeInBytes, D3D12_RESOURCE_FLAG_NONE, std::max(D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT)); - CD3DX12_HEAP_PROPERTIES heap = + CD3DX12_HEAP_PROPERTIES Heap = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); - VERIFY_SUCCEEDED(device->CreateCommittedResource( - &heap, D3D12_HEAP_FLAG_NONE, &desc, + VERIFY_SUCCEEDED(Device->CreateCommittedResource( + &Heap, D3D12_HEAP_FLAG_NONE, &Desc, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, nullptr, - IID_PPV_ARGS(&m_sbtResource))); - m_sbtResource->SetName(L"SBT Resource Heap"); - CD3DX12_HEAP_PROPERTIES upload = + IID_PPV_ARGS(&SBTResource))); + SBTResource->SetName(L"SBT Resource Heap"); + CD3DX12_HEAP_PROPERTIES Upload = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); - VERIFY_SUCCEEDED(device->CreateCommittedResource( - &upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, IID_PPV_ARGS(&m_sbtUploadResource))); - m_sbtUploadResource->SetName(L"SBT Upload Heap"); + VERIFY_SUCCEEDED(Device->CreateCommittedResource( + &Upload, D3D12_HEAP_FLAG_NONE, &Desc, D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, IID_PPV_ARGS(&SBTUploadResource))); + SBTUploadResource->SetName(L"SBT Upload Heap"); - VERIFY_SUCCEEDED(m_sbtUploadResource->Map(0, nullptr, (void **)&m_hostPtr)); + VERIFY_SUCCEEDED(SBTUploadResource->Map(0, nullptr, (void **)&HostPtr)); } - void Upload(ID3D12GraphicsCommandList *cmdlist) { - CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - m_sbtResource, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + void Upload(ID3D12GraphicsCommandList *CmdList) { + CD3DX12_RESOURCE_BARRIER Barrier = CD3DX12_RESOURCE_BARRIER::Transition( + SBTResource, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST); - cmdlist->ResourceBarrier(1, &barrier); - cmdlist->CopyResource(m_sbtResource, m_sbtUploadResource); - CD3DX12_RESOURCE_BARRIER barrier2 = CD3DX12_RESOURCE_BARRIER::Transition( - m_sbtResource, D3D12_RESOURCE_STATE_COPY_DEST, + CmdList->ResourceBarrier(1, &Barrier); + CmdList->CopyResource(SBTResource, SBTUploadResource); + CD3DX12_RESOURCE_BARRIER Barrier2 = CD3DX12_RESOURCE_BARRIER::Transition( + SBTResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); - cmdlist->ResourceBarrier(1, &barrier2); + CmdList->ResourceBarrier(1, &Barrier2); } - int GetShaderRecordSizeInBytes() { return m_shaderRecordSizeInBytes; } + int GetShaderRecordSizeInBytes() { return ShaderRecordSizeInBytes; } - int GetRaygenShaderRecordIdx(int idx) { return idx; } - int GetMissShaderRecordIdx(int idx, int rayType) { - return m_missStartIdx + idx * m_rayTypeCount + rayType; + int GetRaygenShaderRecordIdx(int Idx) { return Idx; } + int GetMissShaderRecordIdx(int Idx, int RayType) { + return MissStartIdx + Idx * RayTypeCount + RayType; } - int GetHitGroupShaderRecordIdx(int idx, int rayType) { - return m_hitGroupStartIdx + idx * m_rayTypeCount + rayType; + int GetHitGroupShaderRecordIdx(int Idx, int RayType) { + return HitGroupStartIdx + Idx * RayTypeCount + RayType; } - void *GetRaygenShaderIdPtr(int idx) { - return m_hostPtr + - GetRaygenShaderRecordIdx(idx) * m_shaderRecordSizeInBytes; + void *GetRaygenShaderIdPtr(int Idx) { + return HostPtr + GetRaygenShaderRecordIdx(Idx) * ShaderRecordSizeInBytes; } - void *GetMissShaderIdPtr(int idx, int rayType) { - return m_hostPtr + - GetMissShaderRecordIdx(idx, rayType) * m_shaderRecordSizeInBytes; + void *GetMissShaderIdPtr(int Idx, int RayType) { + return HostPtr + + GetMissShaderRecordIdx(Idx, RayType) * ShaderRecordSizeInBytes; } - void *GetHitGroupShaderIdPtr(int idx, int rayType) { - return m_hostPtr + - GetHitGroupShaderRecordIdx(idx, rayType) * m_shaderRecordSizeInBytes; + void *GetHitGroupShaderIdPtr(int Idx, int RayType) { + return HostPtr + + GetHitGroupShaderRecordIdx(Idx, RayType) * ShaderRecordSizeInBytes; } - void *GetRaygenRootTablePtr(int idx) { - return (char *)GetRaygenShaderIdPtr(idx) + SHADER_ID_SIZE_IN_BYTES; + void *GetRaygenRootTablePtr(int Idx) { + return (char *)GetRaygenShaderIdPtr(Idx) + SHADER_ID_SIZE_IN_BYTES; } - void *GetMissRootTablePtr(int idx, int rayType) { - return (char *)GetMissShaderIdPtr(idx, rayType) + SHADER_ID_SIZE_IN_BYTES; + void *GetMissRootTablePtr(int Idx, int RayType) { + return (char *)GetMissShaderIdPtr(Idx, RayType) + SHADER_ID_SIZE_IN_BYTES; } - void *GetHitGroupRootTablePtr(int idx, int rayType) { - return (char *)GetHitGroupShaderIdPtr(idx, rayType) + + void *GetHitGroupRootTablePtr(int Idx, int RayType) { + return (char *)GetHitGroupShaderIdPtr(Idx, RayType) + SHADER_ID_SIZE_IN_BYTES; } - int GetRaygenRangeInBytes() { - return m_raygenCount * m_shaderRecordSizeInBytes; - } - int GetMissRangeInBytes() { return m_missCount * m_shaderRecordSizeInBytes; } + int GetRaygenRangeInBytes() { return RaygenCount * ShaderRecordSizeInBytes; } + int GetMissRangeInBytes() { return MissCount * ShaderRecordSizeInBytes; } int GetHitGroupRangeInBytes() { - return m_hitGroupCount * m_shaderRecordSizeInBytes; + return HitGroupCount * ShaderRecordSizeInBytes; } D3D12_GPU_VIRTUAL_ADDRESS GetRaygenStartGpuVA() { - return m_sbtResource->GetGPUVirtualAddress() + - GetRaygenShaderRecordIdx(0) * m_shaderRecordSizeInBytes; + return SBTResource->GetGPUVirtualAddress() + + GetRaygenShaderRecordIdx(0) * ShaderRecordSizeInBytes; } D3D12_GPU_VIRTUAL_ADDRESS GetMissStartGpuVA() { - return m_sbtResource->GetGPUVirtualAddress() + - GetMissShaderRecordIdx(0, 0) * m_shaderRecordSizeInBytes; + return SBTResource->GetGPUVirtualAddress() + + GetMissShaderRecordIdx(0, 0) * ShaderRecordSizeInBytes; } D3D12_GPU_VIRTUAL_ADDRESS GetHitGroupStartGpuVA() { - return m_sbtResource->GetGPUVirtualAddress() + - GetHitGroupShaderRecordIdx(0, 0) * m_shaderRecordSizeInBytes; + return SBTResource->GetGPUVirtualAddress() + + GetHitGroupShaderRecordIdx(0, 0) * ShaderRecordSizeInBytes; } private: - CComPtr m_sbtResource; - CComPtr m_sbtUploadResource; - char *m_hostPtr = nullptr; - int m_rayTypeCount = 0; - int m_raygenCount = 0; - int m_missCount = 0; - int m_hitGroupCount = 0; - int m_rootTableSizeInBytes = 0; - int m_shaderRecordSizeInBytes = 0; - int m_missStartIdx = 0; - int m_hitGroupStartIdx = 0; + CComPtr SBTResource; + CComPtr SBTUploadResource; + char *HostPtr = nullptr; + int RayTypeCount = 0; + int RaygenCount = 0; + int MissCount = 0; + int HitGroupCount = 0; + int RootTableSizeInBytes = 0; + int ShaderRecordSizeInBytes = 0; + int MissStartIdx = 0; + int HitGroupStartIdx = 0; }; //----------------------------------------------------------------------------- void AllocateBuffer( - ID3D12Device *pDevice, UINT64 bufferSize, ID3D12Resource **ppResource, - bool allowUAV = false, - D3D12_RESOURCE_STATES initialResourceState = D3D12_RESOURCE_STATE_COMMON, - const wchar_t *resourceName = nullptr) { - auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); - auto bufferDesc = CD3DX12_RESOURCE_DESC::Buffer( - bufferSize, allowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + ID3D12Device *Device, UINT64 BufferSize, ID3D12Resource **Resource, + bool AllowUAV = false, + D3D12_RESOURCE_STATES InitialResourceState = D3D12_RESOURCE_STATE_COMMON, + const wchar_t *ResourceName = nullptr) { + auto UploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + auto BufferDesc = CD3DX12_RESOURCE_DESC::Buffer( + BufferSize, AllowUAV ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE); - VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( - &uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, - initialResourceState, nullptr, IID_PPV_ARGS(ppResource))); - if (resourceName) { - (*ppResource)->SetName(resourceName); + VERIFY_SUCCEEDED(Device->CreateCommittedResource( + &UploadHeapProperties, D3D12_HEAP_FLAG_NONE, &BufferDesc, + InitialResourceState, nullptr, IID_PPV_ARGS(Resource))); + if (ResourceName) { + (*Resource)->SetName(ResourceName); } } //----------------------------------------------------------------------------- -void ReallocScratchResource(ID3D12Device *pDevice, ID3D12Resource **ppResource, - UINT64 nbytes) { - - if (!(*ppResource) || (*ppResource)->GetDesc().Width < nbytes) { - AllocateBuffer(pDevice, nbytes, ppResource, true, +void ReallocScratchResource(ID3D12Device *Device, ID3D12Resource **Resource, + UINT64 NBytes) { + if (!(*Resource) || (*Resource)->GetDesc().Width < NBytes) { + AllocateBuffer(Device, NBytes, Resource, true, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, L"scratchResource"); } } //----------------------------------------------------------------------------- -void AllocateUploadBuffer(ID3D12Device *pDevice, const void *pData, - UINT64 datasize, ID3D12Resource **ppResource, - const wchar_t *resourceName = nullptr) { - auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); - auto bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(datasize); - VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( - &uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(ppResource))); - if (resourceName) { - (*ppResource)->SetName(resourceName); - } - void *pMappedData; - VERIFY_SUCCEEDED((*ppResource)->Map(0, nullptr, &pMappedData)); - memcpy(pMappedData, pData, datasize); - (*ppResource)->Unmap(0, nullptr); +void AllocateUploadBuffer(ID3D12Device *Device, const void *Data, + UINT64 DataSize, ID3D12Resource **Resource, + const wchar_t *ResourceName = nullptr) { + auto UploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + auto BufferDesc = CD3DX12_RESOURCE_DESC::Buffer(DataSize); + VERIFY_SUCCEEDED(Device->CreateCommittedResource( + &UploadHeapProperties, D3D12_HEAP_FLAG_NONE, &BufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(Resource))); + if (ResourceName) { + (*Resource)->SetName(ResourceName); + } + void *MappedData; + VERIFY_SUCCEEDED((*Resource)->Map(0, nullptr, &MappedData)); + memcpy(MappedData, Data, DataSize); + (*Resource)->Unmap(0, nullptr); } //----------------------------------------------------------------------------- -void AllocateBufferFromUpload(ID3D12Device *pDevice, - ID3D12GraphicsCommandList *pCommandList, - ID3D12Resource *uploadSource, - ID3D12Resource **ppResource, - D3D12_RESOURCE_STATES targetResourceState, - const wchar_t *resourceName = nullptr) { - const bool allowUAV = - targetResourceState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - AllocateBuffer(pDevice, uploadSource->GetDesc().Width, ppResource, allowUAV, - D3D12_RESOURCE_STATE_COPY_DEST, resourceName); - pCommandList->CopyResource(*ppResource, uploadSource); - CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - *ppResource, D3D12_RESOURCE_STATE_COPY_DEST, targetResourceState); - pCommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&barrier); +void AllocateBufferFromUpload(ID3D12Device *Device, + ID3D12GraphicsCommandList *CommandList, + ID3D12Resource *UploadSource, + ID3D12Resource **Resource, + D3D12_RESOURCE_STATES TargetResourceState, + const wchar_t *ResourceName = nullptr) { + const bool AllowUAV = + TargetResourceState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + AllocateBuffer(Device, UploadSource->GetDesc().Width, Resource, AllowUAV, + D3D12_RESOURCE_STATE_COPY_DEST, ResourceName); + CommandList->CopyResource(*Resource, UploadSource); + CD3DX12_RESOURCE_BARRIER Barrier = CD3DX12_RESOURCE_BARRIER::Transition( + *Resource, D3D12_RESOURCE_STATE_COPY_DEST, TargetResourceState); + CommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&Barrier); } //= DXR Utility diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index d921c54489..25c7170316 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -60,7 +60,6 @@ #include "ShaderOpTest.h" #include #include - #include "DXRUtil.h" // clang-format on @@ -294,17 +293,6 @@ class ExecutionTest { TEST_METHOD(SaturateTest); TEST_METHOD(SignTest); TEST_METHOD(Int64Test); - TEST_METHOD(SERBasicTest); - TEST_METHOD(SERScalarGetterTest); - TEST_METHOD(SERVectorGetterTest); - TEST_METHOD(SERMatrixGetterTest); - TEST_METHOD(SERRayQueryTest); - TEST_METHOD(SERIntersectionTest); - TEST_METHOD(SERGetAttributesTest); - TEST_METHOD(SERTraceHitMissNopTest); - TEST_METHOD(SERIsMissTest); - TEST_METHOD(SERShaderTableIndexTest); - TEST_METHOD(SERLoadLocalRootTableConstantTest); TEST_METHOD(LifetimeIntrinsicTest) TEST_METHOD(WaveIntrinsicsTest); TEST_METHOD(WaveIntrinsicsDDITest); @@ -514,6 +502,20 @@ class ExecutionTest { L"Table:ShaderOpArithTable.xml#PackUnpackOpTable") END_TEST_METHOD() + // Shader Execution Reordering tests + TEST_METHOD(SERBasicTest); + TEST_METHOD(SERScalarGetterTest); + TEST_METHOD(SERVectorGetterTest); + TEST_METHOD(SERMatrixGetterTest); + TEST_METHOD(SERRayQueryTest); + TEST_METHOD(SERIntersectionTest); + TEST_METHOD(SERGetAttributesTest); + TEST_METHOD(SERTraceHitMissNopTest); + TEST_METHOD(SERIsMissTest); + TEST_METHOD(SERShaderTableIndexTest); + TEST_METHOD(SERLoadLocalRootTableConstantTest); + TEST_METHOD(SERInvokeNoSBTTest); + dxc::DxcDllSupport m_support; bool m_D3DInitCompleted = false; @@ -1930,12 +1932,15 @@ class ExecutionTest { CComPtr &pRootSignature, LPCWSTR pTargetProfile, LPCWSTR *pOptions, int numOptions); - CComPtr - RunDXRTest(ID3D12Device *pDevice0, LPCSTR shader, - D3D_SHADER_MODEL shaderModel, LPCWSTR *pOptions, int numOptions, - std::vector &testData, int windowWidth, int windowHeight, - bool useMesh, bool useProceduralGeometry, bool useIS, - int payloadCount = 1, int attributeCount = 2); + bool CreateDXRDevice(ID3D12Device **ppDevice, D3D_SHADER_MODEL testModel, + bool skipUnsupported); + CComPtr RunDXRTest(ID3D12Device *Device0, LPCSTR ShaderSrc, + LPCWSTR TargetProfile, LPCWSTR *Options, + int NumOptions, std::vector &TestData, + int WindowWidth, int WindowHeight, + bool UseMesh, bool UseProceduralGeometry, + bool UseIS, int PayloadCount = 1, + int AttributeCount = 2); void SetDescriptorHeap(ID3D12GraphicsCommandList *pCommandList, ID3D12DescriptorHeap *pHeap) { @@ -2097,53 +2102,42 @@ void ExecutionTest::RunRWByteBufferComputeTest(ID3D12Device *pDevice, WaitForSignal(pCommandQueue, FO); } -CComPtr ExecutionTest::RunDXRTest( - ID3D12Device *pDevice0, LPCSTR shader, D3D_SHADER_MODEL shaderModel, - LPCWSTR *pOptions, int numOptions, std::vector &testData, - int windowWidth, int windowHeight, bool useMesh, bool useProceduralGeometry, - bool useIS, int payloadCount, int attributeCount) { - CComPtr pDevice; - VERIFY_SUCCEEDED(pDevice0->QueryInterface(IID_PPV_ARGS(&pDevice))); +bool ExecutionTest::CreateDXRDevice(ID3D12Device **ppDevice, + D3D_SHADER_MODEL testModel, + bool skipUnsupported) { + bool SupportsSM = CreateDevice(ppDevice, testModel, skipUnsupported); + if (!SupportsSM) + return false; - LPCWSTR pTargetProfile; - switch (shaderModel) { - case D3D_SHADER_MODEL_6_9: - pTargetProfile = L"lib_6_9"; - break; - case D3D_SHADER_MODEL_6_8: - pTargetProfile = L"lib_6_8"; - break; - case D3D_SHADER_MODEL_6_7: - pTargetProfile = L"lib_6_7"; - break; - case D3D_SHADER_MODEL_6_6: - pTargetProfile = L"lib_6_6"; - break; - case D3D_SHADER_MODEL_6_5: - pTargetProfile = L"lib_6_5"; - break; - case D3D_SHADER_MODEL_6_4: - pTargetProfile = L"lib_6_4"; - break; - case D3D_SHADER_MODEL_6_3: - pTargetProfile = L"lib_6_3"; - break; - default: - // DXR capable shader model not found. - LogErrorFmt(L"DXR capable shader model not found."); - return nullptr; + if (DoesDeviceSupportRayTracing(*ppDevice)) + return true; + + if (skipUnsupported) { + WEX::Logging::Log::Comment( + L"DXR test skipped: device does not support DXR."); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); } + return false; +} + +CComPtr ExecutionTest::RunDXRTest( + ID3D12Device *Device0, LPCSTR ShaderSrc, LPCWSTR TargetProfile, + LPCWSTR *Options, int NumOptions, std::vector &TestData, + int WindowWidth, int WindowHeight, bool UseMesh, bool UseProceduralGeometry, + bool UseIS, int PayloadCount, int AttributeCount) { + CComPtr Device; + VERIFY_SUCCEEDED(Device0->QueryInterface(IID_PPV_ARGS(&Device))); FenceObj FO; - InitFenceObj(pDevice, &FO); + InitFenceObj(Device, &FO); // Setup Resources - CComPtr pTestBuffer; - CComPtr pTestBufferRead; - CComPtr pSceneConstantBuffer; + CComPtr TestBuffer; + CComPtr TestBufferRead; + CComPtr SceneConstantBuffer; // Descriptor heap - CComPtr pDescriptorHeap; + CComPtr DescriptorHeap; { // // UAV descriptor heap layout: @@ -2151,693 +2145,684 @@ CComPtr ExecutionTest::RunDXRTest( // 1 - vertex buffer SRV // 2 - index buffer SRV // - D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; - descriptorHeapDesc.NumDescriptors = 3; - descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - pDevice->CreateDescriptorHeap(&descriptorHeapDesc, - IID_PPV_ARGS(&pDescriptorHeap)); - pDescriptorHeap->SetName(L"Descriptor Heap"); - } - int descriptorSize = pDevice->GetDescriptorHandleIncrementSize( + D3D12_DESCRIPTOR_HEAP_DESC DescriptorHeapDesc = {}; + DescriptorHeapDesc.NumDescriptors = 3; + DescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + DescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + Device->CreateDescriptorHeap(&DescriptorHeapDesc, + IID_PPV_ARGS(&DescriptorHeap)); + DescriptorHeap->SetName(L"Descriptor Heap"); + } + int DescriptorSize = Device->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // Testbuffer { - auto resDesc = CD3DX12_RESOURCE_DESC::Buffer( - testData.size() * sizeof(int), + auto ResDesc = CD3DX12_RESOURCE_DESC::Buffer( + TestData.size() * sizeof(int), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - auto defaultHeapProperties = + auto DefaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); - VERIFY_SUCCEEDED(pDevice->CreateCommittedResource( - &defaultHeapProperties, D3D12_HEAP_FLAG_NONE, &resDesc, + VERIFY_SUCCEEDED(Device->CreateCommittedResource( + &DefaultHeapProperties, D3D12_HEAP_FLAG_NONE, &ResDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, - IID_PPV_ARGS(&pTestBuffer))); - pTestBuffer->SetName(L"Test Buffer"); + IID_PPV_ARGS(&TestBuffer))); + TestBuffer->SetName(L"Test Buffer"); - const int descriptorIndex = 0; - D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + const int DescriptorIndex = 0; + D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE( - pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - descriptorIndex, descriptorSize); + DescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + DescriptorIndex, DescriptorSize); D3D12_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {}; UAVDesc.Format = DXGI_FORMAT_UNKNOWN; UAVDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; UAVDesc.Buffer.FirstElement = 0; - UAVDesc.Buffer.NumElements = (UINT)testData.size(); + UAVDesc.Buffer.NumElements = (UINT)TestData.size(); UAVDesc.Buffer.StructureByteStride = sizeof(int); UAVDesc.Buffer.CounterOffsetInBytes = 0; UAVDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; - pDevice->CreateUnorderedAccessView(pTestBuffer, nullptr, &UAVDesc, - cpuDescriptorHandle); + Device->CreateUnorderedAccessView(TestBuffer, nullptr, &UAVDesc, + CPUDescriptorHandle); } // Testbuffer Readback { - CD3DX12_HEAP_PROPERTIES readHeap(D3D12_HEAP_TYPE_READBACK); - CD3DX12_RESOURCE_DESC readDesc( - CD3DX12_RESOURCE_DESC::Buffer(testData.size() * sizeof(int))); - pDevice->CreateCommittedResource(&readHeap, D3D12_HEAP_FLAG_NONE, &readDesc, - D3D12_RESOURCE_STATE_COPY_DEST, nullptr, - IID_PPV_ARGS(&pTestBufferRead)); + CD3DX12_HEAP_PROPERTIES ReadHeap(D3D12_HEAP_TYPE_READBACK); + CD3DX12_RESOURCE_DESC ReadDesc( + CD3DX12_RESOURCE_DESC::Buffer(TestData.size() * sizeof(int))); + Device->CreateCommittedResource(&ReadHeap, D3D12_HEAP_FLAG_NONE, &ReadDesc, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + IID_PPV_ARGS(&TestBufferRead)); } // Create CBV resource (sceneConstantBuffer), index 1 { - const int descriptorIndex = 1; - const UINT constantBufferSize = + const int DescriptorIndex = 1; + const UINT ConstantBufferSize = (sizeof(SceneConsts) + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1); // must be a multiple 256 bytes - D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE( - pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - descriptorIndex, descriptorSize); - auto resDesc = CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize); - auto uploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); - pDevice->CreateCommittedResource(&uploadHeapProperties, - D3D12_HEAP_FLAG_NONE, &resDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - IID_PPV_ARGS(&pSceneConstantBuffer)); - - UINT8 *sceneConstantBufferWO; - CD3DX12_RANGE readRange( + DescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + DescriptorIndex, DescriptorSize); + auto ResDesc = CD3DX12_RESOURCE_DESC::Buffer(ConstantBufferSize); + auto UploadHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + Device->CreateCommittedResource(&UploadHeapProperties, D3D12_HEAP_FLAG_NONE, + &ResDesc, D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&SceneConstantBuffer)); + + UINT8 *SceneConstantBufferWO; + CD3DX12_RANGE ReadRange( 0, 0); // We do not intend to read from this resource on the CPU. - pSceneConstantBuffer->Map( - 0, &readRange, reinterpret_cast(&sceneConstantBufferWO)); + SceneConstantBuffer->Map(0, &ReadRange, + reinterpret_cast(&SceneConstantBufferWO)); // Setup Scene Constants - SceneConsts sceneConsts = { + SceneConsts SceneConsts = { {25.f, -25.f, 700.f, 0.f}, {536.f, 0.f, 0.f, 0.f}, {0.f, 301.f, 0.f, 0.f}, {0.f, 0., -699.f, 0.f}, 100.f, - {(unsigned int)windowWidth, (unsigned int)windowHeight}, + {(unsigned int)WindowWidth, (unsigned int)WindowHeight}, 0x00}; - memcpy(sceneConstantBufferWO, &sceneConsts, sizeof(SceneConsts)); - pSceneConstantBuffer->Unmap(0, nullptr); + memcpy(SceneConstantBufferWO, &SceneConsts, sizeof(SceneConsts)); + SceneConstantBuffer->Unmap(0, nullptr); - D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {}; - desc.SizeInBytes = constantBufferSize; - desc.BufferLocation = pSceneConstantBuffer->GetGPUVirtualAddress(); - pDevice->CreateConstantBufferView(&desc, cpuDescriptorHandle); + D3D12_CONSTANT_BUFFER_VIEW_DESC Desc = {}; + Desc.SizeInBytes = ConstantBufferSize; + Desc.BufferLocation = SceneConstantBuffer->GetGPUVirtualAddress(); + Device->CreateConstantBufferView(&Desc, CPUDescriptorHandle); } // Local (SBT) root signature - CComPtr pLocalRootSignature; + CComPtr LocalRootSignature; { - CD3DX12_DESCRIPTOR_RANGE bufferRanges[1]; - CD3DX12_ROOT_PARAMETER rootParameters[2]; - bufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1, 0, + CD3DX12_DESCRIPTOR_RANGE BufferRanges[1]; + CD3DX12_ROOT_PARAMETER RootParameters[2]; + BufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 1, 0, 2); // vertexBuffer(t1), indexBuffer(t2) - rootParameters[0].InitAsDescriptorTable( - _countof(bufferRanges), bufferRanges, D3D12_SHADER_VISIBILITY_ALL); - rootParameters[1].InitAsConstants(4, 1, 0, D3D12_SHADER_VISIBILITY_ALL); + RootParameters[0].InitAsDescriptorTable( + _countof(BufferRanges), BufferRanges, D3D12_SHADER_VISIBILITY_ALL); + RootParameters[1].InitAsConstants(4, 1, 0, D3D12_SHADER_VISIBILITY_ALL); - CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, + CD3DX12_ROOT_SIGNATURE_DESC RootSignatureDesc; + RootSignatureDesc.Init(_countof(RootParameters), RootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE); - CComPtr signature; - CComPtr error; + CComPtr Signature; + CComPtr Error; VERIFY_SUCCEEDED(D3D12SerializeRootSignature( - &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); - VERIFY_SUCCEEDED(pDevice->CreateRootSignature( - 0, signature->GetBufferPointer(), signature->GetBufferSize(), - IID_PPV_ARGS(&pLocalRootSignature))); - pLocalRootSignature->SetName(L"Local Root Signature"); + &RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &Signature, &Error)); + VERIFY_SUCCEEDED(Device->CreateRootSignature( + 0, Signature->GetBufferPointer(), Signature->GetBufferSize(), + IID_PPV_ARGS(&LocalRootSignature))); + LocalRootSignature->SetName(L"Local Root Signature"); } // Global root signature - CComPtr pGlobalRootSignature; + CComPtr GlobalRootSignature; { - CD3DX12_DESCRIPTOR_RANGE bufferRanges[1]; - CD3DX12_ROOT_PARAMETER rootParameters[3]; - bufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, + CD3DX12_DESCRIPTOR_RANGE BufferRanges[1]; + CD3DX12_ROOT_PARAMETER RootParameters[3]; + BufferRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0); // testBuffer(u0) - rootParameters[0].InitAsShaderResourceView( + RootParameters[0].InitAsShaderResourceView( 0, 0, D3D12_SHADER_VISIBILITY_ALL); // accelStruct(t0) - rootParameters[1].InitAsConstantBufferView(0); // sceneConstants(b0) - rootParameters[2].InitAsDescriptorTable( - _countof(bufferRanges), bufferRanges, D3D12_SHADER_VISIBILITY_ALL); + RootParameters[1].InitAsConstantBufferView(0); // sceneConstants(b0) + RootParameters[2].InitAsDescriptorTable( + _countof(BufferRanges), BufferRanges, D3D12_SHADER_VISIBILITY_ALL); - CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, + CD3DX12_ROOT_SIGNATURE_DESC RootSignatureDesc; + RootSignatureDesc.Init(_countof(RootParameters), RootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_NONE); - CComPtr signature; - CComPtr error; + CComPtr Signature; + CComPtr Error; VERIFY_SUCCEEDED(D3D12SerializeRootSignature( - &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); - VERIFY_SUCCEEDED(pDevice->CreateRootSignature( - 0, signature->GetBufferPointer(), signature->GetBufferSize(), - IID_PPV_ARGS(&pGlobalRootSignature))); - pGlobalRootSignature->SetName(L"Global Root Signature"); + &RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &Signature, &Error)); + VERIFY_SUCCEEDED(Device->CreateRootSignature( + 0, Signature->GetBufferPointer(), Signature->GetBufferSize(), + IID_PPV_ARGS(&GlobalRootSignature))); + GlobalRootSignature->SetName(L"Global Root Signature"); } // Create command queue. - CComPtr pCommandQueue; - CreateCommandQueue(pDevice, L"RunDXRTest Command Queue", &pCommandQueue, + CComPtr CommandQueue; + CreateCommandQueue(Device, L"RunDXRTest Command Queue", &CommandQueue, D3D12_COMMAND_LIST_TYPE_DIRECT); // Compile raygen shader. - CComPtr pShaderLib; - CompileFromText(shader, L"raygen", pTargetProfile, &pShaderLib, pOptions, - numOptions); + CComPtr ShaderLib; + CompileFromText(ShaderSrc, L"raygen", TargetProfile, &ShaderLib, Options, + NumOptions); // Describe and create the RT pipeline state object (RTPSO). - CD3DX12_STATE_OBJECT_DESC stateObjectDesc( + CD3DX12_STATE_OBJECT_DESC StateObjectDesc( D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE); - auto lib = stateObjectDesc.CreateSubobject(); - CD3DX12_SHADER_BYTECODE byteCode(pShaderLib); - lib->SetDXILLibrary(&byteCode); - lib->DefineExport(L"raygen"); - lib->DefineExport(L"closesthit"); - lib->DefineExport(L"anyhit"); - lib->DefineExport(L"miss"); - if (useIS) { - lib->DefineExport(L"intersection"); - } - if (useMesh && useProceduralGeometry) { - lib->DefineExport(L"chAABB"); - } - - const int maxRecursion = 1; - stateObjectDesc.CreateSubobject() - ->Config(payloadCount * sizeof(float), attributeCount * sizeof(float)); - stateObjectDesc + auto Lib = StateObjectDesc.CreateSubobject(); + CD3DX12_SHADER_BYTECODE ByteCode(ShaderLib); + Lib->SetDXILLibrary(&ByteCode); + Lib->DefineExport(L"raygen"); + Lib->DefineExport(L"closesthit"); + Lib->DefineExport(L"anyhit"); + Lib->DefineExport(L"miss"); + if (UseIS) + Lib->DefineExport(L"intersection"); + if (UseMesh && UseProceduralGeometry) + Lib->DefineExport(L"chAABB"); + + const int MaxRecursion = 1; + StateObjectDesc.CreateSubobject() + ->Config(PayloadCount * sizeof(float), AttributeCount * sizeof(float)); + StateObjectDesc .CreateSubobject() - ->Config(maxRecursion); + ->Config(MaxRecursion); // Set Global Root Signature subobject. - auto globalRootSigSubObj = - stateObjectDesc + auto GlobalRootSigSubObj = + StateObjectDesc .CreateSubobject(); - globalRootSigSubObj->SetRootSignature(pGlobalRootSignature); + GlobalRootSigSubObj->SetRootSignature(GlobalRootSignature); // Set Local Root Signature subobject. - stateObjectDesc.CreateSubobject() - ->SetRootSignature(pLocalRootSignature); + StateObjectDesc.CreateSubobject() + ->SetRootSignature(LocalRootSignature); - auto exports = stateObjectDesc.CreateSubobject< + auto Exports = StateObjectDesc.CreateSubobject< CD3DX12_SUBOBJECT_TO_EXPORTS_ASSOCIATION_SUBOBJECT>(); - exports->SetSubobjectToAssociate(*globalRootSigSubObj); - exports->AddExport(L"raygen"); - exports->AddExport(L"closesthit"); - exports->AddExport(L"anyhit"); - exports->AddExport(L"miss"); - if (useIS) { - exports->AddExport(L"intersection"); - } - if (useMesh && useProceduralGeometry) { - exports->AddExport(L"chAABB"); - } - - auto hitGroup = - stateObjectDesc.CreateSubobject(); - hitGroup->SetClosestHitShaderImport(L"closesthit"); - hitGroup->SetAnyHitShaderImport(L"anyhit"); - if (useIS) { - hitGroup->SetIntersectionShaderImport(L"intersection"); - hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); - } - hitGroup->SetHitGroupExport(L"HitGroup"); - - if (useMesh && useProceduralGeometry) { - auto hitGroupAABB = - stateObjectDesc.CreateSubobject(); - hitGroupAABB->SetClosestHitShaderImport(L"chAABB"); - hitGroupAABB->SetAnyHitShaderImport(L"anyhit"); - if (useIS) { - hitGroup->SetIntersectionShaderImport(L"intersection"); - hitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); - } - hitGroupAABB->SetHitGroupExport(L"HitGroupAABB"); - } - - CComPtr pStateObject; - CComPtr pStateObjectProperties; + Exports->SetSubobjectToAssociate(*GlobalRootSigSubObj); + Exports->AddExport(L"raygen"); + Exports->AddExport(L"closesthit"); + Exports->AddExport(L"anyhit"); + Exports->AddExport(L"miss"); + if (UseIS) + Exports->AddExport(L"intersection"); + if (UseMesh && UseProceduralGeometry) + Exports->AddExport(L"chAABB"); + + auto HitGroup = + StateObjectDesc.CreateSubobject(); + HitGroup->SetClosestHitShaderImport(L"closesthit"); + HitGroup->SetAnyHitShaderImport(L"anyhit"); + if (UseIS) { + HitGroup->SetIntersectionShaderImport(L"intersection"); + HitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); + } + HitGroup->SetHitGroupExport(L"HitGroup"); + + if (UseMesh && UseProceduralGeometry) { + auto HitGroupAABB = + StateObjectDesc.CreateSubobject(); + HitGroupAABB->SetClosestHitShaderImport(L"chAABB"); + HitGroupAABB->SetAnyHitShaderImport(L"anyhit"); + if (UseIS) { + HitGroupAABB->SetIntersectionShaderImport(L"intersection"); + HitGroupAABB->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); + } + HitGroupAABB->SetHitGroupExport(L"HitGroupAABB"); + } + + CComPtr StateObject; + CComPtr StateObjectProperties; VERIFY_SUCCEEDED( - pDevice->CreateStateObject(stateObjectDesc, IID_PPV_ARGS(&pStateObject))); - VERIFY_SUCCEEDED(pStateObject->QueryInterface(&pStateObjectProperties)); + Device->CreateStateObject(StateObjectDesc, IID_PPV_ARGS(&StateObject))); + VERIFY_SUCCEEDED(StateObject->QueryInterface(&StateObjectProperties)); // Create SBT - ShaderTable shaderTable; - shaderTable.Init(pDevice, + ShaderTable ShaderTable; + ShaderTable.Init(Device, 1, // raygen count 1, // miss count - useMesh && useProceduralGeometry ? 2 : 1, // hit group count + UseMesh && UseProceduralGeometry ? 2 : 1, // hit group count 1, // ray type count 4 // dwords per root table ); - int localRootConsts[4] = {12, 34, 56, 78}; - memcpy(shaderTable.GetRaygenShaderIdPtr(0), - pStateObjectProperties->GetShaderIdentifier(L"raygen"), + int LocalRootConsts[4] = {12, 34, 56, 78}; + memcpy(ShaderTable.GetRaygenShaderIdPtr(0), + StateObjectProperties->GetShaderIdentifier(L"raygen"), SHADER_ID_SIZE_IN_BYTES); - memcpy(shaderTable.GetRaygenRootTablePtr(0), localRootConsts, - sizeof(localRootConsts)); - memcpy(shaderTable.GetMissShaderIdPtr(0, 0), - pStateObjectProperties->GetShaderIdentifier(L"miss"), + memcpy(ShaderTable.GetRaygenRootTablePtr(0), LocalRootConsts, + sizeof(LocalRootConsts)); + memcpy(ShaderTable.GetMissShaderIdPtr(0, 0), + StateObjectProperties->GetShaderIdentifier(L"miss"), SHADER_ID_SIZE_IN_BYTES); - memcpy(shaderTable.GetMissRootTablePtr(0, 0), localRootConsts, - sizeof(localRootConsts)); - memcpy(shaderTable.GetHitGroupShaderIdPtr(0, 0), - pStateObjectProperties->GetShaderIdentifier(L"HitGroup"), + memcpy(ShaderTable.GetMissRootTablePtr(0, 0), LocalRootConsts, + sizeof(LocalRootConsts)); + memcpy(ShaderTable.GetHitGroupShaderIdPtr(0, 0), + StateObjectProperties->GetShaderIdentifier(L"HitGroup"), SHADER_ID_SIZE_IN_BYTES); - memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), localRootConsts, - sizeof(localRootConsts)); - if (useMesh && useProceduralGeometry) { - memcpy(shaderTable.GetHitGroupShaderIdPtr(0, 1), - pStateObjectProperties->GetShaderIdentifier(L"HitGroupAABB"), + memcpy(ShaderTable.GetHitGroupRootTablePtr(0, 0), LocalRootConsts, + sizeof(LocalRootConsts)); + if (UseMesh && UseProceduralGeometry) + memcpy(ShaderTable.GetHitGroupShaderIdPtr(0, 1), + StateObjectProperties->GetShaderIdentifier(L"HitGroupAABB"), SHADER_ID_SIZE_IN_BYTES); - } - - // auto tbl = pDescriptorHeap->GetGPUDescriptorHandleForHeapStart().ptr; - // memcpy(shaderTable.GetHitGroupRootTablePtr(0, 0), &tbl, 8); // Create a command allocator and list. - CComPtr pCommandAllocator; - CComPtr pCommandList; - VERIFY_SUCCEEDED(pDevice->CreateCommandAllocator( - D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCommandAllocator))); - VERIFY_SUCCEEDED(pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, - pCommandAllocator, nullptr, - IID_PPV_ARGS(&pCommandList))); - pCommandList->SetName(L"ExecutionTest::RunDXRTest Command List"); - - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); - - VERIFY_SUCCEEDED(pCommandAllocator->Reset()); - VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + CComPtr CommandAllocator; + CComPtr CommandList; + VERIFY_SUCCEEDED(Device->CreateCommandAllocator( + D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&CommandAllocator))); + VERIFY_SUCCEEDED(Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, + CommandAllocator, nullptr, + IID_PPV_ARGS(&CommandList))); + CommandList->SetName(L"ExecutionTest::RunDXRTest Command List"); + + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); + + VERIFY_SUCCEEDED(CommandAllocator->Reset()); + VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); // Create scene geometry. - CComPtr tlasResource; - CComPtr blasMeshResource; - CComPtr blasProceduralGeometryResource; - CComPtr instanceDescs; - CComPtr scratchResource; - - if (useMesh) { - CComPtr vertexBuffer; - CComPtr vertexBufferUpload; - CComPtr indexBuffer; - CComPtr indexBufferUpload; + CComPtr TLASResource; + CComPtr BLASMeshResource; + CComPtr BLASProceduralGeometryResource; + CComPtr InstanceDescs; + CComPtr ScratchResource; + + if (UseMesh) { + CComPtr VertexBuffer; + CComPtr VertexBufferUpload; + CComPtr IndexBuffer; + CComPtr IndexBufferUpload; // Define a Quad - const float verts[] = { + const float Verts[] = { -50.5f, 50.5f, 0.5f, // top left 50.5f, -50.5f, 0.5f, // bottom right -50.5f, -50.5f, 0.5f, // bottom left 50.5f, 50.5f, 0.5f // top right }; - const int indices[] = { + const int Indices[] = { 0, 1, 2, // first triangle 0, 3, 1 // second triangle }; - const UINT64 vertexDataSize = sizeof(verts); - const UINT64 indexDataSize = sizeof(indices); + const UINT64 VertexDataSize = sizeof(Verts); + const UINT64 IndexDataSize = sizeof(Indices); - AllocateUploadBuffer(pDevice, verts, vertexDataSize, &vertexBufferUpload, - L"vertexBufferUpload"); - AllocateUploadBuffer(pDevice, indices, indexDataSize, &indexBufferUpload, - L"indexBufferUpload"); + AllocateUploadBuffer(Device, Verts, VertexDataSize, &VertexBufferUpload, + L"VertexBufferUpload"); + AllocateUploadBuffer(Device, Indices, IndexDataSize, &IndexBufferUpload, + L"IndexBufferUpload"); AllocateBufferFromUpload( - pDevice, pCommandList, vertexBufferUpload, &vertexBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"vertexBuffer"); + Device, CommandList, VertexBufferUpload, &VertexBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"VertexBuffer"); AllocateBufferFromUpload( - pDevice, pCommandList, indexBufferUpload, &indexBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"indexBuffer"); + Device, CommandList, IndexBufferUpload, &IndexBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"IndexBuffer"); { - const int descriptorIndex = 1; - D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + const int DescriptorIndex = 1; + D3D12_CPU_DESCRIPTOR_HANDLE CpuDescriptorHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE( - pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - descriptorIndex, descriptorSize); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Shader4ComponentMapping = + DescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + DescriptorIndex, DescriptorSize); + D3D12_SHADER_RESOURCE_VIEW_DESC SrvDesc = {}; + SrvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + SrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.Buffer.NumElements = - UINT(vertexDataSize / sizeof(DirectX::XMFLOAT3)); - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - srvDesc.Buffer.StructureByteStride = sizeof(DirectX::XMFLOAT3); - pDevice->CreateShaderResourceView(vertexBuffer, &srvDesc, - cpuDescriptorHandle); + SrvDesc.Buffer.NumElements = + UINT(VertexDataSize / sizeof(DirectX::XMFLOAT3)); + SrvDesc.Format = DXGI_FORMAT_UNKNOWN; + SrvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + SrvDesc.Buffer.StructureByteStride = sizeof(DirectX::XMFLOAT3); + Device->CreateShaderResourceView(VertexBuffer, &SrvDesc, + CpuDescriptorHandle); } { - const int descriptorIndex = 2; - D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = + const int DescriptorIndex = 2; + D3D12_CPU_DESCRIPTOR_HANDLE CpuDescriptorHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE( - pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - descriptorIndex, descriptorSize); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Shader4ComponentMapping = + DescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + DescriptorIndex, DescriptorSize); + D3D12_SHADER_RESOURCE_VIEW_DESC SrvDesc = {}; + SrvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + SrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.Buffer.NumElements = UINT(indexDataSize / sizeof(int)); - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - srvDesc.Buffer.StructureByteStride = sizeof(int); - pDevice->CreateShaderResourceView(indexBuffer, &srvDesc, - cpuDescriptorHandle); + SrvDesc.Buffer.NumElements = UINT(IndexDataSize / sizeof(int)); + SrvDesc.Format = DXGI_FORMAT_UNKNOWN; + SrvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + SrvDesc.Buffer.StructureByteStride = sizeof(int); + Device->CreateShaderResourceView(IndexBuffer, &SrvDesc, + CpuDescriptorHandle); } - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); - VERIFY_SUCCEEDED(pCommandAllocator->Reset()); - VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + VERIFY_SUCCEEDED(CommandAllocator->Reset()); + VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); - if (!useIS) { + if (!UseIS) { // Build BLAS. { - D3D12_RAYTRACING_GEOMETRY_DESC geometryDesc = {}; - geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - geometryDesc.Triangles.IndexBuffer = - indexBuffer->GetGPUVirtualAddress(); - geometryDesc.Triangles.IndexCount = - static_cast(indexBuffer->GetDesc().Width) / sizeof(int); - geometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; - geometryDesc.Triangles.Transform3x4 = 0; - geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; - geometryDesc.Triangles.VertexCount = - static_cast(vertexBuffer->GetDesc().Width) / + D3D12_RAYTRACING_GEOMETRY_DESC GeometryDesc = {}; + GeometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + GeometryDesc.Triangles.IndexBuffer = + IndexBuffer->GetGPUVirtualAddress(); + GeometryDesc.Triangles.IndexCount = + static_cast(IndexBuffer->GetDesc().Width) / sizeof(int); + GeometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + GeometryDesc.Triangles.Transform3x4 = 0; + GeometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + GeometryDesc.Triangles.VertexCount = + static_cast(VertexBuffer->GetDesc().Width) / sizeof(DirectX::XMFLOAT3); - geometryDesc.Triangles.VertexBuffer.StartAddress = - vertexBuffer->GetGPUVirtualAddress(); - geometryDesc.Triangles.VertexBuffer.StrideInBytes = + GeometryDesc.Triangles.VertexBuffer.StartAddress = + VertexBuffer->GetGPUVirtualAddress(); + GeometryDesc.Triangles.VertexBuffer.StrideInBytes = sizeof(DirectX::XMFLOAT3); - geometryDesc.Flags = + GeometryDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; // Non-opaque to trigger // anyhit. - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; - accelInputs.Type = + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; + AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - accelInputs.pGeometryDescs = &geometryDesc; - accelInputs.NumDescs = 1; - accelInputs.Flags = buildFlags; - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, - &prebuildInfo); - - scratchResource.Release(); - ReallocScratchResource(pDevice, &scratchResource, - prebuildInfo.ScratchDataSizeInBytes); - AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, - &blasMeshResource, true, + AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + AccelInputs.pGeometryDescs = &GeometryDesc; + AccelInputs.NumDescs = 1; + AccelInputs.Flags = BuildFlags; + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, + &PrebuildInfo); + + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer(Device, PrebuildInfo.ResultDataMaxSizeInBytes, + &BLASMeshResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"blasMesh"); - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; - buildDesc.Inputs = accelInputs; - buildDesc.ScratchAccelerationStructureData = - scratchResource->GetGPUVirtualAddress(); - buildDesc.DestAccelerationStructureData = - blasMeshResource->GetGPUVirtualAddress(); - - pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, - nullptr); - CD3DX12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::UAV(blasMeshResource); - pCommandList->ResourceBarrier(1, - (const D3D12_RESOURCE_BARRIER *)&barrier); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; + BuildDesc.Inputs = AccelInputs; + BuildDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BuildDesc.DestAccelerationStructureData = + BLASMeshResource->GetGPUVirtualAddress(); + + CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, + nullptr); + CD3DX12_RESOURCE_BARRIER Barrier = + CD3DX12_RESOURCE_BARRIER::UAV(BLASMeshResource); + CommandList->ResourceBarrier(1, + (const D3D12_RESOURCE_BARRIER *)&Barrier); } } - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); - VERIFY_SUCCEEDED(pCommandAllocator->Reset()); - VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + VERIFY_SUCCEEDED(CommandAllocator->Reset()); + VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); } - if (useProceduralGeometry) { + if (UseProceduralGeometry) { // Define procedural geometry AABB for a plane - CComPtr aabbBuffer; - CComPtr aabbBufferUpload; + CComPtr AabbBuffer; + CComPtr AabbBufferUpload; // Define the AABB for the plane, matching the size of the quad defined by // verts[] - const D3D12_RAYTRACING_AABB aabb = { + const D3D12_RAYTRACING_AABB Aabb = { -150.5f, -500.5f, -1000.0f, // Min corner (x, y, z) 150.5f, -150.5f, 1000.0f // Max corner (x, y, z) }; - const UINT64 aabbDataSize = sizeof(aabb); + const UINT64 AabbDataSize = sizeof(Aabb); // Create an upload buffer for the AABB - AllocateUploadBuffer(pDevice, &aabb, aabbDataSize, &aabbBufferUpload, - L"aabbBufferUpload"); + AllocateUploadBuffer(Device, &Aabb, AabbDataSize, &AabbBufferUpload, + L"AabbBufferUpload"); // Create a GPU buffer for the AABB - AllocateBufferFromUpload( - pDevice, pCommandList, aabbBufferUpload, &aabbBuffer, - D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, L"aabbBuffer"); + AllocateBufferFromUpload(Device, CommandList, AabbBufferUpload, &AabbBuffer, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, + L"AabbBuffer"); // Describe the procedural geometry - D3D12_RAYTRACING_GEOMETRY_DESC procGeometryDesc = {}; - procGeometryDesc.Type = + D3D12_RAYTRACING_GEOMETRY_DESC ProcGeometryDesc = {}; + ProcGeometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; - procGeometryDesc.AABBs.AABBs.StartAddress = - aabbBuffer->GetGPUVirtualAddress(); - procGeometryDesc.AABBs.AABBs.StrideInBytes = sizeof(D3D12_RAYTRACING_AABB); - procGeometryDesc.AABBs.AABBCount = 1; + ProcGeometryDesc.AABBs.AABBs.StartAddress = + AabbBuffer->GetGPUVirtualAddress(); + ProcGeometryDesc.AABBs.AABBs.StrideInBytes = sizeof(D3D12_RAYTRACING_AABB); + ProcGeometryDesc.AABBs.AABBCount = 1; // Build the BLAS for the procedural geometry - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS blasInputs = {}; - blasInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - blasInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - blasInputs.NumDescs = 1; - blasInputs.pGeometryDescs = &procGeometryDesc; - blasInputs.Flags = + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS BLASInputs = {}; + BLASInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + BLASInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + BLASInputs.NumDescs = 1; + BLASInputs.pGeometryDescs = &ProcGeometryDesc; + BLASInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&blasInputs, - &prebuildInfo); + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&BLASInputs, + &PrebuildInfo); // Allocate scratch and result buffers for the BLAS - scratchResource.Release(); - ReallocScratchResource(pDevice, &scratchResource, - prebuildInfo.ScratchDataSizeInBytes); - AllocateBuffer(pDevice, prebuildInfo.ResultDataMaxSizeInBytes, - &blasProceduralGeometryResource, true, + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer(Device, PrebuildInfo.ResultDataMaxSizeInBytes, + &BLASProceduralGeometryResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, - L"blasProceduralGeometry"); + L"BlasProceduralGeometry"); // Build the BLAS - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC blasDesc = {}; - blasDesc.Inputs = blasInputs; - blasDesc.ScratchAccelerationStructureData = - scratchResource->GetGPUVirtualAddress(); - blasDesc.DestAccelerationStructureData = - blasProceduralGeometryResource->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BLASDesc = {}; + BLASDesc.Inputs = BLASInputs; + BLASDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BLASDesc.DestAccelerationStructureData = + BLASProceduralGeometryResource->GetGPUVirtualAddress(); - pCommandList->BuildRaytracingAccelerationStructure(&blasDesc, 0, nullptr); + CommandList->BuildRaytracingAccelerationStructure(&BLASDesc, 0, nullptr); // Add a UAV barrier to ensure the BLAS is built before using it - CD3DX12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::UAV(blasProceduralGeometryResource); - pCommandList->ResourceBarrier(1, &barrier); + CD3DX12_RESOURCE_BARRIER Barrier = + CD3DX12_RESOURCE_BARRIER::UAV(BLASProceduralGeometryResource); + CommandList->ResourceBarrier(1, &Barrier); - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); - VERIFY_SUCCEEDED(pCommandAllocator->Reset()); - VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + VERIFY_SUCCEEDED(CommandAllocator->Reset()); + VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); } // Build TLAS. { - if (useMesh) { - D3D12_RAYTRACING_INSTANCE_DESC instanceDesc = {}; - instanceDesc.Transform[0][0] = instanceDesc.Transform[1][1] = - instanceDesc.Transform[2][2] = 1; - instanceDesc.InstanceMask = 1; - instanceDesc.AccelerationStructure = - blasMeshResource->GetGPUVirtualAddress(); - - AllocateUploadBuffer(pDevice, &instanceDesc, sizeof(instanceDesc), - &instanceDescs, L"instanceDescs"); - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + if (UseMesh) { + D3D12_RAYTRACING_INSTANCE_DESC InstanceDesc = {}; + InstanceDesc.Transform[0][0] = InstanceDesc.Transform[1][1] = + InstanceDesc.Transform[2][2] = 1; + InstanceDesc.InstanceMask = 1; + InstanceDesc.AccelerationStructure = + BLASMeshResource->GetGPUVirtualAddress(); + + AllocateUploadBuffer(Device, &InstanceDesc, sizeof(InstanceDesc), + &InstanceDescs, L"InstanceDescs"); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; - accelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - accelInputs.NumDescs = 1; - accelInputs.Flags = buildFlags; - accelInputs.InstanceDescs = instanceDescs->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; + AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + AccelInputs.NumDescs = 1; + AccelInputs.Flags = BuildFlags; + AccelInputs.InstanceDescs = InstanceDescs->GetGPUVirtualAddress(); - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, - &prebuildInfo); + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, + &PrebuildInfo); - scratchResource.Release(); - ReallocScratchResource(pDevice, &scratchResource, - prebuildInfo.ScratchDataSizeInBytes); + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); AllocateBuffer( - pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, + Device, PrebuildInfo.ResultDataMaxSizeInBytes, &TLASResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; - buildDesc.Inputs = accelInputs; - buildDesc.ScratchAccelerationStructureData = - scratchResource->GetGPUVirtualAddress(); - buildDesc.DestAccelerationStructureData = - tlasResource->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; + BuildDesc.Inputs = AccelInputs; + BuildDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BuildDesc.DestAccelerationStructureData = + TLASResource->GetGPUVirtualAddress(); - pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, 0); + CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, 0); } else { - D3D12_RAYTRACING_INSTANCE_DESC instanceDesc = {}; - instanceDesc.Transform[0][0] = instanceDesc.Transform[1][1] = - instanceDesc.Transform[2][2] = 1; - instanceDesc.InstanceMask = 1; - instanceDesc.AccelerationStructure = - blasProceduralGeometryResource->GetGPUVirtualAddress(); + D3D12_RAYTRACING_INSTANCE_DESC InstanceDesc = {}; + InstanceDesc.Transform[0][0] = InstanceDesc.Transform[1][1] = + InstanceDesc.Transform[2][2] = 1; + InstanceDesc.InstanceMask = 1; + InstanceDesc.AccelerationStructure = + BLASProceduralGeometryResource->GetGPUVirtualAddress(); - AllocateUploadBuffer(pDevice, &instanceDesc, sizeof(instanceDesc), - &instanceDescs, L"instanceDescs"); + AllocateUploadBuffer(Device, &InstanceDesc, sizeof(InstanceDesc), + &InstanceDescs, L"InstanceDescs"); - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS accelInputs = {}; - accelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - accelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - accelInputs.NumDescs = 1; - accelInputs.Flags = buildFlags; - accelInputs.InstanceDescs = instanceDescs->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; + AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + AccelInputs.NumDescs = 1; + AccelInputs.Flags = BuildFlags; + AccelInputs.InstanceDescs = InstanceDescs->GetGPUVirtualAddress(); - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo = {}; - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&accelInputs, - &prebuildInfo); + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, + &PrebuildInfo); - scratchResource.Release(); - ReallocScratchResource(pDevice, &scratchResource, - prebuildInfo.ScratchDataSizeInBytes); + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); AllocateBuffer( - pDevice, prebuildInfo.ResultDataMaxSizeInBytes, &tlasResource, true, + Device, PrebuildInfo.ResultDataMaxSizeInBytes, &TLASResource, true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {}; - buildDesc.Inputs = accelInputs; - buildDesc.ScratchAccelerationStructureData = - scratchResource->GetGPUVirtualAddress(); - buildDesc.DestAccelerationStructureData = - tlasResource->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; + BuildDesc.Inputs = AccelInputs; + BuildDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BuildDesc.DestAccelerationStructureData = + TLASResource->GetGPUVirtualAddress(); - pCommandList->BuildRaytracingAccelerationStructure(&buildDesc, 0, 0); + CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, 0); } - CD3DX12_RESOURCE_BARRIER barrier = - CD3DX12_RESOURCE_BARRIER::UAV(tlasResource); - pCommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&barrier); + CD3DX12_RESOURCE_BARRIER Barrier = + CD3DX12_RESOURCE_BARRIER::UAV(TLASResource); + CommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&Barrier); } // Set the local root constants. - pCommandList->SetComputeRootSignature(pLocalRootSignature); - pCommandList->SetComputeRoot32BitConstant(1, 12, 0); - pCommandList->SetComputeRoot32BitConstant(1, 34, 1); - pCommandList->SetComputeRoot32BitConstant(1, 56, 2); - pCommandList->SetComputeRoot32BitConstant(1, 78, 3); - - shaderTable.Upload(pCommandList); - - ID3D12DescriptorHeap *const pHeaps[1] = {pDescriptorHeap}; - pCommandList->SetDescriptorHeaps(1, pHeaps); - pCommandList->SetComputeRootSignature(pGlobalRootSignature); - pCommandList->SetComputeRootShaderResourceView( - 0, tlasResource->GetGPUVirtualAddress()); - pCommandList->SetComputeRootConstantBufferView( - 1, pSceneConstantBuffer->GetGPUVirtualAddress()); - pCommandList->SetComputeRootDescriptorTable( - 2, pDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); - - D3D12_DISPATCH_RAYS_DESC dispatchDesc = {}; - dispatchDesc.RayGenerationShaderRecord.StartAddress = - shaderTable.GetRaygenStartGpuVA(); - dispatchDesc.RayGenerationShaderRecord.SizeInBytes = - shaderTable.GetRaygenRangeInBytes(); - dispatchDesc.MissShaderTable.StartAddress = shaderTable.GetMissStartGpuVA(); - dispatchDesc.MissShaderTable.SizeInBytes = shaderTable.GetMissRangeInBytes(); - dispatchDesc.MissShaderTable.StrideInBytes = - shaderTable.GetShaderRecordSizeInBytes(); - dispatchDesc.HitGroupTable.StartAddress = shaderTable.GetHitGroupStartGpuVA(); - dispatchDesc.HitGroupTable.SizeInBytes = - shaderTable.GetHitGroupRangeInBytes(); - dispatchDesc.HitGroupTable.StrideInBytes = - shaderTable.GetShaderRecordSizeInBytes(); - dispatchDesc.Width = windowWidth; - dispatchDesc.Height = windowHeight; - dispatchDesc.Depth = 1; - pCommandList->SetPipelineState1(pStateObject); - pCommandList->DispatchRays(&dispatchDesc); - - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); - - VERIFY_SUCCEEDED(pCommandAllocator->Reset()); - VERIFY_SUCCEEDED(pCommandList->Reset(pCommandAllocator, nullptr)); + CommandList->SetComputeRootSignature(LocalRootSignature); + CommandList->SetComputeRoot32BitConstant(1, 12, 0); + CommandList->SetComputeRoot32BitConstant(1, 34, 1); + CommandList->SetComputeRoot32BitConstant(1, 56, 2); + CommandList->SetComputeRoot32BitConstant(1, 78, 3); + + ShaderTable.Upload(CommandList); + + ID3D12DescriptorHeap *const Heaps[1] = {DescriptorHeap}; + CommandList->SetDescriptorHeaps(1, Heaps); + CommandList->SetComputeRootSignature(GlobalRootSignature); + CommandList->SetComputeRootShaderResourceView( + 0, TLASResource->GetGPUVirtualAddress()); + CommandList->SetComputeRootConstantBufferView( + 1, SceneConstantBuffer->GetGPUVirtualAddress()); + CommandList->SetComputeRootDescriptorTable( + 2, DescriptorHeap->GetGPUDescriptorHandleForHeapStart()); + + D3D12_DISPATCH_RAYS_DESC DispatchDesc = {}; + DispatchDesc.RayGenerationShaderRecord.StartAddress = + ShaderTable.GetRaygenStartGpuVA(); + DispatchDesc.RayGenerationShaderRecord.SizeInBytes = + ShaderTable.GetRaygenRangeInBytes(); + DispatchDesc.MissShaderTable.StartAddress = ShaderTable.GetMissStartGpuVA(); + DispatchDesc.MissShaderTable.SizeInBytes = ShaderTable.GetMissRangeInBytes(); + DispatchDesc.MissShaderTable.StrideInBytes = + ShaderTable.GetShaderRecordSizeInBytes(); + DispatchDesc.HitGroupTable.StartAddress = ShaderTable.GetHitGroupStartGpuVA(); + DispatchDesc.HitGroupTable.SizeInBytes = + ShaderTable.GetHitGroupRangeInBytes(); + DispatchDesc.HitGroupTable.StrideInBytes = + ShaderTable.GetShaderRecordSizeInBytes(); + DispatchDesc.Width = WindowWidth; + DispatchDesc.Height = WindowHeight; + DispatchDesc.Depth = 1; + CommandList->SetPipelineState1(StateObject); + CommandList->DispatchRays(&DispatchDesc); + + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); + + VERIFY_SUCCEEDED(CommandAllocator->Reset()); + VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); // Copy the testBuffer contents to CPU - D3D12_RESOURCE_BARRIER barriers[1]; - barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( - pTestBuffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_BARRIER Barriers[1]; + Barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + TestBuffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); - pCommandList->ResourceBarrier(1, barriers); - pCommandList->CopyResource(pTestBufferRead, pTestBuffer); - barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( - pTestBuffer, D3D12_RESOURCE_STATE_COPY_SOURCE, + CommandList->ResourceBarrier(1, Barriers); + CommandList->CopyResource(TestBufferRead, TestBuffer); + Barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + TestBuffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - pCommandList->ResourceBarrier(1, barriers); + CommandList->ResourceBarrier(1, Barriers); - pCommandList->Close(); - ExecuteCommandList(pCommandQueue, pCommandList); - WaitForSignal(pCommandQueue, FO); + CommandList->Close(); + ExecuteCommandList(CommandQueue, CommandList); + WaitForSignal(CommandQueue, FO); // Copy the shader test data into 'testData'. - MappedData data(pTestBufferRead, (UINT32)testData.size() * sizeof(int)); - const int *pData = (int *)data.data(); + MappedData Data(TestBufferRead, (UINT32)TestData.size() * sizeof(int)); + const int *DataPtr = (int *)Data.data(); - for (int i = 0; i < testData.size(); i++) { - testData[i] = *pData++; - } + for (int i = 0; i < TestData.size(); i++) + TestData[i] = *DataPtr++; // Cleanup resources - pTestBuffer.Release(); - pTestBufferRead.Release(); - pSceneConstantBuffer.Release(); - pDescriptorHeap.Release(); - pCommandQueue.Release(); - pCommandAllocator.Release(); - pCommandList.Release(); - pStateObject.Release(); - pStateObjectProperties.Release(); - tlasResource.Release(); - blasMeshResource.Release(); - blasProceduralGeometryResource.Release(); - instanceDescs.Release(); - scratchResource.Release(); - - return pTestBufferRead; + TestBuffer.Release(); + TestBufferRead.Release(); + SceneConstantBuffer.Release(); + DescriptorHeap.Release(); + CommandQueue.Release(); + CommandAllocator.Release(); + CommandList.Release(); + StateObject.Release(); + StateObjectProperties.Release(); + TLASResource.Release(); + BLASMeshResource.Release(); + BLASProceduralGeometryResource.Release(); + InstanceDescs.Release(); + ScratchResource.Release(); + + return TestBufferRead; } // SER TESTS diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 1c24795a0c..1a5c2eb7ab 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -10,9 +10,11 @@ // // /////////////////////////////////////////////////////////////////////////////// +#pragma once + TEST_F(ExecutionTest, SERScalarGetterTest) { // SER: Test basic function of HitObject getters. - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -20,7 +22,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -96,54 +98,33 @@ void closesthit(inout PerRayData payload, in Attrs attrs) } )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - - if (!bDXRSupported) - return; - - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + const int WindowSize = 64; // RayTMin { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetRayTMin()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=float", L"-DHIT_GET_SCALAR=RayTMin", L"-DMISS_GET_SCALAR=RayTMin", L"-DSER_GET_SCALAR=GetRayTMin"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - float *resArray = (float *)(testData.data() + id); - float refVal = resArray[0]; - float serVal = resArray[1]; - const bool passRayTMin = CompareFloatEpsilon(serVal, refVal, 0.0008f); - if (!passRayTMin) { - VERIFY_IS_TRUE(passRayTMin); - WEX::Logging::Log::Comment(L"HitObject::GetRayTMin() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + float *ResArray = (float *)(TestData.data() + Id); + float RefVal = ResArray[0]; + float SerVal = ResArray[1]; + const bool PassRayTMin = CompareFloatEpsilon(SerVal, RefVal, 0.0008f); + if (!PassRayTMin) { + VERIFY_IS_TRUE(PassRayTMin); return; } } @@ -152,24 +133,24 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // RayTCurrent { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetRayTCurrent()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=float", L"-DHIT_GET_SCALAR=RayTCurrent", L"-DMISS_GET_SCALAR=RayTCurrent", L"-DSER_GET_SCALAR=GetRayTCurrent"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - float *resArray = (float *)(testData.data() + id); - float refVal = resArray[0]; - float serVal = resArray[1]; - const bool passRayTCurrent = CompareFloatEpsilon(serVal, refVal, 0.0008f); - if (!passRayTCurrent) { - VERIFY_IS_TRUE(passRayTCurrent); - WEX::Logging::Log::Comment(L"HitObject::GetRayTCurrent() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + float *ResArray = (float *)(TestData.data() + Id); + float RefVal = ResArray[0]; + float SerVal = ResArray[1]; + const bool PassRayTCurrent = CompareFloatEpsilon(SerVal, RefVal, 0.0008f); + if (!PassRayTCurrent) { + VERIFY_IS_TRUE(PassRayTCurrent); return; } } @@ -178,22 +159,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // RayFlags { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetRayFlags()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=RayFlags", L"-DMISS_GET_SCALAR=RayFlags", L"-DSER_GET_SCALAR=GetRayFlags"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetRayFlags() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -202,22 +183,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // HitKind { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetHitKind()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=HitKind", L"-DMISS_GET_SCALAR=getIntZero", L"-DSER_GET_SCALAR=GetHitKind"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetHitKind() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -226,22 +207,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // GeometryIndex { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetGeometryIndex()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=GeometryIndex", L"-DMISS_GET_SCALAR=getIntZero", L"-DSER_GET_SCALAR=GetGeometryIndex"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetGeometryIndex() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -250,22 +231,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // InstanceIndex { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetInstanceIndex()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=InstanceIndex", L"-DMISS_GET_SCALAR=getIntZero", L"-DSER_GET_SCALAR=GetInstanceIndex"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetInstanceIndex() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -274,22 +255,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // InstanceID { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetInstanceID()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=InstanceID", L"-DMISS_GET_SCALAR=getIntZero", L"-DSER_GET_SCALAR=GetInstanceID"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetInstanceID() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -298,22 +279,22 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // PrimitiveIndex { - std::vector testData(windowSize * windowSize * 2, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetPrimitiveIndex()"); + std::vector TestData(WindowSize * WindowSize * 2, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DVALTYPE=uint", L"-DHIT_GET_SCALAR=PrimitiveIndex", L"-DMISS_GET_SCALAR=getIntZero", L"-DSER_GET_SCALAR=GetPrimitiveIndex"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - for (int id = 0; id < testData.size(); id += 2) { - const int refVal = testData[id]; - const int serVal = testData[id + 1]; - if (refVal != serVal) { - VERIFY_ARE_EQUAL(refVal, serVal); - WEX::Logging::Log::Comment(L"HitObject::GetPrimitiveIndex() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 2) { + const int RefVal = TestData[Id]; + const int SerVal = TestData[Id + 1]; + if (RefVal != SerVal) { + VERIFY_ARE_EQUAL(RefVal, SerVal); return; } } @@ -323,7 +304,7 @@ void closesthit(inout PerRayData payload, in Attrs attrs) TEST_F(ExecutionTest, SERVectorGetterTest) { // SER: Test basic function of HitObject getters. - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -331,7 +312,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -410,60 +391,39 @@ void closesthit(inout PerRayData payload, in Attrs attrs) } )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - - if (!bDXRSupported) - return; - - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + const int WindowSize = 64; // WorldRayOrigin { - std::vector testData(windowSize * windowSize * 6, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=WorldRayOrigin", + WEX::Logging::Log::Comment(L"Testing HitObject::GetWorldRayOrigin()"); + std::vector TestData(WindowSize * WindowSize * 6, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=WorldRayOrigin", L"-DMISS_GET_VECTOR=WorldRayOrigin", L"-DSER_GET_VECTOR=GetWorldRayOrigin"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 3 /*payloadCount*/); - for (int id = 0; id < testData.size(); id += 6) { - float *resArray = (float *)(testData.data() + id); - float refX = resArray[0]; - float serX = resArray[1]; - float refY = resArray[2]; - float serY = resArray[3]; - float refZ = resArray[4]; - float serZ = resArray[5]; - const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); - const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); - const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); - if (!passX || !passY || !passZ) { - VERIFY_ARE_EQUAL(serX, refX); - VERIFY_ARE_EQUAL(serY, refY); - VERIFY_ARE_EQUAL(serZ, refZ); - WEX::Logging::Log::Comment(L"HitObject::GetWorldRayOrigin() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 6) { + float *ResArray = (float *)(TestData.data() + Id); + float RefX = ResArray[0]; + float SerX = ResArray[1]; + float RefY = ResArray[2]; + float SerY = ResArray[3]; + float RefZ = ResArray[4]; + float SerZ = ResArray[5]; + const bool PassX = CompareFloatEpsilon(SerX, RefX, 0.0008f); + const bool PassY = CompareFloatEpsilon(SerY, RefY, 0.0008f); + const bool PassZ = CompareFloatEpsilon(SerZ, RefZ, 0.0008f); + if (!PassX || !PassY || !PassZ) { + VERIFY_ARE_EQUAL(SerX, RefX); + VERIFY_ARE_EQUAL(SerY, RefY); + VERIFY_ARE_EQUAL(SerZ, RefZ); break; } } @@ -472,32 +432,32 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // WorldRayDirection { - std::vector testData(windowSize * windowSize * 6, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd", + WEX::Logging::Log::Comment(L"Testing HitObject::GetWorldRayDirection()"); + std::vector TestData(WindowSize * WindowSize * 6, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=WorldRayDirection", L"-DMISS_GET_VECTOR=WorldRayDirection", L"-DSER_GET_VECTOR=GetWorldRayDirection"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 3 /*payloadCount*/); - for (int id = 0; id < testData.size(); id += 6) { - float *resArray = (float *)(testData.data() + id); - float refX = resArray[0]; - float serX = resArray[1]; - float refY = resArray[2]; - float serY = resArray[3]; - float refZ = resArray[4]; - float serZ = resArray[5]; - const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); - const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); - const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); - if (!passX || !passY || !passZ) { - VERIFY_ARE_EQUAL(serX, refX); - VERIFY_ARE_EQUAL(serY, refY); - VERIFY_ARE_EQUAL(serZ, refZ); - WEX::Logging::Log::Comment(L"HitObject::GetWorldRayDirection() FAILED"); - return; + for (int Id = 0; Id < TestData.size(); Id += 6) { + float *ResArray = (float *)(TestData.data() + Id); + float RefX = ResArray[0]; + float SerX = ResArray[1]; + float RefY = ResArray[2]; + float SerY = ResArray[3]; + float RefZ = ResArray[4]; + float SerZ = ResArray[5]; + const bool PassX = CompareFloatEpsilon(SerX, RefX, 0.0008f); + const bool PassY = CompareFloatEpsilon(SerY, RefY, 0.0008f); + const bool PassZ = CompareFloatEpsilon(SerZ, RefZ, 0.0008f); + if (!PassX || !PassY || !PassZ) { + VERIFY_ARE_EQUAL(SerX, RefX); + VERIFY_ARE_EQUAL(SerY, RefY); + VERIFY_ARE_EQUAL(SerZ, RefZ); + break; } } WEX::Logging::Log::Comment(L"HitObject::GetWorldRayDirection() PASSED"); @@ -505,30 +465,30 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // ObjectRayOrigin { - std::vector testData(windowSize * windowSize * 6, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=ObjectRayOrigin", + WEX::Logging::Log::Comment(L"Testing HitObject::GetObjectRayOrigin()"); + std::vector TestData(WindowSize * WindowSize * 6, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=ObjectRayOrigin", L"-DMISS_GET_VECTOR=WorldRayOrigin", L"-DSER_GET_VECTOR=GetObjectRayOrigin"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 3 /*payloadCount*/); - for (int id = 0; id < testData.size(); id += 6) { - float *resArray = (float *)(testData.data() + id); - float refX = resArray[0]; - float serX = resArray[1]; - float refY = resArray[2]; - float serY = resArray[3]; - float refZ = resArray[4]; - float serZ = resArray[5]; - const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); - const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); - const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); - if (!passX || !passY || !passZ) { - VERIFY_ARE_EQUAL(serX, refX); - VERIFY_ARE_EQUAL(serY, refY); - VERIFY_ARE_EQUAL(serZ, refZ); - WEX::Logging::Log::Comment(L"HitObject::GetObjectRayOrigin() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 6) { + float *ResArray = (float *)(TestData.data() + Id); + float RefX = ResArray[0]; + float SerX = ResArray[1]; + float RefY = ResArray[2]; + float SerY = ResArray[3]; + float RefZ = ResArray[4]; + float SerZ = ResArray[5]; + const bool PassX = CompareFloatEpsilon(SerX, RefX, 0.0008f); + const bool PassY = CompareFloatEpsilon(SerY, RefY, 0.0008f); + const bool PassZ = CompareFloatEpsilon(SerZ, RefZ, 0.0008f); + if (!PassX || !PassY || !PassZ) { + VERIFY_ARE_EQUAL(SerX, RefX); + VERIFY_ARE_EQUAL(SerY, RefY); + VERIFY_ARE_EQUAL(SerZ, RefZ); break; } } @@ -537,32 +497,31 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // ObjectRayDirection { - std::vector testData(windowSize * windowSize * 6, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd", + WEX::Logging::Log::Comment(L"Testing HitObject::GetObjectRayDirection()"); + std::vector TestData(WindowSize * WindowSize * 6, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_VECTOR=ObjectRayDirection", L"-DMISS_GET_VECTOR=WorldRayDirection", L"-DSER_GET_VECTOR=GetObjectRayDirection"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 3 /*payloadCount*/); - for (int id = 0; id < testData.size(); id += 6) { - float *resArray = (float *)(testData.data() + id); - float refX = resArray[0]; - float serX = resArray[1]; - float refY = resArray[2]; - float serY = resArray[3]; - float refZ = resArray[4]; - float serZ = resArray[5]; - const bool passX = CompareFloatEpsilon(serX, refX, 0.0008f); - const bool passY = CompareFloatEpsilon(serY, refY, 0.0008f); - const bool passZ = CompareFloatEpsilon(serZ, refZ, 0.0008f); - if (!passX || !passY || !passZ) { - VERIFY_ARE_EQUAL(serX, refX); - VERIFY_ARE_EQUAL(serY, refY); - VERIFY_ARE_EQUAL(serZ, refZ); - WEX::Logging::Log::Comment( - L"HitObject::GetObjectRayDirection() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 6) { + float *ResArray = (float *)(TestData.data() + Id); + float RefX = ResArray[0]; + float SerX = ResArray[1]; + float RefY = ResArray[2]; + float SerY = ResArray[3]; + float RefZ = ResArray[4]; + float SerZ = ResArray[5]; + const bool PassX = CompareFloatEpsilon(SerX, RefX, 0.0008f); + const bool PassY = CompareFloatEpsilon(SerY, RefY, 0.0008f); + const bool PassZ = CompareFloatEpsilon(SerZ, RefZ, 0.0008f); + if (!PassX || !PassY || !PassZ) { + VERIFY_ARE_EQUAL(SerX, RefX); + VERIFY_ARE_EQUAL(SerY, RefY); + VERIFY_ARE_EQUAL(SerZ, RefZ); break; } } @@ -572,7 +531,7 @@ void closesthit(inout PerRayData payload, in Attrs attrs) TEST_F(ExecutionTest, SERMatrixGetterTest) { // SER: Test basic function of HitObject getters. - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -580,7 +539,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -679,59 +638,38 @@ void closesthit(inout PerRayData payload, in Attrs attrs) } )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } - // Initialize test data. - const int windowSize = 64; - - if (!bDXRSupported) - return; - - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + const int WindowSize = 64; // WorldToObject3x4 { - std::vector testData(windowSize * windowSize * 24, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetWorldToObject3x4()"); + std::vector TestData(WindowSize * WindowSize * 24, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_MATRIX=WorldToObject3x4", L"-DMISS_GET_MATRIX=getMatIdentity", L"-DSER_GET_MATRIX=GetWorldToObject3x4", L"-DROWS=3", L"-DCOLS=4"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 12 /*payloadCount*/); const int ROWS = 3; const int COLS = 4; - for (int id = 0; id < testData.size(); id += 24) { - float *resArray = (float *)(testData.data() + id); - for (int r = 0; r < ROWS; r++) { - for (int c = 0; c < COLS; c++) { - int refIdx = 2 * (r * COLS + c); - float ref = resArray[refIdx]; - float ser = resArray[1 + refIdx]; - if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { - VERIFY_ARE_EQUAL(ser, ref); + for (int Id = 0; Id < TestData.size(); Id += 24) { + float *ResArray = (float *)(TestData.data() + Id); + for (int RowIdx = 0; RowIdx < ROWS; RowIdx++) { + for (int ColIdx = 0; ColIdx < COLS; ColIdx++) { + int RefIdx = 2 * (RowIdx * COLS + ColIdx); + float Ref = ResArray[RefIdx]; + float Ser = ResArray[1 + RefIdx]; + if (!CompareFloatEpsilon(Ser, Ref, 0.0008f)) { + VERIFY_ARE_EQUAL(Ser, Ref); } } } @@ -741,29 +679,30 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // WorldToObject4x3 { + WEX::Logging::Log::Comment(L"Testing HitObject::GetWorldToObject4x3()"); const int ROWS = 4; const int COLS = 3; - std::vector testData(windowSize * windowSize * 2 * ROWS * COLS, 0); - LPCWSTR args[] = {L"-HV 2021", + std::vector TestData(WindowSize * WindowSize * 2 * ROWS * COLS, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_MATRIX=WorldToObject4x3", L"-DMISS_GET_MATRIX=getMatIdentity", L"-DSER_GET_MATRIX=GetWorldToObject4x3", L"-DROWS=4", L"-DCOLS=3"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 12 /*payloadCount*/); - for (int id = 0; id < testData.size(); id += 2 * ROWS * COLS) { - float *resArray = (float *)(testData.data() + id); - for (int r = 0; r < ROWS; r++) { - for (int c = 0; c < COLS; c++) { - int refIdx = 2 * (r * COLS + c); - float ref = resArray[refIdx]; - float ser = resArray[1 + refIdx]; - if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { - VERIFY_ARE_EQUAL(ser, ref); + for (int Id = 0; Id < TestData.size(); Id += 2 * ROWS * COLS) { + float *ResArray = (float *)(TestData.data() + Id); + for (int RowIdx = 0; RowIdx < ROWS; RowIdx++) { + for (int ColIdx = 0; ColIdx < COLS; ColIdx++) { + int RefIdx = 2 * (RowIdx * COLS + ColIdx); + float Ref = ResArray[RefIdx]; + float Ser = ResArray[1 + RefIdx]; + if (!CompareFloatEpsilon(Ser, Ref, 0.0008f)) { + VERIFY_ARE_EQUAL(Ser, Ref); } } } @@ -773,29 +712,30 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // ObjectToWorld3x4 { - std::vector testData(windowSize * windowSize * 24, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetObjectToWorld3x4()"); + std::vector TestData(WindowSize * WindowSize * 24, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_MATRIX=ObjectToWorld3x4", L"-DMISS_GET_MATRIX=getMatIdentity", L"-DSER_GET_MATRIX=GetObjectToWorld3x4", L"-DROWS=3", L"-DCOLS=4"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 12 /*payloadCount*/); const int ROWS = 3; const int COLS = 4; - for (int id = 0; id < testData.size(); id += 24) { - float *resArray = (float *)(testData.data() + id); - for (int r = 0; r < ROWS; r++) { - for (int c = 0; c < COLS; c++) { - int refIdx = 2 * (r * COLS + c); - float ref = resArray[refIdx]; - float ser = resArray[1 + refIdx]; - if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { - VERIFY_ARE_EQUAL(ser, ref); + for (int Id = 0; Id < TestData.size(); Id += 24) { + float *ResArray = (float *)(TestData.data() + Id); + for (int RowIdx = 0; RowIdx < ROWS; RowIdx++) { + for (int ColIdx = 0; ColIdx < COLS; ColIdx++) { + int RefIdx = 2 * (RowIdx * COLS + ColIdx); + float Ref = ResArray[RefIdx]; + float Ser = ResArray[1 + RefIdx]; + if (!CompareFloatEpsilon(Ser, Ref, 0.0008f)) { + VERIFY_ARE_EQUAL(Ser, Ref); } } } @@ -805,31 +745,30 @@ void closesthit(inout PerRayData payload, in Attrs attrs) // ObjectToWorld4x3 { - std::vector testData(windowSize * windowSize * 24, 0); - LPCWSTR args[] = {L"-HV 2021", + WEX::Logging::Log::Comment(L"Testing HitObject::GetObjectToWorld4x3()"); + std::vector TestData(WindowSize * WindowSize * 24, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd", L"-DHIT_GET_MATRIX=ObjectToWorld4x3", L"-DMISS_GET_MATRIX=getMatIdentity", L"-DSER_GET_MATRIX=GetObjectToWorld4x3", L"-DROWS=4", L"-DCOLS=3"}; - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/, 12 /*payloadCount*/); const int ROWS = 4; const int COLS = 3; - for (int id = 0; id < testData.size(); id += 24) { - float *resArray = (float *)(testData.data() + id); - for (int r = 0; r < ROWS; r++) { - for (int c = 0; c < COLS; c++) { - int refIdx = 2 * (r * COLS + c); - float ref = resArray[refIdx]; - float ser = resArray[1 + refIdx]; - if (!CompareFloatEpsilon(ser, ref, 0.0008f)) { - VERIFY_ARE_EQUAL(ser, ref); - WEX::Logging::Log::Comment( - L"HitObject::GetObjectToWorld4x3() FAILED"); + for (int Id = 0; Id < TestData.size(); Id += 24) { + float *ResArray = (float *)(TestData.data() + Id); + for (int RowIdx = 0; RowIdx < ROWS; RowIdx++) { + for (int ColIdx = 0; ColIdx < COLS; ColIdx++) { + int RefIdx = 2 * (RowIdx * COLS + ColIdx); + float Ref = ResArray[RefIdx]; + float Ser = ResArray[1 + RefIdx]; + if (!CompareFloatEpsilon(Ser, Ref, 0.0008f)) { + VERIFY_ARE_EQUAL(Ser, Ref); break; } } @@ -841,7 +780,7 @@ void closesthit(inout PerRayData payload, in Attrs attrs) TEST_F(ExecutionTest, SERBasicTest) { // SER: Test basic functionality. - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -849,7 +788,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -922,50 +861,29 @@ void closesthit(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; - // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 2); - VERIFY_ARE_EQUAL(histo[2], 4030); - VERIFY_ARE_EQUAL(histo[5], 66); - } + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[2], 4030); + VERIFY_ARE_EQUAL(Histo[5], 66); } TEST_F(ExecutionTest, SERShaderTableIndexTest) { // Test SER with HitObject::SetShaderTableIndex and // HitObject::GetShaderTableIndex - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -973,7 +891,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1063,49 +981,30 @@ void chAABB(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*mesh*/, - true /*procedural geometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 2); - VERIFY_ARE_EQUAL(histo[2], 4030); - VERIFY_ARE_EQUAL(histo[13], 66); - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*mesh*/, + true /*procedural geometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[2], 4030); + VERIFY_ARE_EQUAL(Histo[13], 66); } TEST_F(ExecutionTest, SERLoadLocalRootTableConstantTest) { // Test SER with HitObject::LoadLocalRootTableConstant - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1113,7 +1012,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1204,48 +1103,28 @@ void closesthit(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; - if (!bDXRSupported) - return; - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, false /*useProceduralGeometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 1); - VERIFY_ARE_EQUAL(histo[126], 4096); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 1); + VERIFY_ARE_EQUAL(Histo[126], 4096); } TEST_F(ExecutionTest, SERRayQueryTest) { // Test SER RayQuery - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1253,7 +1132,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1381,49 +1260,29 @@ void closesthit(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERRayQueryTest requires shader model 6.9+ " - L"but no supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SERRayQueryTest skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SERRayQueryTest skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 2); - VERIFY_ARE_EQUAL(histo[0], 66); - VERIFY_ARE_EQUAL(histo[2], 4030); - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[0], 66); + VERIFY_ARE_EQUAL(Histo[2], 4030); } TEST_F(ExecutionTest, SERIntersectionTest) { // Test SER with Intersection and procedural geometry - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1431,7 +1290,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1517,49 +1376,29 @@ void intersection() )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, false /*mesh*/, - true /*procedural geometry*/, true /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 2); - VERIFY_ARE_EQUAL(histo[2], 3400); - VERIFY_ARE_EQUAL(histo[5], 696); - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, false /*mesh*/, + true /*procedural geometry*/, true /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[2], 3400); + VERIFY_ARE_EQUAL(Histo[5], 696); } TEST_F(ExecutionTest, SERGetAttributesTest) { // Test SER with HitObject::GetAttributes - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1567,7 +1406,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1681,52 +1520,32 @@ void intersection() )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, false /*mesh*/, - true /*procedural geometry*/, true /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 4); - VERIFY_ARE_EQUAL(histo[0], 328); - VERIFY_ARE_EQUAL(histo[1], 186); - VERIFY_ARE_EQUAL(histo[3], 182); - VERIFY_ARE_EQUAL(histo[255], 3400); - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, false /*mesh*/, + true /*procedural geometry*/, true /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 4); + VERIFY_ARE_EQUAL(Histo[0], 328); + VERIFY_ARE_EQUAL(Histo[1], 186); + VERIFY_ARE_EQUAL(Histo[3], 182); + VERIFY_ARE_EQUAL(Histo[255], 3400); } TEST_F(ExecutionTest, SERTraceHitMissNopTest) { // Test SER with conditional HitObject::TraceRay, HitObject::IsHit, // HitObject::IsMiss, HitObject::IsNop - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1734,7 +1553,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1819,56 +1638,36 @@ void closesthit(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*mesh*/, - false /*procedural geometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; - } - VERIFY_ARE_EQUAL(histo.size(), 3); - VERIFY_ARE_EQUAL( - histo[1], - 2048); // isNop && !isMiss && !isHit && !anyhit && !closesthit && !miss - VERIFY_ARE_EQUAL( - histo[18], - 2015); // !isNop && isMiss && !isHit && !anyhit && !closesthit && miss - VERIFY_ARE_EQUAL( - histo[44], - 33); // !isNop && !isMiss && isHit && anyhit && closesthit && !miss - } + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*mesh*/, + false /*procedural geometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 3); + VERIFY_ARE_EQUAL( + Histo[1], + 2048); // isNop && !isMiss && !isHit && !anyhit && !closesthit && !miss + VERIFY_ARE_EQUAL( + Histo[18], + 2015); // !isNop && isMiss && !isHit && !anyhit && !closesthit && miss + VERIFY_ARE_EQUAL( + Histo[44], + 33); // !isNop && !isMiss && isHit && anyhit && closesthit && !miss } TEST_F(ExecutionTest, SERIsMissTest) { // Test SER with HitObject::IsMiss - static const char *pShader = R"( + static const char *ShaderSrc = R"( struct SceneConstants { float4 eye; @@ -1876,7 +1675,7 @@ struct SceneConstants float4 V; float4 W; float sceneScale; - uint2 windowSize; + uint2 WindowSize; int rayFlags; }; @@ -1953,42 +1752,151 @@ void closesthit(inout PerRayData payload, in Attrs attrs) )"; - CComPtr pDevice; - bool bSM_6_9_Supported = CreateDevice(&pDevice, D3D_SHADER_MODEL_6_9, false); - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment(L"SERTest requires shader model 6.9+ but no " - L"supported device was found."); - WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped); + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, true)) return; - } - bool bDXRSupported = - bSM_6_9_Supported && DoesDeviceSupportRayTracing(pDevice); - - if (!bSM_6_9_Supported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support SM 6.9."); - } - if (!bDXRSupported) { - WEX::Logging::Log::Comment( - L"SER tests skipped, device does not support DXR."); - } // Initialize test data. - const int windowSize = 64; - std::vector testData(windowSize * windowSize, 0); - LPCWSTR args[] = {L"-HV 2021", L"-Vd"}; - - if (bDXRSupported) { - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); - RunDXRTest(pDevice, pShader, D3D_SHADER_MODEL_6_9, args, _countof(args), - testData, windowSize, windowSize, true /*mesh*/, - false /*procedural geometry*/, false /*useIS*/); - std::map histo; - for (int val : testData) { - ++histo[val]; + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*mesh*/, + false /*procedural geometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[2], 4030); + VERIFY_ARE_EQUAL(Histo[5], 66); +} + +TEST_F(ExecutionTest, SERInvokeNoSBTTest) { + // Test SER RayQuery with Invoke + static const char *ShaderSrc = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 WindowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // Template parameter set at runtime before compilation + RayQuery rayQ; + + // Funtion parameter set at runtime before compilation + rayQ.TraceRayInline(topObject, RAY_FLAG_NONE, 0xFF, ray); + + // Storage for procedural primitive hit attributes + Attrs attrs; + attrs.barycentrics = float2(1, 1); + + while (rayQ.Proceed()) + { + switch (rayQ.CandidateType()) + { + case CANDIDATE_NON_OPAQUE_TRIANGLE: + { + // The system has already determined that the candidate would be the closest + // hit so far in the ray extents + rayQ.CommitNonOpaqueTriangleHit(); + } + } } - VERIFY_ARE_EQUAL(histo.size(), 2); - VERIFY_ARE_EQUAL(histo[2], 4030); - VERIFY_ARE_EQUAL(histo[5], 66); - } + + dx::HitObject hit = dx::HitObject::FromRayQuery(rayQ); + dx::MaybeReorderThread(hit); + // Set the payload based on the HitObject. + if (hit.IsHit()) + payload.visited |= 8U; + else + payload.visited |= 16U; + // Invoke should not trigger any shader. + dx::HitObject::Invoke(hit, payload); + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; + AcceptHitAndEndSearch(); } + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, false)) + return; + + // Initialize test data. + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[8], 66); + VERIFY_ARE_EQUAL(Histo[16], 4030); +} \ No newline at end of file From c2e2dee306ee735994790901a0062893aca1f3e7 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Fri, 2 May 2025 18:28:44 +0200 Subject: [PATCH 04/13] Test all MaybeReorderThread variants (in wave-incoherent execution) --- .../unittests/HLSLExec/ExecutionTest.cpp | 1 + .../unittests/HLSLExec/ExecutionTest_SER.h | 112 ++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index dfb2eb1328..061751e72a 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -631,6 +631,7 @@ class ExecutionTest { TEST_METHOD(SERShaderTableIndexTest); TEST_METHOD(SERLoadLocalRootTableConstantTest); TEST_METHOD(SERInvokeNoSBTTest); + TEST_METHOD(SERMaybeReorderThreadTest) dxc::DxcDllSupport m_support; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 1a5c2eb7ab..616433fb58 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -1899,4 +1899,116 @@ void closesthit(inout PerRayData payload, in Attrs attrs) VERIFY_ARE_EQUAL(Histo.size(), 2); VERIFY_ARE_EQUAL(Histo[8], 66); VERIFY_ARE_EQUAL(Histo[16], 4030); +} + +TEST_F(ExecutionTest, SERMaybeReorderThreadTest) { + // SER: Test MaybeReorderThread variants. + static const char *ShaderSrc = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + + if (launchIndex.x % 3 == 0) { + dx::MaybeReorderThread(hitObject); + } + else if (launchIndex.x % 3 == 1) { + dx::MaybeReorderThread(hitObject, 0xFF, 7); + } + else { + dx::MaybeReorderThread(0xFFF, 5); + } + + dx::HitObject::Invoke(hitObject, payload); + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, false)) + return; + + // Initialize test data. + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 2); + VERIFY_ARE_EQUAL(Histo[2], 4030); + VERIFY_ARE_EQUAL(Histo[5], 66); } \ No newline at end of file From 6ab79fe5bbbb69a643c69b804574fd6bc587b58a Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 5 May 2025 13:08:31 +0200 Subject: [PATCH 05/13] DynamicHitObjectArrayTest - Array of 8 HitObjects, each with different ray flags - Samples at 'random' positions to block SROA from breaking down the array --- .../unittests/HLSLExec/ExecutionTest.cpp | 1 + .../unittests/HLSLExec/ExecutionTest_SER.h | 162 ++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index 061751e72a..b626519e8b 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -632,6 +632,7 @@ class ExecutionTest { TEST_METHOD(SERLoadLocalRootTableConstantTest); TEST_METHOD(SERInvokeNoSBTTest); TEST_METHOD(SERMaybeReorderThreadTest) + TEST_METHOD(SERDynamicHitObjectArrayTest); dxc::DxcDllSupport m_support; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 616433fb58..7bbdd17073 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -2011,4 +2011,166 @@ void closesthit(inout PerRayData payload, in Attrs attrs) VERIFY_ARE_EQUAL(Histo.size(), 2); VERIFY_ARE_EQUAL(Histo[2], 4030); VERIFY_ARE_EQUAL(Histo[5], 66); +} + +TEST_F(ExecutionTest, SERDynamicHitObjectArrayTest) { + // Test SER with dynamic access to local HitObject array + static const char *ShaderSrc = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +struct[raypayload] PerRayData +{ + uint dummy : read(caller) : write(miss, closesthit); +}; + +struct LocalConstants +{ + int c0; + int c1; + int c2; + int c3; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); +ConstantBuffer localConstants : register(b1); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x * sceneConstants.U.xyz + d.y * sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + int constants[4] = { localConstants.c0, localConstants.c1, localConstants.c2, localConstants.c3 }; + + const int NUM_SAMPLES = 64; + const int NUM_HITOBJECTS = 8; + + // Generate wave-incoerent sample positions + int sampleIndices[NUM_SAMPLES]; + int threadOffset = launchIndex.x; + for (int i = 0; i < NUM_SAMPLES; i++) + { + int baseIndex = i % 4; // Cycle through the 4 constants + sampleIndices[i] = abs(constants[baseIndex] + threadOffset + i * 3) % NUM_HITOBJECTS; + } + + // Define an array of ray flags + uint rayFlagsArray[NUM_HITOBJECTS] = { + RAY_FLAG_NONE, + RAY_FLAG_FORCE_OPAQUE, + RAY_FLAG_FORCE_NON_OPAQUE, + RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, + RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, + RAY_FLAG_CULL_BACK_FACING_TRIANGLES, + RAY_FLAG_CULL_FRONT_FACING_TRIANGLES, + RAY_FLAG_CULL_OPAQUE + }; + + // Create a local array of HitObjects with TraceRay + dx::HitObject hitObjects[NUM_HITOBJECTS]; + for (uint i = 0; i < NUM_HITOBJECTS; ++i) + { + PerRayData payload; + uint expectedRayFlags = rayFlagsArray[i]; + hitObjects[i] = dx::HitObject::TraceRay( + topObject, // Acceleration structure + expectedRayFlags, // Unique ray flag + 0xFF, // Instance mask + 0, // Ray contribution to hit group index + 1, // Multiplier for geometry contribution + 0, // Miss shader index + ray, // Ray description + payload // Payload + ); + } + + // Evaluate at sample positions. + int testVal = 0; + + for (uint i = 0; i < NUM_SAMPLES; i++) + { + int idx = sampleIndices[i]; + // Verify that the rayFlags match + uint actualRayFlags = hitObjects[idx].GetRayFlags(); + uint expectedRayFlags = rayFlagsArray[idx]; + if (expectedRayFlags != actualRayFlags) + { + testVal = 1; // Mark as failure if flags do not match + } + } + + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = testVal; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + // UNUSED +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + // UNUSED +} + +)"; + + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, false)) + return; + + // Initialize test data. + const int WindowSize = 64; + + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*mesh*/, + false /*procedural geometry*/, false /*useIS*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 1); + VERIFY_ARE_EQUAL(Histo[0], 4096); } \ No newline at end of file From d31a0ad3474ae459392a6d16f80f1b4afc1c4e9b Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Tue, 6 May 2025 10:48:17 +0200 Subject: [PATCH 06/13] Cleanup / fixes and update expected values based on changed geometry (procedural) - Support for procedural geometry and triangles at the same time - fix: make IS non-optional - Made payload/attributeCount in RunDXRTest non-defaulting - Use a circle for procedural geoemtry and make sure it fits into the AABB --- .../unittests/HLSLExec/ExecutionTest.cpp | 262 ++++++++---------- .../unittests/HLSLExec/ExecutionTest_SER.h | 165 +++++++---- 2 files changed, 228 insertions(+), 199 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index b626519e8b..c650f275cc 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -2061,8 +2061,7 @@ class ExecutionTest { int NumOptions, std::vector &TestData, int WindowWidth, int WindowHeight, bool UseMesh, bool UseProceduralGeometry, - bool UseIS, int PayloadCount = 1, - int AttributeCount = 2); + int PayloadCount, int AttributeCount); void SetDescriptorHeap(ID3D12GraphicsCommandList *pCommandList, ID3D12DescriptorHeap *pHeap) { @@ -2246,7 +2245,7 @@ CComPtr ExecutionTest::RunDXRTest( ID3D12Device *Device0, LPCSTR ShaderSrc, LPCWSTR TargetProfile, LPCWSTR *Options, int NumOptions, std::vector &TestData, int WindowWidth, int WindowHeight, bool UseMesh, bool UseProceduralGeometry, - bool UseIS, int PayloadCount, int AttributeCount) { + int PayloadCount, int AttributeCount) { CComPtr Device; VERIFY_SUCCEEDED(Device0->QueryInterface(IID_PPV_ARGS(&Device))); @@ -2432,10 +2431,12 @@ CComPtr ExecutionTest::RunDXRTest( Lib->DefineExport(L"closesthit"); Lib->DefineExport(L"anyhit"); Lib->DefineExport(L"miss"); - if (UseIS) + if (UseProceduralGeometry) Lib->DefineExport(L"intersection"); - if (UseMesh && UseProceduralGeometry) + if (UseMesh && UseProceduralGeometry) { + Lib->DefineExport(L"ahAABB"); Lib->DefineExport(L"chAABB"); + } const int MaxRecursion = 1; StateObjectDesc.CreateSubobject() @@ -2460,30 +2461,32 @@ CComPtr ExecutionTest::RunDXRTest( Exports->AddExport(L"closesthit"); Exports->AddExport(L"anyhit"); Exports->AddExport(L"miss"); - if (UseIS) + if (UseProceduralGeometry) Exports->AddExport(L"intersection"); - if (UseMesh && UseProceduralGeometry) + if (UseMesh && UseProceduralGeometry) { + Exports->AddExport(L"ahAABB"); Exports->AddExport(L"chAABB"); + } auto HitGroup = StateObjectDesc.CreateSubobject(); HitGroup->SetClosestHitShaderImport(L"closesthit"); HitGroup->SetAnyHitShaderImport(L"anyhit"); - if (UseIS) { + if (!UseMesh && UseProceduralGeometry) { HitGroup->SetIntersectionShaderImport(L"intersection"); HitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); + } else { + HitGroup->SetHitGroupType(D3D12_HIT_GROUP_TYPE_TRIANGLES); } HitGroup->SetHitGroupExport(L"HitGroup"); if (UseMesh && UseProceduralGeometry) { auto HitGroupAABB = StateObjectDesc.CreateSubobject(); + HitGroupAABB->SetAnyHitShaderImport(L"ahAABB"); HitGroupAABB->SetClosestHitShaderImport(L"chAABB"); - HitGroupAABB->SetAnyHitShaderImport(L"anyhit"); - if (UseIS) { - HitGroupAABB->SetIntersectionShaderImport(L"intersection"); - HitGroupAABB->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); - } + HitGroupAABB->SetIntersectionShaderImport(L"intersection"); + HitGroupAABB->SetHitGroupType(D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE); HitGroupAABB->SetHitGroupExport(L"HitGroupAABB"); } @@ -2545,7 +2548,6 @@ CComPtr ExecutionTest::RunDXRTest( CComPtr TLASResource; CComPtr BLASMeshResource; CComPtr BLASProceduralGeometryResource; - CComPtr InstanceDescs; CComPtr ScratchResource; if (UseMesh) { @@ -2624,67 +2626,58 @@ CComPtr ExecutionTest::RunDXRTest( VERIFY_SUCCEEDED(CommandAllocator->Reset()); VERIFY_SUCCEEDED(CommandList->Reset(CommandAllocator, nullptr)); - if (!UseIS) { - // Build BLAS. - { - D3D12_RAYTRACING_GEOMETRY_DESC GeometryDesc = {}; - GeometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - GeometryDesc.Triangles.IndexBuffer = - IndexBuffer->GetGPUVirtualAddress(); - GeometryDesc.Triangles.IndexCount = - static_cast(IndexBuffer->GetDesc().Width) / sizeof(int); - GeometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; - GeometryDesc.Triangles.Transform3x4 = 0; - GeometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; - GeometryDesc.Triangles.VertexCount = - static_cast(VertexBuffer->GetDesc().Width) / - sizeof(DirectX::XMFLOAT3); - GeometryDesc.Triangles.VertexBuffer.StartAddress = - VertexBuffer->GetGPUVirtualAddress(); - GeometryDesc.Triangles.VertexBuffer.StrideInBytes = - sizeof(DirectX::XMFLOAT3); - GeometryDesc.Flags = - D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; // Non-opaque to trigger - // anyhit. - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; - AccelInputs.Type = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - AccelInputs.pGeometryDescs = &GeometryDesc; - AccelInputs.NumDescs = 1; - AccelInputs.Flags = BuildFlags; - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; - Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, - &PrebuildInfo); - - ScratchResource.Release(); - ReallocScratchResource(Device, &ScratchResource, - PrebuildInfo.ScratchDataSizeInBytes); - AllocateBuffer(Device, PrebuildInfo.ResultDataMaxSizeInBytes, - &BLASMeshResource, true, - D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, - L"blasMesh"); - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; - BuildDesc.Inputs = AccelInputs; - BuildDesc.ScratchAccelerationStructureData = - ScratchResource->GetGPUVirtualAddress(); - BuildDesc.DestAccelerationStructureData = - BLASMeshResource->GetGPUVirtualAddress(); - - CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, - nullptr); - CD3DX12_RESOURCE_BARRIER Barrier = - CD3DX12_RESOURCE_BARRIER::UAV(BLASMeshResource); - CommandList->ResourceBarrier(1, - (const D3D12_RESOURCE_BARRIER *)&Barrier); - } - } + // Build triangle BLAS. + D3D12_RAYTRACING_GEOMETRY_DESC GeometryDesc = {}; + GeometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + GeometryDesc.Triangles.IndexBuffer = IndexBuffer->GetGPUVirtualAddress(); + GeometryDesc.Triangles.IndexCount = + static_cast(IndexBuffer->GetDesc().Width) / sizeof(int); + GeometryDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; + GeometryDesc.Triangles.Transform3x4 = 0; + GeometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + GeometryDesc.Triangles.VertexCount = + static_cast(VertexBuffer->GetDesc().Width) / + sizeof(DirectX::XMFLOAT3); + GeometryDesc.Triangles.VertexBuffer.StartAddress = + VertexBuffer->GetGPUVirtualAddress(); + GeometryDesc.Triangles.VertexBuffer.StrideInBytes = + sizeof(DirectX::XMFLOAT3); + GeometryDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; // Non-opaque to + // trigger anyhit. + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; + AccelInputs.Type = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + AccelInputs.pGeometryDescs = &GeometryDesc; + AccelInputs.NumDescs = 1; + AccelInputs.Flags = BuildFlags; + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, + &PrebuildInfo); + + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer( + Device, PrebuildInfo.ResultDataMaxSizeInBytes, &BLASMeshResource, true, + D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"blasMesh"); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; + BuildDesc.Inputs = AccelInputs; + BuildDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BuildDesc.DestAccelerationStructureData = + BLASMeshResource->GetGPUVirtualAddress(); + + CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, nullptr); + CD3DX12_RESOURCE_BARRIER Barrier = + CD3DX12_RESOURCE_BARRIER::UAV(BLASMeshResource); + CommandList->ResourceBarrier(1, (const D3D12_RESOURCE_BARRIER *)&Barrier); CommandList->Close(); ExecuteCommandList(CommandQueue, CommandList); @@ -2701,9 +2694,10 @@ CComPtr ExecutionTest::RunDXRTest( // Define the AABB for the plane, matching the size of the quad defined by // verts[] + const float BoxSize = 500.f; const D3D12_RAYTRACING_AABB Aabb = { - -150.5f, -500.5f, -1000.0f, // Min corner (x, y, z) - 150.5f, -150.5f, 1000.0f // Max corner (x, y, z) + -BoxSize, -BoxSize, -BoxSize, // Min corner (x, y, z) + BoxSize, BoxSize, BoxSize // Max corner (x, y, z) }; const UINT64 AabbDataSize = sizeof(Aabb); @@ -2771,88 +2765,64 @@ CComPtr ExecutionTest::RunDXRTest( } // Build TLAS. + CComPtr InstanceDescs; { - if (UseMesh) { - D3D12_RAYTRACING_INSTANCE_DESC InstanceDesc = {}; - InstanceDesc.Transform[0][0] = InstanceDesc.Transform[1][1] = - InstanceDesc.Transform[2][2] = 1; - InstanceDesc.InstanceMask = 1; - InstanceDesc.AccelerationStructure = - BLASMeshResource->GetGPUVirtualAddress(); + D3D12_RAYTRACING_INSTANCE_DESC CPUInstanceDescs[2] = {}; + const int MeshIdx = 0; + const int ProcGeoIdx = UseMesh && UseProceduralGeometry ? 1 : 0; + const int NumInstanceDescs = ProcGeoIdx + 1; - AllocateUploadBuffer(Device, &InstanceDesc, sizeof(InstanceDesc), - &InstanceDescs, L"InstanceDescs"); - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; - AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - AccelInputs.NumDescs = 1; - AccelInputs.Flags = BuildFlags; - AccelInputs.InstanceDescs = InstanceDescs->GetGPUVirtualAddress(); - - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; - Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, - &PrebuildInfo); - - ScratchResource.Release(); - ReallocScratchResource(Device, &ScratchResource, - PrebuildInfo.ScratchDataSizeInBytes); - AllocateBuffer( - Device, PrebuildInfo.ResultDataMaxSizeInBytes, &TLASResource, true, - D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); - - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; - BuildDesc.Inputs = AccelInputs; - BuildDesc.ScratchAccelerationStructureData = - ScratchResource->GetGPUVirtualAddress(); - BuildDesc.DestAccelerationStructureData = - TLASResource->GetGPUVirtualAddress(); - - CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, 0); - } else { - D3D12_RAYTRACING_INSTANCE_DESC InstanceDesc = {}; + for (int i = 0; i < NumInstanceDescs; ++i) { + D3D12_RAYTRACING_INSTANCE_DESC &InstanceDesc = CPUInstanceDescs[i]; InstanceDesc.Transform[0][0] = InstanceDesc.Transform[1][1] = InstanceDesc.Transform[2][2] = 1; + InstanceDesc.InstanceID = i; + InstanceDesc.InstanceContributionToHitGroupIndex = i; InstanceDesc.InstanceMask = 1; - InstanceDesc.AccelerationStructure = + InstanceDesc.Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; + } + + if (UseMesh) + CPUInstanceDescs[MeshIdx].AccelerationStructure = + BLASMeshResource->GetGPUVirtualAddress(); + if (UseProceduralGeometry) + CPUInstanceDescs[ProcGeoIdx].AccelerationStructure = BLASProceduralGeometryResource->GetGPUVirtualAddress(); - AllocateUploadBuffer(Device, &InstanceDesc, sizeof(InstanceDesc), - &InstanceDescs, L"InstanceDescs"); + AllocateUploadBuffer(Device, &CPUInstanceDescs, + NumInstanceDescs * + sizeof(D3D12_RAYTRACING_INSTANCE_DESC), + &InstanceDescs, L"InstanceDescs"); - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildFlags = + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; - AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - AccelInputs.NumDescs = 1; - AccelInputs.Flags = BuildFlags; - AccelInputs.InstanceDescs = InstanceDescs->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS AccelInputs = {}; + AccelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + AccelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + AccelInputs.NumDescs = NumInstanceDescs; + AccelInputs.Flags = BuildFlags; + AccelInputs.InstanceDescs = InstanceDescs->GetGPUVirtualAddress(); - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; - Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, - &PrebuildInfo); + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO PrebuildInfo = {}; + Device->GetRaytracingAccelerationStructurePrebuildInfo(&AccelInputs, + &PrebuildInfo); - ScratchResource.Release(); - ReallocScratchResource(Device, &ScratchResource, - PrebuildInfo.ScratchDataSizeInBytes); - AllocateBuffer( - Device, PrebuildInfo.ResultDataMaxSizeInBytes, &TLASResource, true, - D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, L"TLAS"); + ScratchResource.Release(); + ReallocScratchResource(Device, &ScratchResource, + PrebuildInfo.ScratchDataSizeInBytes); + AllocateBuffer(Device, PrebuildInfo.ResultDataMaxSizeInBytes, &TLASResource, + true, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, + L"TLAS"); - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; - BuildDesc.Inputs = AccelInputs; - BuildDesc.ScratchAccelerationStructureData = - ScratchResource->GetGPUVirtualAddress(); - BuildDesc.DestAccelerationStructureData = - TLASResource->GetGPUVirtualAddress(); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC BuildDesc = {}; + BuildDesc.Inputs = AccelInputs; + BuildDesc.ScratchAccelerationStructureData = + ScratchResource->GetGPUVirtualAddress(); + BuildDesc.DestAccelerationStructureData = + TLASResource->GetGPUVirtualAddress(); - CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, 0); - } + CommandList->BuildRaytracingAccelerationStructure(&BuildDesc, 0, 0); CD3DX12_RESOURCE_BARRIER Barrier = CD3DX12_RESOURCE_BARRIER::UAV(TLASResource); diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 7bbdd17073..be8df24b19 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -23,7 +23,7 @@ struct SceneConstants float4 W; float sceneScale; uint2 WindowSize; - int rayFlags; + int rayFlags; }; struct[raypayload] PerRayData @@ -117,7 +117,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetRayTMin"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { float *ResArray = (float *)(TestData.data() + Id); float RefVal = ResArray[0]; @@ -143,7 +144,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetRayTCurrent"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { float *ResArray = (float *)(TestData.data() + Id); float RefVal = ResArray[0]; @@ -169,7 +171,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetRayFlags"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -193,7 +196,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetHitKind"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -217,7 +221,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetGeometryIndex"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -241,7 +246,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetInstanceIndex"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -265,7 +271,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetInstanceID"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -289,7 +296,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_SCALAR=GetPrimitiveIndex"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2) { const int RefVal = TestData[Id]; const int SerVal = TestData[Id + 1]; @@ -407,8 +415,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_VECTOR=GetWorldRayOrigin"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 3 /*payloadCount*/); + false /*useProceduralGeometry*/, 3 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 6) { float *ResArray = (float *)(TestData.data() + Id); float RefX = ResArray[0]; @@ -440,8 +448,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_VECTOR=GetWorldRayDirection"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 3 /*payloadCount*/); + false /*useProceduralGeometry*/, 3 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 6) { float *ResArray = (float *)(TestData.data() + Id); float RefX = ResArray[0]; @@ -472,8 +480,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_VECTOR=GetObjectRayOrigin"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 3 /*payloadCount*/); + false /*useProceduralGeometry*/, 3 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 6) { float *ResArray = (float *)(TestData.data() + Id); float RefX = ResArray[0]; @@ -505,8 +513,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DSER_GET_VECTOR=GetObjectRayDirection"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 3 /*payloadCount*/); + false /*useProceduralGeometry*/, 3 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 6) { float *ResArray = (float *)(TestData.data() + Id); float RefX = ResArray[0]; @@ -657,8 +665,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DCOLS=4"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 12 /*payloadCount*/); + false /*useProceduralGeometry*/, 12 /*payloadCount*/, + 2 /*attributeCount*/); const int ROWS = 3; const int COLS = 4; for (int Id = 0; Id < TestData.size(); Id += 24) { @@ -692,8 +700,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DCOLS=3"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 12 /*payloadCount*/); + false /*useProceduralGeometry*/, 12 /*payloadCount*/, + 2 /*attributeCount*/); for (int Id = 0; Id < TestData.size(); Id += 2 * ROWS * COLS) { float *ResArray = (float *)(TestData.data() + Id); for (int RowIdx = 0; RowIdx < ROWS; RowIdx++) { @@ -723,8 +731,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DCOLS=4"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 12 /*payloadCount*/); + false /*useProceduralGeometry*/, 12 /*payloadCount*/, + 2 /*attributeCount*/); const int ROWS = 3; const int COLS = 4; for (int Id = 0; Id < TestData.size(); Id += 24) { @@ -756,8 +764,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) L"-DCOLS=3"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/, - 12 /*payloadCount*/); + false /*useProceduralGeometry*/, 12 /*payloadCount*/, + 2 /*attributeCount*/); const int ROWS = 4; const int COLS = 3; for (int Id = 0; Id < TestData.size(); Id += 24) { @@ -871,7 +879,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -905,6 +914,11 @@ struct Attrs float2 barycentrics : BARYCENTRICS; }; +struct CustomAttrs +{ + float dist; +}; + RWStructuredBuffer testBuffer : register(u0); RaytracingAccelerationStructure topObject : register(t0); ConstantBuffer sceneConstants : register(b0); @@ -938,7 +952,6 @@ void raygen() // SER Test dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); dx::MaybeReorderThread(hitObject); - dx::HitObject::Invoke(hitObject, payload); if (hitObject.IsHit()) { @@ -947,7 +960,7 @@ void raygen() dx::HitObject::Invoke( hitObject, payload ); // Poison the test data if GetShaderTableIndex does not match SetShaderTableIndex. if (hitObject.GetShaderTableIndex() != 1) - payload.visited = 0; + payload.visited = 12345; } int id = launchIndex.x + launchIndex.y * launchDim.x; @@ -957,13 +970,14 @@ void raygen() [shader("miss")] void miss(inout PerRayData payload) { - payload.visited |= 2U; + payload.visited |= 1U; } +// Triangles [shader("anyhit")] void anyhit(inout PerRayData payload, in Attrs attrs) { - payload.visited |= 1U; + payload.visited |= 2U; AcceptHitAndEndSearch(); } @@ -973,10 +987,43 @@ void closesthit(inout PerRayData payload, in Attrs attrs) payload.visited |= 4U; } +// Procedural +[shader("intersection")] +void intersection() +{ + // Intersection with circle on a plane (base, n, radius) + // hitPos is intersection point with plane (base, n) + float3 base = {0.0f,0.0f,0.5f}; + float3 n = normalize(float3(0.2f,0.2f,0.5f)); + float radius = 150.f; + // Plane hit + float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); + if (t > RayTCurrent() || t < RayTMin()) { + return; + } + float3 hitPos = ObjectRayOrigin() + t * ObjectRayDirection(); + float3 relHitPos = hitPos - base; + // Circle hit + float hitDist = length(relHitPos); + if (hitDist > radius) + return; + + CustomAttrs attrs; + attrs.dist = hitDist; + ReportHit(t, 1, attrs); +} + +[shader("anyhit")] +void ahAABB(inout PerRayData payload, in CustomAttrs attrs) +{ + payload.visited |= 8U; + IgnoreHit(); +} + [shader("closesthit")] void chAABB(inout PerRayData payload, in Attrs attrs) { - payload.visited |= 8U; + payload.visited |= 16U; } )"; @@ -990,16 +1037,19 @@ void chAABB(inout PerRayData payload, in Attrs attrs) std::vector TestData(WindowSize * WindowSize, 0); LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; - WEX::Logging::Log::Comment(L"==== DXR lib_6_9 with SER"); RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*mesh*/, - true /*procedural geometry*/, false /*useIS*/); + true /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 2); - VERIFY_ARE_EQUAL(Histo[2], 4030); - VERIFY_ARE_EQUAL(Histo[13], 66); + VERIFY_ARE_EQUAL(Histo.size(), 3); + VERIFY_ARE_EQUAL(Histo[0], 3696); // Miss (not Invoked) + VERIFY_ARE_EQUAL(Histo[8], 334); // AABB ignored hit -> (Miss not Invoked) + VERIFY_ARE_EQUAL( + Histo[26], + 66); // AABB ignored hit + TriHit -> setSBT(1) -> chAABB invoked } TEST_F(ExecutionTest, SERLoadLocalRootTableConstantTest) { @@ -1114,7 +1164,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -1271,7 +1322,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -1387,13 +1439,13 @@ void intersection() RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, false /*mesh*/, - true /*procedural geometry*/, true /*useIS*/); + true /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 2); - VERIFY_ARE_EQUAL(Histo[2], 3400); - VERIFY_ARE_EQUAL(Histo[5], 696); + VERIFY_ARE_EQUAL(Histo.size(), 1); + VERIFY_ARE_EQUAL(Histo[5], 4096); // All rays hitting the procedural geometry } TEST_F(ExecutionTest, SERGetAttributesTest) { @@ -1531,15 +1583,17 @@ void intersection() RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, false /*mesh*/, - true /*procedural geometry*/, true /*useIS*/); + true /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 4); - VERIFY_ARE_EQUAL(Histo[0], 328); - VERIFY_ARE_EQUAL(Histo[1], 186); - VERIFY_ARE_EQUAL(Histo[3], 182); - VERIFY_ARE_EQUAL(Histo[255], 3400); + VERIFY_ARE_EQUAL(Histo.size(), 5); + VERIFY_ARE_EQUAL(Histo[0], 2009); + VERIFY_ARE_EQUAL(Histo[1], 561); + VERIFY_ARE_EQUAL(Histo[3], 587); + VERIFY_ARE_EQUAL(Histo[4], 454); + VERIFY_ARE_EQUAL(Histo[6], 485); } TEST_F(ExecutionTest, SERTraceHitMissNopTest) { @@ -1649,7 +1703,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*mesh*/, - false /*procedural geometry*/, false /*useIS*/); + false /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -1763,7 +1818,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*mesh*/, - false /*procedural geometry*/, false /*useIS*/); + false /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -1892,7 +1948,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -2004,7 +2061,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*useMesh*/, - false /*useProceduralGeometry*/, false /*useIS*/); + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; @@ -2167,7 +2225,8 @@ void closesthit(inout PerRayData payload, in Attrs attrs) LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, WindowSize, WindowSize, true /*mesh*/, - false /*procedural geometry*/, false /*useIS*/); + false /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); std::map Histo; for (int Val : TestData) ++Histo[Val]; From 8f1c59847e888921ca6475ddc0e4870372ce5bd0 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Mon, 5 May 2025 14:00:03 +0200 Subject: [PATCH 07/13] WaveIncoherentHitTest --- .../unittests/HLSLExec/ExecutionTest.cpp | 1 + .../unittests/HLSLExec/ExecutionTest_SER.h | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index c650f275cc..ffa696d88c 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -633,6 +633,7 @@ class ExecutionTest { TEST_METHOD(SERInvokeNoSBTTest); TEST_METHOD(SERMaybeReorderThreadTest) TEST_METHOD(SERDynamicHitObjectArrayTest); + TEST_METHOD(SERWaveIncoherentHitTest); dxc::DxcDllSupport m_support; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index be8df24b19..9e69d7f50b 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -2232,4 +2232,186 @@ void closesthit(inout PerRayData payload, in Attrs attrs) ++Histo[Val]; VERIFY_ARE_EQUAL(Histo.size(), 1); VERIFY_ARE_EQUAL(Histo[0], 4096); +} + +TEST_F(ExecutionTest, SERWaveIncoherentHitTest) { + // Test SER with wave incoherent conditional assignment of HitObject values + // with and without procedural attributes. + static const char *ShaderSrc = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +struct CustomAttrs +{ + float dist; +}; + +RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +static const uint ProceduralHitKind = 11; + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + dx::HitObject hitObject; + + // Use wave incoherence to decide how to create the HitObject + if (launchIndex.x % 4 == 1) + { + ray.Origin.x += 2.0f; + hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, 0xFF, 0, 0, 0, ray, payload); + } + else if (launchIndex.x % 4 == 2) + { + hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES, 0xFF, 0, 0, 0, ray, payload); + } + else if (launchIndex.x % 4 == 3) + { + hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_TRIANGLES, 0xFF, 0, 0, 0, ray, payload); + } + + dx::MaybeReorderThread(hitObject); + + if (hitObject.IsNop()) + payload.visited |= 1U; + if (hitObject.IsMiss()) + payload.visited |= 2U; + + if (hitObject.GetHitKind() == ProceduralHitKind) + payload.visited |= 8U; + else if (hitObject.IsHit()) + payload.visited |= 4U; + + dx::HitObject::Invoke(hitObject, payload); + + // Store the result in the buffer + int id = launchIndex.x + launchIndex.y * launchDim.x; + testBuffer[id] = payload.visited; +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + // UNUSED +} + +// Triangles +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + AcceptHitAndEndSearch(); +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 16U; +} + +// Procedural +[shader("closesthit")] +void chAABB(inout PerRayData payload, in CustomAttrs attrs) +{ + payload.visited |= 32U; +} + +[shader("anyhit")] +void ahAABB(inout PerRayData payload, in CustomAttrs attrs) +{ + // UNUSED +} + +[shader("intersection")] +void intersection() +{ + // Intersection with circle on a plane (base, n, radius) + // hitPos is intersection point with plane (base, n) + float3 base = {0.0f,0.0f,0.5f}; + float3 n = normalize(float3(0.0f,0.5f,0.5f)); + float radius = 1000.f; + // Plane hit + float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); + if (t > RayTCurrent() || t < RayTMin()) { + return; + } + float3 hitPos = ObjectRayOrigin() + t * ObjectRayDirection(); + float3 relHitPos = hitPos - base; + // Circle hit + float hitDist = length(relHitPos); + if (hitDist > radius) + return; + + CustomAttrs attrs; + attrs.dist = hitDist; + ReportHit(t, ProceduralHitKind, attrs); +} + +)"; + + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, false)) + return; + + // Initialize test data. + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*mesh*/, + true /*procedural geometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 6); + VERIFY_ARE_EQUAL(Histo[1], 1024); // nop + VERIFY_ARE_EQUAL(Histo[2], 1022); // miss + VERIFY_ARE_EQUAL(Histo[4], 12); // triangle hit, no ch + VERIFY_ARE_EQUAL(Histo[8], 1008); // procedural hit, no ch + VERIFY_ARE_EQUAL(Histo[20], 11); // triangle hit, 'closesthit' invoked + VERIFY_ARE_EQUAL(Histo[40], 1019); // procedural hit, 'chAABB' invoked } \ No newline at end of file From e1df92bfc1952717fc44388bbbb5c16d527eb1cf Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Tue, 6 May 2025 10:23:30 +0200 Subject: [PATCH 08/13] SERReorderCoherentTest --- .../unittests/HLSLExec/ExecutionTest.cpp | 1 + .../unittests/HLSLExec/ExecutionTest_SER.h | 137 ++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index ffa696d88c..9be631fd83 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -634,6 +634,7 @@ class ExecutionTest { TEST_METHOD(SERMaybeReorderThreadTest) TEST_METHOD(SERDynamicHitObjectArrayTest); TEST_METHOD(SERWaveIncoherentHitTest); + TEST_METHOD(SERReorderCoherentTest); dxc::DxcDllSupport m_support; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 9e69d7f50b..18a4397e0d 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -2414,4 +2414,141 @@ void intersection() VERIFY_ARE_EQUAL(Histo[8], 1008); // procedural hit, no ch VERIFY_ARE_EQUAL(Histo[20], 11); // triangle hit, 'closesthit' invoked VERIFY_ARE_EQUAL(Histo[40], 1019); // procedural hit, 'chAABB' invoked +} + +TEST_F(ExecutionTest, SERReorderCoherentTest) { + // SER: Test reordercoherent + static const char *ShaderSrc = R"( +struct SceneConstants +{ + float4 eye; + float4 U; + float4 V; + float4 W; + float sceneScale; + uint2 windowSize; + int rayFlags; +}; + +struct[raypayload] PerRayData +{ + uint visited : read(anyhit,closesthit,miss,caller) : write(anyhit,miss,closesthit,caller); +}; + +struct Attrs +{ + float2 barycentrics : BARYCENTRICS; +}; + +reordercoherent RWStructuredBuffer testBuffer : register(u0); +RaytracingAccelerationStructure topObject : register(t0); +ConstantBuffer sceneConstants : register(b0); + +RayDesc ComputeRay() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float2 d = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy) * 2.0f - 1.0f; + RayDesc ray; + ray.Origin = sceneConstants.eye.xyz; + ray.Direction = normalize(d.x*sceneConstants.U.xyz + d.y*sceneConstants.V.xyz + sceneConstants.W.xyz); + ray.TMin = 0; + ray.TMax = 1e18; + + return ray; +} + +[shader("raygeneration")] +void raygen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + uint threadId = launchIndex.x + launchIndex.y * launchDim.x; + + RayDesc ray = ComputeRay(); + + PerRayData payload; + payload.visited = 0; + + // Initial test value. + testBuffer[threadId] = threadId; + + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + + // Conditionally update the test value. + if (hitObject.IsHit()) + { + testBuffer[threadId] += 10; // Add 10 to hits + } + else + { + testBuffer[threadId] += 20; // Add 20 to misses + } + + Barrier(UAV_MEMORY, REORDER_SCOPE); + dx::MaybeReorderThread(hitObject); + + // Conditionally update the test value. + if (threadId % 2 == 0) + { + testBuffer[threadId] += 1000; // Add 1000 to even threads + } + else + { + testBuffer[threadId] += 2000; // Add 2000 to odd threads + } + + // Verify test value. + uint expectedValue = (hitObject.IsHit() ? threadId + 10 : threadId + 20); + expectedValue += (threadId % 2 == 0 ? 1000 : 2000); + if (testBuffer[threadId] != expectedValue) + { + // Mark failure in the buffer if the result does not match + testBuffer[threadId] = 0; + } + else + { + testBuffer[threadId] = 1; + } +} + +[shader("miss")] +void miss(inout PerRayData payload) +{ + payload.visited |= 2U; +} + +[shader("anyhit")] +void anyhit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 1U; +} + +[shader("closesthit")] +void closesthit(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 4U; +} + +)"; + + CComPtr Device; + if (!CreateDXRDevice(&Device, D3D_SHADER_MODEL_6_9, false)) + return; + + // Initialize test data. + const int WindowSize = 64; + std::vector TestData(WindowSize * WindowSize, 0); + LPCWSTR Args[] = {L"-HV 2021", L"-Vd"}; + + RunDXRTest(Device, ShaderSrc, L"lib_6_9", Args, _countof(Args), TestData, + WindowSize, WindowSize, true /*useMesh*/, + false /*useProceduralGeometry*/, 1 /*payloadCount*/, + 2 /*attributeCount*/); + std::map Histo; + for (int Val : TestData) + ++Histo[Val]; + VERIFY_ARE_EQUAL(Histo.size(), 1); + VERIFY_ARE_EQUAL(Histo[1], 4096); } \ No newline at end of file From c6fce45d1160bf289244b8523ccc46822a620869 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 8 May 2025 10:08:37 +0200 Subject: [PATCH 09/13] Fixed SERShaderTableIndexTest (not relying on is/ah any longer) --- .../unittests/HLSLExec/ExecutionTest_SER.h | 72 +++++++++---------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 18a4397e0d..130eeea744 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -949,15 +949,23 @@ void raygen() PerRayData payload; payload.visited = 0; - // SER Test - dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload); + dx::HitObject hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES, 0xFF, 0, 1, 0, ray, payload); dx::MaybeReorderThread(hitObject); + // Invoke hit/miss for triangle + dx::HitObject::Invoke( hitObject, payload ); + if (hitObject.IsHit()) { - // Alter the hit object to point to a new shader index to hit chAABB. + // Transform to an 'aabb' hit. hitObject.SetShaderTableIndex( 1 ); - dx::HitObject::Invoke( hitObject, payload ); + } + + // Invoke hit/miss for aabb + dx::HitObject::Invoke( hitObject, payload ); + + if (hitObject.IsHit()) + { // Poison the test data if GetShaderTableIndex does not match SetShaderTableIndex. if (hitObject.GetShaderTableIndex() != 1) payload.visited = 12345; @@ -970,60 +978,44 @@ void raygen() [shader("miss")] void miss(inout PerRayData payload) { - payload.visited |= 1U; + if ((payload.visited & 4U) == 0) + payload.visited |= 4U; // First 'miss' invocation + else + payload.visited |= 8U; // Second 'miss' invocation } // Triangles [shader("anyhit")] void anyhit(inout PerRayData payload, in Attrs attrs) { - payload.visited |= 2U; AcceptHitAndEndSearch(); } +// Triangle closest hit [shader("closesthit")] void closesthit(inout PerRayData payload, in Attrs attrs) { - payload.visited |= 4U; + payload.visited |= 1U; +} + +// AABB closest hit +[shader("closesthit")] +void chAABB(inout PerRayData payload, in Attrs attrs) +{ + payload.visited |= 2U; } // Procedural [shader("intersection")] void intersection() { - // Intersection with circle on a plane (base, n, radius) - // hitPos is intersection point with plane (base, n) - float3 base = {0.0f,0.0f,0.5f}; - float3 n = normalize(float3(0.2f,0.2f,0.5f)); - float radius = 150.f; - // Plane hit - float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); - if (t > RayTCurrent() || t < RayTMin()) { - return; - } - float3 hitPos = ObjectRayOrigin() + t * ObjectRayDirection(); - float3 relHitPos = hitPos - base; - // Circle hit - float hitDist = length(relHitPos); - if (hitDist > radius) - return; - - CustomAttrs attrs; - attrs.dist = hitDist; - ReportHit(t, 1, attrs); + // UNUSED } [shader("anyhit")] void ahAABB(inout PerRayData payload, in CustomAttrs attrs) { - payload.visited |= 8U; - IgnoreHit(); -} - -[shader("closesthit")] -void chAABB(inout PerRayData payload, in Attrs attrs) -{ - payload.visited |= 16U; + // UNUSED } )"; @@ -1044,12 +1036,12 @@ void chAABB(inout PerRayData payload, in Attrs attrs) std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 3); - VERIFY_ARE_EQUAL(Histo[0], 3696); // Miss (not Invoked) - VERIFY_ARE_EQUAL(Histo[8], 334); // AABB ignored hit -> (Miss not Invoked) + + VERIFY_ARE_EQUAL(Histo.size(), 2); VERIFY_ARE_EQUAL( - Histo[26], - 66); // AABB ignored hit + TriHit -> setSBT(1) -> chAABB invoked + Histo[3], + 66); // 'closesthit' invoked at index 0, then 'chAABB' invoked at index 1 + VERIFY_ARE_EQUAL(Histo[12], 4030); // Miss shader invoked twice } TEST_F(ExecutionTest, SERLoadLocalRootTableConstantTest) { From c3c399f308197d61bf4ee8f31c19bae63d381d5f Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 8 May 2025 10:15:43 +0200 Subject: [PATCH 10/13] Turn ShaderTable::Init into a ctor with initializer list --- tools/clang/unittests/HLSLExec/DXRUtil.h | 22 +++++++++---------- .../unittests/HLSLExec/ExecutionTest.cpp | 14 ++++++------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/DXRUtil.h b/tools/clang/unittests/HLSLExec/DXRUtil.h index 54828f4857..14bbf5bf1b 100644 --- a/tools/clang/unittests/HLSLExec/DXRUtil.h +++ b/tools/clang/unittests/HLSLExec/DXRUtil.h @@ -42,18 +42,16 @@ struct Instance { class ShaderTable { public: - void Init(ID3D12Device *Device, int RaygenCount, int MissCount, - int HitGroupCount, int RayTypeCount, int RootTableDwords) { - RayTypeCount = RayTypeCount; - RaygenCount = RaygenCount; - MissCount = MissCount * RayTypeCount; - HitGroupCount = HitGroupCount * RayTypeCount; - RootTableSizeInBytes = RootTableDwords * 4; - ShaderRecordSizeInBytes = - ROUND_UP(RootTableSizeInBytes + SHADER_ID_SIZE_IN_BYTES, - D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT); - MissStartIdx = RaygenCount; - HitGroupStartIdx = MissStartIdx + MissCount; + ShaderTable(ID3D12Device *Device, int RaygenCount, int MissCount, + int HitGroupCount, int RayTypeCount, int RootTableDwords) + : RayTypeCount(RayTypeCount), RaygenCount(RaygenCount), + MissCount(MissCount * RayTypeCount), + HitGroupCount(HitGroupCount * RayTypeCount), + RootTableSizeInBytes(RootTableDwords * 4), + ShaderRecordSizeInBytes( + ROUND_UP(RootTableSizeInBytes + SHADER_ID_SIZE_IN_BYTES, + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT)), + MissStartIdx(RaygenCount), HitGroupStartIdx(MissStartIdx + MissCount) { const int TotalSizeInBytes = (RaygenCount + MissCount + HitGroupCount) * ShaderRecordSizeInBytes; diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp index 9be631fd83..02652deef0 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest.cpp +++ b/tools/clang/unittests/HLSLExec/ExecutionTest.cpp @@ -2499,13 +2499,13 @@ CComPtr ExecutionTest::RunDXRTest( VERIFY_SUCCEEDED(StateObject->QueryInterface(&StateObjectProperties)); // Create SBT - ShaderTable ShaderTable; - ShaderTable.Init(Device, - 1, // raygen count - 1, // miss count - UseMesh && UseProceduralGeometry ? 2 : 1, // hit group count - 1, // ray type count - 4 // dwords per root table + ShaderTable ShaderTable( + Device, + 1, // raygen count + 1, // miss count + UseMesh && UseProceduralGeometry ? 2 : 1, // hit group count + 1, // ray type count + 4 // dwords per root table ); int LocalRootConsts[4] = {12, 34, 56, 78}; From 15140b12156312f5bb35430230a41de2f10147ee Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 8 May 2025 10:28:53 +0200 Subject: [PATCH 11/13] Fix GetAttributesTest: procedural not contained in AABB / use integer arith for hitKind computation --- .../unittests/HLSLExec/ExecutionTest_SER.h | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 130eeea744..e3f5758d78 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -1509,7 +1509,7 @@ void raygen() } else { - // Use 255 to keep outside the HitKind range [0, 127] we passthru for hits. + // Use 255 to keep outside the HitKind range [0,15] we passthru for hits. testVal = 255; } int id = launchIndex.x + launchIndex.y * launchDim.x; @@ -1537,28 +1537,35 @@ void closesthit(inout PerRayData payload, in CustomAttrs attrs) [shader("intersection")] void intersection() { + // Intersection with circle on a plane (base, n, radius) // hitPos is intersection point with plane (base, n) float3 base = {0.0f,0.0f,0.5f}; float3 n = normalize(float3(0.0f,0.5f,0.5f)); + float radius = 500.f; + // Plane hit float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); - if (t > RayTCurrent() || t < RayTMin()) { + if (t > RayTCurrent() || t < RayTMin()) return; - } float3 hitPos = ObjectRayOrigin() + t * ObjectRayDirection(); float3 relHitPos = hitPos - base; - // Encode some hit information in hitKind - int hitKind = 0; - if (relHitPos.y >= 0.0f) - hitKind = 1; - hitKind *= 2; - if (relHitPos.x >= 0.0f) - hitKind += 1; - hitKind *= 2; - if (relHitPos.z >= 0.0f) - hitKind += 1; + // Circle hit + float hitDist = length(relHitPos); + if (hitDist > radius) + return; CustomAttrs attrs; - attrs.dist = length(relHitPos); + attrs.dist = hitDist; + + // Generate wave-incoherent hitKind + uint2 launchIndex = DispatchRaysIndex().xy; + uint hitKind = 1U; + if (launchIndex.x >= 32) + hitKind |= 2U; + if (launchIndex.y >= 32) + hitKind |= 4U; + if ((launchIndex.x + launchIndex.y) % 2 == 0) + hitKind |= 8U; + ReportHit(t, hitKind, attrs); } @@ -1580,12 +1587,18 @@ void intersection() std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 5); - VERIFY_ARE_EQUAL(Histo[0], 2009); - VERIFY_ARE_EQUAL(Histo[1], 561); - VERIFY_ARE_EQUAL(Histo[3], 587); - VERIFY_ARE_EQUAL(Histo[4], 454); - VERIFY_ARE_EQUAL(Histo[6], 485); + + VERIFY_ARE_EQUAL(Histo.size(), 10); + VERIFY_ARE_EQUAL(Histo[0], 1587); + VERIFY_ARE_EQUAL(Histo[1], 277); + VERIFY_ARE_EQUAL(Histo[3], 256); + VERIFY_ARE_EQUAL(Histo[5], 167); + VERIFY_ARE_EQUAL(Histo[7], 153); + VERIFY_ARE_EQUAL(Histo[9], 249); + VERIFY_ARE_EQUAL(Histo[11], 260); + VERIFY_ARE_EQUAL(Histo[13], 158); + VERIFY_ARE_EQUAL(Histo[15], 142); + VERIFY_ARE_EQUAL(Histo[255], 847); } TEST_F(ExecutionTest, SERTraceHitMissNopTest) { From 6e42757a4e182e17e5a62f12c5e4577a7c0ef16c Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 8 May 2025 10:50:36 +0200 Subject: [PATCH 12/13] Fix SERWaveIncoherentHitTest: Use ray_flags to be independent of aabb/tri hit order --- .../unittests/HLSLExec/ExecutionTest_SER.h | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index e3f5758d78..30b6547730 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -2303,17 +2303,20 @@ void raygen() dx::HitObject hitObject; + int cat = (launchIndex.x + launchIndex.y) % 4; + // Use wave incoherence to decide how to create the HitObject - if (launchIndex.x % 4 == 1) + if (cat == 1) { - ray.Origin.x += 2.0f; - hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, 0xFF, 0, 0, 0, ray, payload); + // Turn this into an expected miss by moving eye behind triangles + ray.Origin.z -= 1000.0f; + hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES, 0xFF, 0, 0, 0, ray, payload); } - else if (launchIndex.x % 4 == 2) + else if (cat == 2) { hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES, 0xFF, 0, 0, 0, ray, payload); } - else if (launchIndex.x % 4 == 3) + else if (cat == 3) { hitObject = dx::HitObject::TraceRay(topObject, RAY_FLAG_SKIP_TRIANGLES, 0xFF, 0, 0, 0, ray, payload); } @@ -2376,7 +2379,7 @@ void intersection() // hitPos is intersection point with plane (base, n) float3 base = {0.0f,0.0f,0.5f}; float3 n = normalize(float3(0.0f,0.5f,0.5f)); - float radius = 1000.f; + float radius = 500.f; // Plane hit float t = dot(n, base - ObjectRayOrigin()) / dot(n, ObjectRayDirection()); if (t > RayTCurrent() || t < RayTMin()) { @@ -2412,13 +2415,12 @@ void intersection() std::map Histo; for (int Val : TestData) ++Histo[Val]; - VERIFY_ARE_EQUAL(Histo.size(), 6); - VERIFY_ARE_EQUAL(Histo[1], 1024); // nop - VERIFY_ARE_EQUAL(Histo[2], 1022); // miss - VERIFY_ARE_EQUAL(Histo[4], 12); // triangle hit, no ch - VERIFY_ARE_EQUAL(Histo[8], 1008); // procedural hit, no ch - VERIFY_ARE_EQUAL(Histo[20], 11); // triangle hit, 'closesthit' invoked - VERIFY_ARE_EQUAL(Histo[40], 1019); // procedural hit, 'chAABB' invoked + + VERIFY_ARE_EQUAL(Histo.size(), 4); + VERIFY_ARE_EQUAL(Histo[1], 1024); // nop + VERIFY_ARE_EQUAL(Histo[2], 2243); // miss + VERIFY_ARE_EQUAL(Histo[20], 16); // triangle hit + VERIFY_ARE_EQUAL(Histo[40], 813); // procedural hit } TEST_F(ExecutionTest, SERReorderCoherentTest) { From 0aee7ff984dbf0ad6cddd6084fe25eb047a75571 Mon Sep 17 00:00:00 2001 From: Simon Moll Date: Thu, 8 May 2025 10:54:28 +0200 Subject: [PATCH 13/13] nfc: formatting --- tools/clang/unittests/HLSLExec/ExecutionTest_SER.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h index 30b6547730..8bffa410d5 100644 --- a/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h +++ b/tools/clang/unittests/HLSLExec/ExecutionTest_SER.h @@ -2419,7 +2419,7 @@ void intersection() VERIFY_ARE_EQUAL(Histo.size(), 4); VERIFY_ARE_EQUAL(Histo[1], 1024); // nop VERIFY_ARE_EQUAL(Histo[2], 2243); // miss - VERIFY_ARE_EQUAL(Histo[20], 16); // triangle hit + VERIFY_ARE_EQUAL(Histo[20], 16); // triangle hit VERIFY_ARE_EQUAL(Histo[40], 813); // procedural hit }