diff --git a/tools/clang/unittests/HLSLExec/HlslExecTestUtils.cpp b/tools/clang/unittests/HLSLExec/HlslExecTestUtils.cpp index b5b05f0d87..85cb351afd 100644 --- a/tools/clang/unittests/HLSLExec/HlslExecTestUtils.cpp +++ b/tools/clang/unittests/HLSLExec/HlslExecTestUtils.cpp @@ -636,3 +636,137 @@ UINT getMaxGroupSharedMemoryMS(ID3D12Device *Device) { D3D12_FEATURE_D3D12_OPTIONS_PREVIEW, &O, sizeof(O))); return O.MaxGroupSharedMemoryPerGroupMS; } + +std::unique_ptr createComputeOp(const char *Source, + const char *Target, + const char *RootSig, + const char *Args, UINT DispatchX, + UINT DispatchY, UINT DispatchZ) { + auto Op = std::make_unique(); + LPCSTR CSName = Op->Strings.insert("CS"); + Op->Name = CSName; + Op->CS = CSName; + Op->RootSignature = Op->Strings.insert(RootSig); + Op->DispatchX = DispatchX; + Op->DispatchY = DispatchY; + Op->DispatchZ = DispatchZ; + Op->UseWarpDevice = true; + + st::ShaderOpShader Shader = {}; + Shader.Name = CSName; + Shader.Target = Op->Strings.insert(Target); + Shader.EntryPoint = Op->Strings.insert("main"); + Shader.Text = Op->Strings.insert(Source); + Shader.Arguments = Args ? Op->Strings.insert(Args) : nullptr; + Shader.Compiled = FALSE; + Shader.Callback = FALSE; + Op->Shaders.push_back(Shader); + + return Op; +} + +void addUAVBuffer(st::ShaderOp *Op, const char *Name, UINT64 Width, + bool ReadBack, const char *Init) { + st::ShaderOpResource Res = {}; + Res.Name = Op->Strings.insert(Name); + Res.Init = Op->Strings.insert(Init); + Res.ReadBack = ReadBack ? TRUE : FALSE; + + Res.HeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + Res.HeapFlags = D3D12_HEAP_FLAG_NONE; + Res.Desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + Res.Desc.Width = Width; + Res.Desc.Height = 1; + Res.Desc.DepthOrArraySize = 1; + Res.Desc.MipLevels = 1; + Res.Desc.SampleDesc.Count = 1; + Res.Desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + Res.Desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + Res.InitialResourceState = D3D12_RESOURCE_STATE_COPY_DEST; + Res.TransitionTo = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + + Op->Resources.push_back(Res); +} + +void addRootUAV(st::ShaderOp *Op, UINT Index, const char *ResName) { + st::ShaderOpRootValue RV = {}; + RV.ResName = Op->Strings.insert(ResName); + RV.HeapName = nullptr; + RV.Index = Index; + Op->RootValues.push_back(RV); +} + +std::shared_ptr +runShaderOp(ID3D12Device *Device, dxc::SpecificDllLoader &DxcSupport, + std::unique_ptr Op, + st::ShaderOpTest::TInitCallbackFn InitCallback) { + auto OpSet = std::make_shared(); + OpSet->ShaderOps.push_back(std::move(Op)); + + return st::RunShaderOpTestAfterParse( + Device, DxcSupport, nullptr, std::move(InitCallback), std::move(OpSet)); +} + +void compileShader(dxc::SpecificDllLoader &DxcSupport, const char *Source, + const char *Target, const std::string &Args, + bool VerboseLogging) { + CComPtr Compiler; + VERIFY_SUCCEEDED(DxcSupport.CreateInstance(CLSID_DxcCompiler, &Compiler)); + + CComPtr Utils; + VERIFY_SUCCEEDED(DxcSupport.CreateInstance(CLSID_DxcUtils, &Utils)); + + CComPtr SourceBlob; + VERIFY_SUCCEEDED(Utils->CreateBlobFromPinned( + Source, static_cast(strlen(Source)), DXC_CP_UTF8, &SourceBlob)); + + // Build wide-string argument list: -T -E main . + std::vector WArgStorage; + WArgStorage.push_back(L"-T"); + WArgStorage.push_back(std::wstring(Target, Target + strlen(Target))); + WArgStorage.push_back(L"-E"); + WArgStorage.push_back(L"main"); + + // Tokenize the additional arguments string. + std::istringstream SS(Args); + std::string Tok; + while (SS >> Tok) + WArgStorage.push_back(std::wstring(Tok.begin(), Tok.end())); + + std::vector WArgPtrs; + std::wstringstream LogFlags; + LogFlags << L"Compiling with flags:"; + for (const auto &A : WArgStorage) { + WArgPtrs.push_back(A.c_str()); + LogFlags << L" " << A; + } + + DxcBuffer Buf = {}; + Buf.Ptr = SourceBlob->GetBufferPointer(); + Buf.Size = SourceBlob->GetBufferSize(); + Buf.Encoding = DXC_CP_UTF8; + + if (VerboseLogging) { + hlsl_test::LogCommentFmt(L"Shader Source:"); + hlsl_test::LogCommentFmt(L"%c", Source); + } + + hlsl_test::LogCommentFmt(LogFlags.str().c_str()); + + CComPtr Result; + VERIFY_SUCCEEDED(Compiler->Compile(&Buf, WArgPtrs.data(), + static_cast(WArgPtrs.size()), + nullptr, IID_PPV_ARGS(&Result))); + + HRESULT HR; + VERIFY_SUCCEEDED(Result->GetStatus(&HR)); + + if (FAILED(HR)) { + CComPtr Errors; + Result->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&Errors), nullptr); + if (Errors && Errors->GetStringLength() > 0) + hlsl_test::LogErrorFmt(L"Shader compilation failed:\n%S", + Errors->GetStringPointer()); + VERIFY_SUCCEEDED(HR); + } +} diff --git a/tools/clang/unittests/HLSLExec/HlslExecTestUtils.h b/tools/clang/unittests/HLSLExec/HlslExecTestUtils.h index a16be6a16c..ddbb96b7c1 100644 --- a/tools/clang/unittests/HLSLExec/HlslExecTestUtils.h +++ b/tools/clang/unittests/HLSLExec/HlslExecTestUtils.h @@ -3,9 +3,12 @@ #include #include +#include #include +#include #include +#include "ShaderOpTest.h" #include "dxc/Support/dxcapi.use.h" // D3D_SHADER_MODEL_6_10 is not yet in the released Windows SDK. @@ -74,4 +77,29 @@ UINT getMaxGroupSharedMemoryCS(ID3D12Device *Device); UINT getMaxGroupSharedMemoryAS(ID3D12Device *Device); UINT getMaxGroupSharedMemoryMS(ID3D12Device *Device); +/// Create a ShaderOp for a compute shader dispatch. +std::unique_ptr +createComputeOp(const char *Source, const char *Target, const char *RootSig, + const char *Args = nullptr, UINT DispatchX = 1, + UINT DispatchY = 1, UINT DispatchZ = 1); + +/// Add a UAV buffer resource to a ShaderOp. +void addUAVBuffer(st::ShaderOp *Op, const char *Name, UINT64 Width, + bool ReadBack, const char *Init = "zero"); + +/// Bind a resource to a root UAV parameter by index. +void addRootUAV(st::ShaderOp *Op, UINT Index, const char *ResName); + +/// Run a programmatically-built ShaderOp and return the result. +std::shared_ptr +runShaderOp(ID3D12Device *Device, dxc::SpecificDllLoader &DxcSupport, + std::unique_ptr Op, + st::ShaderOpTest::TInitCallbackFn InitCallback = nullptr); + +/// Compiles an HLSL shader using the DXC API to verify it is well-formed. +/// Fails the test on compile error. +void compileShader(dxc::SpecificDllLoader &DxcSupport, const char *Source, + const char *Target, const std::string &Args, + bool VerboseLogging = false); + #endif // HLSLEXECTESTUTILS_H diff --git a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp index cf770f8f3d..1044119685 100644 --- a/tools/clang/unittests/HLSLExec/LinAlgTests.cpp +++ b/tools/clang/unittests/HLSLExec/LinAlgTests.cpp @@ -24,6 +24,7 @@ #include "HlslExecTestUtils.h" +#include #include #include #include @@ -52,134 +53,6 @@ static int elemSize(ComponentType CT) { } } -/// Create a ShaderOp for a compute shader dispatch. -static std::unique_ptr -createComputeOp(const char *Source, const char *Target, const char *RootSig, - const char *Args = nullptr, UINT DispatchX = 1, - UINT DispatchY = 1, UINT DispatchZ = 1) { - auto Op = std::make_unique(); - LPCSTR CSName = Op->Strings.insert("CS"); - Op->Name = CSName; - Op->CS = CSName; - Op->RootSignature = Op->Strings.insert(RootSig); - Op->DispatchX = DispatchX; - Op->DispatchY = DispatchY; - Op->DispatchZ = DispatchZ; - Op->UseWarpDevice = true; - - st::ShaderOpShader Shader = {}; - Shader.Name = CSName; - Shader.Target = Op->Strings.insert(Target); - Shader.EntryPoint = Op->Strings.insert("main"); - Shader.Text = Op->Strings.insert(Source); - Shader.Arguments = Args ? Op->Strings.insert(Args) : nullptr; - Shader.Compiled = FALSE; - Shader.Callback = FALSE; - Op->Shaders.push_back(Shader); - - return Op; -} - -/// Add a UAV buffer resource to a ShaderOp. -static void addUAVBuffer(st::ShaderOp *Op, const char *Name, UINT64 Width, - bool ReadBack, const char *Init = "zero") { - st::ShaderOpResource Res = {}; - Res.Name = Op->Strings.insert(Name); - Res.Init = Op->Strings.insert(Init); - Res.ReadBack = ReadBack ? TRUE : FALSE; - - Res.HeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; - Res.HeapFlags = D3D12_HEAP_FLAG_NONE; - Res.Desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - Res.Desc.Width = Width; - Res.Desc.Height = 1; - Res.Desc.DepthOrArraySize = 1; - Res.Desc.MipLevels = 1; - Res.Desc.SampleDesc.Count = 1; - Res.Desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - Res.Desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - Res.InitialResourceState = D3D12_RESOURCE_STATE_COPY_DEST; - Res.TransitionTo = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - - Op->Resources.push_back(Res); -} - -/// Bind a resource to a root UAV parameter by index. -static void addRootUAV(st::ShaderOp *Op, UINT Index, const char *ResName) { - st::ShaderOpRootValue RV = {}; - RV.ResName = Op->Strings.insert(ResName); - RV.HeapName = nullptr; - RV.Index = Index; - Op->RootValues.push_back(RV); -} - -/// Run a programmatically-built ShaderOp and return the result. -static std::shared_ptr -runShaderOp(ID3D12Device *Device, dxc::SpecificDllLoader &DxcSupport, - std::unique_ptr Op, - st::ShaderOpTest::TInitCallbackFn InitCallback = nullptr) { - auto OpSet = std::make_shared(); - OpSet->ShaderOps.push_back(std::move(Op)); - - return st::RunShaderOpTestAfterParse( - Device, DxcSupport, nullptr, std::move(InitCallback), std::move(OpSet)); -} - -/// Compiles an HLSL shader using the DXC API to verify it is well-formed. -/// Fails the test on compile error. -static void compileShader(dxc::SpecificDllLoader &DxcSupport, - const char *Source, const char *Target, - const std::string &Args) { - CComPtr Compiler; - VERIFY_SUCCEEDED(DxcSupport.CreateInstance(CLSID_DxcCompiler, &Compiler)); - - CComPtr Utils; - VERIFY_SUCCEEDED(DxcSupport.CreateInstance(CLSID_DxcUtils, &Utils)); - - CComPtr SourceBlob; - VERIFY_SUCCEEDED(Utils->CreateBlobFromPinned( - Source, static_cast(strlen(Source)), DXC_CP_UTF8, &SourceBlob)); - - // Build wide-string argument list: -T -E main . - std::vector WArgStorage; - WArgStorage.push_back(L"-T"); - WArgStorage.push_back(std::wstring(Target, Target + strlen(Target))); - WArgStorage.push_back(L"-E"); - WArgStorage.push_back(L"main"); - - // Tokenize the additional arguments string. - std::istringstream SS(Args); - std::string Tok; - while (SS >> Tok) - WArgStorage.push_back(std::wstring(Tok.begin(), Tok.end())); - - std::vector WArgPtrs; - for (const auto &A : WArgStorage) - WArgPtrs.push_back(A.c_str()); - - DxcBuffer Buf = {}; - Buf.Ptr = SourceBlob->GetBufferPointer(); - Buf.Size = SourceBlob->GetBufferSize(); - Buf.Encoding = DXC_CP_UTF8; - - CComPtr Result; - VERIFY_SUCCEEDED(Compiler->Compile(&Buf, WArgPtrs.data(), - static_cast(WArgPtrs.size()), - nullptr, IID_PPV_ARGS(&Result))); - - HRESULT HR; - VERIFY_SUCCEEDED(Result->GetStatus(&HR)); - - if (FAILED(HR)) { - CComPtr Errors; - Result->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&Errors), nullptr); - if (Errors && Errors->GetStringLength() > 0) - hlsl_test::LogErrorFmt(L"Shader compilation failed:\n%S", - Errors->GetStringPointer()); - VERIFY_SUCCEEDED(HR); - } -} - struct MatrixParams { ComponentType CompType; int M; @@ -292,6 +165,9 @@ class DxilConf_SM610_LinAlg { bool VerboseLogging = false; bool Initialized = false; std::optional D3D12SDK; + + WEX::TestExecution::SetVerifyOutput VerifyOutput{ + WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures}; }; /// Creates the device and setups the test scenario with the following variants @@ -322,9 +198,6 @@ bool DxilConf_SM610_LinAlg::createDevice() { } bool DxilConf_SM610_LinAlg::setupClass() { - WEX::TestExecution::SetVerifyOutput VerifySettings( - WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures); - if (!Initialized) { Initialized = true; VERIFY_SUCCEEDED( @@ -381,7 +254,7 @@ static void runLoadStoreRoundtrip(ID3D12Device *Device, std::string Args = buildCompilerArgs(Params, ExtraDefs.str().c_str()); // Always verify the shader compiles. - compileShader(DxcSupport, LoadStoreShader, "cs_6_10", Args); + compileShader(DxcSupport, LoadStoreShader, "cs_6_10", Args, Verbose); #ifndef _HLK_CONF // Skip GPU execution if no device. @@ -504,7 +377,7 @@ static void runSplatStore(ID3D12Device *Device, std::string Args = buildCompilerArgs(Params, ExtraDefs.str().c_str()); // Always verify the shader compiles. - compileShader(DxcSupport, SplatStoreShader, "cs_6_10", Args); + compileShader(DxcSupport, SplatStoreShader, "cs_6_10", Args, Verbose); #ifndef _HLK_CONF // Skip GPU execution if no device. @@ -523,6 +396,8 @@ static void runSplatStore(ID3D12Device *Device, ExpectedFloats.assign(NumElements, FillValue); break; case ComponentType::I32: + VERIFY_IS_TRUE(FillValue < static_cast(INT_MAX), + "FillValue too large to cast to int32_t"); ExpectedInts.assign(NumElements, static_cast(FillValue)); break; default: