diff --git a/include/dxc/DxilRootSignature/DxilRootSignature.h b/include/dxc/DxilRootSignature/DxilRootSignature.h index 7b0c89ee99..87d0bf9b0f 100644 --- a/include/dxc/DxilRootSignature/DxilRootSignature.h +++ b/include/dxc/DxilRootSignature/DxilRootSignature.h @@ -385,6 +385,43 @@ bool VerifyRootSignature(_In_ const DxilVersionedRootSignatureDesc *pDesc, _In_ llvm::raw_ostream &DiagStream, _In_ bool bAllowReservedRegisterSpace); +class DxilVersionedRootSignature { + DxilVersionedRootSignatureDesc *m_pRootSignature; + +public: + // Non-copyable: + DxilVersionedRootSignature(DxilVersionedRootSignature const &) = delete; + DxilVersionedRootSignature const & + operator=(DxilVersionedRootSignature const &) = delete; + + // but movable: + DxilVersionedRootSignature(DxilVersionedRootSignature &&) = default; + DxilVersionedRootSignature & + operator=(DxilVersionedRootSignature &&) = default; + + DxilVersionedRootSignature() : m_pRootSignature(nullptr) {} + explicit DxilVersionedRootSignature( + const DxilVersionedRootSignatureDesc *pRootSignature) + : m_pRootSignature( + const_cast (pRootSignature)) {} + ~DxilVersionedRootSignature() { + DeleteRootSignature(m_pRootSignature); + } + const DxilVersionedRootSignatureDesc* operator -> () const { + return m_pRootSignature; + } + const DxilVersionedRootSignatureDesc ** get_address_of() { + if (m_pRootSignature != nullptr) + return nullptr; // You're probably about to leak... + return const_cast (&m_pRootSignature); + } + const DxilVersionedRootSignatureDesc* get() const { + return m_pRootSignature; + } + DxilVersionedRootSignatureDesc* get_mutable() const { + return m_pRootSignature; + } +}; } // namespace hlsl #endif // __DXC_ROOTSIGNATURE__ diff --git a/lib/DxilPIXPasses/PixPassHelpers.cpp b/lib/DxilPIXPasses/PixPassHelpers.cpp index 28a9bd19f1..fbc80ddb0b 100644 --- a/lib/DxilPIXPasses/PixPassHelpers.cpp +++ b/lib/DxilPIXPasses/PixPassHelpers.cpp @@ -9,10 +9,12 @@ #include "dxc/DXIL/DxilOperations.h" #include "dxc/DXIL/DxilInstructions.h" +#include "dxc/DXIL/DxilFunctionProps.h" #include "dxc/DXIL/DxilModule.h" #include "dxc/DXIL/DxilResourceBinding.h" #include "dxc/DXIL/DxilResourceProperties.h" #include "dxc/HLSL/DxilSpanAllocator.h" +#include "dxc/DxilRootSignature/DxilRootSignature.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" @@ -21,6 +23,10 @@ #include "PixPassHelpers.h" +#include "dxc/Support/Global.h" +#include "dxc/Support/WinIncludes.h" +#include "dxc/dxcapi.h" + #ifdef PIX_DEBUG_DUMP_HELPER #include #include "llvm/IR/DebugInfo.h" @@ -159,7 +165,93 @@ llvm::CallInst *CreateHandleForResource(hlsl::DxilModule &DM, } } -// Set up a UAV with structure of a single int +static std::vector SerializeRootSignatureToVector(DxilVersionedRootSignatureDesc const *rootSignature) { + CComPtr serializedRootSignature; + CComPtr errorBlob; + constexpr bool allowReservedRegisterSpace = true; + SerializeRootSignature(rootSignature, &serializedRootSignature, &errorBlob, + allowReservedRegisterSpace); + std::vector ret; + auto const *serializedData = reinterpret_cast( + serializedRootSignature->GetBufferPointer()); + ret.assign(serializedData, + serializedData + serializedRootSignature->GetBufferSize()); + + return ret; +} + +constexpr uint32_t toolsRegisterSpace = static_cast(-2); +constexpr uint32_t toolsUAVRegister = 0; + +template +void ExtendRootSig(RootSigDesc &rootSigDesc) { + auto *existingParams = rootSigDesc.pParameters; + auto *newParams = new RootParameterDesc[rootSigDesc.NumParameters + 1]; + if (existingParams != nullptr) { + memcpy(newParams, existingParams, + rootSigDesc.NumParameters * sizeof(RootParameterDesc)); + delete[] existingParams; + } + rootSigDesc.pParameters = newParams; + rootSigDesc.pParameters[rootSigDesc.NumParameters].ParameterType = DxilRootParameterType::UAV; + rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.RegisterSpace = toolsRegisterSpace; + rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.ShaderRegister = toolsUAVRegister; + rootSigDesc.pParameters[rootSigDesc.NumParameters].ShaderVisibility = DxilShaderVisibility::All; + rootSigDesc.NumParameters++; +} + +static std::vector AddUAVParamterToRootSignature(const void *Data, + uint32_t Size) { + DxilVersionedRootSignature rootSignature; + DeserializeRootSignature(Data, Size, rootSignature.get_address_of()); + auto *rs = rootSignature.get_mutable(); + switch (rootSignature->Version) { + case DxilRootSignatureVersion::Version_1_0: + ExtendRootSig(rs->Desc_1_0); + break; + case DxilRootSignatureVersion::Version_1_1: + ExtendRootSig(rs->Desc_1_1); + rs->Desc_1_1.pParameters[rs->Desc_1_1.NumParameters - 1].Descriptor.Flags = + hlsl::DxilRootDescriptorFlags::None; + break; + } + return SerializeRootSignatureToVector(rs); +} + +static void AddUAVToShaderAttributeRootSignature(DxilModule &DM) { + auto rs = DM.GetSerializedRootSignature(); + if(!rs.empty()) { + std::vector asVector = AddUAVParamterToRootSignature(rs.data(), static_cast(rs.size())); + DM.ResetSerializedRootSignature(asVector); + } +} + +static void AddUAVToDxilDefinedGlobalRootSignatures(DxilModule& DM) { + auto *subObjects = DM.GetSubobjects(); + if (subObjects != nullptr) { + for (auto const &subObject : subObjects->GetSubobjects()) { + if (subObject.second->GetKind() == + DXIL::SubobjectKind::GlobalRootSignature) { + const void *Data = nullptr; + uint32_t Size = 0; + constexpr bool notALocalRS = false; + if (subObject.second->GetRootSignature(notALocalRS, Data, Size, + nullptr)) { + auto extendedRootSig = AddUAVParamterToRootSignature(Data, Size); + auto rootSignatureSubObjectName = subObject.first; + subObjects->RemoveSubobject(rootSignatureSubObjectName); + subObjects->CreateRootSignature(rootSignatureSubObjectName, + notALocalRS, + extendedRootSig.data(), + static_cast(extendedRootSig.size())); + break; + } + } + } + } +} + + // Set up a UAV with structure of a single int llvm::CallInst *CreateUAV(DxilModule &DM, IRBuilder<> &Builder, unsigned int registerId, const char *name) { LLVMContext &Ctx = DM.GetModule()->getContext(); @@ -170,6 +262,11 @@ llvm::CallInst *CreateUAV(DxilModule &DM, IRBuilder<> &Builder, if (UAVStructTy == nullptr) { SmallVector Elements{Type::getInt32Ty(Ctx)}; UAVStructTy = llvm::StructType::create(Elements, PIXStructTypeName); + + // Since we only have to do this once per module, we can do it now when + // we're adding the singular UAV structure type to the module: + AddUAVToDxilDefinedGlobalRootSignatures(DM); + AddUAVToShaderAttributeRootSignature(DM); } std::unique_ptr pUAV = llvm::make_unique(); diff --git a/lib/DxilRootSignature/DxilRootSignatureSerializer.cpp b/lib/DxilRootSignature/DxilRootSignatureSerializer.cpp index a2acac8a52..29a449e9bc 100644 --- a/lib/DxilRootSignature/DxilRootSignatureSerializer.cpp +++ b/lib/DxilRootSignature/DxilRootSignatureSerializer.cpp @@ -332,93 +332,6 @@ void SerializeRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature } } -//============================================================================= -// -// CVersionedRootSignatureDeserializer. -// -//============================================================================= -class CVersionedRootSignatureDeserializer { -protected: - const DxilVersionedRootSignatureDesc *m_pRootSignature; - const DxilVersionedRootSignatureDesc *m_pRootSignature10; - const DxilVersionedRootSignatureDesc *m_pRootSignature11; - -public: - CVersionedRootSignatureDeserializer(); - ~CVersionedRootSignatureDeserializer(); - - void Initialize(_In_reads_bytes_(SrcDataSizeInBytes) const void *pSrcData, - _In_ uint32_t SrcDataSizeInBytes); - - const DxilVersionedRootSignatureDesc *GetRootSignatureDescAtVersion(DxilRootSignatureVersion convertToVersion); - - const DxilVersionedRootSignatureDesc *GetUnconvertedRootSignatureDesc(); -}; - -CVersionedRootSignatureDeserializer::CVersionedRootSignatureDeserializer() - : m_pRootSignature(nullptr) - , m_pRootSignature10(nullptr) - , m_pRootSignature11(nullptr) { -} - -CVersionedRootSignatureDeserializer::~CVersionedRootSignatureDeserializer() { - DeleteRootSignature(m_pRootSignature10); - DeleteRootSignature(m_pRootSignature11); -} - -void CVersionedRootSignatureDeserializer::Initialize(_In_reads_bytes_(SrcDataSizeInBytes) const void *pSrcData, - _In_ uint32_t SrcDataSizeInBytes) { - const DxilVersionedRootSignatureDesc *pRootSignature = nullptr; - DeserializeRootSignature(pSrcData, SrcDataSizeInBytes, &pRootSignature); - - switch (pRootSignature->Version) { - case DxilRootSignatureVersion::Version_1_0: - m_pRootSignature10 = pRootSignature; - break; - - case DxilRootSignatureVersion::Version_1_1: - m_pRootSignature11 = pRootSignature; - break; - - default: - DeleteRootSignature(pRootSignature); - return; - } - - m_pRootSignature = pRootSignature; -} - -const DxilVersionedRootSignatureDesc * -CVersionedRootSignatureDeserializer::GetUnconvertedRootSignatureDesc() { - return m_pRootSignature; -} - -const DxilVersionedRootSignatureDesc * -CVersionedRootSignatureDeserializer::GetRootSignatureDescAtVersion(DxilRootSignatureVersion ConvertToVersion) { - switch (ConvertToVersion) { - case DxilRootSignatureVersion::Version_1_0: - if (m_pRootSignature10 == nullptr) { - ConvertRootSignature(m_pRootSignature, - ConvertToVersion, - (const DxilVersionedRootSignatureDesc **)&m_pRootSignature10); - } - return m_pRootSignature10; - - case DxilRootSignatureVersion::Version_1_1: - if (m_pRootSignature11 == nullptr) { - ConvertRootSignature(m_pRootSignature, - ConvertToVersion, - (const DxilVersionedRootSignatureDesc **)&m_pRootSignature11); - } - return m_pRootSignature11; - - default: - IFTBOOL(false, E_FAIL); - } - - return nullptr; -} - templateReserve(pWriter->size()); pWriter->write(pOutputStream); + DxilVersionedRootSignature desc; try { - const DxilVersionedRootSignatureDesc* pDesc = nullptr; - DeserializeRootSignature(SerializedRootSig.data(), SerializedRootSig.size(), &pDesc); - if (!pDesc) { + DeserializeRootSignature(SerializedRootSig.data(), + SerializedRootSig.size(), desc.get_address_of()); + if (!desc.get()) { return DXC_E_INCORRECT_ROOT_SIGNATURE; } - IFTBOOL(VerifyRootSignatureWithShaderPSV(pDesc, + IFTBOOL(VerifyRootSignatureWithShaderPSV(desc.get(), dxilModule.GetShaderModel()->GetKind(), pOutputStream->GetPtr(), pWriter->size(), DiagStream), DXC_E_INCORRECT_ROOT_SIGNATURE); diff --git a/tools/clang/unittests/HLSL/PixTest.cpp b/tools/clang/unittests/HLSL/PixTest.cpp index 18de9f0773..0192e5ad43 100644 --- a/tools/clang/unittests/HLSL/PixTest.cpp +++ b/tools/clang/unittests/HLSL/PixTest.cpp @@ -25,7 +25,12 @@ #include #include #include + +#include "dxc/Support/WinIncludes.h" + #include "dxc/DxilContainer/DxilContainer.h" +#include "dxc/DxilContainer/DxilRuntimeReflection.h" +#include "dxc/DxilRootSignature/DxilRootSignature.h" #include "dxc/Support/WinIncludes.h" #include "dxc/dxcapi.h" #include "dxc/dxcpix.h" @@ -195,10 +200,6 @@ class PixTest { TEST_METHOD(DiaCompileArgs) TEST_METHOD(PixDebugCompileInfo) - TEST_METHOD(CheckSATPassFor66_NoDynamicAccess) - TEST_METHOD(CheckSATPassFor66_DynamicFromRootSig) - TEST_METHOD(CheckSATPassFor66_DynamicFromHeap) - TEST_METHOD(AddToASPayload) TEST_METHOD(PixStructAnnotation_Lib_DualRaygen) @@ -223,6 +224,9 @@ class PixTest { TEST_METHOD(VirtualRegisters_InstructionCounts) + TEST_METHOD(RootSignatureUpgrade_SubObjects) + TEST_METHOD(RootSignatureUpgrade_Annotation) + dxc::DxcDllSupport m_dllSupport; VersionSupportInfo m_ver; @@ -1003,8 +1007,9 @@ class PixTest { bool validateCoverage = true, const wchar_t *profile = L"as_6_5"); void ValidateAllocaWrite(std::vector const& allocaWrites, size_t index, const char* name); - std::string RunShaderAccessTrackingPassAndReturnOutputMessages(IDxcBlob* blob); - std::string RunDxilPIXAddTidToAmplificationShaderPayloadPass(IDxcBlob* blob); + CComPtr RunShaderAccessTrackingPass(IDxcBlob* blob); + std::string RunDxilPIXAddTidToAmplificationShaderPayloadPass(IDxcBlob * + blob); CComPtr RunDxilPIXMeshShaderOutputPass(IDxcBlob* blob); }; @@ -1665,81 +1670,35 @@ TEST_F(PixTest, PixDebugCompileInfo) { VERIFY_ARE_EQUAL(std::wstring(profile), std::wstring(hlslTarget)); } -std::string PixTest::RunShaderAccessTrackingPassAndReturnOutputMessages(IDxcBlob* blob) -{ - CComPtr dxil = FindModule(DFCC_ShaderDebugInfoDXIL, blob); +CComPtr PixTest::RunShaderAccessTrackingPass(IDxcBlob *blob) { CComPtr pOptimizer; VERIFY_SUCCEEDED( m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer)); std::vector Options; Options.push_back(L"-opt-mod-passes"); - Options.push_back(L"-hlsl-dxil-pix-shader-access-instrumentation,config=,checkForDynamicIndexing=1"); + Options.push_back(L"-hlsl-dxil-pix-shader-access-instrumentation,config="); CComPtr pOptimizedModule; CComPtr pText; VERIFY_SUCCEEDED(pOptimizer->RunOptimizer( - dxil, Options.data(), Options.size(), &pOptimizedModule, &pText)); - - std::string outputText; - if (pText->GetBufferSize() != 0) { - outputText = reinterpret_cast(pText->GetBufferPointer()); - } + blob, Options.data(), Options.size(), &pOptimizedModule, &pText)); - return outputText; -} - -TEST_F(PixTest, CheckSATPassFor66_NoDynamicAccess) { - - const char *noDynamicAccess = R"( - [RootSignature("")] - float main(float pos : A) : SV_Target { - float x = abs(pos); - float y = sin(pos); - float z = x + y; - return z; - } - )"; - - auto compiled = Compile(noDynamicAccess, L"ps_6_6"); - auto satResults = RunShaderAccessTrackingPassAndReturnOutputMessages(compiled); - VERIFY_IS_TRUE(satResults.empty()); -} - -TEST_F(PixTest, CheckSATPassFor66_DynamicFromRootSig) { - - const char *dynamicTextureAccess = R"x( -Texture1D tex[5] : register(t3); -SamplerState SS[3] : register(s2); - -[RootSignature("DescriptorTable(SRV(t3, numDescriptors=5)),\ - DescriptorTable(Sampler(s2, numDescriptors=3))")] -float4 main(int i : A, float j : B) : SV_TARGET -{ - float4 r = tex[i].Sample(SS[i], i); - return r; -} - )x"; + CComPtr pAssembler; + VERIFY_SUCCEEDED( + m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler)); - auto compiled = Compile(dynamicTextureAccess, L"ps_6_6"); - auto satResults = RunShaderAccessTrackingPassAndReturnOutputMessages(compiled); - VERIFY_IS_TRUE(satResults.find("FoundDynamicIndexing") != string::npos); -} + CComPtr pAssembleResult; + VERIFY_SUCCEEDED( + pAssembler->AssembleToContainer(pOptimizedModule, &pAssembleResult)); -TEST_F(PixTest, CheckSATPassFor66_DynamicFromHeap) { + HRESULT hr; + VERIFY_SUCCEEDED(pAssembleResult->GetStatus(&hr)); + VERIFY_SUCCEEDED(hr); - const char *dynamicResourceDecriptorHeapAccess = R"( -static sampler sampler0 = SamplerDescriptorHeap[0]; -float4 main(int input : INPUT) : SV_Target -{ - Texture2D texture = ResourceDescriptorHeap[input]; - return texture.Sample(sampler0, float2(0,0)); -} - )"; + CComPtr pNewContainer; + VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pNewContainer)); - auto compiled = Compile(dynamicResourceDecriptorHeapAccess, L"ps_6_6"); - auto satResults = - RunShaderAccessTrackingPassAndReturnOutputMessages(compiled); - VERIFY_IS_TRUE(satResults.find("FoundDynamicIndexing") != string::npos); + return pNewContainer; } CComPtr PixTest::RunDxilPIXMeshShaderOutputPass(IDxcBlob *blob) { @@ -3427,4 +3386,222 @@ void MyMissShader(inout RayPayload payload) } } +static void VerifyOperationSucceeded(IDxcOperationResult *pResult) +{ + HRESULT result; + VERIFY_SUCCEEDED(pResult->GetStatus(&result)); + if (FAILED(result)) { + CComPtr pErrors; + VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors)); + CA2W errorsWide(BlobToUtf8(pErrors).c_str(), CP_UTF8); + WEX::Logging::Log::Comment(errorsWide); + } + VERIFY_SUCCEEDED(result); +} + +TEST_F(PixTest, RootSignatureUpgrade_SubObjects) { + + const char *source = R"x( +GlobalRootSignature so_GlobalRootSignature = +{ + "RootConstants(num32BitConstants=1, b8), " +}; + +StateObjectConfig so_StateObjectConfig = +{ + STATE_OBJECT_FLAGS_ALLOW_LOCAL_DEPENDENCIES_ON_EXTERNAL_DEFINITONS +}; + +LocalRootSignature so_LocalRootSignature1 = +{ + "RootConstants(num32BitConstants=3, b2), " + "UAV(u6),RootFlags(LOCAL_ROOT_SIGNATURE)" +}; + +LocalRootSignature so_LocalRootSignature2 = +{ + "RootConstants(num32BitConstants=3, b2), " + "UAV(u8, flags=DATA_STATIC), " + "RootFlags(LOCAL_ROOT_SIGNATURE)" +}; + +RaytracingShaderConfig so_RaytracingShaderConfig = +{ + 128, // max payload size + 32 // max attribute size +}; + +RaytracingPipelineConfig so_RaytracingPipelineConfig = +{ + 2 // max trace recursion depth +}; + +TriangleHitGroup MyHitGroup = +{ + "MyAnyHit", // AnyHit + "MyClosestHit", // ClosestHit +}; + +SubobjectToExportsAssociation so_Association1 = +{ + "so_LocalRootSignature1", // subobject name + "MyRayGen" // export association +}; + +SubobjectToExportsAssociation so_Association2 = +{ + "so_LocalRootSignature2", // subobject name + "MyAnyHit" // export association +}; + +struct MyPayload +{ + float4 color; +}; + +[shader("raygeneration")] +void MyRayGen() +{ +} + +[shader("closesthit")] +void MyClosestHit(inout MyPayload payload, in BuiltInTriangleIntersectionAttributes attr) +{ +} + +[shader("anyhit")] +void MyAnyHit(inout MyPayload payload, in BuiltInTriangleIntersectionAttributes attr) +{ +} + +[shader("miss")] +void MyMiss(inout MyPayload payload) +{ +} + +)x"; + + CComPtr pCompiler; + VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler)); + + CComPtr pSource; + Utf8ToBlob(m_dllSupport, source, &pSource); + + CComPtr pResult; + VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"", L"lib_6_6", + nullptr, 0, nullptr, 0, nullptr, + &pResult)); + VerifyOperationSucceeded(pResult); + CComPtr compiled; + VERIFY_SUCCEEDED(pResult->GetResult(&compiled)); + + auto optimizedContainer = RunShaderAccessTrackingPass(compiled); + + const char *pBlobContent = + reinterpret_cast(optimizedContainer->GetBufferPointer()); + unsigned blobSize = optimizedContainer->GetBufferSize(); + const hlsl::DxilContainerHeader *pContainerHeader = + hlsl::IsDxilContainerLike(pBlobContent, blobSize); + + const hlsl::DxilPartHeader *pPartHeader = + GetDxilPartByType(pContainerHeader, hlsl::DFCC_RuntimeData); + VERIFY_ARE_NOT_EQUAL(pPartHeader, nullptr); + + hlsl::RDAT::DxilRuntimeData rdat(GetDxilPartData(pPartHeader), + pPartHeader->PartSize); + + auto const subObjectTableReader = rdat.GetSubobjectTable(); + + // There are 9 subobjects in the HLSL above: + VERIFY_ARE_EQUAL(subObjectTableReader.Count(), 9u); + + bool foundGlobalRS = false; + for (uint32_t i = 0; i < subObjectTableReader.Count(); ++i) { + auto subObject = subObjectTableReader[i]; + hlsl::DXIL::SubobjectKind subobjectKind = subObject.getKind(); + switch (subobjectKind) { + case hlsl::DXIL::SubobjectKind::GlobalRootSignature: { + foundGlobalRS = true; + VERIFY_IS_TRUE(0 == + strcmp(subObject.getName(), "so_GlobalRootSignature")); + + auto rootSigReader = subObject.getRootSignature(); + DxilVersionedRootSignatureDesc const *rootSignature = nullptr; + DeserializeRootSignature(rootSigReader.getData(), + rootSigReader.sizeData(), &rootSignature); + VERIFY_ARE_EQUAL(rootSignature->Version, + DxilRootSignatureVersion::Version_1_1); + VERIFY_ARE_EQUAL(rootSignature->Desc_1_1.NumParameters, 2); + VERIFY_ARE_EQUAL(rootSignature->Desc_1_1.pParameters[1].ParameterType, + DxilRootParameterType::UAV); + VERIFY_ARE_EQUAL(rootSignature->Desc_1_1.pParameters[1].ShaderVisibility, + DxilShaderVisibility::All); + VERIFY_ARE_EQUAL( + rootSignature->Desc_1_1.pParameters[1].Descriptor.RegisterSpace, + static_cast(-2)); + VERIFY_ARE_EQUAL( + rootSignature->Desc_1_1.pParameters[1].Descriptor.ShaderRegister, 0u); + DeleteRootSignature(rootSignature); + break; + } + } + } + VERIFY_IS_TRUE(foundGlobalRS); +} + +TEST_F(PixTest, RootSignatureUpgrade_Annotation) +{ + + const char *dynamicTextureAccess = R"x( +Texture1D tex[5] : register(t3); +SamplerState SS[3] : register(s2); + +[RootSignature("DescriptorTable(SRV(t3, numDescriptors=5)),\ + DescriptorTable(Sampler(s2, numDescriptors=3))")] +float4 main(int i : A, float j : B) : SV_TARGET +{ + float4 r = tex[i].Sample(SS[i], i); + return r; +} + )x"; + + auto compiled = Compile(dynamicTextureAccess, L"ps_6_6"); + auto pOptimizedContainer = RunShaderAccessTrackingPass(compiled); + + const char *pBlobContent = + reinterpret_cast(pOptimizedContainer->GetBufferPointer()); + unsigned blobSize = pOptimizedContainer->GetBufferSize(); + const hlsl::DxilContainerHeader *pContainerHeader = + hlsl::IsDxilContainerLike(pBlobContent, blobSize); + + const hlsl::DxilPartHeader *pPartHeader = + GetDxilPartByType(pContainerHeader, hlsl::DFCC_RootSignature); + VERIFY_ARE_NOT_EQUAL(pPartHeader, nullptr); + + hlsl::RootSignatureHandle RSH; + RSH.LoadSerialized((const uint8_t *)GetDxilPartData(pPartHeader), + pPartHeader->PartSize); + + RSH.Deserialize(); + + auto const *desc = RSH.GetDesc(); + + bool foundGlobalRS = false; + + VERIFY_ARE_EQUAL(desc->Version, hlsl::DxilRootSignatureVersion::Version_1_1); + VERIFY_ARE_EQUAL(desc->Desc_1_1.NumParameters, 3u); + for (unsigned int i = 0; i < desc->Desc_1_1.NumParameters; ++i) { + hlsl::DxilRootParameter1 const *param = desc->Desc_1_1.pParameters + i; + switch (param->ParameterType) { + case hlsl::DxilRootParameterType::UAV: + VERIFY_ARE_EQUAL(param->Descriptor.RegisterSpace, static_cast(-2)); + VERIFY_ARE_EQUAL(param->Descriptor.ShaderRegister, 0u); + foundGlobalRS = true; + break; + } + } + + VERIFY_IS_TRUE(foundGlobalRS); +} + #endif