DxilContainerTest.cpp 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilContainerTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides tests for container formatting and validation. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #ifndef UNICODE
  12. #define UNICODE
  13. #endif
  14. #ifdef __APPLE__
  15. // Workaround for ambiguous wcsstr on Mac
  16. #define _WCHAR_H_CPLUSPLUS_98_CONFORMANCE_
  17. #endif
  18. #include <memory>
  19. #include <vector>
  20. #include <string>
  21. #include <tuple>
  22. #include <cassert>
  23. #include <sstream>
  24. #include <algorithm>
  25. #include <unordered_set>
  26. #include "dxc/Support/WinIncludes.h"
  27. #include "dxc/dxcapi.h"
  28. #ifdef _WIN32
  29. #include <atlfile.h>
  30. #include <d3dcompiler.h>
  31. #pragma comment(lib, "d3dcompiler.lib")
  32. #if _MSC_VER >= 1920
  33. #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
  34. #include <experimental/filesystem>
  35. #else
  36. #include <filesystem>
  37. #endif
  38. #endif
  39. #include "llvm/Support/Format.h"
  40. #include "llvm/Support/raw_ostream.h"
  41. #include "dxc/Test/HLSLTestData.h"
  42. #include "dxc/Test/HlslTestUtils.h"
  43. #include "dxc/Test/DxcTestUtils.h"
  44. #include "dxc/Support/Global.h"
  45. #include "dxc/Support/dxcapi.use.h"
  46. #include "dxc/Support/HLSLOptions.h"
  47. #include "dxc/DxilContainer/DxilContainer.h"
  48. #include "dxc/DxilContainer/DxilRuntimeReflection.h"
  49. #include "dxc/DxilContainer/DxilPipelineStateValidation.h"
  50. #include "dxc/DXIL/DxilShaderFlags.h"
  51. #include "dxc/DXIL/DxilUtil.h"
  52. #include <fstream>
  53. #include <chrono>
  54. #include <codecvt>
  55. using namespace std;
  56. using namespace hlsl_test;
  57. #ifdef _WIN32
  58. using namespace std::experimental::filesystem;
  59. static uint8_t MaskCount(uint8_t V) {
  60. DXASSERT_NOMSG(0 <= V && V <= 0xF);
  61. static const uint8_t Count[16] = {
  62. 0, 1, 1, 2,
  63. 1, 2, 2, 3,
  64. 1, 2, 2, 3,
  65. 2, 3, 3, 4
  66. };
  67. return Count[V];
  68. }
  69. #endif
  70. #ifdef _WIN32
  71. class DxilContainerTest {
  72. #else
  73. class DxilContainerTest : public ::testing::Test {
  74. #endif
  75. public:
  76. BEGIN_TEST_CLASS(DxilContainerTest)
  77. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  78. TEST_METHOD_PROPERTY(L"Priority", L"0")
  79. END_TEST_CLASS()
  80. TEST_CLASS_SETUP(InitSupport);
  81. TEST_METHOD(CompileWhenDebugSourceThenSourceMatters)
  82. TEST_METHOD(CompileAS_CheckPSV0)
  83. TEST_METHOD(CompileWhenOkThenCheckRDAT)
  84. TEST_METHOD(CompileWhenOkThenCheckRDAT2)
  85. TEST_METHOD(CompileWhenOkThenCheckReflection1)
  86. TEST_METHOD(DxcUtils_CreateReflection)
  87. TEST_METHOD(CompileWhenOKThenIncludesFeatureInfo)
  88. TEST_METHOD(CompileWhenOKThenIncludesSignatures)
  89. TEST_METHOD(CompileWhenSigSquareThenIncludeSplit)
  90. TEST_METHOD(DisassemblyWhenMissingThenFails)
  91. TEST_METHOD(DisassemblyWhenBCInvalidThenFails)
  92. TEST_METHOD(DisassemblyWhenInvalidThenFails)
  93. TEST_METHOD(DisassemblyWhenValidThenOK)
  94. TEST_METHOD(ValidateFromLL_Abs2)
  95. TEST_METHOD(DxilContainerUnitTest)
  96. TEST_METHOD(ReflectionMatchesDXBC_CheckIn)
  97. BEGIN_TEST_METHOD(ReflectionMatchesDXBC_Full)
  98. TEST_METHOD_PROPERTY(L"Priority", L"1")
  99. END_TEST_METHOD()
  100. dxc::DxcDllSupport m_dllSupport;
  101. VersionSupportInfo m_ver;
  102. void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
  103. UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
  104. CComPtr<IDxcLibrary> library;
  105. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  106. IFT(library->CreateBlobWithEncodingFromPinned((LPBYTE)data, size, codePage,
  107. ppBlob));
  108. }
  109. void CreateBlobFromText(_In_z_ const char *pText,
  110. _Outptr_ IDxcBlobEncoding **ppBlob) {
  111. CreateBlobPinned(pText, strlen(pText), CP_UTF8, ppBlob);
  112. }
  113. HRESULT CreateCompiler(IDxcCompiler **ppResult) {
  114. if (!m_dllSupport.IsEnabled()) {
  115. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  116. }
  117. return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
  118. }
  119. #ifdef _WIN32 // - Reflection Unsupported
  120. void CompareShaderInputBindDesc(D3D12_SHADER_INPUT_BIND_DESC *pTestDesc,
  121. D3D12_SHADER_INPUT_BIND_DESC *pBaseDesc) {
  122. VERIFY_ARE_EQUAL(pTestDesc->BindCount, pBaseDesc->BindCount);
  123. VERIFY_ARE_EQUAL(pTestDesc->BindPoint, pBaseDesc->BindPoint);
  124. VERIFY_ARE_EQUAL(pTestDesc->Dimension, pBaseDesc->Dimension);
  125. VERIFY_ARE_EQUAL_STR(pTestDesc->Name, pBaseDesc->Name);
  126. VERIFY_ARE_EQUAL(pTestDesc->NumSamples, pBaseDesc->NumSamples);
  127. VERIFY_ARE_EQUAL(pTestDesc->ReturnType, pBaseDesc->ReturnType);
  128. VERIFY_ARE_EQUAL(pTestDesc->Space, pBaseDesc->Space);
  129. if (pBaseDesc->Type == D3D_SIT_UAV_APPEND_STRUCTURED ||
  130. pBaseDesc->Type == D3D_SIT_UAV_CONSUME_STRUCTURED) {
  131. // dxil only have rw with counter.
  132. VERIFY_ARE_EQUAL(pTestDesc->Type, D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER);
  133. } else if (pTestDesc->Type == D3D_SIT_STRUCTURED &&
  134. pBaseDesc->Type != D3D_SIT_STRUCTURED) {
  135. VERIFY_ARE_EQUAL(pBaseDesc->Type, D3D_SIT_TEXTURE);
  136. } else
  137. VERIFY_ARE_EQUAL(pTestDesc->Type, pBaseDesc->Type);
  138. // D3D_SIF_USERPACKED is never set in dxil.
  139. UINT unusedFlag = D3D_SIF_USERPACKED;
  140. VERIFY_ARE_EQUAL(pTestDesc->uFlags, pBaseDesc->uFlags & ~unusedFlag);
  141. // VERIFY_ARE_EQUAL(pTestDesc->uID, pBaseDesc->uID); // Like register, this can vary.
  142. }
  143. void CompareParameterDesc(D3D12_SIGNATURE_PARAMETER_DESC *pTestDesc,
  144. D3D12_SIGNATURE_PARAMETER_DESC *pBaseDesc, bool isInput) {
  145. VERIFY_ARE_EQUAL(0, _stricmp(pTestDesc->SemanticName, pBaseDesc->SemanticName));
  146. if (pTestDesc->SystemValueType == D3D_NAME_CLIP_DISTANCE) return; // currently generating multiple clip distance params, one per component
  147. VERIFY_ARE_EQUAL(pTestDesc->ComponentType, pBaseDesc->ComponentType);
  148. VERIFY_ARE_EQUAL(MaskCount(pTestDesc->Mask), MaskCount(pBaseDesc->Mask));
  149. VERIFY_ARE_EQUAL(pTestDesc->MinPrecision, pBaseDesc->MinPrecision);
  150. if (!isInput) {
  151. if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0)
  152. VERIFY_ARE_EQUAL(pTestDesc->ReadWriteMask != 0, pBaseDesc->ReadWriteMask != 0);
  153. else
  154. VERIFY_ARE_EQUAL(MaskCount(pTestDesc->ReadWriteMask), MaskCount(pBaseDesc->ReadWriteMask));
  155. }
  156. // VERIFY_ARE_EQUAL(pTestDesc->Register, pBaseDesc->Register);
  157. //VERIFY_ARE_EQUAL(pTestDesc->SemanticIndex, pBaseDesc->SemanticIndex);
  158. VERIFY_ARE_EQUAL(pTestDesc->Stream, pBaseDesc->Stream);
  159. VERIFY_ARE_EQUAL(pTestDesc->SystemValueType, pBaseDesc->SystemValueType);
  160. }
  161. void CompareType(ID3D12ShaderReflectionType *pTest,
  162. ID3D12ShaderReflectionType *pBase)
  163. {
  164. D3D12_SHADER_TYPE_DESC testDesc, baseDesc;
  165. VERIFY_SUCCEEDED(pTest->GetDesc(&testDesc));
  166. VERIFY_SUCCEEDED(pBase->GetDesc(&baseDesc));
  167. VERIFY_ARE_EQUAL(testDesc.Class, baseDesc.Class);
  168. VERIFY_ARE_EQUAL(testDesc.Type, baseDesc.Type);
  169. VERIFY_ARE_EQUAL(testDesc.Rows, baseDesc.Rows);
  170. VERIFY_ARE_EQUAL(testDesc.Columns, baseDesc.Columns);
  171. VERIFY_ARE_EQUAL(testDesc.Elements, baseDesc.Elements);
  172. VERIFY_ARE_EQUAL(testDesc.Members, baseDesc.Members);
  173. VERIFY_ARE_EQUAL(testDesc.Offset, baseDesc.Offset);
  174. VERIFY_ARE_EQUAL(0, strcmp(testDesc.Name, baseDesc.Name));
  175. for (UINT i = 0; i < baseDesc.Members; ++i) {
  176. ID3D12ShaderReflectionType* testMemberType = pTest->GetMemberTypeByIndex(i);
  177. ID3D12ShaderReflectionType* baseMemberType = pBase->GetMemberTypeByIndex(i);
  178. VERIFY_IS_NOT_NULL(testMemberType);
  179. VERIFY_IS_NOT_NULL(baseMemberType);
  180. CompareType(testMemberType, baseMemberType);
  181. LPCSTR testMemberName = pTest->GetMemberTypeName(i);
  182. LPCSTR baseMemberName = pBase->GetMemberTypeName(i);
  183. VERIFY_ARE_EQUAL(0, strcmp(testMemberName, baseMemberName));
  184. }
  185. }
  186. typedef HRESULT (__stdcall ID3D12ShaderReflection::*GetParameterDescFn)(UINT, D3D12_SIGNATURE_PARAMETER_DESC*);
  187. void SortNameIdxVector(std::vector<std::tuple<LPCSTR, UINT, UINT>> &value) {
  188. struct FirstPredT {
  189. bool operator()(std::tuple<LPCSTR, UINT, UINT> &l,
  190. std::tuple<LPCSTR, UINT, UINT> &r) {
  191. int strResult = strcmp(std::get<0>(l), std::get<0>(r));
  192. return (strResult < 0 ) || (strResult == 0 && std::get<1>(l) < std::get<1>(r));
  193. }
  194. } FirstPred;
  195. std::sort(value.begin(), value.end(), FirstPred);
  196. }
  197. void CompareParameterDescs(UINT count, ID3D12ShaderReflection *pTest,
  198. ID3D12ShaderReflection *pBase,
  199. GetParameterDescFn Fn, bool isInput) {
  200. std::vector<std::tuple<LPCSTR, UINT, UINT>> testParams, baseParams;
  201. testParams.reserve(count);
  202. baseParams.reserve(count);
  203. for (UINT i = 0; i < count; ++i) {
  204. D3D12_SIGNATURE_PARAMETER_DESC D;
  205. VERIFY_SUCCEEDED((pTest->*Fn)(i, &D));
  206. testParams.push_back(std::make_tuple(D.SemanticName, D.SemanticIndex, i));
  207. VERIFY_SUCCEEDED((pBase->*Fn)(i, &D));
  208. baseParams.push_back(std::make_tuple(D.SemanticName, D.SemanticIndex, i));
  209. }
  210. SortNameIdxVector(testParams);
  211. SortNameIdxVector(baseParams);
  212. for (UINT i = 0; i < count; ++i) {
  213. D3D12_SIGNATURE_PARAMETER_DESC testParamDesc, baseParamDesc;
  214. VERIFY_SUCCEEDED(
  215. (pTest->*Fn)(std::get<2>(testParams[i]), &testParamDesc));
  216. VERIFY_SUCCEEDED(
  217. (pBase->*Fn)(std::get<2>(baseParams[i]), &baseParamDesc));
  218. CompareParameterDesc(&testParamDesc, &baseParamDesc, isInput);
  219. }
  220. }
  221. void CompareReflection(ID3D12ShaderReflection *pTest, ID3D12ShaderReflection *pBase) {
  222. D3D12_SHADER_DESC testDesc, baseDesc;
  223. VERIFY_SUCCEEDED(pTest->GetDesc(&testDesc));
  224. VERIFY_SUCCEEDED(pBase->GetDesc(&baseDesc));
  225. VERIFY_ARE_EQUAL(D3D12_SHVER_GET_TYPE(testDesc.Version), D3D12_SHVER_GET_TYPE(baseDesc.Version));
  226. VERIFY_ARE_EQUAL(testDesc.ConstantBuffers, baseDesc.ConstantBuffers);
  227. VERIFY_ARE_EQUAL(testDesc.BoundResources, baseDesc.BoundResources);
  228. VERIFY_ARE_EQUAL(testDesc.InputParameters, baseDesc.InputParameters);
  229. VERIFY_ARE_EQUAL(testDesc.OutputParameters, baseDesc.OutputParameters);
  230. VERIFY_ARE_EQUAL(testDesc.PatchConstantParameters, baseDesc.PatchConstantParameters);
  231. {
  232. for (UINT i = 0; i < testDesc.ConstantBuffers; ++i) {
  233. ID3D12ShaderReflectionConstantBuffer *pTestCB, *pBaseCB;
  234. D3D12_SHADER_BUFFER_DESC testCB, baseCB;
  235. pTestCB = pTest->GetConstantBufferByIndex(i);
  236. VERIFY_SUCCEEDED(pTestCB->GetDesc(&testCB));
  237. pBaseCB = pBase->GetConstantBufferByName(testCB.Name);
  238. VERIFY_SUCCEEDED(pBaseCB->GetDesc(&baseCB));
  239. VERIFY_ARE_EQUAL_STR(testCB.Name, baseCB.Name);
  240. VERIFY_ARE_EQUAL(testCB.Type, baseCB.Type);
  241. VERIFY_ARE_EQUAL(testCB.Variables, baseCB.Variables);
  242. VERIFY_ARE_EQUAL(testCB.Size, baseCB.Size);
  243. VERIFY_ARE_EQUAL(testCB.uFlags, baseCB.uFlags);
  244. llvm::StringMap<D3D12_SHADER_VARIABLE_DESC> variableMap;
  245. llvm::StringMap<ID3D12ShaderReflectionType*> variableTypeMap;
  246. for (UINT vi = 0; vi < testCB.Variables; ++vi) {
  247. ID3D12ShaderReflectionVariable *pBaseConst;
  248. D3D12_SHADER_VARIABLE_DESC baseConst;
  249. pBaseConst = pBaseCB->GetVariableByIndex(vi);
  250. VERIFY_SUCCEEDED(pBaseConst->GetDesc(&baseConst));
  251. variableMap[baseConst.Name] = baseConst;
  252. ID3D12ShaderReflectionType* pBaseType = pBaseConst->GetType();
  253. VERIFY_IS_NOT_NULL(pBaseType);
  254. variableTypeMap[baseConst.Name] = pBaseType;
  255. }
  256. for (UINT vi = 0; vi < testCB.Variables; ++vi) {
  257. ID3D12ShaderReflectionVariable *pTestConst;
  258. D3D12_SHADER_VARIABLE_DESC testConst;
  259. pTestConst = pTestCB->GetVariableByIndex(vi);
  260. VERIFY_SUCCEEDED(pTestConst->GetDesc(&testConst));
  261. VERIFY_ARE_EQUAL(variableMap.count(testConst.Name), 1);
  262. D3D12_SHADER_VARIABLE_DESC baseConst = variableMap[testConst.Name];
  263. VERIFY_ARE_EQUAL(testConst.uFlags, baseConst.uFlags);
  264. VERIFY_ARE_EQUAL(testConst.StartOffset, baseConst.StartOffset);
  265. VERIFY_ARE_EQUAL(testConst.Size, baseConst.Size);
  266. ID3D12ShaderReflectionType* pTestType = pTestConst->GetType();
  267. VERIFY_IS_NOT_NULL(pTestType);
  268. VERIFY_ARE_EQUAL(variableTypeMap.count(testConst.Name), 1);
  269. ID3D12ShaderReflectionType* pBaseType = variableTypeMap[testConst.Name];
  270. CompareType(pTestType, pBaseType);
  271. }
  272. }
  273. }
  274. for (UINT i = 0; i < testDesc.BoundResources; ++i) {
  275. D3D12_SHADER_INPUT_BIND_DESC testParamDesc, baseParamDesc;
  276. VERIFY_SUCCEEDED(pTest->GetResourceBindingDesc(i, &testParamDesc), WStrFmt(L"i=%u", i));
  277. VERIFY_SUCCEEDED(pBase->GetResourceBindingDescByName(testParamDesc.Name, &baseParamDesc));
  278. CompareShaderInputBindDesc(&testParamDesc, &baseParamDesc);
  279. }
  280. CompareParameterDescs(testDesc.InputParameters, pTest, pBase, &ID3D12ShaderReflection::GetInputParameterDesc, true);
  281. CompareParameterDescs(testDesc.OutputParameters, pTest, pBase,
  282. &ID3D12ShaderReflection::GetOutputParameterDesc,
  283. false);
  284. bool isHs = testDesc.HSPartitioning != D3D_TESSELLATOR_PARTITIONING::D3D11_TESSELLATOR_PARTITIONING_UNDEFINED;
  285. CompareParameterDescs(
  286. testDesc.PatchConstantParameters, pTest, pBase,
  287. &ID3D12ShaderReflection::GetPatchConstantParameterDesc, !isHs);
  288. {
  289. UINT32 testTotal, testX, testY, testZ;
  290. UINT32 baseTotal, baseX, baseY, baseZ;
  291. testTotal = pTest->GetThreadGroupSize(&testX, &testY, &testZ);
  292. baseTotal = pBase->GetThreadGroupSize(&baseX, &baseY, &baseZ);
  293. VERIFY_ARE_EQUAL(testTotal, baseTotal);
  294. VERIFY_ARE_EQUAL(testX, baseX);
  295. VERIFY_ARE_EQUAL(testY, baseY);
  296. VERIFY_ARE_EQUAL(testZ, baseZ);
  297. }
  298. }
  299. #endif // _WIN32 - Reflection unsupported
  300. #ifdef _WIN32 // - Reflection unsupported
  301. HRESULT CompileFromFile(LPCWSTR path, bool useDXBC, IDxcBlob **ppBlob) {
  302. std::vector<FileRunCommandPart> parts;
  303. ParseCommandPartsFromFile(path, parts);
  304. VERIFY_IS_TRUE(parts.size() > 0);
  305. unsigned partIdx = 0;
  306. if (parts[0].Command.compare("%dxilver") == 0) {
  307. partIdx = 1;
  308. }
  309. FileRunCommandPart &dxc = parts[partIdx];
  310. VERIFY_ARE_EQUAL_STR(dxc.Command.c_str(), "%dxc");
  311. m_dllSupport.Initialize();
  312. hlsl::options::MainArgs args;
  313. hlsl::options::DxcOpts opts;
  314. dxc.ReadOptsForDxc(args, opts);
  315. if (opts.CodeGenHighLevel) return E_FAIL; // skip for now
  316. if (useDXBC) {
  317. // Consider supporting defines and flags if/when needed.
  318. std::string TargetProfile(opts.TargetProfile.str());
  319. TargetProfile[3] = '5'; TargetProfile[5] = '1';
  320. CComPtr<ID3DBlob> pDxbcBlob;
  321. CComPtr<ID3DBlob> pDxbcErrors;
  322. UINT unboundDescTab = (1 << 20);
  323. IFR(D3DCompileFromFile(path, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
  324. opts.EntryPoint.str().c_str(),
  325. TargetProfile.c_str(),
  326. unboundDescTab, 0, &pDxbcBlob, &pDxbcErrors));
  327. IFR(pDxbcBlob.QueryInterface(ppBlob));
  328. }
  329. else {
  330. FileRunCommandResult result = dxc.Run(m_dllSupport, nullptr);
  331. IFRBOOL(result.ExitCode == 0, E_FAIL);
  332. IFR(result.OpResult->GetResult(ppBlob));
  333. }
  334. return S_OK;
  335. }
  336. void CreateReflectionFromBlob(IDxcBlob *pBlob, ID3D12ShaderReflection **ppReflection) {
  337. CComPtr<IDxcContainerReflection> pReflection;
  338. UINT32 shaderIdx;
  339. m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection);
  340. VERIFY_SUCCEEDED(pReflection->Load(pBlob));
  341. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_DXIL, &shaderIdx));
  342. VERIFY_SUCCEEDED(pReflection->GetPartReflection(shaderIdx, __uuidof(ID3D12ShaderReflection), (void**)ppReflection));
  343. }
  344. void CreateReflectionFromDXBC(IDxcBlob *pBlob, ID3D12ShaderReflection **ppReflection) {
  345. VERIFY_SUCCEEDED(
  346. D3DReflect(pBlob->GetBufferPointer(), pBlob->GetBufferSize(),
  347. __uuidof(ID3D12ShaderReflection), (void **)ppReflection));
  348. }
  349. #endif // _WIN32 - Reflection unsupported
  350. void CompileToProgram(LPCSTR program, LPCWSTR entryPoint, LPCWSTR target,
  351. LPCWSTR *pArguments, UINT32 argCount,
  352. IDxcBlob **ppProgram,
  353. IDxcOperationResult **ppResult = nullptr) {
  354. CComPtr<IDxcCompiler> pCompiler;
  355. CComPtr<IDxcBlobEncoding> pSource;
  356. CComPtr<IDxcBlob> pProgram;
  357. CComPtr<IDxcOperationResult> pResult;
  358. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  359. CreateBlobFromText(program, &pSource);
  360. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", entryPoint,
  361. target, pArguments, argCount, nullptr,
  362. 0, nullptr, &pResult));
  363. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  364. *ppProgram = pProgram.Detach();
  365. if (ppResult)
  366. *ppResult = pResult.Detach();
  367. }
  368. bool DoesValidatorSupportDebugName() {
  369. CComPtr<IDxcVersionInfo> pVersionInfo;
  370. UINT Major, Minor;
  371. HRESULT hrVer = m_dllSupport.CreateInstance(CLSID_DxcValidator, &pVersionInfo);
  372. if (hrVer == E_NOINTERFACE) return false;
  373. VERIFY_SUCCEEDED(hrVer);
  374. VERIFY_SUCCEEDED(pVersionInfo->GetVersion(&Major, &Minor));
  375. return !(Major == 1 && Minor < 1);
  376. }
  377. bool DoesValidatorSupportShaderHash() {
  378. CComPtr<IDxcVersionInfo> pVersionInfo;
  379. UINT Major, Minor;
  380. HRESULT hrVer = m_dllSupport.CreateInstance(CLSID_DxcValidator, &pVersionInfo);
  381. if (hrVer == E_NOINTERFACE) return false;
  382. VERIFY_SUCCEEDED(hrVer);
  383. VERIFY_SUCCEEDED(pVersionInfo->GetVersion(&Major, &Minor));
  384. return !(Major == 1 && Minor < 5);
  385. }
  386. std::string CompileToDebugName(LPCSTR program, LPCWSTR entryPoint,
  387. LPCWSTR target, LPCWSTR *pArguments, UINT32 argCount) {
  388. CComPtr<IDxcBlob> pProgram;
  389. CComPtr<IDxcBlob> pNameBlob;
  390. CComPtr<IDxcContainerReflection> pContainer;
  391. UINT32 index;
  392. CompileToProgram(program, entryPoint, target, pArguments, argCount, &pProgram);
  393. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pContainer));
  394. VERIFY_SUCCEEDED(pContainer->Load(pProgram));
  395. if (FAILED(pContainer->FindFirstPartKind(hlsl::DFCC_ShaderDebugName, &index))) {
  396. return std::string();
  397. }
  398. VERIFY_SUCCEEDED(pContainer->GetPartContent(index, &pNameBlob));
  399. const hlsl::DxilShaderDebugName *pDebugName = (hlsl::DxilShaderDebugName *)pNameBlob->GetBufferPointer();
  400. return std::string((const char *)(pDebugName + 1));
  401. }
  402. std::string RetrieveHashFromBlob(IDxcBlob* pHashBlob) {
  403. VERIFY_ARE_NOT_EQUAL(pHashBlob, nullptr);
  404. VERIFY_ARE_EQUAL(pHashBlob->GetBufferSize(), sizeof(DxcShaderHash));
  405. const hlsl::DxilShaderHash *pShaderHash = (hlsl::DxilShaderHash *)pHashBlob->GetBufferPointer();
  406. std::string result;
  407. llvm::raw_string_ostream os(result);
  408. for (int i = 0; i < 16; ++i)
  409. os << llvm::format("%.2x", pShaderHash->Digest[i]);
  410. return os.str();
  411. }
  412. std::string CompileToShaderHash(LPCSTR program, LPCWSTR entryPoint,
  413. LPCWSTR target, LPCWSTR *pArguments, UINT32 argCount) {
  414. CComPtr<IDxcOperationResult> pResult;
  415. CComPtr<IDxcBlob> pProgram;
  416. CComPtr<IDxcBlob> pHashBlob;
  417. CComPtr<IDxcContainerReflection> pContainer;
  418. UINT32 index;
  419. CompileToProgram(program, entryPoint, target, pArguments, argCount, &pProgram, &pResult);
  420. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pContainer));
  421. VERIFY_SUCCEEDED(pContainer->Load(pProgram));
  422. if (FAILED(pContainer->FindFirstPartKind(hlsl::DFCC_ShaderHash, &index))) {
  423. return std::string();
  424. }
  425. VERIFY_SUCCEEDED(pContainer->GetPartContent(index, &pHashBlob));
  426. std::string hashFromPart = RetrieveHashFromBlob(pHashBlob);
  427. CComPtr<IDxcResult> pDxcResult;
  428. if (SUCCEEDED(pResult->QueryInterface(&pDxcResult))) {
  429. // Make sure shader hash was returned in result
  430. VERIFY_IS_TRUE(pDxcResult->HasOutput(DXC_OUT_SHADER_HASH));
  431. pHashBlob.Release();
  432. VERIFY_SUCCEEDED(pDxcResult->GetOutput(DXC_OUT_SHADER_HASH, IID_PPV_ARGS(&pHashBlob), nullptr));
  433. std::string hashFromResult = RetrieveHashFromBlob(pHashBlob);
  434. VERIFY_ARE_EQUAL(hashFromPart, hashFromPart);
  435. }
  436. return hashFromPart;
  437. }
  438. std::string DisassembleProgram(LPCSTR program, LPCWSTR entryPoint,
  439. LPCWSTR target) {
  440. CComPtr<IDxcCompiler> pCompiler;
  441. CComPtr<IDxcBlob> pProgram;
  442. CComPtr<IDxcBlobEncoding> pDisassembly;
  443. CompileToProgram(program, entryPoint, target, nullptr, 0, &pProgram);
  444. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  445. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  446. return BlobToUtf8(pDisassembly);
  447. }
  448. void SetupBasicHeader(hlsl::DxilContainerHeader *pHeader,
  449. uint32_t partCount = 0) {
  450. ZeroMemory(pHeader, sizeof(*pHeader));
  451. pHeader->HeaderFourCC = hlsl::DFCC_Container;
  452. pHeader->Version.Major = 1;
  453. pHeader->Version.Minor = 0;
  454. pHeader->PartCount = partCount;
  455. pHeader->ContainerSizeInBytes =
  456. sizeof(hlsl::DxilContainerHeader) +
  457. sizeof(uint32_t) * partCount +
  458. sizeof(hlsl::DxilPartHeader) * partCount;
  459. }
  460. void CodeGenTestCheck(LPCWSTR name) {
  461. std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
  462. FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath.c_str());
  463. if (t.RunResult != 0) {
  464. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  465. WEX::Logging::Log::Comment(commentWide);
  466. WEX::Logging::Log::Error(L"Run result is not zero");
  467. }
  468. }
  469. #ifdef _WIN32 // Reflection unsupported
  470. WEX::Common::String WStrFmt(const wchar_t* msg, ...) {
  471. va_list args;
  472. va_start(args, msg);
  473. WEX::Common::String result = WEX::Common::String().FormatV(msg, args);
  474. va_end(args);
  475. return result;
  476. }
  477. void ReflectionTest(LPCWSTR name, bool ignoreIfDXBCFails) {
  478. WEX::Logging::Log::Comment(WEX::Common::String().Format(L"Reflection comparison for %s", name));
  479. // Skip if unsupported.
  480. std::vector<FileRunCommandPart> parts;
  481. ParseCommandPartsFromFile(name, parts);
  482. VERIFY_IS_TRUE(parts.size() > 0);
  483. if (parts[0].Command.compare("%dxilver") == 0) {
  484. VERIFY_IS_TRUE(parts.size() > 1);
  485. auto result = parts[0].Run(m_dllSupport, nullptr);
  486. if (result.ExitCode != 0)
  487. return;
  488. }
  489. CComPtr<IDxcBlob> pProgram;
  490. CComPtr<IDxcBlob> pProgramDXBC;
  491. HRESULT hrDXBC = CompileFromFile(name, true, &pProgramDXBC);
  492. if (FAILED(hrDXBC)) {
  493. WEX::Logging::Log::Comment(L"Failed to compile DXBC blob.");
  494. if (ignoreIfDXBCFails) return;
  495. VERIFY_FAIL();
  496. }
  497. if (FAILED(CompileFromFile(name, false, &pProgram))) {
  498. WEX::Logging::Log::Comment(L"Failed to compile DXIL blob.");
  499. VERIFY_FAIL();
  500. }
  501. CComPtr<ID3D12ShaderReflection> pProgramReflection;
  502. CComPtr<ID3D12ShaderReflection> pProgramReflectionDXBC;
  503. CreateReflectionFromBlob(pProgram, &pProgramReflection);
  504. CreateReflectionFromDXBC(pProgramDXBC, &pProgramReflectionDXBC);
  505. CompareReflection(pProgramReflection, pProgramReflectionDXBC);
  506. }
  507. #endif // _WIN32 - Reflection unsupported
  508. };
  509. bool DxilContainerTest::InitSupport() {
  510. if (!m_dllSupport.IsEnabled()) {
  511. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  512. m_ver.Initialize(m_dllSupport);
  513. }
  514. return true;
  515. }
  516. #ifdef _WIN32
  517. TEST_F(DxilContainerTest, CompileWhenDebugSourceThenSourceMatters) {
  518. char program1[] = "float4 main() : SV_Target { return 0; }";
  519. char program2[] = " float4 main() : SV_Target { return 0; } ";
  520. LPCWSTR Zi[] = { L"/Zi", L"/Qembed_debug" };
  521. LPCWSTR ZiZss[] = { L"/Zi", L"/Qembed_debug", L"/Zss" };
  522. LPCWSTR ZiZsb[] = { L"/Zi", L"/Qembed_debug", L"/Zsb" };
  523. LPCWSTR Zsb[] = { L"/Zsb" };
  524. // No debug info, no debug name...
  525. std::string noName = CompileToDebugName(program1, L"main", L"ps_6_0", nullptr, 0);
  526. VERIFY_IS_TRUE(noName.empty());
  527. if (!DoesValidatorSupportDebugName())
  528. return;
  529. // Debug info, default to source name.
  530. std::string sourceName1 = CompileToDebugName(program1, L"main", L"ps_6_0", Zi, _countof(Zi));
  531. VERIFY_IS_FALSE(sourceName1.empty());
  532. // Deterministic naming.
  533. std::string sourceName1Again = CompileToDebugName(program1, L"main", L"ps_6_0", Zi, _countof(Zi));
  534. VERIFY_ARE_EQUAL_STR(sourceName1.c_str(), sourceName1Again.c_str());
  535. // Use program binary by default, so name should be the same.
  536. std::string sourceName2 = CompileToDebugName(program2, L"main", L"ps_6_0", Zi, _countof(Zi));
  537. VERIFY_IS_TRUE(0 == strcmp(sourceName2.c_str(), sourceName1.c_str()));
  538. // Source again, different because different switches are specified.
  539. std::string sourceName1Zss = CompileToDebugName(program1, L"main", L"ps_6_0", ZiZss, _countof(ZiZss));
  540. VERIFY_IS_FALSE(0 == strcmp(sourceName1Zss.c_str(), sourceName1.c_str()));
  541. // Binary program 1 and 2 should be different from source and equal to each other.
  542. std::string binName1 = CompileToDebugName(program1, L"main", L"ps_6_0", ZiZsb, _countof(ZiZsb));
  543. std::string binName2 = CompileToDebugName(program2, L"main", L"ps_6_0", ZiZsb, _countof(ZiZsb));
  544. VERIFY_ARE_EQUAL_STR(binName1.c_str(), binName2.c_str());
  545. VERIFY_IS_FALSE(0 == strcmp(sourceName1Zss.c_str(), binName1.c_str()));
  546. if (!DoesValidatorSupportShaderHash())
  547. return;
  548. // Verify source hash
  549. std::string binHash1Zss = CompileToShaderHash(program1, L"main", L"ps_6_0", ZiZss, _countof(ZiZss));
  550. VERIFY_IS_FALSE(binHash1Zss.empty());
  551. // bin hash when compiling with /Zi
  552. std::string binHash1 = CompileToShaderHash(program1, L"main", L"ps_6_0", ZiZsb, _countof(ZiZsb));
  553. VERIFY_IS_FALSE(binHash1.empty());
  554. // Without /Zi hash for /Zsb should be the same
  555. std::string binHash2 = CompileToShaderHash(program2, L"main", L"ps_6_0", Zsb, _countof(Zsb));
  556. VERIFY_IS_FALSE(binHash2.empty());
  557. VERIFY_ARE_EQUAL_STR(binHash1.c_str(), binHash2.c_str());
  558. // Source hash and bin hash should be different
  559. VERIFY_IS_FALSE(0 == strcmp(binHash1Zss.c_str(), binHash1.c_str()));
  560. }
  561. #endif // _WIN32
  562. TEST_F(DxilContainerTest, CompileWhenOKThenIncludesSignatures) {
  563. char program[] =
  564. "struct PSInput {\r\n"
  565. " float4 position : SV_POSITION;\r\n"
  566. " float4 color : COLOR;\r\n"
  567. "};\r\n"
  568. "PSInput VSMain(float4 position : POSITION, float4 color : COLOR) {\r\n"
  569. " PSInput result;\r\n"
  570. " result.position = position;\r\n"
  571. " result.color = color;\r\n"
  572. " return result;\r\n"
  573. "}\r\n"
  574. "float4 PSMain(PSInput input) : SV_TARGET {\r\n"
  575. " return input.color;\r\n"
  576. "}";
  577. {
  578. std::string s = DisassembleProgram(program, L"VSMain", L"vs_6_0");
  579. // NOTE: this will change when proper packing is done, and when 'always-reads' is accurately implemented.
  580. const char expected_1_4[] =
  581. ";\n"
  582. "; Input signature:\n"
  583. ";\n"
  584. "; Name Index Mask Register SysValue Format Used\n"
  585. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  586. "; POSITION 0 xyzw 0 NONE float \n" // should read 'xyzw' in Used
  587. "; COLOR 0 xyzw 1 NONE float \n" // should read '1' in register
  588. ";\n"
  589. ";\n"
  590. "; Output signature:\n"
  591. ";\n"
  592. "; Name Index Mask Register SysValue Format Used\n"
  593. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  594. "; SV_Position 0 xyzw 0 POS float xyzw\n" // could read SV_POSITION
  595. "; COLOR 0 xyzw 1 NONE float xyzw\n"; // should read '1' in register
  596. const char expected[] =
  597. ";\n"
  598. "; Input signature:\n"
  599. ";\n"
  600. "; Name Index Mask Register SysValue Format Used\n"
  601. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  602. "; POSITION 0 xyzw 0 NONE float xyzw\n" // should read 'xyzw' in Used
  603. "; COLOR 0 xyzw 1 NONE float xyzw\n" // should read '1' in register
  604. ";\n"
  605. ";\n"
  606. "; Output signature:\n"
  607. ";\n"
  608. "; Name Index Mask Register SysValue Format Used\n"
  609. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  610. "; SV_Position 0 xyzw 0 POS float xyzw\n" // could read SV_POSITION
  611. "; COLOR 0 xyzw 1 NONE float xyzw\n"; // should read '1' in register
  612. if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0) {
  613. std::string start(s.c_str(), strlen(expected_1_4));
  614. VERIFY_ARE_EQUAL_STR(expected_1_4, start.c_str());
  615. } else {
  616. std::string start(s.c_str(), strlen(expected));
  617. VERIFY_ARE_EQUAL_STR(expected, start.c_str());
  618. }
  619. }
  620. {
  621. std::string s = DisassembleProgram(program, L"PSMain", L"ps_6_0");
  622. // NOTE: this will change when proper packing is done, and when 'always-reads' is accurately implemented.
  623. const char expected_1_4[] =
  624. ";\n"
  625. "; Input signature:\n"
  626. ";\n"
  627. "; Name Index Mask Register SysValue Format Used\n"
  628. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  629. "; SV_Position 0 xyzw 0 POS float \n" // could read SV_POSITION
  630. "; COLOR 0 xyzw 1 NONE float \n" // should read '1' in register, xyzw in Used
  631. ";\n"
  632. ";\n"
  633. "; Output signature:\n"
  634. ";\n"
  635. "; Name Index Mask Register SysValue Format Used\n"
  636. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  637. "; SV_Target 0 xyzw 0 TARGET float xyzw\n";// could read SV_TARGET
  638. const char expected[] =
  639. ";\n"
  640. "; Input signature:\n"
  641. ";\n"
  642. "; Name Index Mask Register SysValue Format Used\n"
  643. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  644. "; SV_Position 0 xyzw 0 POS float \n" // could read SV_POSITION
  645. "; COLOR 0 xyzw 1 NONE float xyzw\n" // should read '1' in register, xyzw in Used
  646. ";\n"
  647. ";\n"
  648. "; Output signature:\n"
  649. ";\n"
  650. "; Name Index Mask Register SysValue Format Used\n"
  651. "; -------------------- ----- ------ -------- -------- ------- ------\n"
  652. "; SV_Target 0 xyzw 0 TARGET float xyzw\n";// could read SV_TARGET
  653. if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0) {
  654. std::string start(s.c_str(), strlen(expected_1_4));
  655. VERIFY_ARE_EQUAL_STR(expected_1_4, start.c_str());
  656. } else {
  657. std::string start(s.c_str(), strlen(expected));
  658. VERIFY_ARE_EQUAL_STR(expected, start.c_str());
  659. }
  660. }
  661. }
  662. TEST_F(DxilContainerTest, CompileWhenSigSquareThenIncludeSplit) {
  663. #if 0 // TODO: reenable test when multiple rows are supported.
  664. const char program[] =
  665. "float main(float4x4 a : A, int4 b : B) : SV_Target {\n"
  666. " return a[b.x][b.y];\n"
  667. "}";
  668. std::string s = DisassembleProgram(program, L"main", L"ps_6_0");
  669. const char expected[] =
  670. "// Input signature:\n"
  671. "//\n"
  672. "// Name Index Mask Register SysValue Format Used\n"
  673. "// -------------------- ----- ------ -------- -------- ------- ------\n"
  674. "// A 0 xyzw 0 NONE float xyzw\n"
  675. "// A 1 xyzw 1 NONE float xyzw\n"
  676. "// A 2 xyzw 2 NONE float xyzw\n"
  677. "// A 3 xyzw 3 NONE float xyzw\n"
  678. "// B 0 xyzw 4 NONE int xy\n"
  679. "//\n"
  680. "//\n"
  681. "// Output signature:\n"
  682. "//\n"
  683. "// Name Index Mask Register SysValue Format Used\n"
  684. "// -------------------- ----- ------ -------- -------- ------- ------\n"
  685. "// SV_Target 0 x 0 TARGET float x\n";
  686. std::string start(s.c_str(), strlen(expected));
  687. VERIFY_ARE_EQUAL_STR(expected, start.c_str());
  688. #endif
  689. }
  690. TEST_F(DxilContainerTest, CompileAS_CheckPSV0) {
  691. if (m_ver.SkipDxilVersion(1, 5)) return;
  692. const char asSource[] =
  693. "struct PayloadType { uint a, b, c; };\n"
  694. "[shader(\"amplification\")]\n"
  695. "[numthreads(1,1,1)]\n"
  696. "void main(uint idx : SV_GroupIndex) {\n"
  697. " PayloadType p = { idx, 2, 3 };\n"
  698. " DispatchMesh(1,1,1, p);\n"
  699. "}";
  700. CComPtr<IDxcCompiler> pCompiler;
  701. CComPtr<IDxcBlobEncoding> pSource;
  702. CComPtr<IDxcBlob> pProgram;
  703. CComPtr<IDxcOperationResult> pResult;
  704. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  705. CreateBlobFromText(asSource, &pSource);
  706. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main",
  707. L"as_6_5", nullptr, 0, nullptr, 0,
  708. nullptr, &pResult));
  709. HRESULT hrStatus;
  710. VERIFY_SUCCEEDED(pResult->GetStatus(&hrStatus));
  711. VERIFY_SUCCEEDED(hrStatus);
  712. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  713. CComPtr<IDxcContainerReflection> containerReflection;
  714. uint32_t partCount;
  715. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
  716. IFT(containerReflection->Load(pProgram));
  717. IFT(containerReflection->GetPartCount(&partCount));
  718. bool blobFound = false;
  719. for (uint32_t i = 0; i < partCount; ++i) {
  720. uint32_t kind;
  721. VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
  722. if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_PipelineStateValidation) {
  723. blobFound = true;
  724. CComPtr<IDxcBlob> pBlob;
  725. VERIFY_SUCCEEDED(containerReflection->GetPartContent(i, &pBlob));
  726. DxilPipelineStateValidation PSV;
  727. PSV.InitFromPSV0(pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  728. PSVShaderKind kind = PSV.GetShaderKind();
  729. VERIFY_ARE_EQUAL(PSVShaderKind::Amplification, kind);
  730. PSVRuntimeInfo0* pInfo = PSV.GetPSVRuntimeInfo0();
  731. VERIFY_IS_NOT_NULL(pInfo);
  732. VERIFY_ARE_EQUAL(12, pInfo->AS.PayloadSizeInBytes);
  733. break;
  734. }
  735. }
  736. VERIFY_IS_TRUE(blobFound);
  737. }
  738. TEST_F(DxilContainerTest, CompileWhenOkThenCheckRDAT) {
  739. if (m_ver.SkipDxilVersion(1, 3)) return;
  740. const char *shader = "float c_buf;"
  741. "RWTexture1D<int4> tex : register(u5);"
  742. "Texture1D<float4> tex2 : register(t0);"
  743. "RWByteAddressBuffer b_buf;"
  744. "struct Foo { float2 f2; int2 i2; };"
  745. "AppendStructuredBuffer<Foo> append_buf;"
  746. "ConsumeStructuredBuffer<Foo> consume_buf;"
  747. "RasterizerOrderedByteAddressBuffer rov_buf;"
  748. "globallycoherent RWByteAddressBuffer gc_buf;"
  749. "float function_import(float x);"
  750. "export float function0(min16float x) { "
  751. " return x + 1 + tex[0].x; }"
  752. "export float function1(float x, min12int i) {"
  753. " return x + c_buf + b_buf.Load(x) + tex2[i].x; }"
  754. "export float function2(float x) { return x + function_import(x); }"
  755. "export void function3(int i) {"
  756. " Foo f = consume_buf.Consume();"
  757. " f.f2 += 0.5; append_buf.Append(f);"
  758. " rov_buf.Store(i, f.i2.x);"
  759. " gc_buf.Store(i, f.i2.y);"
  760. " b_buf.Store(i, f.i2.x + f.i2.y); }";
  761. CComPtr<IDxcCompiler> pCompiler;
  762. CComPtr<IDxcBlobEncoding> pSource;
  763. CComPtr<IDxcBlob> pProgram;
  764. CComPtr<IDxcBlobEncoding> pDisassembly;
  765. CComPtr<IDxcOperationResult> pResult;
  766. struct CheckResFlagInfo { std::string name; hlsl::DXIL::ResourceKind kind; hlsl::RDAT::DxilResourceFlag flag; };
  767. const unsigned numResFlagCheck = 5;
  768. CheckResFlagInfo resFlags[numResFlagCheck] = {
  769. { "b_buf", hlsl::DXIL::ResourceKind::RawBuffer, hlsl::RDAT::DxilResourceFlag::None },
  770. { "append_buf", hlsl::DXIL::ResourceKind::StructuredBuffer, hlsl::RDAT::DxilResourceFlag::UAVCounter },
  771. { "consume_buf", hlsl::DXIL::ResourceKind::StructuredBuffer, hlsl::RDAT::DxilResourceFlag::UAVCounter },
  772. { "gc_buf", hlsl::DXIL::ResourceKind::RawBuffer, hlsl::RDAT::DxilResourceFlag::UAVGloballyCoherent },
  773. { "rov_buf", hlsl::DXIL::ResourceKind::RawBuffer, hlsl::RDAT::DxilResourceFlag::UAVRasterizerOrderedView }
  774. };
  775. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  776. CreateBlobFromText(shader, &pSource);
  777. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main",
  778. L"lib_6_3", nullptr, 0, nullptr, 0,
  779. nullptr, &pResult));
  780. HRESULT hrStatus;
  781. VERIFY_SUCCEEDED(pResult->GetStatus(&hrStatus));
  782. VERIFY_SUCCEEDED(hrStatus);
  783. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  784. CComPtr<IDxcContainerReflection> containerReflection;
  785. uint32_t partCount;
  786. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
  787. IFT(containerReflection->Load(pProgram));
  788. IFT(containerReflection->GetPartCount(&partCount));
  789. bool blobFound = false;
  790. for (uint32_t i = 0; i < partCount; ++i) {
  791. uint32_t kind;
  792. IFT(containerReflection->GetPartKind(i, &kind));
  793. if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_RuntimeData) {
  794. blobFound = true;
  795. using namespace hlsl::RDAT;
  796. CComPtr<IDxcBlob> pBlob;
  797. IFT(containerReflection->GetPartContent(i, &pBlob));
  798. // Validate using DxilRuntimeData
  799. DxilRuntimeData context;
  800. context.InitFromRDAT((char *)pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  801. FunctionTableReader *funcTableReader = context.GetFunctionTableReader();
  802. ResourceTableReader *resTableReader = context.GetResourceTableReader();
  803. VERIFY_ARE_EQUAL(funcTableReader->GetNumFunctions(), 4);
  804. std::string str("function");
  805. for (uint32_t j = 0; j < funcTableReader->GetNumFunctions(); ++j) {
  806. FunctionReader funcReader = funcTableReader->GetItem(j);
  807. std::string funcName(funcReader.GetUnmangledName());
  808. VERIFY_IS_TRUE(str.compare(funcName.substr(0,8)) == 0);
  809. std::string cur_str = str;
  810. cur_str.push_back('0' + j);
  811. if (cur_str.compare("function0") == 0) {
  812. VERIFY_ARE_EQUAL(funcReader.GetNumResources(), 1);
  813. hlsl::ShaderFlags flag;
  814. flag.SetUAVLoadAdditionalFormats(true);
  815. flag.SetLowPrecisionPresent(true);
  816. uint64_t rawFlag = flag.GetFeatureInfo();
  817. VERIFY_ARE_EQUAL(funcReader.GetFeatureFlag(), rawFlag);
  818. ResourceReader resReader = funcReader.GetResource(0);
  819. VERIFY_ARE_EQUAL(resReader.GetResourceClass(), hlsl::DXIL::ResourceClass::UAV);
  820. VERIFY_ARE_EQUAL(resReader.GetResourceKind(), hlsl::DXIL::ResourceKind::Texture1D);
  821. }
  822. else if (cur_str.compare("function1") == 0) {
  823. hlsl::ShaderFlags flag;
  824. flag.SetLowPrecisionPresent(true);
  825. uint64_t rawFlag = flag.GetFeatureInfo();
  826. VERIFY_ARE_EQUAL(funcReader.GetFeatureFlag(), rawFlag);
  827. VERIFY_ARE_EQUAL(funcReader.GetNumResources(), 3);
  828. }
  829. else if (cur_str.compare("function2") == 0) {
  830. VERIFY_ARE_EQUAL(funcReader.GetFeatureFlag() & 0xffffffffffffffff, 0);
  831. VERIFY_ARE_EQUAL(funcReader.GetNumResources(), 0);
  832. std::string dependency = funcReader.GetDependency(0);
  833. VERIFY_IS_TRUE(dependency.find("function_import") != std::string::npos);
  834. }
  835. else if (cur_str.compare("function3") == 0) {
  836. VERIFY_ARE_EQUAL(funcReader.GetFeatureFlag() & 0xffffffffffffffff, 0);
  837. VERIFY_ARE_EQUAL(funcReader.GetNumResources(), numResFlagCheck);
  838. for (unsigned i = 0; i < funcReader.GetNumResources(); ++i) {
  839. ResourceReader resReader = funcReader.GetResource(0);
  840. VERIFY_ARE_EQUAL(resReader.GetResourceClass(), hlsl::DXIL::ResourceClass::UAV);
  841. unsigned j = 0;
  842. for (; j < numResFlagCheck; ++j) {
  843. if (resFlags[j].name.compare(resReader.GetName()) == 0)
  844. break;
  845. }
  846. VERIFY_IS_LESS_THAN(j, numResFlagCheck);
  847. VERIFY_ARE_EQUAL(resReader.GetResourceKind(), resFlags[j].kind);
  848. VERIFY_ARE_EQUAL(resReader.GetFlags(), static_cast<uint32_t>(resFlags[j].flag));
  849. }
  850. }
  851. else {
  852. IFTBOOLMSG(false, E_FAIL, "unknown function name");
  853. }
  854. }
  855. VERIFY_ARE_EQUAL(resTableReader->GetNumResources(), 8);
  856. // This is validation test for DxilRuntimeReflection implemented on DxilRuntimeReflection.inl
  857. unique_ptr<DxilRuntimeReflection> pReflection(CreateDxilRuntimeReflection());
  858. VERIFY_IS_TRUE(pReflection->InitFromRDAT(pBlob->GetBufferPointer(), pBlob->GetBufferSize()));
  859. DxilLibraryDesc lib_reflection = pReflection->GetLibraryReflection();
  860. VERIFY_ARE_EQUAL(lib_reflection.NumFunctions, 4);
  861. for (uint32_t j = 0; j < 3; ++j) {
  862. DxilFunctionDesc function = lib_reflection.pFunction[j];
  863. std::string cur_str = str;
  864. cur_str.push_back('0' + j);
  865. if (cur_str.compare("function0") == 0) {
  866. hlsl::ShaderFlags flag;
  867. flag.SetUAVLoadAdditionalFormats(true);
  868. flag.SetLowPrecisionPresent(true);
  869. uint64_t rawFlag = flag.GetFeatureInfo();
  870. uint64_t featureFlag = static_cast<uint64_t>(function.FeatureInfo2) << 32;
  871. featureFlag |= static_cast<uint64_t>(function.FeatureInfo1);
  872. VERIFY_ARE_EQUAL(featureFlag, rawFlag);
  873. VERIFY_ARE_EQUAL(function.NumResources, 1);
  874. VERIFY_ARE_EQUAL(function.NumFunctionDependencies, 0);
  875. const DxilResourceDesc &resource = *function.Resources[0];
  876. VERIFY_ARE_EQUAL(resource.Class, (uint32_t)hlsl::DXIL::ResourceClass::UAV);
  877. VERIFY_ARE_EQUAL(resource.Kind, (uint32_t)hlsl::DXIL::ResourceKind::Texture1D);
  878. std::wstring wName = resource.Name;
  879. VERIFY_ARE_EQUAL(wName.compare(L"tex"), 0);
  880. }
  881. else if (cur_str.compare("function1") == 0) {
  882. hlsl::ShaderFlags flag;
  883. flag.SetLowPrecisionPresent(true);
  884. uint64_t rawFlag = flag.GetFeatureInfo();
  885. uint64_t featureFlag = static_cast<uint64_t>(function.FeatureInfo2) << 32;
  886. featureFlag |= static_cast<uint64_t>(function.FeatureInfo1);
  887. VERIFY_ARE_EQUAL(featureFlag, rawFlag);
  888. VERIFY_ARE_EQUAL(function.NumResources, 3);
  889. VERIFY_ARE_EQUAL(function.NumFunctionDependencies, 0);
  890. std::unordered_set<std::wstring> stringSet = { L"$Globals", L"b_buf", L"tex2" };
  891. for (uint32_t j = 0; j < 3; ++j) {
  892. const DxilResourceDesc &resource = *function.Resources[j];
  893. std::wstring compareName = resource.Name;
  894. VERIFY_IS_TRUE(stringSet.find(compareName) != stringSet.end());
  895. }
  896. }
  897. else if (cur_str.compare("function2") == 0) {
  898. VERIFY_ARE_EQUAL(function.FeatureInfo1, 0);
  899. VERIFY_ARE_EQUAL(function.FeatureInfo2, 0);
  900. VERIFY_ARE_EQUAL(function.NumResources, 0);
  901. VERIFY_ARE_EQUAL(function.NumFunctionDependencies, 1);
  902. std::wstring dependency = function.FunctionDependencies[0];
  903. VERIFY_IS_TRUE(dependency.find(L"function_import") != std::wstring::npos);
  904. }
  905. else if (cur_str.compare("function3") == 0) {
  906. VERIFY_ARE_EQUAL(function.FeatureInfo1, 0);
  907. VERIFY_ARE_EQUAL(function.FeatureInfo2, 0);
  908. VERIFY_ARE_EQUAL(function.NumResources, numResFlagCheck);
  909. VERIFY_ARE_EQUAL(function.NumFunctionDependencies, 0);
  910. for (unsigned i = 0; i < function.NumResources; ++i) {
  911. const DxilResourceDesc *res = function.Resources[i];
  912. VERIFY_ARE_EQUAL(res->Class, static_cast<uint32_t>(hlsl::DXIL::ResourceClass::UAV));
  913. unsigned j = 0;
  914. for (; j < numResFlagCheck; ++j) {
  915. CA2W WName(resFlags[j].name.c_str());
  916. std::wstring compareName(WName);
  917. if (compareName.compare(res->Name) == 0)
  918. break;
  919. }
  920. VERIFY_IS_LESS_THAN(j, numResFlagCheck);
  921. VERIFY_ARE_EQUAL(res->Kind, static_cast<uint32_t>(resFlags[j].kind));
  922. VERIFY_ARE_EQUAL(res->Flags, static_cast<uint32_t>(resFlags[j].flag));
  923. }
  924. }
  925. else {
  926. IFTBOOLMSG(false, E_FAIL, "unknown function name");
  927. }
  928. }
  929. VERIFY_IS_TRUE(lib_reflection.NumResources == 8);
  930. }
  931. }
  932. IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
  933. }
  934. TEST_F(DxilContainerTest, CompileWhenOkThenCheckRDAT2) {
  935. if (m_ver.SkipDxilVersion(1, 3)) return;
  936. // This is a case when the user of resource is a constant, not instruction.
  937. // Compiler generates the following load instruction for texture.
  938. // load %class.Texture2D, %class.Texture2D* getelementptr inbounds ([3 x
  939. // %class.Texture2D], [3 x %class.Texture2D]*
  940. // @"\01?ThreeTextures@@3PAV?$Texture2D@M@@A", i32 0, i32 0), align 4
  941. const char *shader =
  942. "SamplerState Sampler : register(s0); RWBuffer<float> Uav : "
  943. "register(u0); Texture2D<float> ThreeTextures[3] : register(t0); "
  944. "float function1();"
  945. "[shader(\"raygeneration\")] void RayGenMain() { Uav[0] = "
  946. "ThreeTextures[0].SampleLevel(Sampler, float2(0, 0), 0) + "
  947. "ThreeTextures[2].SampleLevel(Sampler, float2(0, 0), 0) + function1(); }";
  948. CComPtr<IDxcCompiler> pCompiler;
  949. CComPtr<IDxcBlobEncoding> pSource;
  950. CComPtr<IDxcBlob> pProgram;
  951. CComPtr<IDxcBlobEncoding> pDisassembly;
  952. CComPtr<IDxcOperationResult> pResult;
  953. HRESULT status;
  954. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  955. CreateBlobFromText(shader, &pSource);
  956. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main",
  957. L"lib_6_3", nullptr, 0, nullptr, 0,
  958. nullptr, &pResult));
  959. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  960. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  961. VERIFY_SUCCEEDED(status);
  962. CComPtr<IDxcContainerReflection> pReflection;
  963. uint32_t partCount;
  964. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  965. IFT(pReflection->Load(pProgram));
  966. IFT(pReflection->GetPartCount(&partCount));
  967. bool blobFound = false;
  968. for (uint32_t i = 0; i < partCount; ++i) {
  969. uint32_t kind;
  970. IFT(pReflection->GetPartKind(i, &kind));
  971. if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_RuntimeData) {
  972. blobFound = true;
  973. using namespace hlsl::RDAT;
  974. CComPtr<IDxcBlob> pBlob;
  975. IFT(pReflection->GetPartContent(i, &pBlob));
  976. DxilRuntimeData context;
  977. context.InitFromRDAT((char *)pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  978. FunctionTableReader *funcTableReader = context.GetFunctionTableReader();
  979. ResourceTableReader *resTableReader = context.GetResourceTableReader();
  980. VERIFY_IS_TRUE(funcTableReader->GetNumFunctions() == 1);
  981. VERIFY_IS_TRUE(resTableReader->GetNumResources() == 3);
  982. FunctionReader funcReader = funcTableReader->GetItem(0);
  983. llvm::StringRef name(funcReader.GetUnmangledName());
  984. VERIFY_IS_TRUE(name.compare("RayGenMain") == 0);
  985. VERIFY_IS_TRUE(funcReader.GetShaderKind() ==
  986. hlsl::DXIL::ShaderKind::RayGeneration);
  987. VERIFY_IS_TRUE(funcReader.GetNumResources() == 3);
  988. VERIFY_IS_TRUE(funcReader.GetNumDependencies() == 1);
  989. llvm::StringRef dependencyName =
  990. hlsl::dxilutil::DemangleFunctionName(funcReader.GetDependency(0));
  991. VERIFY_IS_TRUE(dependencyName.compare("function1") == 0);
  992. }
  993. }
  994. IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
  995. }
  996. static uint32_t EncodedVersion_lib_6_3 = hlsl::EncodeVersion(hlsl::DXIL::ShaderKind::Library, 6, 3);
  997. static uint32_t EncodedVersion_vs_6_3 = hlsl::EncodeVersion(hlsl::DXIL::ShaderKind::Vertex, 6, 3);
  998. static void Ref1_CheckCBuffer_Globals(ID3D12ShaderReflectionConstantBuffer *pCBReflection, D3D12_SHADER_BUFFER_DESC &cbDesc) {
  999. std::string cbName = cbDesc.Name;
  1000. VERIFY_IS_TRUE(cbName.compare("$Globals") == 0);
  1001. VERIFY_ARE_EQUAL(cbDesc.Size, 16);
  1002. VERIFY_ARE_EQUAL(cbDesc.Type, D3D_CT_CBUFFER);
  1003. VERIFY_ARE_EQUAL(cbDesc.Variables, 1);
  1004. // cbval1
  1005. ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(0);
  1006. D3D12_SHADER_VARIABLE_DESC varDesc;
  1007. VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
  1008. VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval1");
  1009. VERIFY_ARE_EQUAL(varDesc.StartOffset, 0);
  1010. VERIFY_ARE_EQUAL(varDesc.Size, 4);
  1011. // TODO: verify rest of variable
  1012. ID3D12ShaderReflectionType *pType = pVar->GetType();
  1013. D3D12_SHADER_TYPE_DESC tyDesc;
  1014. VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
  1015. VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_SCALAR);
  1016. VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_FLOAT);
  1017. // TODO: verify rest of type
  1018. }
  1019. static void Ref1_CheckCBuffer_MyCB(ID3D12ShaderReflectionConstantBuffer *pCBReflection, D3D12_SHADER_BUFFER_DESC &cbDesc) {
  1020. std::string cbName = cbDesc.Name;
  1021. VERIFY_IS_TRUE(cbName.compare("MyCB") == 0);
  1022. VERIFY_ARE_EQUAL(cbDesc.Size, 32);
  1023. VERIFY_ARE_EQUAL(cbDesc.Type, D3D_CT_CBUFFER);
  1024. VERIFY_ARE_EQUAL(cbDesc.Variables, 2);
  1025. // cbval2
  1026. {
  1027. ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(0);
  1028. D3D12_SHADER_VARIABLE_DESC varDesc;
  1029. VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
  1030. VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval2");
  1031. VERIFY_ARE_EQUAL(varDesc.StartOffset, 0);
  1032. VERIFY_ARE_EQUAL(varDesc.Size, 16);
  1033. // TODO: verify rest of variable
  1034. ID3D12ShaderReflectionType *pType = pVar->GetType();
  1035. D3D12_SHADER_TYPE_DESC tyDesc;
  1036. VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
  1037. VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_VECTOR);
  1038. VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_INT);
  1039. // TODO: verify rest of type
  1040. }
  1041. // cbval3
  1042. {
  1043. ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(1);
  1044. D3D12_SHADER_VARIABLE_DESC varDesc;
  1045. VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
  1046. VERIFY_ARE_EQUAL_STR(varDesc.Name, "cbval3");
  1047. VERIFY_ARE_EQUAL(varDesc.StartOffset, 16);
  1048. VERIFY_ARE_EQUAL(varDesc.Size, 16);
  1049. // TODO: verify rest of variable
  1050. ID3D12ShaderReflectionType *pType = pVar->GetType();
  1051. D3D12_SHADER_TYPE_DESC tyDesc;
  1052. VERIFY_SUCCEEDED(pType->GetDesc(&tyDesc));
  1053. VERIFY_ARE_EQUAL(tyDesc.Class, D3D_SVC_VECTOR);
  1054. VERIFY_ARE_EQUAL(tyDesc.Type, D3D_SVT_INT);
  1055. // TODO: verify rest of type
  1056. }
  1057. }
  1058. static void Ref1_CheckBinding_Globals(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1059. std::string resName = resDesc.Name;
  1060. VERIFY_IS_TRUE(resName.compare("$Globals") == 0);
  1061. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_CBUFFER);
  1062. // not explicitly bound:
  1063. VERIFY_ARE_EQUAL(resDesc.BindPoint, 4294967295);
  1064. VERIFY_ARE_EQUAL(resDesc.Space, 0);
  1065. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1066. }
  1067. static void Ref1_CheckBinding_MyCB(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1068. std::string resName = resDesc.Name;
  1069. VERIFY_IS_TRUE(resName.compare("MyCB") == 0);
  1070. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_CBUFFER);
  1071. VERIFY_ARE_EQUAL(resDesc.BindPoint, 11);
  1072. VERIFY_ARE_EQUAL(resDesc.Space, 2);
  1073. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1074. }
  1075. static void Ref1_CheckBinding_tex(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1076. std::string resName = resDesc.Name;
  1077. VERIFY_IS_TRUE(resName.compare("tex") == 0);
  1078. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_UAV_RWTYPED);
  1079. VERIFY_ARE_EQUAL(resDesc.BindPoint, 5);
  1080. VERIFY_ARE_EQUAL(resDesc.Space, 0);
  1081. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1082. }
  1083. static void Ref1_CheckBinding_tex2(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1084. std::string resName = resDesc.Name;
  1085. VERIFY_IS_TRUE(resName.compare("tex2") == 0);
  1086. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_TEXTURE);
  1087. VERIFY_ARE_EQUAL(resDesc.BindPoint, 0);
  1088. VERIFY_ARE_EQUAL(resDesc.Space, 0);
  1089. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1090. }
  1091. static void Ref1_CheckBinding_samp(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1092. std::string resName = resDesc.Name;
  1093. VERIFY_IS_TRUE(resName.compare("samp") == 0);
  1094. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_SAMPLER);
  1095. VERIFY_ARE_EQUAL(resDesc.BindPoint, 7);
  1096. VERIFY_ARE_EQUAL(resDesc.Space, 0);
  1097. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1098. }
  1099. static void Ref1_CheckBinding_b_buf(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
  1100. std::string resName = resDesc.Name;
  1101. VERIFY_IS_TRUE(resName.compare("b_buf") == 0);
  1102. VERIFY_ARE_EQUAL(resDesc.Type, D3D_SIT_UAV_RWBYTEADDRESS);
  1103. // not explicitly bound:
  1104. VERIFY_ARE_EQUAL(resDesc.BindPoint, 4294967295);
  1105. VERIFY_ARE_EQUAL(resDesc.Space, 4294967295);
  1106. VERIFY_ARE_EQUAL(resDesc.BindCount, 1);
  1107. }
  1108. const char *Ref1_Shader =
  1109. "float cbval1;"
  1110. "cbuffer MyCB : register(b11, space2) { int4 cbval2, cbval3; }"
  1111. "RWTexture1D<int4> tex : register(u5);"
  1112. "Texture1D<float4> tex2 : register(t0);"
  1113. "SamplerState samp : register(s7);"
  1114. "RWByteAddressBuffer b_buf;"
  1115. "export float function0(min16float x) { "
  1116. " return x + cbval2.x + tex[0].x; }"
  1117. "export float function1(float x, min12int i) {"
  1118. " return x + cbval1 + b_buf.Load(x) + tex2.Sample(samp, x).x; }"
  1119. "[shader(\"vertex\")]"
  1120. "float4 function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3.x; }";
  1121. TEST_F(DxilContainerTest, CompileWhenOkThenCheckReflection1) {
  1122. if (m_ver.SkipDxilVersion(1, 3)) return;
  1123. CComPtr<IDxcCompiler> pCompiler;
  1124. CComPtr<IDxcBlobEncoding> pSource;
  1125. CComPtr<IDxcBlob> pProgram;
  1126. CComPtr<IDxcBlobEncoding> pDisassembly;
  1127. CComPtr<IDxcOperationResult> pResult;
  1128. CComPtr<ID3D12LibraryReflection> pLibraryReflection;
  1129. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1130. CreateBlobFromText(Ref1_Shader, &pSource);
  1131. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"",
  1132. L"lib_6_3", nullptr, 0, nullptr, 0,
  1133. nullptr, &pResult));
  1134. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1135. CComPtr<IDxcContainerReflection> containerReflection;
  1136. uint32_t partCount;
  1137. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
  1138. VERIFY_SUCCEEDED(containerReflection->Load(pProgram));
  1139. VERIFY_SUCCEEDED(containerReflection->GetPartCount(&partCount));
  1140. bool blobFound = false;
  1141. for (uint32_t i = 0; i < partCount; ++i) {
  1142. uint32_t kind;
  1143. VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
  1144. if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_DXIL) {
  1145. blobFound = true;
  1146. VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
  1147. D3D12_LIBRARY_DESC LibDesc;
  1148. VERIFY_SUCCEEDED(pLibraryReflection->GetDesc(&LibDesc));
  1149. VERIFY_ARE_EQUAL(LibDesc.FunctionCount, 3);
  1150. for (INT iFn = 0; iFn < (INT)LibDesc.FunctionCount; iFn++) {
  1151. ID3D12FunctionReflection *pFunctionReflection = pLibraryReflection->GetFunctionByIndex(iFn);
  1152. D3D12_FUNCTION_DESC FnDesc;
  1153. pFunctionReflection->GetDesc(&FnDesc);
  1154. std::string Name = FnDesc.Name;
  1155. if (Name.compare("\01?function0@@YAM$min16f@@Z") == 0) {
  1156. VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
  1157. VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 1);
  1158. VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
  1159. D3D12_SHADER_BUFFER_DESC cbDesc;
  1160. ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
  1161. VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
  1162. std::string cbName = cbDesc.Name;
  1163. (void)(cbName);
  1164. Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
  1165. for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
  1166. D3D12_SHADER_INPUT_BIND_DESC resDesc;
  1167. pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
  1168. std::string resName = resDesc.Name;
  1169. if (resName.compare("$Globals") == 0) {
  1170. Ref1_CheckBinding_Globals(resDesc);
  1171. } else if (resName.compare("MyCB") == 0) {
  1172. Ref1_CheckBinding_MyCB(resDesc);
  1173. } else if (resName.compare("samp") == 0) {
  1174. Ref1_CheckBinding_samp(resDesc);
  1175. } else if (resName.compare("tex") == 0) {
  1176. Ref1_CheckBinding_tex(resDesc);
  1177. } else if (resName.compare("tex2") == 0) {
  1178. Ref1_CheckBinding_tex2(resDesc);
  1179. } else if (resName.compare("b_buf") == 0) {
  1180. Ref1_CheckBinding_b_buf(resDesc);
  1181. } else {
  1182. VERIFY_FAIL(L"Unexpected resource used");
  1183. }
  1184. }
  1185. } else if (Name.compare("\01?function1@@YAMM$min12i@@Z") == 0) {
  1186. VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_lib_6_3);
  1187. VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 1);
  1188. VERIFY_ARE_EQUAL(FnDesc.BoundResources, 4);
  1189. D3D12_SHADER_BUFFER_DESC cbDesc;
  1190. ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
  1191. VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
  1192. std::string cbName = cbDesc.Name;
  1193. (void)(cbName);
  1194. Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
  1195. for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
  1196. D3D12_SHADER_INPUT_BIND_DESC resDesc;
  1197. pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
  1198. std::string resName = resDesc.Name;
  1199. if (resName.compare("$Globals") == 0) {
  1200. Ref1_CheckBinding_Globals(resDesc);
  1201. } else if (resName.compare("MyCB") == 0) {
  1202. Ref1_CheckBinding_MyCB(resDesc);
  1203. } else if (resName.compare("samp") == 0) {
  1204. Ref1_CheckBinding_samp(resDesc);
  1205. } else if (resName.compare("tex") == 0) {
  1206. Ref1_CheckBinding_tex(resDesc);
  1207. } else if (resName.compare("tex2") == 0) {
  1208. Ref1_CheckBinding_tex2(resDesc);
  1209. } else if (resName.compare("b_buf") == 0) {
  1210. Ref1_CheckBinding_b_buf(resDesc);
  1211. } else {
  1212. VERIFY_FAIL(L"Unexpected resource used");
  1213. }
  1214. }
  1215. } else if (Name.compare("function2") == 0) {
  1216. // shader function with unmangled name
  1217. VERIFY_ARE_EQUAL(FnDesc.Version, EncodedVersion_vs_6_3);
  1218. VERIFY_ARE_EQUAL(FnDesc.ConstantBuffers, 2);
  1219. VERIFY_ARE_EQUAL(FnDesc.BoundResources, 2);
  1220. for (INT iCB = 0; iCB < (INT)FnDesc.BoundResources; iCB++) {
  1221. D3D12_SHADER_BUFFER_DESC cbDesc;
  1222. ID3D12ShaderReflectionConstantBuffer *pCBReflection = pFunctionReflection->GetConstantBufferByIndex(0);
  1223. VERIFY_SUCCEEDED(pCBReflection->GetDesc(&cbDesc));
  1224. std::string cbName = cbDesc.Name;
  1225. if (cbName.compare("$Globals") == 0) {
  1226. Ref1_CheckCBuffer_Globals(pCBReflection, cbDesc);
  1227. } else if (cbName.compare("MyCB") == 0) {
  1228. Ref1_CheckCBuffer_MyCB(pCBReflection, cbDesc);
  1229. }
  1230. }
  1231. for (INT iRes = 0; iRes < (INT)FnDesc.BoundResources; iRes++) {
  1232. D3D12_SHADER_INPUT_BIND_DESC resDesc;
  1233. pFunctionReflection->GetResourceBindingDesc(iRes, &resDesc);
  1234. std::string resName = resDesc.Name;
  1235. if (resName.compare("$Globals") == 0) {
  1236. Ref1_CheckBinding_Globals(resDesc);
  1237. } else if (resName.compare("MyCB") == 0) {
  1238. Ref1_CheckBinding_MyCB(resDesc);
  1239. } else {
  1240. VERIFY_FAIL(L"Unexpected resource used");
  1241. }
  1242. }
  1243. } else {
  1244. VERIFY_FAIL(L"Unexpected function");
  1245. }
  1246. }
  1247. // TODO: FINISH THIS
  1248. }
  1249. }
  1250. IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
  1251. }
  1252. TEST_F(DxilContainerTest, DxcUtils_CreateReflection) {
  1253. if (m_ver.SkipDxilVersion(1, 3)) return;
  1254. CComPtr<IDxcUtils> pUtils;
  1255. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcUtils, &pUtils));
  1256. CComPtr<IDxcCompiler> pCompiler;
  1257. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1258. CComPtr<IDxcBlobEncoding> pSource;
  1259. CreateBlobFromText(Ref1_Shader, &pSource);
  1260. LPCWSTR options[] = {
  1261. L"-Qstrip_reflect_from_dxil",
  1262. L"-Qstrip_reflect"
  1263. };
  1264. const UINT32 kStripFromDxilOnly = 1; // just strip reflection from DXIL, not container
  1265. const UINT32 kStripFromContainer = 2; // strip reflection from DXIL and container
  1266. auto VerifyStripReflection = [&](IDxcBlob *pBlob, bool bShouldSucceed) {
  1267. CComPtr<IDxcContainerReflection> pReflection;
  1268. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1269. VERIFY_SUCCEEDED(pReflection->Load(pBlob));
  1270. UINT32 idxPart = (UINT32)-1;
  1271. if (bShouldSucceed)
  1272. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(DXC_PART_REFLECTION_DATA, &idxPart));
  1273. else
  1274. VERIFY_FAILED(pReflection->FindFirstPartKind(DXC_PART_REFLECTION_DATA, &idxPart));
  1275. CComPtr<IDxcContainerBuilder> pBuilder;
  1276. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, &pBuilder));
  1277. VERIFY_SUCCEEDED(pBuilder->Load(pBlob));
  1278. if (bShouldSucceed) {
  1279. VERIFY_SUCCEEDED(pBuilder->RemovePart(DXC_PART_REFLECTION_DATA));
  1280. CComPtr<IDxcOperationResult> pResult;
  1281. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1282. HRESULT hr = E_FAIL;
  1283. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1284. VERIFY_SUCCEEDED(hr);
  1285. CComPtr<IDxcBlob> pStrippedBlob;
  1286. pResult->GetResult(&pStrippedBlob);
  1287. CComPtr<IDxcContainerReflection> pReflection2;
  1288. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection2));
  1289. VERIFY_SUCCEEDED(pReflection2->Load(pStrippedBlob));
  1290. idxPart = (UINT32)-1;
  1291. VERIFY_FAILED(pReflection2->FindFirstPartKind(DXC_PART_REFLECTION_DATA, &idxPart));
  1292. } else {
  1293. VERIFY_FAILED(pBuilder->RemovePart(DXC_PART_REFLECTION_DATA));
  1294. }
  1295. };
  1296. {
  1297. // Test Shader path
  1298. auto VerifyCreateReflectionShader = [&](IDxcBlob *pBlob, bool bValid)
  1299. {
  1300. DxcBuffer buffer = { pBlob->GetBufferPointer(), pBlob->GetBufferSize(), 0 };
  1301. CComPtr<ID3D12ShaderReflection> pShaderReflection;
  1302. VERIFY_SUCCEEDED(pUtils->CreateReflection(&buffer, IID_PPV_ARGS(&pShaderReflection)));
  1303. D3D12_SHADER_DESC desc;
  1304. VERIFY_SUCCEEDED(pShaderReflection->GetDesc(&desc));
  1305. VERIFY_ARE_EQUAL(desc.Version, EncodedVersion_vs_6_3);
  1306. if (bValid) {
  1307. VERIFY_ARE_EQUAL(desc.ConstantBuffers, 2);
  1308. VERIFY_ARE_EQUAL(desc.BoundResources, 2);
  1309. // That should be good enough to check that IDxcUtils::CreateReflection worked
  1310. }
  1311. };
  1312. {
  1313. // Test Full container path
  1314. CComPtr<IDxcOperationResult> pResult;
  1315. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"function2",
  1316. L"vs_6_3", options, kStripFromDxilOnly,
  1317. nullptr, 0, nullptr, &pResult));
  1318. HRESULT hr;
  1319. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1320. VERIFY_SUCCEEDED(hr);
  1321. CComPtr<IDxcBlob> pProgram;
  1322. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1323. VerifyCreateReflectionShader(pProgram, true);
  1324. // Verify reflection stripping
  1325. VerifyStripReflection(pProgram, true);
  1326. }
  1327. {
  1328. // From New IDxcResult API
  1329. CComPtr<IDxcOperationResult> pResult;
  1330. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"function2",
  1331. L"vs_6_3", options, kStripFromContainer,
  1332. nullptr, 0, nullptr, &pResult));
  1333. HRESULT hr;
  1334. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1335. VERIFY_SUCCEEDED(hr);
  1336. // Test separate reflection result path
  1337. CComPtr<IDxcResult> pResultV2;
  1338. CComPtr<IDxcBlob> pReflectionPart;
  1339. VERIFY_SUCCEEDED(pResult->QueryInterface(&pResultV2));
  1340. VERIFY_SUCCEEDED(pResultV2->GetOutput(DXC_OUT_REFLECTION, IID_PPV_ARGS(&pReflectionPart), nullptr));
  1341. VerifyCreateReflectionShader(pReflectionPart, true);
  1342. // Container should have limited reflection, and no reflection part
  1343. CComPtr<IDxcBlob> pProgram;
  1344. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1345. VerifyCreateReflectionShader(pProgram, false);
  1346. VerifyStripReflection(pProgram, false);
  1347. }
  1348. }
  1349. {
  1350. // Test Library path
  1351. auto VerifyCreateReflectionLibrary = [&](IDxcBlob *pBlob, bool bValid)
  1352. {
  1353. DxcBuffer buffer = { pBlob->GetBufferPointer(), pBlob->GetBufferSize(), 0 };
  1354. CComPtr<ID3D12LibraryReflection> pLibraryReflection;
  1355. VERIFY_SUCCEEDED(pUtils->CreateReflection(&buffer, IID_PPV_ARGS(&pLibraryReflection)));
  1356. D3D12_LIBRARY_DESC desc;
  1357. VERIFY_SUCCEEDED(pLibraryReflection->GetDesc(&desc));
  1358. if (bValid) {
  1359. VERIFY_ARE_EQUAL(desc.FunctionCount, 3);
  1360. // That should be good enough to check that IDxcUtils::CreateReflection worked
  1361. }
  1362. };
  1363. {
  1364. // Test Full container path
  1365. CComPtr<IDxcOperationResult> pResult;
  1366. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"",
  1367. L"lib_6_3", options, kStripFromDxilOnly,
  1368. nullptr, 0, nullptr, &pResult));
  1369. HRESULT hr;
  1370. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1371. VERIFY_SUCCEEDED(hr);
  1372. CComPtr<IDxcBlob> pProgram;
  1373. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1374. VerifyCreateReflectionLibrary(pProgram, true);
  1375. // Verify reflection stripping
  1376. VerifyStripReflection(pProgram, true);
  1377. }
  1378. {
  1379. // From New IDxcResult API
  1380. CComPtr<IDxcOperationResult> pResult;
  1381. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"",
  1382. L"lib_6_3", options, kStripFromContainer,
  1383. nullptr, 0, nullptr, &pResult));
  1384. HRESULT hr;
  1385. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1386. VERIFY_SUCCEEDED(hr);
  1387. // Test separate reflection result path
  1388. CComPtr<IDxcResult> pResultV2;
  1389. CComPtr<IDxcBlob> pReflectionPart;
  1390. VERIFY_SUCCEEDED(pResult->QueryInterface(&pResultV2));
  1391. VERIFY_SUCCEEDED(pResultV2->GetOutput(DXC_OUT_REFLECTION, IID_PPV_ARGS(&pReflectionPart), nullptr));
  1392. // Test Reflection part path
  1393. VerifyCreateReflectionLibrary(pReflectionPart, true);
  1394. // Container should have limited reflection, and no reflection part
  1395. CComPtr<IDxcBlob> pProgram;
  1396. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1397. VerifyCreateReflectionLibrary(pProgram, false);
  1398. VerifyStripReflection(pProgram, false);
  1399. }
  1400. }
  1401. }
  1402. TEST_F(DxilContainerTest, CompileWhenOKThenIncludesFeatureInfo) {
  1403. CComPtr<IDxcCompiler> pCompiler;
  1404. CComPtr<IDxcBlobEncoding> pSource;
  1405. CComPtr<IDxcBlob> pProgram;
  1406. CComPtr<IDxcBlobEncoding> pDisassembly;
  1407. CComPtr<IDxcOperationResult> pResult;
  1408. hlsl::DxilContainerHeader *pHeader;
  1409. hlsl::DxilPartIterator pPartIter(nullptr, 0);
  1410. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1411. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1412. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0",
  1413. nullptr, 0, nullptr, 0, nullptr,
  1414. &pResult));
  1415. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1416. // Now mess with the program bitcode.
  1417. pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer();
  1418. pPartIter = std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader),
  1419. hlsl::DxilPartIsType(hlsl::DFCC_FeatureInfo));
  1420. VERIFY_ARE_NOT_EQUAL(hlsl::end(pHeader), pPartIter);
  1421. VERIFY_ARE_EQUAL(sizeof(uint64_t), (*pPartIter)->PartSize);
  1422. VERIFY_ARE_EQUAL(0U, *(const uint64_t *)hlsl::GetDxilPartData(*pPartIter));
  1423. }
  1424. TEST_F(DxilContainerTest, DisassemblyWhenBCInvalidThenFails) {
  1425. CComPtr<IDxcCompiler> pCompiler;
  1426. CComPtr<IDxcBlobEncoding> pSource;
  1427. CComPtr<IDxcBlob> pProgram;
  1428. CComPtr<IDxcBlobEncoding> pDisassembly;
  1429. CComPtr<IDxcOperationResult> pResult;
  1430. hlsl::DxilContainerHeader *pHeader;
  1431. hlsl::DxilPartHeader *pPart;
  1432. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1433. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1434. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0",
  1435. nullptr, 0, nullptr, 0, nullptr,
  1436. &pResult));
  1437. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1438. // Now mess with the program bitcode.
  1439. pHeader = (hlsl::DxilContainerHeader *)pProgram->GetBufferPointer();
  1440. pPart = const_cast<hlsl::DxilPartHeader *>(
  1441. *std::find_if(hlsl::begin(pHeader), hlsl::end(pHeader),
  1442. hlsl::DxilPartIsType(hlsl::DFCC_DXIL)));
  1443. strcpy_s(hlsl::GetDxilPartData(pPart), pPart->PartSize, "corruption");
  1444. VERIFY_FAILED(pCompiler->Disassemble(pProgram, &pDisassembly));
  1445. }
  1446. TEST_F(DxilContainerTest, DisassemblyWhenMissingThenFails) {
  1447. CComPtr<IDxcCompiler> pCompiler;
  1448. CComPtr<IDxcBlobEncoding> pSource;
  1449. CComPtr<IDxcBlobEncoding> pDisassembly;
  1450. hlsl::DxilContainerHeader header;
  1451. SetupBasicHeader(&header);
  1452. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1453. CreateBlobPinned(&header, header.ContainerSizeInBytes, 0, &pSource);
  1454. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1455. }
  1456. TEST_F(DxilContainerTest, DisassemblyWhenInvalidThenFails) {
  1457. CComPtr<IDxcCompiler> pCompiler;
  1458. CComPtr<IDxcBlobEncoding> pDisassembly;
  1459. uint8_t scratch[1024];
  1460. hlsl::DxilContainerHeader *pHeader = (hlsl::DxilContainerHeader *)scratch;
  1461. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1462. // Too small to contain header.
  1463. {
  1464. CComPtr<IDxcBlobEncoding> pSource;
  1465. SetupBasicHeader(pHeader);
  1466. CreateBlobPinned(pHeader, sizeof(hlsl::DxilContainerHeader) - 4, 0,
  1467. &pSource);
  1468. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1469. }
  1470. // Wrong major version.
  1471. {
  1472. CComPtr<IDxcBlobEncoding> pSource;
  1473. SetupBasicHeader(pHeader);
  1474. pHeader->Version.Major = 100;
  1475. CreateBlobPinned(pHeader, pHeader->ContainerSizeInBytes, 0, &pSource);
  1476. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1477. }
  1478. // Size out of bounds.
  1479. {
  1480. CComPtr<IDxcBlobEncoding> pSource;
  1481. SetupBasicHeader(pHeader);
  1482. pHeader->ContainerSizeInBytes = 1024;
  1483. CreateBlobPinned(pHeader, sizeof(hlsl::DxilContainerHeader), 0,
  1484. &pSource);
  1485. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1486. }
  1487. // Size too large as per spec limit.
  1488. {
  1489. CComPtr<IDxcBlobEncoding> pSource;
  1490. SetupBasicHeader(pHeader);
  1491. pHeader->ContainerSizeInBytes = hlsl::DxilContainerMaxSize + 1;
  1492. CreateBlobPinned(pHeader, pHeader->ContainerSizeInBytes, 0, &pSource);
  1493. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1494. }
  1495. // Not large enough to hold offset table.
  1496. {
  1497. CComPtr<IDxcBlobEncoding> pSource;
  1498. SetupBasicHeader(pHeader);
  1499. pHeader->PartCount = 1;
  1500. CreateBlobPinned(pHeader, pHeader->ContainerSizeInBytes, 0, &pSource);
  1501. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1502. }
  1503. // Part offset out of bounds.
  1504. {
  1505. CComPtr<IDxcBlobEncoding> pSource;
  1506. SetupBasicHeader(pHeader);
  1507. pHeader->PartCount = 1;
  1508. *((uint32_t *)(pHeader + 1)) = 1024;
  1509. pHeader->ContainerSizeInBytes += sizeof(uint32_t);
  1510. CreateBlobPinned(pHeader, pHeader->ContainerSizeInBytes, 0, &pSource);
  1511. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1512. }
  1513. // Part size out of bounds.
  1514. {
  1515. CComPtr<IDxcBlobEncoding> pSource;
  1516. SetupBasicHeader(pHeader);
  1517. pHeader->PartCount = 1;
  1518. *((uint32_t *)(pHeader + 1)) = sizeof(*pHeader) + sizeof(uint32_t);
  1519. pHeader->ContainerSizeInBytes += sizeof(uint32_t);
  1520. hlsl::GetDxilContainerPart(pHeader, 0)->PartSize = 1024;
  1521. pHeader->ContainerSizeInBytes += sizeof(hlsl::DxilPartHeader);
  1522. CreateBlobPinned(pHeader, pHeader->ContainerSizeInBytes, 0, &pSource);
  1523. VERIFY_FAILED(pCompiler->Disassemble(pSource, &pDisassembly));
  1524. }
  1525. }
  1526. TEST_F(DxilContainerTest, DisassemblyWhenValidThenOK) {
  1527. CComPtr<IDxcCompiler> pCompiler;
  1528. CComPtr<IDxcBlobEncoding> pSource;
  1529. CComPtr<IDxcBlob> pProgram;
  1530. CComPtr<IDxcBlobEncoding> pDisassembly;
  1531. CComPtr<IDxcOperationResult> pResult;
  1532. hlsl::DxilContainerHeader header;
  1533. SetupBasicHeader(&header);
  1534. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1535. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1536. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0",
  1537. nullptr, 0, nullptr, 0, nullptr,
  1538. &pResult));
  1539. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1540. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  1541. std::string disassembleString(BlobToUtf8(pDisassembly));
  1542. VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
  1543. }
  1544. class HlslFileVariables {
  1545. private:
  1546. std::wstring m_Entry;
  1547. std::wstring m_Mode;
  1548. std::wstring m_Target;
  1549. std::vector<std::wstring> m_Arguments;
  1550. std::vector<LPCWSTR> m_ArgumentPtrs;
  1551. public:
  1552. HlslFileVariables(HlslFileVariables &other) = delete;
  1553. const LPCWSTR *GetArguments() const { return m_ArgumentPtrs.data(); }
  1554. UINT32 GetArgumentCount() const { return m_ArgumentPtrs.size(); }
  1555. LPCWSTR GetEntry() const { return m_Entry.c_str(); }
  1556. LPCWSTR GetMode() const { return m_Mode.c_str(); }
  1557. LPCWSTR GetTarget() const { return m_Target.c_str(); }
  1558. void Reset();
  1559. HRESULT SetFromText(_In_count_(len) const char *pText, size_t len);
  1560. };
  1561. void HlslFileVariables::Reset() {
  1562. m_Entry.resize(0);
  1563. m_Mode.resize(0);
  1564. m_Target.resize(0);
  1565. m_Arguments.resize(0);
  1566. m_ArgumentPtrs.resize(0);
  1567. }
  1568. #include <codecvt>
  1569. static bool wcsneq(const wchar_t *pValue, const wchar_t *pCheck) {
  1570. return 0 == wcsncmp(pValue, pCheck, wcslen(pCheck));
  1571. }
  1572. HRESULT HlslFileVariables::SetFromText(_In_count_(len) const char *pText, size_t len) {
  1573. // Look for the line of interest.
  1574. const char *pEnd = pText + len;
  1575. const char *pLineEnd = pText;
  1576. while (pLineEnd < pEnd && *pLineEnd != '\n') pLineEnd++;
  1577. // Create a UTF-16-backing store.
  1578. std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > w;
  1579. std::wstring line = w.from_bytes(pText, pLineEnd);
  1580. // Find starting and ending '-*-' delimiters.
  1581. const wchar_t *pWText = line.c_str();
  1582. const wchar_t *pVarStart = wcsstr(pWText, L"-*-");
  1583. if (!pVarStart) return E_INVALIDARG;
  1584. pVarStart += 3;
  1585. const wchar_t *pVarEnd = wcsstr(pVarStart, L"-*-");
  1586. if (!pVarEnd) return E_INVALIDARG;
  1587. for (;;) {
  1588. // Find 'name' ':' 'value' ';'
  1589. const wchar_t *pVarNameStart = pVarStart;
  1590. while (pVarNameStart < pVarEnd && L' ' == *pVarNameStart) ++pVarNameStart;
  1591. if (pVarNameStart == pVarEnd) break;
  1592. const wchar_t *pVarValDelim = pVarNameStart;
  1593. while (pVarValDelim < pVarEnd && L':' != *pVarValDelim) ++pVarValDelim;
  1594. if (pVarValDelim == pVarEnd) break;
  1595. const wchar_t *pVarValStart = pVarValDelim + 1;
  1596. while (pVarValStart < pVarEnd && L' ' == *pVarValStart) ++pVarValStart;
  1597. if (pVarValStart == pVarEnd) break;
  1598. const wchar_t *pVarValEnd = pVarValStart;
  1599. while (pVarValEnd < pVarEnd && L';' != *pVarValEnd) ++pVarValEnd;
  1600. if (wcsneq(pVarNameStart, L"mode")) {
  1601. m_Mode.assign(pVarValStart, pVarValEnd - pVarValStart - 1);
  1602. }
  1603. else if (wcsneq(pVarNameStart, L"hlsl-entry")) {
  1604. m_Entry.assign(pVarValStart, pVarValEnd - pVarValStart - 1);
  1605. }
  1606. else if (wcsneq(pVarNameStart, L"hlsl-target")) {
  1607. m_Target.assign(pVarValStart, pVarValEnd - pVarValStart - 1);
  1608. }
  1609. else if (wcsneq(pVarNameStart, L"hlsl-args")) {
  1610. // skip for now
  1611. }
  1612. }
  1613. return S_OK;
  1614. }
  1615. #ifdef _WIN32 // Reflection unsupported
  1616. TEST_F(DxilContainerTest, ReflectionMatchesDXBC_CheckIn) {
  1617. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  1618. ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\CodeGenHLSL\\container\\SimpleBezier11DS.hlsl").c_str(), false);
  1619. ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\CodeGenHLSL\\container\\SubD11_SmoothPS.hlsl").c_str(), false);
  1620. ReflectionTest(hlsl_test::GetPathToHlslDataFile(L"..\\HLSLFileCheck\\d3dreflect\\structured_buffer_layout.hlsl").c_str(), false);
  1621. }
  1622. TEST_F(DxilContainerTest, ReflectionMatchesDXBC_Full) {
  1623. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  1624. std::wstring codeGenPath = hlsl_test::GetPathToHlslDataFile(L"..\\CodeGenHLSL\\Samples");
  1625. // This test was running at about three minutes; that can be enabled with TestAll=True,
  1626. // otherwise the much shorter list is used.
  1627. const bool TestAll = false;
  1628. LPCWSTR PreApprovedPaths[] = {
  1629. L"2DQuadShaders_VS.hlsl",
  1630. L"BC6HEncode_TryModeLE10CS.hlsl",
  1631. L"DepthViewerVS.hlsl",
  1632. L"DetailTessellation11_DS.hlsl",
  1633. L"GenerateHistogramCS.hlsl",
  1634. L"OIT_PS.hlsl",
  1635. L"PNTriangles11_DS.hlsl",
  1636. L"PerfGraphPS.hlsl",
  1637. L"PerfGraphVS.hlsl",
  1638. L"ScreenQuadVS.hlsl",
  1639. L"SimpleBezier11HS.hlsl"
  1640. };
  1641. for (auto &p: recursive_directory_iterator(path(codeGenPath))) {
  1642. if (is_regular_file(p)) {
  1643. LPCWSTR fullPath = p.path().c_str();
  1644. if (wcsstr(fullPath, L".hlsli") != nullptr) continue;
  1645. if (wcsstr(fullPath, L"TessellatorCS40_defines.h") != nullptr) continue;
  1646. // Skip failed tests.
  1647. if (wcsstr(fullPath, L"SubD11_SubDToBezierHS") != nullptr) continue;
  1648. if (!TestAll) {
  1649. bool shouldTest = false;
  1650. LPCWSTR *PreApprovedEnd = PreApprovedPaths + _countof(PreApprovedPaths);
  1651. shouldTest = PreApprovedEnd == std::find_if(PreApprovedPaths, PreApprovedEnd,
  1652. [&](LPCWSTR candidate) { return nullptr != wcsstr(fullPath, candidate); });
  1653. if (!shouldTest) {
  1654. break;
  1655. }
  1656. }
  1657. auto start = std::chrono::system_clock::now();
  1658. ReflectionTest(fullPath, true);
  1659. if (TestAll) {
  1660. // If testing all cases, print out their timing.
  1661. auto end = std::chrono::system_clock::now();
  1662. auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
  1663. LogCommentFmt(L"%s,%u", fullPath, (unsigned)dur.count());
  1664. }
  1665. }
  1666. }
  1667. }
  1668. #endif // _WIN32 - Reflection unsupported
  1669. TEST_F(DxilContainerTest, ValidateFromLL_Abs2) {
  1670. CodeGenTestCheck(L"..\\CodeGenHLSL\\container\\abs2_m.ll");
  1671. }
  1672. TEST_F(DxilContainerTest, DxilContainerUnitTest) {
  1673. CComPtr<IDxcCompiler> pCompiler;
  1674. CComPtr<IDxcBlobEncoding> pSource;
  1675. CComPtr<IDxcBlob> pProgram;
  1676. CComPtr<IDxcBlobEncoding> pDisassembly;
  1677. CComPtr<IDxcOperationResult> pResult;
  1678. std::vector<LPCWSTR> arguments;
  1679. arguments.emplace_back(L"/Zi");
  1680. arguments.emplace_back(L"/Qembed_debug");
  1681. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1682. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1683. // Test DxilContainer with ShaderDebugInfoDXIL
  1684. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", arguments.data(), arguments.size(), nullptr, 0, nullptr, &pResult));
  1685. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1686. const hlsl::DxilContainerHeader *pHeader = hlsl::IsDxilContainerLike(pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  1687. VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(pHeader, pProgram->GetBufferSize()));
  1688. VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(pHeader, pProgram->GetBufferSize()));
  1689. VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
  1690. VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  1691. VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
  1692. VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  1693. pResult.Release();
  1694. pProgram.Release();
  1695. // Test DxilContainer without ShaderDebugInfoDXIL
  1696. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  1697. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1698. pHeader = hlsl::IsDxilContainerLike(pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  1699. VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(pHeader, pProgram->GetBufferSize()));
  1700. VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(pHeader, pProgram->GetBufferSize()));
  1701. VERIFY_IS_NOT_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
  1702. VERIFY_IS_NULL(hlsl::GetDxilProgramHeader(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  1703. VERIFY_IS_NOT_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_DXIL));
  1704. VERIFY_IS_NULL(hlsl::GetDxilPartByType(pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  1705. // Test Empty DxilContainer
  1706. hlsl::DxilContainerHeader header;
  1707. SetupBasicHeader(&header);
  1708. VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(&header, header.ContainerSizeInBytes));
  1709. VERIFY_IS_NOT_NULL(hlsl::IsDxilContainerLike(&header, header.ContainerSizeInBytes));
  1710. VERIFY_IS_NULL(hlsl::GetDxilProgramHeader(&header, hlsl::DxilFourCC::DFCC_DXIL));
  1711. VERIFY_IS_NULL(hlsl::GetDxilPartByType(&header, hlsl::DxilFourCC::DFCC_DXIL));
  1712. }