PixTest.cpp 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // PixTest.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 the PIX-specific components //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. // This whole file is win32-only
  12. #ifdef _WIN32
  13. #ifndef UNICODE
  14. #define UNICODE
  15. #endif
  16. #include <memory>
  17. #include <vector>
  18. #include <string>
  19. #include <map>
  20. #include <cassert>
  21. #include <sstream>
  22. #include <algorithm>
  23. #include <cfloat>
  24. #include "dxc/DxilContainer/DxilContainer.h"
  25. #include "dxc/Support/WinIncludes.h"
  26. #include "dxc/dxcapi.h"
  27. #include "dxc/dxcpix.h"
  28. #include <atlfile.h>
  29. #include "dia2.h"
  30. #include "dxc/DXIL/DxilModule.h"
  31. #include "dxc/Test/HLSLTestData.h"
  32. #include "dxc/Test/HlslTestUtils.h"
  33. #include "dxc/Test/DxcTestUtils.h"
  34. #include "llvm/Support/raw_os_ostream.h"
  35. #include "dxc/Support/Global.h"
  36. #include "dxc/Support/dxcapi.use.h"
  37. #include "dxc/Support/microcom.h"
  38. #include "dxc/Support/HLSLOptions.h"
  39. #include "dxc/Support/Unicode.h"
  40. #include <fstream>
  41. #include "llvm/Bitcode/ReaderWriter.h"
  42. #include "llvm/IR/Instructions.h"
  43. #include "llvm/IR/Intrinsics.h"
  44. #include "llvm/IR/IntrinsicInst.h"
  45. #include "llvm/IR/LLVMContext.h"
  46. #include "llvm/IR/Module.h"
  47. #include "llvm/IR/ModuleSlotTracker.h"
  48. #include "llvm/Support/FileSystem.h"
  49. #include "llvm/Support/MemoryBuffer.h"
  50. #include "llvm/Support/MSFileSystem.h"
  51. #include "llvm/Support/Path.h"
  52. #include "llvm/ADT/SmallString.h"
  53. #include "llvm/ADT/StringSwitch.h"
  54. #include <../lib/DxilDia/DxilDiaSession.h>
  55. #include <../lib/DxilDia/DxcPixLiveVariables.h>
  56. #include <../lib/DxilDia/DxcPixLiveVariables_FragmentIterator.h>
  57. #include <dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h>
  58. using namespace std;
  59. using namespace hlsl;
  60. using namespace hlsl_test;
  61. // Aligned to SymTagEnum.
  62. const char *SymTagEnumText[] = {
  63. "Null", // SymTagNull
  64. "Exe", // SymTagExe
  65. "Compiland", // SymTagCompiland
  66. "CompilandDetails", // SymTagCompilandDetails
  67. "CompilandEnv", // SymTagCompilandEnv
  68. "Function", // SymTagFunction
  69. "Block", // SymTagBlock
  70. "Data", // SymTagData
  71. "Annotation", // SymTagAnnotation
  72. "Label", // SymTagLabel
  73. "PublicSymbol", // SymTagPublicSymbol
  74. "UDT", // SymTagUDT
  75. "Enum", // SymTagEnum
  76. "FunctionType", // SymTagFunctionType
  77. "PointerType", // SymTagPointerType
  78. "ArrayType", // SymTagArrayType
  79. "BaseType", // SymTagBaseType
  80. "Typedef", // SymTagTypedef
  81. "BaseClass", // SymTagBaseClass
  82. "Friend", // SymTagFriend
  83. "FunctionArgType", // SymTagFunctionArgType
  84. "FuncDebugStart", // SymTagFuncDebugStart
  85. "FuncDebugEnd", // SymTagFuncDebugEnd
  86. "UsingNamespace", // SymTagUsingNamespace
  87. "VTableShape", // SymTagVTableShape
  88. "VTable", // SymTagVTable
  89. "Custom", // SymTagCustom
  90. "Thunk", // SymTagThunk
  91. "CustomType", // SymTagCustomType
  92. "ManagedType", // SymTagManagedType
  93. "Dimension", // SymTagDimension
  94. "CallSite", // SymTagCallSite
  95. "InlineSite", // SymTagInlineSite
  96. "BaseInterface", // SymTagBaseInterface
  97. "VectorType", // SymTagVectorType
  98. "MatrixType", // SymTagMatrixType
  99. "HLSLType", // SymTagHLSLType
  100. "Caller", // SymTagCaller
  101. "Callee", // SymTagCallee
  102. "Export", // SymTagExport
  103. "HeapAllocationSite", // SymTagHeapAllocationSite
  104. "CoffGroup", // SymTagCoffGroup
  105. };
  106. // Aligned to LocationType.
  107. const char* LocationTypeText[] =
  108. {
  109. "Null",
  110. "Static",
  111. "TLS",
  112. "RegRel",
  113. "ThisRel",
  114. "Enregistered",
  115. "BitField",
  116. "Slot",
  117. "IlRel",
  118. "MetaData",
  119. "Constant",
  120. };
  121. // Aligned to DataKind.
  122. const char* DataKindText[] =
  123. {
  124. "Unknown",
  125. "Local",
  126. "StaticLocal",
  127. "Param",
  128. "ObjectPtr",
  129. "FileStatic",
  130. "Global",
  131. "Member",
  132. "StaticMember",
  133. "Constant",
  134. };
  135. // Aligned to UdtKind.
  136. const char* UdtKindText[] =
  137. {
  138. "Struct",
  139. "Class",
  140. "Union",
  141. "Interface",
  142. };
  143. static std::vector<std::string> Tokenize(const std::string &str,
  144. const char *delimiters) {
  145. std::vector<std::string> tokens;
  146. std::string copy = str;
  147. for (auto i = strtok(&copy[0], delimiters); i != nullptr;
  148. i = strtok(nullptr, delimiters)) {
  149. tokens.push_back(i);
  150. }
  151. return tokens;
  152. }
  153. class PixTest {
  154. public:
  155. BEGIN_TEST_CLASS(PixTest)
  156. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  157. TEST_METHOD_PROPERTY(L"Priority", L"0")
  158. END_TEST_CLASS()
  159. TEST_CLASS_SETUP(InitSupport);
  160. TEST_METHOD(CompileWhenDebugThenDIPresent)
  161. TEST_METHOD(CompileDebugPDB)
  162. TEST_METHOD(CompileDebugDisasmPDB)
  163. TEST_METHOD(DiaLoadBadBitcodeThenFail)
  164. TEST_METHOD(DiaLoadDebugThenOK)
  165. TEST_METHOD(DiaTableIndexThenOK)
  166. TEST_METHOD(DiaLoadDebugSubrangeNegativeThenOK)
  167. TEST_METHOD(DiaLoadRelocatedBitcode)
  168. TEST_METHOD(DiaLoadBitcodePlusExtraData)
  169. TEST_METHOD(DiaCompileArgs)
  170. TEST_METHOD(PixDebugCompileInfo)
  171. TEST_METHOD(PixStructAnnotation_Simple)
  172. TEST_METHOD(PixStructAnnotation_CopiedStruct)
  173. TEST_METHOD(PixStructAnnotation_MixedSizes)
  174. TEST_METHOD(PixStructAnnotation_StructWithinStruct)
  175. TEST_METHOD(PixStructAnnotation_1DArray)
  176. TEST_METHOD(PixStructAnnotation_2DArray)
  177. TEST_METHOD(PixStructAnnotation_EmbeddedArray)
  178. TEST_METHOD(PixStructAnnotation_FloatN)
  179. TEST_METHOD(PixStructAnnotation_SequentialFloatN)
  180. TEST_METHOD(PixStructAnnotation_EmbeddedFloatN)
  181. TEST_METHOD(PixStructAnnotation_Matrix)
  182. TEST_METHOD(PixStructAnnotation_MemberFunction)
  183. TEST_METHOD(PixStructAnnotation_BigMess)
  184. TEST_METHOD(PixStructAnnotation_AlignedFloat4Arrays)
  185. TEST_METHOD(PixStructAnnotation_Inheritance)
  186. TEST_METHOD(PixStructAnnotation_ResourceAsMember)
  187. TEST_METHOD(PixStructAnnotation_WheresMyDbgValue)
  188. dxc::DxcDllSupport m_dllSupport;
  189. VersionSupportInfo m_ver;
  190. void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
  191. UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
  192. CComPtr<IDxcLibrary> library;
  193. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  194. IFT(library->CreateBlobWithEncodingFromPinned(data, size, codePage,
  195. ppBlob));
  196. }
  197. void CreateBlobFromFile(LPCWSTR name, _Outptr_ IDxcBlobEncoding **ppBlob) {
  198. CComPtr<IDxcLibrary> library;
  199. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  200. const std::wstring path = hlsl_test::GetPathToHlslDataFile(name);
  201. IFT(library->CreateBlobFromFile(path.c_str(), nullptr, ppBlob));
  202. }
  203. void CreateBlobFromText(_In_z_ const char *pText,
  204. _Outptr_ IDxcBlobEncoding **ppBlob) {
  205. CreateBlobPinned(pText, strlen(pText) + 1, CP_UTF8, ppBlob);
  206. }
  207. HRESULT CreateCompiler(IDxcCompiler **ppResult) {
  208. return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
  209. }
  210. HRESULT CreateContainerBuilder(IDxcContainerBuilder **ppResult) {
  211. return m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, ppResult);
  212. }
  213. template <typename T, typename TDefault, typename TIface>
  214. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  215. TDefault defaultValue, LPCWSTR valueLabel,
  216. HRESULT (__stdcall TIface::*pFn)(T *)) {
  217. T value;
  218. HRESULT hr = (pSymbol->*(pFn))(&value);
  219. if (SUCCEEDED(hr) && value != defaultValue) {
  220. o << L", " << valueLabel << L": " << value;
  221. }
  222. }
  223. template <typename TIface>
  224. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  225. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(BSTR *)) {
  226. CComBSTR value;
  227. HRESULT hr = (pSymbol->*(pFn))(&value);
  228. if (SUCCEEDED(hr) && value.Length()) {
  229. o << L", " << valueLabel << L": " << (LPCWSTR)value;
  230. }
  231. }
  232. template <typename TIface>
  233. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  234. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(VARIANT *)) {
  235. CComVariant value;
  236. HRESULT hr = (pSymbol->*(pFn))(&value);
  237. if (SUCCEEDED(hr) && value.vt != VT_NULL && value.vt != VT_EMPTY) {
  238. if (SUCCEEDED(value.ChangeType(VT_BSTR))) {
  239. o << L", " << valueLabel << L": " << (LPCWSTR)value.bstrVal;
  240. }
  241. }
  242. }
  243. template <typename TIface>
  244. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  245. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(IDiaSymbol **)) {
  246. CComPtr<IDiaSymbol> value;
  247. HRESULT hr = (pSymbol->*(pFn))(&value);
  248. if (SUCCEEDED(hr) && value.p != nullptr) {
  249. DWORD symId;
  250. value->get_symIndexId(&symId);
  251. o << L", " << valueLabel << L": id=" << symId;
  252. }
  253. }
  254. std::wstring GetDebugInfoAsText(_In_ IDiaDataSource* pDataSource) {
  255. CComPtr<IDiaSession> pSession;
  256. CComPtr<IDiaTable> pTable;
  257. CComPtr<IDiaEnumTables> pEnumTables;
  258. std::wstringstream o;
  259. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  260. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  261. LONG count;
  262. VERIFY_SUCCEEDED(pEnumTables->get_Count(&count));
  263. for (LONG i = 0; i < count; ++i) {
  264. pTable.Release();
  265. ULONG fetched;
  266. VERIFY_SUCCEEDED(pEnumTables->Next(1, &pTable, &fetched));
  267. VERIFY_ARE_EQUAL(fetched, 1);
  268. CComBSTR tableName;
  269. VERIFY_SUCCEEDED(pTable->get_name(&tableName));
  270. o << L"Table: " << (LPWSTR)tableName << std::endl;
  271. LONG rowCount;
  272. IFT(pTable->get_Count(&rowCount));
  273. o << L" Row count: " << rowCount << std::endl;
  274. for (LONG rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
  275. CComPtr<IUnknown> item;
  276. o << L'#' << rowIndex;
  277. IFT(pTable->Item(rowIndex, &item));
  278. CComPtr<IDiaSymbol> pSymbol;
  279. if (SUCCEEDED(item.QueryInterface(&pSymbol))) {
  280. DWORD symTag;
  281. DWORD dataKind;
  282. DWORD locationType;
  283. DWORD registerId;
  284. pSymbol->get_symTag(&symTag);
  285. pSymbol->get_dataKind(&dataKind);
  286. pSymbol->get_locationType(&locationType);
  287. pSymbol->get_registerId(&registerId);
  288. //pSymbol->get_value(&value);
  289. WriteIfValue(pSymbol.p, o, 0, L"symIndexId", &IDiaSymbol::get_symIndexId);
  290. o << L", " << SymTagEnumText[symTag];
  291. if (dataKind != 0) o << L", " << DataKindText[dataKind];
  292. WriteIfValue(pSymbol.p, o, L"name", &IDiaSymbol::get_name);
  293. WriteIfValue(pSymbol.p, o, L"lexicalParent", &IDiaSymbol::get_lexicalParent);
  294. WriteIfValue(pSymbol.p, o, L"type", &IDiaSymbol::get_type);
  295. WriteIfValue(pSymbol.p, o, 0, L"slot", &IDiaSymbol::get_slot);
  296. WriteIfValue(pSymbol.p, o, 0, L"platform", &IDiaSymbol::get_platform);
  297. WriteIfValue(pSymbol.p, o, 0, L"language", &IDiaSymbol::get_language);
  298. WriteIfValue(pSymbol.p, o, 0, L"frontEndMajor", &IDiaSymbol::get_frontEndMajor);
  299. WriteIfValue(pSymbol.p, o, 0, L"frontEndMinor", &IDiaSymbol::get_frontEndMinor);
  300. WriteIfValue(pSymbol.p, o, 0, L"token", &IDiaSymbol::get_token);
  301. WriteIfValue(pSymbol.p, o, L"value", &IDiaSymbol::get_value);
  302. WriteIfValue(pSymbol.p, o, 0, L"code", &IDiaSymbol::get_code);
  303. WriteIfValue(pSymbol.p, o, 0, L"function", &IDiaSymbol::get_function);
  304. WriteIfValue(pSymbol.p, o, 0, L"udtKind", &IDiaSymbol::get_udtKind);
  305. WriteIfValue(pSymbol.p, o, 0, L"hasDebugInfo", &IDiaSymbol::get_hasDebugInfo);
  306. WriteIfValue(pSymbol.p, o, L"compilerName", &IDiaSymbol::get_compilerName);
  307. WriteIfValue(pSymbol.p, o, 0, L"isLocationControlFlowDependent", &IDiaSymbol::get_isLocationControlFlowDependent);
  308. WriteIfValue(pSymbol.p, o, 0, L"numberOfRows", &IDiaSymbol::get_numberOfRows);
  309. WriteIfValue(pSymbol.p, o, 0, L"numberOfColumns", &IDiaSymbol::get_numberOfColumns);
  310. WriteIfValue(pSymbol.p, o, 0, L"length", &IDiaSymbol::get_length);
  311. WriteIfValue(pSymbol.p, o, 0, L"isMatrixRowMajor", &IDiaSymbol::get_isMatrixRowMajor);
  312. WriteIfValue(pSymbol.p, o, 0, L"builtInKind", &IDiaSymbol::get_builtInKind);
  313. WriteIfValue(pSymbol.p, o, 0, L"textureSlot", &IDiaSymbol::get_textureSlot);
  314. WriteIfValue(pSymbol.p, o, 0, L"memorySpaceKind", &IDiaSymbol::get_memorySpaceKind);
  315. WriteIfValue(pSymbol.p, o, 0, L"isHLSLData", &IDiaSymbol::get_isHLSLData);
  316. }
  317. CComPtr<IDiaSourceFile> pSourceFile;
  318. if (SUCCEEDED(item.QueryInterface(&pSourceFile))) {
  319. WriteIfValue(pSourceFile.p, o, 0, L"uniqueId", &IDiaSourceFile::get_uniqueId);
  320. WriteIfValue(pSourceFile.p, o, L"fileName", &IDiaSourceFile::get_fileName);
  321. }
  322. CComPtr<IDiaLineNumber> pLineNumber;
  323. if (SUCCEEDED(item.QueryInterface(&pLineNumber))) {
  324. WriteIfValue(pLineNumber.p, o, L"compiland", &IDiaLineNumber::get_compiland);
  325. //WriteIfValue(pLineNumber.p, o, L"sourceFile", &IDiaLineNumber::get_sourceFile);
  326. WriteIfValue(pLineNumber.p, o, 0, L"lineNumber", &IDiaLineNumber::get_lineNumber);
  327. WriteIfValue(pLineNumber.p, o, 0, L"lineNumberEnd", &IDiaLineNumber::get_lineNumberEnd);
  328. WriteIfValue(pLineNumber.p, o, 0, L"columnNumber", &IDiaLineNumber::get_columnNumber);
  329. WriteIfValue(pLineNumber.p, o, 0, L"columnNumberEnd", &IDiaLineNumber::get_columnNumberEnd);
  330. WriteIfValue(pLineNumber.p, o, 0, L"addressSection", &IDiaLineNumber::get_addressSection);
  331. WriteIfValue(pLineNumber.p, o, 0, L"addressOffset", &IDiaLineNumber::get_addressOffset);
  332. WriteIfValue(pLineNumber.p, o, 0, L"relativeVirtualAddress", &IDiaLineNumber::get_relativeVirtualAddress);
  333. WriteIfValue(pLineNumber.p, o, 0, L"virtualAddress", &IDiaLineNumber::get_virtualAddress);
  334. WriteIfValue(pLineNumber.p, o, 0, L"length", &IDiaLineNumber::get_length);
  335. WriteIfValue(pLineNumber.p, o, 0, L"sourceFileId", &IDiaLineNumber::get_sourceFileId);
  336. WriteIfValue(pLineNumber.p, o, 0, L"statement", &IDiaLineNumber::get_statement);
  337. WriteIfValue(pLineNumber.p, o, 0, L"compilandId", &IDiaLineNumber::get_compilandId);
  338. }
  339. CComPtr<IDiaSectionContrib> pSectionContrib;
  340. if (SUCCEEDED(item.QueryInterface(&pSectionContrib))) {
  341. WriteIfValue(pSectionContrib.p, o, L"compiland", &IDiaSectionContrib::get_compiland);
  342. WriteIfValue(pSectionContrib.p, o, 0, L"addressSection", &IDiaSectionContrib::get_addressSection);
  343. WriteIfValue(pSectionContrib.p, o, 0, L"addressOffset", &IDiaSectionContrib::get_addressOffset);
  344. WriteIfValue(pSectionContrib.p, o, 0, L"relativeVirtualAddress", &IDiaSectionContrib::get_relativeVirtualAddress);
  345. WriteIfValue(pSectionContrib.p, o, 0, L"virtualAddress", &IDiaSectionContrib::get_virtualAddress);
  346. WriteIfValue(pSectionContrib.p, o, 0, L"length", &IDiaSectionContrib::get_length);
  347. WriteIfValue(pSectionContrib.p, o, 0, L"notPaged", &IDiaSectionContrib::get_notPaged);
  348. WriteIfValue(pSectionContrib.p, o, 0, L"code", &IDiaSectionContrib::get_code);
  349. WriteIfValue(pSectionContrib.p, o, 0, L"initializedData", &IDiaSectionContrib::get_initializedData);
  350. WriteIfValue(pSectionContrib.p, o, 0, L"uninitializedData", &IDiaSectionContrib::get_uninitializedData);
  351. WriteIfValue(pSectionContrib.p, o, 0, L"remove", &IDiaSectionContrib::get_remove);
  352. WriteIfValue(pSectionContrib.p, o, 0, L"comdat", &IDiaSectionContrib::get_comdat);
  353. WriteIfValue(pSectionContrib.p, o, 0, L"discardable", &IDiaSectionContrib::get_discardable);
  354. WriteIfValue(pSectionContrib.p, o, 0, L"notCached", &IDiaSectionContrib::get_notCached);
  355. WriteIfValue(pSectionContrib.p, o, 0, L"share", &IDiaSectionContrib::get_share);
  356. WriteIfValue(pSectionContrib.p, o, 0, L"execute", &IDiaSectionContrib::get_execute);
  357. WriteIfValue(pSectionContrib.p, o, 0, L"read", &IDiaSectionContrib::get_read);
  358. WriteIfValue(pSectionContrib.p, o, 0, L"write", &IDiaSectionContrib::get_write);
  359. WriteIfValue(pSectionContrib.p, o, 0, L"dataCrc", &IDiaSectionContrib::get_dataCrc);
  360. WriteIfValue(pSectionContrib.p, o, 0, L"relocationsCrc", &IDiaSectionContrib::get_relocationsCrc);
  361. WriteIfValue(pSectionContrib.p, o, 0, L"compilandId", &IDiaSectionContrib::get_compilandId);
  362. }
  363. CComPtr<IDiaSegment> pSegment;
  364. if (SUCCEEDED(item.QueryInterface(&pSegment))) {
  365. WriteIfValue(pSegment.p, o, 0, L"frame", &IDiaSegment::get_frame);
  366. WriteIfValue(pSegment.p, o, 0, L"offset", &IDiaSegment::get_offset);
  367. WriteIfValue(pSegment.p, o, 0, L"length", &IDiaSegment::get_length);
  368. WriteIfValue(pSegment.p, o, 0, L"read", &IDiaSegment::get_read);
  369. WriteIfValue(pSegment.p, o, 0, L"write", &IDiaSegment::get_write);
  370. WriteIfValue(pSegment.p, o, 0, L"execute", &IDiaSegment::get_execute);
  371. WriteIfValue(pSegment.p, o, 0, L"addressSection", &IDiaSegment::get_addressSection);
  372. WriteIfValue(pSegment.p, o, 0, L"relativeVirtualAddress", &IDiaSegment::get_relativeVirtualAddress);
  373. WriteIfValue(pSegment.p, o, 0, L"virtualAddress", &IDiaSegment::get_virtualAddress);
  374. }
  375. CComPtr<IDiaInjectedSource> pInjectedSource;
  376. if (SUCCEEDED(item.QueryInterface(&pInjectedSource))) {
  377. WriteIfValue(pInjectedSource.p, o, 0, L"crc", &IDiaInjectedSource::get_crc);
  378. WriteIfValue(pInjectedSource.p, o, 0, L"length", &IDiaInjectedSource::get_length);
  379. WriteIfValue(pInjectedSource.p, o, L"filename", &IDiaInjectedSource::get_filename);
  380. WriteIfValue(pInjectedSource.p, o, L"objectFilename", &IDiaInjectedSource::get_objectFilename);
  381. WriteIfValue(pInjectedSource.p, o, L"virtualFilename", &IDiaInjectedSource::get_virtualFilename);
  382. WriteIfValue(pInjectedSource.p, o, 0, L"sourceCompression", &IDiaInjectedSource::get_sourceCompression);
  383. // get_source is also available
  384. }
  385. CComPtr<IDiaFrameData> pFrameData;
  386. if (SUCCEEDED(item.QueryInterface(&pFrameData))) {
  387. }
  388. o << std::endl;
  389. }
  390. }
  391. return o.str();
  392. }
  393. std::wstring GetDebugFileContent(_In_ IDiaDataSource *pDataSource) {
  394. CComPtr<IDiaSession> pSession;
  395. CComPtr<IDiaTable> pTable;
  396. CComPtr<IDiaTable> pSourcesTable;
  397. CComPtr<IDiaEnumTables> pEnumTables;
  398. std::wstringstream o;
  399. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  400. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  401. ULONG fetched = 0;
  402. while (pEnumTables->Next(1, &pTable, &fetched) == S_OK && fetched == 1) {
  403. CComBSTR name;
  404. IFT(pTable->get_name(&name));
  405. if (wcscmp(name, L"SourceFiles") == 0) {
  406. pSourcesTable = pTable.Detach();
  407. continue;
  408. }
  409. pTable.Release();
  410. }
  411. if (!pSourcesTable) {
  412. return L"cannot find source";
  413. }
  414. // Get source file contents.
  415. // NOTE: "SourceFiles" has the root file first while "InjectedSources" is in
  416. // alphabetical order.
  417. // It is important to keep the root file first for recompilation, so
  418. // iterate "SourceFiles" and look up the corresponding injected
  419. // source.
  420. LONG count;
  421. IFT(pSourcesTable->get_Count(&count));
  422. CComPtr<IDiaSourceFile> pSourceFile;
  423. CComBSTR pName;
  424. CComPtr<IUnknown> pSymbolUnk;
  425. CComPtr<IDiaEnumInjectedSources> pEnumInjectedSources;
  426. CComPtr<IDiaInjectedSource> pInjectedSource;
  427. std::wstring sourceText, sourceFilename;
  428. while (SUCCEEDED(pSourcesTable->Next(1, &pSymbolUnk, &fetched)) &&
  429. fetched == 1) {
  430. sourceText = sourceFilename = L"";
  431. IFT(pSymbolUnk->QueryInterface(&pSourceFile));
  432. IFT(pSourceFile->get_fileName(&pName));
  433. IFT(pSession->findInjectedSource(pName, &pEnumInjectedSources));
  434. if (SUCCEEDED(pEnumInjectedSources->get_Count(&count)) && count == 1) {
  435. IFT(pEnumInjectedSources->Item(0, &pInjectedSource));
  436. DWORD cbData = 0;
  437. std::string tempString;
  438. CComBSTR bstr;
  439. IFT(pInjectedSource->get_filename(&bstr));
  440. IFT(pInjectedSource->get_source(0, &cbData, nullptr));
  441. tempString.resize(cbData);
  442. IFT(pInjectedSource->get_source(
  443. cbData, &cbData, reinterpret_cast<BYTE *>(&tempString[0])));
  444. CA2W tempWString(tempString.data());
  445. o << tempWString.m_psz;
  446. }
  447. pSymbolUnk.Release();
  448. }
  449. return o.str();
  450. }
  451. struct LineNumber { DWORD line; DWORD rva; };
  452. std::vector<LineNumber> ReadLineNumbers(IDiaEnumLineNumbers *pEnumLineNumbers) {
  453. std::vector<LineNumber> lines;
  454. CComPtr<IDiaLineNumber> pLineNumber;
  455. DWORD lineCount;
  456. while (SUCCEEDED(pEnumLineNumbers->Next(1, &pLineNumber, &lineCount)) && lineCount == 1)
  457. {
  458. DWORD line;
  459. DWORD rva;
  460. VERIFY_SUCCEEDED(pLineNumber->get_lineNumber(&line));
  461. VERIFY_SUCCEEDED(pLineNumber->get_relativeVirtualAddress(&rva));
  462. lines.push_back({ line, rva });
  463. pLineNumber.Release();
  464. }
  465. return lines;
  466. }
  467. std::string GetOption(std::string &cmd, char *opt) {
  468. std::string option = cmd.substr(cmd.find(opt));
  469. option = option.substr(option.find_first_of(' '));
  470. option = option.substr(option.find_first_not_of(' '));
  471. return option.substr(0, option.find_first_of(' '));
  472. }
  473. HRESULT CreateDiaSourceForCompile(const char* hlsl,
  474. IDiaDataSource** ppDiaSource)
  475. {
  476. if (!ppDiaSource)
  477. return E_POINTER;
  478. CComPtr<IDxcCompiler> pCompiler;
  479. CComPtr<IDxcOperationResult> pResult;
  480. CComPtr<IDxcBlobEncoding> pSource;
  481. CComPtr<IDxcBlob> pProgram;
  482. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  483. CreateBlobFromText(hlsl, &pSource);
  484. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug", L"/Od" };
  485. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  486. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult));
  487. HRESULT compilationStatus;
  488. VERIFY_SUCCEEDED(pResult->GetStatus(&compilationStatus));
  489. if (FAILED(compilationStatus))
  490. {
  491. CComPtr<IDxcBlobEncoding> pErrros;
  492. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrros));
  493. CA2W errorTextW(static_cast<const char *>(pErrros->GetBufferPointer()), CP_UTF8);
  494. WEX::Logging::Log::Error(errorTextW);
  495. }
  496. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  497. // Disassemble the compiled (stripped) program.
  498. {
  499. CComPtr<IDxcBlobEncoding> pDisassembly;
  500. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  501. std::string disText = BlobToUtf8(pDisassembly);
  502. CA2W disTextW(disText.c_str(), CP_UTF8);
  503. //WEX::Logging::Log::Comment(disTextW);
  504. }
  505. // CONSIDER: have the dia data source look for the part if passed a whole container.
  506. CComPtr<IDiaDataSource> pDiaSource;
  507. CComPtr<IStream> pProgramStream;
  508. CComPtr<IDxcLibrary> pLib;
  509. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  510. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  511. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  512. VERIFY_IS_NOT_NULL(pContainer);
  513. hlsl::DxilPartIterator partIter =
  514. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  515. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  516. const hlsl::DxilProgramHeader *pProgramHeader =
  517. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  518. uint32_t bitcodeLength;
  519. const char *pBitcode;
  520. CComPtr<IDxcBlob> pProgramPdb;
  521. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  522. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  523. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(), bitcodeLength,
  524. &pProgramPdb));
  525. // Disassemble the program with debug information.
  526. {
  527. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  528. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  529. std::string disText = BlobToUtf8(pDbgDisassembly);
  530. CA2W disTextW(disText.c_str(), CP_UTF8);
  531. //WEX::Logging::Log::Comment(disTextW);
  532. }
  533. // Create a short text dump of debug information.
  534. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pProgramPdb, &pProgramStream));
  535. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  536. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  537. *ppDiaSource = pDiaSource.Detach();
  538. return S_OK;
  539. }
  540. CComPtr<IDxcOperationResult> Compile(
  541. const char* hlsl,
  542. const wchar_t* target,
  543. std::vector<const wchar_t *> extraArgs)
  544. {
  545. CComPtr<IDxcCompiler> pCompiler;
  546. CComPtr<IDxcOperationResult> pResult;
  547. CComPtr<IDxcBlobEncoding> pSource;
  548. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  549. CreateBlobFromText(hlsl, &pSource);
  550. std::vector<const wchar_t*> args = { L"/Zi", L"-enable-16bit-types", L"/Qembed_debug" };
  551. args.insert(args.end(), extraArgs.begin(), extraArgs.end());
  552. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  553. target, args.data(), static_cast<UINT32>(args.size()), nullptr, 0, nullptr, &pResult));
  554. HRESULT compilationStatus;
  555. VERIFY_SUCCEEDED(pResult->GetStatus(&compilationStatus));
  556. if (FAILED(compilationStatus))
  557. {
  558. CComPtr<IDxcBlobEncoding> pErrros;
  559. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrros));
  560. CA2W errorTextW(static_cast<const char*>(pErrros->GetBufferPointer()), CP_UTF8);
  561. WEX::Logging::Log::Error(errorTextW);
  562. }
  563. #if 0 //handy for debugging
  564. {
  565. CComPtr<IDxcBlob> pProgram;
  566. CheckOperationSucceeded(pResult, &pProgram);
  567. CComPtr<IDxcLibrary> pLib;
  568. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  569. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  570. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  571. VERIFY_IS_NOT_NULL(pContainer);
  572. hlsl::DxilPartIterator partIter =
  573. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  574. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  575. const hlsl::DxilProgramHeader *pProgramHeader =
  576. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  577. uint32_t bitcodeLength;
  578. const char *pBitcode;
  579. CComPtr<IDxcBlob> pProgramPdb;
  580. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  581. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  582. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(),
  583. bitcodeLength, &pProgramPdb));
  584. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  585. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  586. std::string disText = BlobToUtf8(pDbgDisassembly);
  587. CA2W disTextW(disText.c_str(), CP_UTF8);
  588. WEX::Logging::Log::Comment(disTextW);
  589. }
  590. #endif
  591. return pResult;
  592. }
  593. CComPtr<IDxcBlob> ExtractDxilPart(IDxcBlob *pProgram) {
  594. CComPtr<IDxcLibrary> pLib;
  595. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  596. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  597. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  598. VERIFY_IS_NOT_NULL(pContainer);
  599. hlsl::DxilPartIterator partIter =
  600. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  601. hlsl::DxilPartIsType(hlsl::DFCC_DXIL));
  602. const hlsl::DxilProgramHeader *pProgramHeader =
  603. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  604. uint32_t bitcodeLength;
  605. const char *pBitcode;
  606. CComPtr<IDxcBlob> pDxilBits;
  607. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  608. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  609. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(),
  610. bitcodeLength, &pDxilBits));
  611. return pDxilBits;
  612. }
  613. struct ValueLocation
  614. {
  615. int base;
  616. int count;
  617. };
  618. struct PassOutput
  619. {
  620. CComPtr<IDxcBlob> blob;
  621. std::vector<ValueLocation> valueLocations;
  622. };
  623. PassOutput RunAnnotationPasses(IDxcBlob * dxil)
  624. {
  625. CComPtr<IDxcOptimizer> pOptimizer;
  626. VERIFY_SUCCEEDED(
  627. m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  628. std::vector<LPCWSTR> Options;
  629. Options.push_back(L"-opt-mod-passes");
  630. Options.push_back(L"-dxil-dbg-value-to-dbg-declare");
  631. Options.push_back(L"-dxil-annotate-with-virtual-regs");
  632. CComPtr<IDxcBlob> pOptimizedModule;
  633. CComPtr<IDxcBlobEncoding> pText;
  634. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(
  635. dxil, Options.data(), Options.size(), &pOptimizedModule, &pText));
  636. std::string outputText;
  637. if (pText->GetBufferSize() != 0)
  638. {
  639. outputText = reinterpret_cast<const char*>(pText->GetBufferPointer());
  640. }
  641. auto lines = Tokenize(outputText, "\n");
  642. std::vector<ValueLocation> valueLocations;
  643. for (size_t line = 0; line < lines.size(); ++line) {
  644. if (lines[line] == "Begin - dxil values to virtual register mapping") {
  645. for (++line; line < lines.size(); ++line) {
  646. if (lines[line] == "End - dxil values to virtual register mapping") {
  647. break;
  648. }
  649. auto lineTokens = Tokenize(lines[line], " ");
  650. VERIFY_IS_TRUE(lineTokens.size() >= 2);
  651. if (lineTokens[1] == "dxil")
  652. {
  653. VERIFY_IS_TRUE(lineTokens.size() == 3);
  654. valueLocations.push_back({atoi(lineTokens[2].c_str()), 1});
  655. }
  656. else if (lineTokens[1] == "alloca")
  657. {
  658. VERIFY_IS_TRUE(lineTokens.size() == 4);
  659. valueLocations.push_back(
  660. {atoi(lineTokens[2].c_str()), atoi(lineTokens[3].c_str())});
  661. }
  662. else
  663. {
  664. VERIFY_IS_TRUE(false);
  665. }
  666. }
  667. }
  668. }
  669. return { std::move(pOptimizedModule), std::move(valueLocations) };
  670. }
  671. std::wstring Disassemble(IDxcBlob * pProgram)
  672. {
  673. CComPtr<IDxcCompiler> pCompiler;
  674. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  675. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  676. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDbgDisassembly));
  677. std::string disText = BlobToUtf8(pDbgDisassembly);
  678. CA2W disTextW(disText.c_str(), CP_UTF8);
  679. return std::wstring(disTextW);
  680. }
  681. CComPtr<IDxcBlob> FindModule(hlsl::DxilFourCC fourCC, IDxcBlob *pSource)
  682. {
  683. const UINT32 BC_C0DE = ((INT32)(INT8)'B' | (INT32)(INT8)'C' << 8 |
  684. (INT32)0xDEC0 << 16); // BC0xc0de in big endian
  685. const char *pBitcode = nullptr;
  686. const hlsl::DxilPartHeader *pDxilPartHeader =
  687. (hlsl::DxilPartHeader *)
  688. pSource->GetBufferPointer(); // Initialize assuming that source is
  689. // starting with DXIL part
  690. if (BC_C0DE == *(UINT32 *)pSource->GetBufferPointer()) {
  691. return pSource;
  692. }
  693. if (hlsl::IsValidDxilContainer(
  694. (hlsl::DxilContainerHeader *)pSource->GetBufferPointer(),
  695. pSource->GetBufferSize())) {
  696. hlsl::DxilContainerHeader *pDxilContainerHeader =
  697. (hlsl::DxilContainerHeader *)pSource->GetBufferPointer();
  698. pDxilPartHeader =
  699. *std::find_if(begin(pDxilContainerHeader), end(pDxilContainerHeader),
  700. hlsl::DxilPartIsType(fourCC));
  701. }
  702. if (fourCC == pDxilPartHeader->PartFourCC) {
  703. UINT32 pBlobSize;
  704. hlsl::DxilProgramHeader *pDxilProgramHeader =
  705. (hlsl::DxilProgramHeader *)(pDxilPartHeader + 1);
  706. hlsl::GetDxilProgramBitcode(pDxilProgramHeader, &pBitcode, &pBlobSize);
  707. UINT32 offset =
  708. (UINT32)(pBitcode - (const char *)pSource->GetBufferPointer());
  709. CComPtr<IDxcLibrary> library;
  710. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  711. CComPtr<IDxcBlob> targetBlob;
  712. library->CreateBlobFromBlob(pSource, offset, pBlobSize, &targetBlob);
  713. return targetBlob;
  714. }
  715. return {};
  716. }
  717. void ReplaceDxilBlobPart(
  718. const void *originalShaderBytecode, SIZE_T originalShaderLength,
  719. IDxcBlob *pNewDxilBlob, IDxcBlob **ppNewShaderOut)
  720. {
  721. CComPtr<IDxcLibrary> pLibrary;
  722. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  723. CComPtr<IDxcBlob> pNewContainer;
  724. // Use the container assembler to build a new container from the
  725. // recently-modified DXIL bitcode. This container will contain new copies of
  726. // things like input signature etc., which will supersede the ones from the
  727. // original compiled shader's container.
  728. {
  729. CComPtr<IDxcAssembler> pAssembler;
  730. IFT(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  731. CComPtr<IDxcOperationResult> pAssembleResult;
  732. VERIFY_SUCCEEDED(
  733. pAssembler->AssembleToContainer(pNewDxilBlob, &pAssembleResult));
  734. CComPtr<IDxcBlobEncoding> pAssembleErrors;
  735. VERIFY_SUCCEEDED(
  736. pAssembleResult->GetErrorBuffer(&pAssembleErrors));
  737. if (pAssembleErrors && pAssembleErrors->GetBufferSize() != 0) {
  738. OutputDebugStringA(
  739. static_cast<LPCSTR>(pAssembleErrors->GetBufferPointer()));
  740. VERIFY_SUCCEEDED(E_FAIL);
  741. }
  742. VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pNewContainer));
  743. }
  744. // Now copy over the blobs from the original container that won't have been
  745. // invalidated by changing the shader code itself, using the container
  746. // reflection API
  747. {
  748. // Wrap the original code in a container blob
  749. CComPtr<IDxcBlobEncoding> pContainer;
  750. VERIFY_SUCCEEDED(
  751. pLibrary->CreateBlobWithEncodingFromPinned(
  752. static_cast<LPBYTE>(const_cast<void *>(originalShaderBytecode)),
  753. static_cast<UINT32>(originalShaderLength), CP_ACP, &pContainer));
  754. CComPtr<IDxcContainerReflection> pReflection;
  755. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  756. // Load the reflector from the original shader
  757. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  758. UINT32 partIndex;
  759. if (SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_PrivateData,
  760. &partIndex))) {
  761. CComPtr<IDxcBlob> pPart;
  762. VERIFY_SUCCEEDED(
  763. pReflection->GetPartContent(partIndex, &pPart));
  764. CComPtr<IDxcContainerBuilder> pContainerBuilder;
  765. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder,
  766. &pContainerBuilder));
  767. VERIFY_SUCCEEDED(
  768. pContainerBuilder->Load(pNewContainer));
  769. VERIFY_SUCCEEDED(
  770. pContainerBuilder->AddPart(hlsl::DFCC_PrivateData, pPart));
  771. CComPtr<IDxcOperationResult> pBuildResult;
  772. VERIFY_SUCCEEDED(
  773. pContainerBuilder->SerializeContainer(&pBuildResult));
  774. CComPtr<IDxcBlobEncoding> pBuildErrors;
  775. VERIFY_SUCCEEDED(
  776. pBuildResult->GetErrorBuffer(&pBuildErrors));
  777. if (pBuildErrors && pBuildErrors->GetBufferSize() != 0) {
  778. OutputDebugStringA(
  779. reinterpret_cast<LPCSTR>(pBuildErrors->GetBufferPointer()));
  780. VERIFY_SUCCEEDED(E_FAIL);
  781. }
  782. VERIFY_SUCCEEDED(
  783. pBuildResult->GetResult(&pNewContainer));
  784. }
  785. }
  786. *ppNewShaderOut = pNewContainer.Detach();
  787. }
  788. class ModuleAndHangersOn
  789. {
  790. std::unique_ptr<llvm::LLVMContext> llvmContext;
  791. std::unique_ptr<llvm::Module> llvmModule;
  792. DxilModule* dxilModule;
  793. public:
  794. ModuleAndHangersOn(IDxcBlob* pBlob)
  795. {
  796. // Verify we have a valid dxil container.
  797. const DxilContainerHeader *pContainer = IsDxilContainerLike(
  798. pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  799. VERIFY_IS_NOT_NULL(pContainer);
  800. VERIFY_IS_TRUE(IsValidDxilContainer(pContainer, pBlob->GetBufferSize()));
  801. // Get Dxil part from container.
  802. DxilPartIterator it =
  803. std::find_if(begin(pContainer), end(pContainer),
  804. DxilPartIsType(DFCC_ShaderDebugInfoDXIL));
  805. VERIFY_IS_FALSE(it == end(pContainer));
  806. const DxilProgramHeader *pProgramHeader =
  807. reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(*it));
  808. VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (*it)->PartSize));
  809. // Get a pointer to the llvm bitcode.
  810. const char *pIL;
  811. uint32_t pILLength;
  812. GetDxilProgramBitcode(pProgramHeader, &pIL, &pILLength);
  813. // Parse llvm bitcode into a module.
  814. std::unique_ptr<llvm::MemoryBuffer> pBitcodeBuf(
  815. llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(pIL, pILLength), "",
  816. false));
  817. llvmContext.reset(new llvm::LLVMContext);
  818. llvm::ErrorOr<std::unique_ptr<llvm::Module>> pModule(
  819. llvm::parseBitcodeFile(pBitcodeBuf->getMemBufferRef(),
  820. *llvmContext));
  821. if (std::error_code ec = pModule.getError()) {
  822. VERIFY_FAIL();
  823. }
  824. llvmModule = std::move(pModule.get());
  825. dxilModule =
  826. DxilModule::TryGetDxilModule(llvmModule.get());
  827. }
  828. DxilModule& GetDxilModule()
  829. {
  830. return *dxilModule;
  831. }
  832. };
  833. struct AggregateOffsetAndSize
  834. {
  835. unsigned countOfMembers;
  836. unsigned offset;
  837. unsigned size;
  838. };
  839. struct AllocaWrite {
  840. std::string memberName;
  841. uint32_t regBase;
  842. uint32_t regSize;
  843. uint64_t index;
  844. };
  845. struct TestableResults
  846. {
  847. std::vector<AggregateOffsetAndSize> OffsetAndSizes;
  848. std::vector<AllocaWrite> AllocaWrites;
  849. };
  850. TestableResults TestStructAnnotationCase(const char* hlsl, const wchar_t* optimizationLevel, bool validateCoverage = true);
  851. void ValidateAllocaWrite(std::vector<AllocaWrite> const& allocaWrites, size_t index, const char* name);
  852. };
  853. bool PixTest::InitSupport() {
  854. if (!m_dllSupport.IsEnabled()) {
  855. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  856. m_ver.Initialize(m_dllSupport);
  857. }
  858. return true;
  859. }
  860. TEST_F(PixTest, CompileWhenDebugThenDIPresent) {
  861. // BUG: the first test written was of this form:
  862. // float4 local = 0; return local;
  863. //
  864. // However we get no numbers because of the _wrapper form
  865. // that exports the zero initialization from main into
  866. // a global can't be attributed to any particular location
  867. // within main, and everything in main is eventually folded away.
  868. //
  869. // Making the function do a bit more work by calling an intrinsic
  870. // helps this case.
  871. CComPtr<IDiaDataSource> pDiaSource;
  872. VERIFY_SUCCEEDED(CreateDiaSourceForCompile(
  873. "float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
  874. " float4 local = abs(pos);\r\n"
  875. " return local;\r\n"
  876. "}", &pDiaSource));
  877. std::wstring diaDump = GetDebugInfoAsText(pDiaSource).c_str();
  878. //WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  879. // Very basic tests - we have basic symbols, line numbers, and files with sources.
  880. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"symIndexId: 5, CompilandEnv, name: hlslTarget, lexicalParent: id=2, value: ps_6_0"));
  881. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"lineNumber: 2"));
  882. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"length: 99, filename: source.hlsl"));
  883. std::wstring diaFileContent = GetDebugFileContent(pDiaSource).c_str();
  884. VERIFY_IS_NOT_NULL(wcsstr(diaFileContent.c_str(), L"loat4 main(float4 pos : SV_Position) : SV_Target"));
  885. #if SUPPORT_FXC_PDB
  886. // Now, fake it by loading from a .pdb!
  887. VERIFY_SUCCEEDED(CoInitializeEx(0, COINITBASE_MULTITHREADED));
  888. const wchar_t path[] = L"path-to-fxc-blob.bin";
  889. pDiaSource.Release();
  890. pProgramStream.Release();
  891. CComPtr<IDxcBlobEncoding> fxcBlob;
  892. CComPtr<IDxcBlob> pdbBlob;
  893. VERIFY_SUCCEEDED(pLib->CreateBlobFromFile(path, nullptr, &fxcBlob));
  894. std::string s = DumpParts(fxcBlob);
  895. CA2W sW(s.c_str(), CP_UTF8);
  896. WEX::Logging::Log::Comment(sW);
  897. VERIFY_SUCCEEDED(CreateDiaSourceFromDxbcBlob(pLib, fxcBlob, &pDiaSource));
  898. WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  899. #endif
  900. }
  901. TEST_F(PixTest, CompileDebugDisasmPDB) {
  902. const char *hlsl = R"(
  903. [RootSignature("")]
  904. float main(float pos : A) : SV_Target {
  905. float x = abs(pos);
  906. float y = sin(pos);
  907. float z = x + y;
  908. return z;
  909. }
  910. )";
  911. CComPtr<IDxcLibrary> pLib;
  912. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  913. CComPtr<IDxcCompiler> pCompiler;
  914. CComPtr<IDxcCompiler2> pCompiler2;
  915. CComPtr<IDxcOperationResult> pResult;
  916. CComPtr<IDxcBlobEncoding> pSource;
  917. CComPtr<IDxcBlob> pProgram;
  918. CComPtr<IDxcBlob> pPdbBlob;
  919. WCHAR *pDebugName = nullptr;
  920. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  921. VERIFY_SUCCEEDED(pCompiler.QueryInterface(&pCompiler2));
  922. CreateBlobFromText(hlsl, &pSource);
  923. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  924. VERIFY_SUCCEEDED(pCompiler2->CompileWithDebug(pSource, L"source.hlsl", L"main",
  925. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult, &pDebugName, &pPdbBlob));
  926. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  927. // Test that disassembler can consume a PDB container
  928. CComPtr<IDxcBlobEncoding> pDisasm;
  929. VERIFY_SUCCEEDED(pCompiler->Disassemble(pPdbBlob, &pDisasm));
  930. }
  931. // Test that the new PDB format still works with Dia
  932. TEST_F(PixTest, CompileDebugPDB) {
  933. const char *hlsl = R"(
  934. [RootSignature("")]
  935. float main(float pos : A) : SV_Target {
  936. float x = abs(pos);
  937. float y = sin(pos);
  938. float z = x + y;
  939. return z;
  940. }
  941. )";
  942. CComPtr<IDxcLibrary> pLib;
  943. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  944. CComPtr<IDxcCompiler> pCompiler;
  945. CComPtr<IDxcCompiler2> pCompiler2;
  946. CComPtr<IDxcOperationResult> pResult;
  947. CComPtr<IDxcBlobEncoding> pSource;
  948. CComPtr<IDxcBlob> pProgram;
  949. CComPtr<IDxcBlob> pPdbBlob;
  950. WCHAR *pDebugName = nullptr;
  951. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  952. VERIFY_SUCCEEDED(pCompiler.QueryInterface(&pCompiler2));
  953. CreateBlobFromText(hlsl, &pSource);
  954. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  955. VERIFY_SUCCEEDED(pCompiler2->CompileWithDebug(pSource, L"source.hlsl", L"main",
  956. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult, &pDebugName, &pPdbBlob));
  957. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  958. CComPtr<IDiaDataSource> pDiaSource;
  959. CComPtr<IStream> pProgramStream;
  960. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pPdbBlob, &pProgramStream));
  961. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  962. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  963. // Test that IDxcContainerReflection can consume a PDB container
  964. CComPtr<IDxcContainerReflection> pReflection;
  965. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  966. VERIFY_SUCCEEDED(pReflection->Load(pPdbBlob));
  967. UINT32 uDebugInfoIndex = 0;
  968. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &uDebugInfoIndex));
  969. }
  970. TEST_F(PixTest, DiaLoadBadBitcodeThenFail) {
  971. CComPtr<IDxcBlob> pBadBitcode;
  972. CComPtr<IDiaDataSource> pDiaSource;
  973. CComPtr<IStream> pStream;
  974. CComPtr<IDxcLibrary> pLib;
  975. Utf8ToBlob(m_dllSupport, "badcode", &pBadBitcode);
  976. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  977. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pBadBitcode, &pStream));
  978. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  979. VERIFY_FAILED(pDiaSource->loadDataFromIStream(pStream));
  980. }
  981. static void CompileAndGetDebugPart(dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDxcBlob **ppDebugPart) {
  982. CComPtr<IDxcBlob> pContainer;
  983. CComPtr<IDxcLibrary> pLib;
  984. CComPtr<IDxcContainerReflection> pReflection;
  985. UINT32 index;
  986. std::vector<LPCWSTR> args;
  987. args.push_back(L"/Zi");
  988. args.push_back(L"/Qembed_debug");
  989. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  990. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  991. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  992. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  993. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  994. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  995. }
  996. static void CompileTestAndLoadDiaSource(dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDiaDataSource **ppDataSource) {
  997. CComPtr<IDxcBlob> pDebugContent;
  998. CComPtr<IStream> pStream;
  999. CComPtr<IDiaDataSource> pDiaSource;
  1000. CComPtr<IDxcLibrary> pLib;
  1001. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1002. CompileAndGetDebugPart(dllSupport, source, profile, &pDebugContent);
  1003. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pDebugContent, &pStream));
  1004. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  1005. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pStream));
  1006. if (ppDataSource) {
  1007. *ppDataSource = pDiaSource.Detach();
  1008. }
  1009. }
  1010. static const char EmptyCompute[] = "[numthreads(8,8,1)] void main() { }";
  1011. static void CompileTestAndLoadDia(dxc::DxcDllSupport &dllSupport, IDiaDataSource **ppDataSource) {
  1012. CompileTestAndLoadDiaSource(dllSupport, EmptyCompute, L"cs_6_0", ppDataSource);
  1013. }
  1014. TEST_F(PixTest, DiaLoadDebugSubrangeNegativeThenOK) {
  1015. static const char source[] = R"(
  1016. SamplerState samp0 : register(s0);
  1017. Texture2DArray tex0 : register(t0);
  1018. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1019. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1020. }
  1021. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1022. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1023. Texture2DArray textures[] = {
  1024. tex0,
  1025. };
  1026. return foo(textures, index, samp0, uvw);
  1027. }
  1028. )";
  1029. CComPtr<IDiaDataSource> pDiaDataSource;
  1030. CComPtr<IDiaSession> pDiaSession;
  1031. CompileTestAndLoadDiaSource(m_dllSupport, source, L"ps_6_0", &pDiaDataSource);
  1032. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pDiaSession));
  1033. }
  1034. TEST_F(PixTest, DiaLoadRelocatedBitcode) {
  1035. static const char source[] = R"(
  1036. SamplerState samp0 : register(s0);
  1037. Texture2DArray tex0 : register(t0);
  1038. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1039. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1040. }
  1041. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1042. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1043. Texture2DArray textures[] = {
  1044. tex0,
  1045. };
  1046. return foo(textures, index, samp0, uvw);
  1047. }
  1048. )";
  1049. CComPtr<IDxcBlob> pPart;
  1050. CComPtr<IDiaDataSource> pDiaSource;
  1051. CComPtr<IStream> pStream;
  1052. CComPtr<IDxcLibrary> pLib;
  1053. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1054. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1055. const char *pPartData = (char *)pPart->GetBufferPointer();
  1056. const size_t uPartSize = pPart->GetBufferSize();
  1057. // Get program header
  1058. const hlsl::DxilProgramHeader *programHeader = (hlsl::DxilProgramHeader *)pPartData;
  1059. const char *pBitcode = nullptr;
  1060. uint32_t uBitcodeSize = 0;
  1061. hlsl::GetDxilProgramBitcode(programHeader, &pBitcode, &uBitcodeSize);
  1062. VERIFY_IS_TRUE(uBitcodeSize % sizeof(UINT32) == 0);
  1063. size_t uNewGapSize = 4 * 10; // Size of some bytes between program header and bitcode
  1064. size_t uNewSuffixeBytes = 4 * 10; // Size of some random bytes after the program
  1065. hlsl::DxilProgramHeader newProgramHeader = {};
  1066. memcpy(&newProgramHeader, programHeader, sizeof(newProgramHeader));
  1067. newProgramHeader.BitcodeHeader.BitcodeOffset = uNewGapSize + sizeof(newProgramHeader.BitcodeHeader);
  1068. unsigned uNewSizeInBytes = sizeof(newProgramHeader) + uNewGapSize + uBitcodeSize + uNewSuffixeBytes;
  1069. VERIFY_IS_TRUE(uNewSizeInBytes % sizeof(UINT32) == 0);
  1070. newProgramHeader.SizeInUint32 = uNewSizeInBytes / sizeof(UINT32);
  1071. llvm::SmallVector<char, 0> buffer;
  1072. llvm::raw_svector_ostream OS(buffer);
  1073. // Write the header
  1074. OS.write((char *)&newProgramHeader, sizeof(newProgramHeader));
  1075. // Write some garbage between the header and the bitcode
  1076. for (unsigned i = 0; i < uNewGapSize; i++) {
  1077. OS.write(0xFF);
  1078. }
  1079. // Write the actual bitcode
  1080. OS.write(pBitcode, uBitcodeSize);
  1081. // Write some garbage after the bitcode
  1082. for (unsigned i = 0; i < uNewSuffixeBytes; i++) {
  1083. OS.write(0xFF);
  1084. }
  1085. OS.flush();
  1086. // Try to load this new program, make sure dia is still okay.
  1087. CComPtr<IDxcBlobEncoding> pNewProgramBlob;
  1088. VERIFY_SUCCEEDED(pLib->CreateBlobWithEncodingFromPinned(buffer.data(), buffer.size(), CP_ACP, &pNewProgramBlob));
  1089. CComPtr<IStream> pNewProgramStream;
  1090. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pNewProgramBlob, &pNewProgramStream));
  1091. CComPtr<IDiaDataSource> pDiaDataSource;
  1092. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1093. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1094. }
  1095. TEST_F(PixTest, DiaCompileArgs) {
  1096. static const char source[] = R"(
  1097. SamplerState samp0 : register(s0);
  1098. Texture2DArray tex0 : register(t0);
  1099. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1100. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1101. }
  1102. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1103. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1104. Texture2DArray textures[] = {
  1105. tex0,
  1106. };
  1107. return foo(textures, index, samp0, uvw);
  1108. }
  1109. )";
  1110. CComPtr<IDxcBlob> pPart;
  1111. CComPtr<IDiaDataSource> pDiaSource;
  1112. CComPtr<IStream> pStream;
  1113. CComPtr<IDxcLibrary> pLib;
  1114. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1115. const WCHAR *FlagList[] = {
  1116. L"/Zi",
  1117. L"-Zpr",
  1118. L"/Qembed_debug",
  1119. L"/Fd", L"F:\\my dir\\",
  1120. L"-Fo", L"F:\\my dir\\file.dxc",
  1121. };
  1122. const WCHAR *DefineList[] = {
  1123. L"MY_SPECIAL_DEFINE",
  1124. L"MY_OTHER_SPECIAL_DEFINE=\"MY_STRING\"",
  1125. };
  1126. std::vector<LPCWSTR> args;
  1127. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1128. args.push_back(FlagList[i]);
  1129. }
  1130. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1131. args.push_back(L"/D");
  1132. args.push_back(DefineList[i]);
  1133. }
  1134. auto CompileAndGetDebugPart = [&args](dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDxcBlob **ppDebugPart) {
  1135. CComPtr<IDxcBlob> pContainer;
  1136. CComPtr<IDxcLibrary> pLib;
  1137. CComPtr<IDxcContainerReflection> pReflection;
  1138. UINT32 index;
  1139. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  1140. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1141. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1142. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1143. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1144. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  1145. };
  1146. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1147. CComPtr<IStream> pNewProgramStream;
  1148. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pPart, &pNewProgramStream));
  1149. CComPtr<IDiaDataSource> pDiaDataSource;
  1150. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1151. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1152. CComPtr<IDiaSession> pSession;
  1153. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pSession));
  1154. CComPtr<IDiaEnumTables> pEnumTables;
  1155. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  1156. CComPtr<IDiaTable> pSymbolTable;
  1157. LONG uCount = 0;
  1158. VERIFY_SUCCEEDED(pEnumTables->get_Count(&uCount));
  1159. for (int i = 0; i < uCount; i++) {
  1160. CComPtr<IDiaTable> pTable;
  1161. VARIANT index = {};
  1162. index.vt = VT_I4;
  1163. index.intVal = i;
  1164. VERIFY_SUCCEEDED(pEnumTables->Item(index, &pTable));
  1165. CComBSTR pName;
  1166. VERIFY_SUCCEEDED(pTable->get_name(&pName));
  1167. if (pName == "Symbols") {
  1168. pSymbolTable = pTable;
  1169. break;
  1170. }
  1171. }
  1172. std::wstring Args;
  1173. std::wstring Entry;
  1174. std::wstring Target;
  1175. std::vector<std::wstring> Defines;
  1176. std::vector<std::wstring> Flags;
  1177. auto ReadNullSeparatedTokens = [](BSTR Str) -> std::vector<std::wstring> {
  1178. std::vector<std::wstring> Result;
  1179. while (*Str) {
  1180. Result.push_back(std::wstring(Str));
  1181. Str += wcslen(Str)+1;
  1182. }
  1183. return Result;
  1184. };
  1185. VERIFY_SUCCEEDED(pSymbolTable->get_Count(&uCount));
  1186. for (int i = 0; i < uCount; i++) {
  1187. CComPtr<IUnknown> pSymbolUnk;
  1188. CComPtr<IDiaSymbol> pSymbol;
  1189. CComVariant pValue;
  1190. CComBSTR pName;
  1191. VERIFY_SUCCEEDED(pSymbolTable->Item(i, &pSymbolUnk));
  1192. VERIFY_SUCCEEDED(pSymbolUnk->QueryInterface(&pSymbol));
  1193. VERIFY_SUCCEEDED(pSymbol->get_name(&pName));
  1194. VERIFY_SUCCEEDED(pSymbol->get_value(&pValue));
  1195. if (pName == "hlslTarget") {
  1196. if (pValue.vt == VT_BSTR)
  1197. Target = pValue.bstrVal;
  1198. }
  1199. else if (pName == "hlslEntry") {
  1200. if (pValue.vt == VT_BSTR)
  1201. Entry = pValue.bstrVal;
  1202. }
  1203. else if (pName == "hlslFlags") {
  1204. if (pValue.vt == VT_BSTR)
  1205. Flags = ReadNullSeparatedTokens(pValue.bstrVal);
  1206. }
  1207. else if (pName == "hlslArguments") {
  1208. if (pValue.vt == VT_BSTR)
  1209. Args = pValue.bstrVal;
  1210. }
  1211. else if (pName == "hlslDefines") {
  1212. if (pValue.vt == VT_BSTR)
  1213. Defines = ReadNullSeparatedTokens(pValue.bstrVal);
  1214. }
  1215. }
  1216. auto VectorContains = [](std::vector<std::wstring> &Tokens, std::wstring Sub) {
  1217. for (unsigned i = 0; i < Tokens.size(); i++) {
  1218. if (Tokens[i].find(Sub) != std::wstring::npos)
  1219. return true;
  1220. }
  1221. return false;
  1222. };
  1223. VERIFY_IS_TRUE(Target == L"ps_6_0");
  1224. VERIFY_IS_TRUE(Entry == L"main");
  1225. VERIFY_IS_TRUE(_countof(FlagList) == Flags.size());
  1226. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1227. VERIFY_IS_TRUE(Flags[i] == FlagList[i]);
  1228. }
  1229. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1230. VERIFY_IS_TRUE(VectorContains(Defines, DefineList[i]));
  1231. }
  1232. }
  1233. TEST_F(PixTest, DiaLoadBitcodePlusExtraData) {
  1234. // Test that dia doesn't crash when bitcode has unused extra data at the end
  1235. static const char source[] = R"(
  1236. SamplerState samp0 : register(s0);
  1237. Texture2DArray tex0 : register(t0);
  1238. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1239. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1240. }
  1241. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1242. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1243. Texture2DArray textures[] = {
  1244. tex0,
  1245. };
  1246. return foo(textures, index, samp0, uvw);
  1247. }
  1248. )";
  1249. CComPtr<IDxcBlob> pPart;
  1250. CComPtr<IDiaDataSource> pDiaSource;
  1251. CComPtr<IStream> pStream;
  1252. CComPtr<IDxcLibrary> pLib;
  1253. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1254. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1255. const char *pPartData = (char *)pPart->GetBufferPointer();
  1256. const size_t uPartSize = pPart->GetBufferSize();
  1257. // Get program header
  1258. const hlsl::DxilProgramHeader *programHeader = (hlsl::DxilProgramHeader *)pPartData;
  1259. const char *pBitcode = nullptr;
  1260. uint32_t uBitcodeSize = 0;
  1261. hlsl::GetDxilProgramBitcode(programHeader, &pBitcode, &uBitcodeSize);
  1262. llvm::SmallVector<char, 0> buffer;
  1263. llvm::raw_svector_ostream OS(buffer);
  1264. // Write the bitcode
  1265. OS.write(pBitcode, uBitcodeSize);
  1266. for (unsigned i = 0; i < 12; i++) {
  1267. OS.write(0xFF);
  1268. }
  1269. OS.flush();
  1270. // Try to load this new program, make sure dia is still okay.
  1271. CComPtr<IDxcBlobEncoding> pNewProgramBlob;
  1272. VERIFY_SUCCEEDED(pLib->CreateBlobWithEncodingFromPinned(buffer.data(), buffer.size(), CP_ACP, &pNewProgramBlob));
  1273. CComPtr<IStream> pNewProgramStream;
  1274. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pNewProgramBlob, &pNewProgramStream));
  1275. CComPtr<IDiaDataSource> pDiaDataSource;
  1276. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1277. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1278. }
  1279. TEST_F(PixTest, DiaLoadDebugThenOK) {
  1280. CompileTestAndLoadDia(m_dllSupport, nullptr);
  1281. }
  1282. TEST_F(PixTest, DiaTableIndexThenOK) {
  1283. CComPtr<IDiaDataSource> pDiaSource;
  1284. CComPtr<IDiaSession> pDiaSession;
  1285. CComPtr<IDiaEnumTables> pEnumTables;
  1286. CComPtr<IDiaTable> pTable;
  1287. VARIANT vtIndex;
  1288. CompileTestAndLoadDia(m_dllSupport, &pDiaSource);
  1289. VERIFY_SUCCEEDED(pDiaSource->openSession(&pDiaSession));
  1290. VERIFY_SUCCEEDED(pDiaSession->getEnumTables(&pEnumTables));
  1291. vtIndex.vt = VT_EMPTY;
  1292. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  1293. vtIndex.vt = VT_I4;
  1294. vtIndex.intVal = 1;
  1295. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  1296. VERIFY_IS_NOT_NULL(pTable.p);
  1297. pTable.Release();
  1298. vtIndex.vt = VT_UI4;
  1299. vtIndex.uintVal = 1;
  1300. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  1301. VERIFY_IS_NOT_NULL(pTable.p);
  1302. pTable.Release();
  1303. vtIndex.uintVal = 100;
  1304. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  1305. }
  1306. TEST_F(PixTest, PixDebugCompileInfo) {
  1307. static const char source[] = R"(
  1308. SamplerState samp0 : register(s0);
  1309. Texture2DArray tex0 : register(t0);
  1310. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1311. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1312. }
  1313. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1314. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1315. Texture2DArray textures[] = {
  1316. tex0,
  1317. };
  1318. return foo(textures, index, samp0, uvw);
  1319. }
  1320. )";
  1321. CComPtr<IDxcBlob> pPart;
  1322. CComPtr<IDiaDataSource> pDiaSource;
  1323. CComPtr<IStream> pStream;
  1324. CComPtr<IDxcLibrary> pLib;
  1325. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1326. const WCHAR *FlagList[] = {
  1327. L"/Zi", L"-Zpr", L"/Qembed_debug", L"/Fd",
  1328. L"F:\\my dir\\", L"-Fo", L"F:\\my dir\\file.dxc",
  1329. };
  1330. const WCHAR *DefineList[] = {
  1331. L"MY_SPECIAL_DEFINE",
  1332. L"MY_OTHER_SPECIAL_DEFINE=\"MY_STRING\"",
  1333. };
  1334. std::vector<LPCWSTR> args;
  1335. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1336. args.push_back(FlagList[i]);
  1337. }
  1338. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1339. args.push_back(L"/D");
  1340. args.push_back(DefineList[i]);
  1341. }
  1342. auto CompileAndGetDebugPart = [&args](dxc::DxcDllSupport &dllSupport,
  1343. const char *source, wchar_t *profile,
  1344. IDxcBlob **ppDebugPart) {
  1345. CComPtr<IDxcBlob> pContainer;
  1346. CComPtr<IDxcLibrary> pLib;
  1347. CComPtr<IDxcContainerReflection> pReflection;
  1348. UINT32 index;
  1349. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  1350. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1351. VERIFY_SUCCEEDED(
  1352. dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1353. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1354. VERIFY_SUCCEEDED(
  1355. pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1356. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  1357. };
  1358. constexpr wchar_t *profile = L"ps_6_0";
  1359. CompileAndGetDebugPart(m_dllSupport, source, profile, &pPart);
  1360. CComPtr<IStream> pNewProgramStream;
  1361. VERIFY_SUCCEEDED(
  1362. pLib->CreateStreamFromBlobReadOnly(pPart, &pNewProgramStream));
  1363. CComPtr<IDiaDataSource> pDiaDataSource;
  1364. VERIFY_SUCCEEDED(
  1365. m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1366. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1367. CComPtr<IDiaSession> pSession;
  1368. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pSession));
  1369. CComPtr<IDxcPixDxilDebugInfoFactory> factory;
  1370. VERIFY_SUCCEEDED(pSession->QueryInterface(IID_PPV_ARGS(&factory)));
  1371. CComPtr<IDxcPixCompilationInfo> compilationInfo;
  1372. VERIFY_SUCCEEDED(factory->NewDxcPixCompilationInfo(&compilationInfo));
  1373. CComBSTR arguments;
  1374. VERIFY_SUCCEEDED(compilationInfo->GetArguments(&arguments));
  1375. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1376. VERIFY_IS_TRUE(nullptr != wcsstr(arguments, FlagList[i]));
  1377. }
  1378. CComBSTR macros;
  1379. VERIFY_SUCCEEDED(compilationInfo->GetMacroDefinitions(&macros));
  1380. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1381. std::wstring MacroDef = std::wstring(L"-D") + DefineList[i];
  1382. VERIFY_IS_TRUE(nullptr != wcsstr(macros, MacroDef.c_str()));
  1383. }
  1384. CComBSTR entryPointFile;
  1385. VERIFY_SUCCEEDED(compilationInfo->GetEntryPointFile(&entryPointFile));
  1386. VERIFY_ARE_EQUAL(std::wstring(L"source.hlsl"), std::wstring(entryPointFile));
  1387. CComBSTR entryPointFunction;
  1388. VERIFY_SUCCEEDED(compilationInfo->GetEntryPoint(&entryPointFunction));
  1389. VERIFY_ARE_EQUAL(std::wstring(L"main"), std::wstring(entryPointFunction));
  1390. CComBSTR hlslTarget;
  1391. VERIFY_SUCCEEDED(compilationInfo->GetHlslTarget(&hlslTarget));
  1392. VERIFY_ARE_EQUAL(std::wstring(profile), std::wstring(hlslTarget));
  1393. }
  1394. // This function lives in lib\DxilPIXPasses\DxilAnnotateWithVirtualRegister.cpp
  1395. // Declared here so we can test it.
  1396. uint32_t CountStructMembers(llvm::Type const* pType);
  1397. PixTest::TestableResults PixTest::TestStructAnnotationCase(
  1398. const char* hlsl,
  1399. const wchar_t * optimizationLevel,
  1400. bool validateCoverage)
  1401. {
  1402. auto pOperationResult = Compile(hlsl, L"as_6_5", { optimizationLevel } );
  1403. CComPtr<IDxcBlob> pBlob;
  1404. CheckOperationSucceeded(pOperationResult, &pBlob);
  1405. CComPtr<IDxcBlob> pDxil = FindModule(DFCC_ShaderDebugInfoDXIL, pBlob);
  1406. PassOutput passOutput = RunAnnotationPasses(pDxil);
  1407. auto pAnnotated = passOutput.blob;
  1408. CComPtr<IDxcBlob> pAnnotatedContainer;
  1409. ReplaceDxilBlobPart(
  1410. pBlob->GetBufferPointer(),
  1411. pBlob->GetBufferSize(),
  1412. pAnnotated,
  1413. &pAnnotatedContainer);
  1414. #if 0 // handy for debugging
  1415. auto disTextW = Disassemble(pAnnotatedContainer);
  1416. WEX::Logging::Log::Comment(disTextW.c_str());
  1417. #endif
  1418. ModuleAndHangersOn moduleEtc(pAnnotatedContainer);
  1419. llvm::Function *entryFunction = moduleEtc.GetDxilModule().GetEntryFunction();
  1420. PixTest::TestableResults ret;
  1421. // For every dbg.declare, run the member iterator and record what it finds:
  1422. for (auto& block : entryFunction->getBasicBlockList())
  1423. {
  1424. for (auto& instruction : block.getInstList())
  1425. {
  1426. if (auto* dbgDeclare = llvm::dyn_cast<llvm::DbgDeclareInst>(&instruction))
  1427. {
  1428. llvm::Value* Address = dbgDeclare->getAddress();
  1429. auto* AddressAsAlloca = llvm::dyn_cast<llvm::AllocaInst>(Address);
  1430. if (AddressAsAlloca != nullptr)
  1431. {
  1432. auto* Expression = dbgDeclare->getExpression();
  1433. std::unique_ptr<dxil_debug_info::MemberIterator> iterator = dxil_debug_info::CreateMemberIterator(
  1434. dbgDeclare,
  1435. moduleEtc.GetDxilModule().GetModule()->getDataLayout(),
  1436. AddressAsAlloca,
  1437. Expression);
  1438. unsigned int startingBit = 0;
  1439. unsigned int coveredBits = 0;
  1440. unsigned int memberIndex = 0;
  1441. unsigned int memberCount = 0;
  1442. while (iterator->Next(&memberIndex))
  1443. {
  1444. memberCount++;
  1445. if (memberIndex == 0)
  1446. {
  1447. startingBit = iterator->OffsetInBits(memberIndex);
  1448. coveredBits = iterator->SizeInBits(memberIndex);
  1449. }
  1450. else
  1451. {
  1452. coveredBits = std::max<unsigned int>(coveredBits, iterator->OffsetInBits(memberIndex) + iterator->SizeInBits(memberIndex));
  1453. }
  1454. }
  1455. ret.OffsetAndSizes.push_back({ memberCount, startingBit, coveredBits });
  1456. // Use this independent count of number of struct members to test the
  1457. // function that operates on the alloca type:
  1458. llvm::Type* pAllocaTy = AddressAsAlloca->getType()->getElementType();
  1459. if (auto* AT = llvm::dyn_cast<llvm::ArrayType>(pAllocaTy))
  1460. {
  1461. // This is the case where a struct is passed to a function, and in
  1462. // these tests there should be only one struct behind the pointer.
  1463. VERIFY_ARE_EQUAL(AT->getNumElements(), 1);
  1464. pAllocaTy = AT->getArrayElementType();
  1465. }
  1466. if (auto* ST = llvm::dyn_cast<llvm::StructType>(pAllocaTy))
  1467. {
  1468. uint32_t countOfMembers = CountStructMembers(ST);
  1469. // memberIndex might be greater, because the fragment iterator also includes contained derived types as
  1470. // fragments, in addition to the members of that contained derived types. CountStructMembers only counts
  1471. // the leaf-node types.
  1472. VERIFY_ARE_EQUAL(countOfMembers, memberCount);
  1473. }
  1474. else if (pAllocaTy->isFloatingPointTy() || pAllocaTy->isIntegerTy())
  1475. {
  1476. // If there's only one member in the struct in the pass-to-function (by pointer)
  1477. // case, then the underlying type will have been reduced to the contained type.
  1478. VERIFY_ARE_EQUAL(1, memberCount);
  1479. }
  1480. else
  1481. {
  1482. VERIFY_IS_TRUE(false);
  1483. }
  1484. }
  1485. }
  1486. }
  1487. }
  1488. // The member iterator should find a solid run of bits that is exactly covered
  1489. // by exactly one of the members found by the annotation pass:
  1490. if (validateCoverage)
  1491. {
  1492. for (auto const& cover : ret.OffsetAndSizes)
  1493. {
  1494. bool found = false;
  1495. for (auto const& valueLocation : passOutput.valueLocations)
  1496. {
  1497. constexpr unsigned int eightBitsPerByte = 8;
  1498. if (valueLocation.base * eightBitsPerByte == cover.offset)
  1499. {
  1500. VERIFY_IS_FALSE(found);
  1501. found = true;
  1502. VERIFY_ARE_EQUAL(valueLocation.count, cover.countOfMembers);
  1503. }
  1504. }
  1505. VERIFY_IS_TRUE(found);
  1506. }
  1507. }
  1508. // For every store operation to the struct alloca, check that the annotation pass correctly determined which alloca
  1509. for (auto& block : entryFunction->getBasicBlockList()) {
  1510. for (auto& instruction : block.getInstList()) {
  1511. if (auto* store =
  1512. llvm::dyn_cast<llvm::StoreInst>(&instruction)) {
  1513. if (auto* pGEP = llvm::dyn_cast<llvm::GetElementPtrInst>(store->getPointerOperand()))
  1514. {
  1515. ret.AllocaWrites.push_back({});
  1516. auto& NewAllocaWrite = ret.AllocaWrites.back();
  1517. llvm::Value* pPointerOperand = pGEP->getPointerOperand();
  1518. if (auto* pGEP2 = llvm::dyn_cast<llvm::GetElementPtrInst>(pPointerOperand))
  1519. {
  1520. auto *pMemberIndex = llvm::dyn_cast<llvm::ConstantInt>(
  1521. pGEP->getOperand(2));
  1522. uint64_t memberIndex = pMemberIndex->getLimitedValue();
  1523. // Until we have debugging info for floatN, matrixNxM etc., we can't get the name:
  1524. // auto *secondPointer = pGEP2->getPointerOperandType();
  1525. // auto* pStruct =
  1526. // llvm::dyn_cast<llvm::StructType>(secondPointer->getVectorElementType());
  1527. NewAllocaWrite.memberName =
  1528. "member" + std::to_string(memberIndex);
  1529. }
  1530. else
  1531. {
  1532. NewAllocaWrite.memberName = pGEP->getName();
  1533. }
  1534. llvm::Value* index;
  1535. if (pix_dxil::PixAllocaRegWrite::FromInst(
  1536. store,
  1537. &NewAllocaWrite.regBase,
  1538. &NewAllocaWrite.regSize,
  1539. &index)) {
  1540. auto* asInt = llvm::dyn_cast<llvm::ConstantInt>(index);
  1541. NewAllocaWrite.index = asInt->getLimitedValue();
  1542. }
  1543. }
  1544. }
  1545. }
  1546. }
  1547. return ret;
  1548. }
  1549. void PixTest::ValidateAllocaWrite(std::vector<AllocaWrite> const &allocaWrites,
  1550. size_t index, const char *name) {
  1551. VERIFY_ARE_EQUAL(index, allocaWrites[index].regBase + allocaWrites[index].index);
  1552. #if DBG
  1553. // Compilation may add a prefix to the struct member name:
  1554. VERIFY_IS_TRUE(0 == strncmp(name, allocaWrites[index].memberName.c_str(), strlen(name)));
  1555. #endif
  1556. }
  1557. std::vector<const wchar_t*> OptimizationChoices ({ L"-Od", L"-O1" });
  1558. TEST_F(PixTest, PixStructAnnotation_Simple) {
  1559. if (m_ver.SkipDxilVersion(1, 5)) return;
  1560. for (auto const* optimization : OptimizationChoices)
  1561. {
  1562. const char* hlsl = R"(
  1563. struct smallPayload
  1564. {
  1565. uint dummy;
  1566. };
  1567. [numthreads(1, 1, 1)]
  1568. void main()
  1569. {
  1570. smallPayload p;
  1571. p.dummy = 42;
  1572. DispatchMesh(1, 1, 1, p);
  1573. }
  1574. )";
  1575. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1576. if (!Testables.OffsetAndSizes.empty())
  1577. {
  1578. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1579. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes[0].countOfMembers);
  1580. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1581. VERIFY_ARE_EQUAL(32, Testables.OffsetAndSizes[0].size);
  1582. }
  1583. VERIFY_ARE_EQUAL(1, Testables.AllocaWrites.size());
  1584. ValidateAllocaWrite(Testables.AllocaWrites, 0, "dummy");
  1585. }
  1586. }
  1587. TEST_F(PixTest, PixStructAnnotation_CopiedStruct) {
  1588. if (m_ver.SkipDxilVersion(1, 5)) return;
  1589. for (auto const* optimization : OptimizationChoices) {
  1590. const char* hlsl = R"(
  1591. struct smallPayload
  1592. {
  1593. uint dummy;
  1594. };
  1595. [numthreads(1, 1, 1)]
  1596. void main()
  1597. {
  1598. smallPayload p;
  1599. p.dummy = 42;
  1600. smallPayload p2 = p;
  1601. DispatchMesh(1, 1, 1, p2);
  1602. }
  1603. )";
  1604. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1605. // 2 in unoptimized case (one for each instance of smallPayload)
  1606. // 1 in optimized case (cuz p2 aliases over p)
  1607. VERIFY_IS_TRUE(Testables.OffsetAndSizes.size() >= 1);
  1608. for (const auto& os : Testables.OffsetAndSizes) {
  1609. VERIFY_ARE_EQUAL(1, os.countOfMembers);
  1610. VERIFY_ARE_EQUAL(0, os.offset);
  1611. VERIFY_ARE_EQUAL(32, os.size);
  1612. }
  1613. VERIFY_ARE_EQUAL(1, Testables.AllocaWrites.size());
  1614. }
  1615. }
  1616. TEST_F(PixTest, PixStructAnnotation_MixedSizes) {
  1617. if (m_ver.SkipDxilVersion(1, 5)) return;
  1618. for (auto const* optimization : OptimizationChoices) {
  1619. const char* hlsl = R"(
  1620. struct smallPayload
  1621. {
  1622. bool b1;
  1623. uint16_t sixteen;
  1624. uint32_t thirtytwo;
  1625. uint64_t sixtyfour;
  1626. };
  1627. [numthreads(1, 1, 1)]
  1628. void main()
  1629. {
  1630. smallPayload p;
  1631. p.b1 = true;
  1632. p.sixteen = 16;
  1633. p.thirtytwo = 32;
  1634. p.sixtyfour = 64;
  1635. DispatchMesh(1, 1, 1, p);
  1636. }
  1637. )";
  1638. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1639. if (!Testables.OffsetAndSizes.empty()) {
  1640. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1641. VERIFY_ARE_EQUAL(4, Testables.OffsetAndSizes[0].countOfMembers);
  1642. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1643. // 8 bytes align for uint64_t:
  1644. VERIFY_ARE_EQUAL(32 + 16 + 16 /*alignment for next field*/ + 32 + 32/*alignment for max align*/ + 64,
  1645. Testables.OffsetAndSizes[0].size);
  1646. }
  1647. VERIFY_ARE_EQUAL(4, Testables.AllocaWrites.size());
  1648. ValidateAllocaWrite(Testables.AllocaWrites, 0, "b1");
  1649. ValidateAllocaWrite(Testables.AllocaWrites, 1, "sixteen");
  1650. ValidateAllocaWrite(Testables.AllocaWrites, 2, "thirtytwo");
  1651. ValidateAllocaWrite(Testables.AllocaWrites, 3, "sixtyfour");
  1652. }
  1653. }
  1654. TEST_F(PixTest, PixStructAnnotation_StructWithinStruct) {
  1655. if (m_ver.SkipDxilVersion(1, 5)) return;
  1656. for (auto const* optimization : OptimizationChoices) {
  1657. const char* hlsl = R"(
  1658. struct Contained
  1659. {
  1660. uint32_t one;
  1661. uint32_t two;
  1662. };
  1663. struct smallPayload
  1664. {
  1665. uint32_t before;
  1666. Contained contained;
  1667. uint32_t after;
  1668. };
  1669. [numthreads(1, 1, 1)]
  1670. void main()
  1671. {
  1672. smallPayload p;
  1673. p.before = 0xb4;
  1674. p.contained.one = 1;
  1675. p.contained.two = 2;
  1676. p.after = 3;
  1677. DispatchMesh(1, 1, 1, p);
  1678. }
  1679. )";
  1680. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1681. if (!Testables.OffsetAndSizes.empty()) {
  1682. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1683. VERIFY_ARE_EQUAL(4, Testables.OffsetAndSizes[0].countOfMembers);
  1684. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1685. VERIFY_ARE_EQUAL(4 * 32, Testables.OffsetAndSizes[0].size);
  1686. }
  1687. ValidateAllocaWrite(Testables.AllocaWrites, 0, "before");
  1688. ValidateAllocaWrite(Testables.AllocaWrites, 1, "one");
  1689. ValidateAllocaWrite(Testables.AllocaWrites, 2, "two");
  1690. ValidateAllocaWrite(Testables.AllocaWrites, 3, "after");
  1691. }
  1692. }
  1693. TEST_F(PixTest, PixStructAnnotation_1DArray) {
  1694. if (m_ver.SkipDxilVersion(1, 5)) return;
  1695. for (auto const* optimization : OptimizationChoices) {
  1696. const char* hlsl = R"(
  1697. struct smallPayload
  1698. {
  1699. uint32_t Array[2];
  1700. };
  1701. [numthreads(1, 1, 1)]
  1702. void main()
  1703. {
  1704. smallPayload p;
  1705. p.Array[0] = 250;
  1706. p.Array[1] = 251;
  1707. DispatchMesh(1, 1, 1, p);
  1708. }
  1709. )";
  1710. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1711. if (!Testables.OffsetAndSizes.empty()) {
  1712. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1713. VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1714. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1715. VERIFY_ARE_EQUAL(2 * 32, Testables.OffsetAndSizes[0].size);
  1716. }
  1717. VERIFY_ARE_EQUAL(2, Testables.AllocaWrites.size());
  1718. }
  1719. }
  1720. TEST_F(PixTest, PixStructAnnotation_2DArray) {
  1721. if (m_ver.SkipDxilVersion(1, 5)) return;
  1722. for (auto const* optimization : OptimizationChoices) {
  1723. const char* hlsl = R"(
  1724. struct smallPayload
  1725. {
  1726. uint32_t TwoDArray[2][3];
  1727. };
  1728. [numthreads(1, 1, 1)]
  1729. void main()
  1730. {
  1731. smallPayload p;
  1732. p.TwoDArray[0][0] = 250;
  1733. p.TwoDArray[0][1] = 251;
  1734. p.TwoDArray[0][2] = 252;
  1735. p.TwoDArray[1][0] = 253;
  1736. p.TwoDArray[1][1] = 254;
  1737. p.TwoDArray[1][2] = 255;
  1738. DispatchMesh(1, 1, 1, p);
  1739. }
  1740. )";
  1741. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1742. if (!Testables.OffsetAndSizes.empty()) {
  1743. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1744. VERIFY_ARE_EQUAL(6, Testables.OffsetAndSizes[0].countOfMembers);
  1745. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1746. VERIFY_ARE_EQUAL(2 * 3 * 32, Testables.OffsetAndSizes[0].size);
  1747. }
  1748. VERIFY_ARE_EQUAL(6, Testables.AllocaWrites.size());
  1749. }
  1750. }
  1751. TEST_F(PixTest, PixStructAnnotation_EmbeddedArray) {
  1752. if (m_ver.SkipDxilVersion(1, 5)) return;
  1753. for (auto const* optimization : OptimizationChoices) {
  1754. const char* hlsl = R"(
  1755. struct Contained
  1756. {
  1757. uint32_t array[3];
  1758. };
  1759. struct smallPayload
  1760. {
  1761. uint32_t before;
  1762. Contained contained;
  1763. uint32_t after;
  1764. };
  1765. [numthreads(1, 1, 1)]
  1766. void main()
  1767. {
  1768. smallPayload p;
  1769. p.before = 0xb4;
  1770. p.contained.array[0] = 0;
  1771. p.contained.array[1] = 1;
  1772. p.contained.array[2] = 2;
  1773. p.after = 3;
  1774. DispatchMesh(1, 1, 1, p);
  1775. }
  1776. )";
  1777. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1778. if (!Testables.OffsetAndSizes.empty()) {
  1779. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1780. VERIFY_ARE_EQUAL(5, Testables.OffsetAndSizes[0].countOfMembers);
  1781. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1782. VERIFY_ARE_EQUAL(5 * 32, Testables.OffsetAndSizes[0].size);
  1783. }
  1784. ValidateAllocaWrite(Testables.AllocaWrites, 0, "before");
  1785. ValidateAllocaWrite(Testables.AllocaWrites, 1, "array");
  1786. ValidateAllocaWrite(Testables.AllocaWrites, 2, "array");
  1787. ValidateAllocaWrite(Testables.AllocaWrites, 3, "array");
  1788. ValidateAllocaWrite(Testables.AllocaWrites, 4, "after");
  1789. }
  1790. }
  1791. TEST_F(PixTest, PixStructAnnotation_FloatN) {
  1792. if (m_ver.SkipDxilVersion(1, 5)) return;
  1793. for (auto const* optimization : OptimizationChoices) {
  1794. const char* hlsl = R"(
  1795. struct smallPayload
  1796. {
  1797. float2 f2;
  1798. };
  1799. [numthreads(1, 1, 1)]
  1800. void main()
  1801. {
  1802. smallPayload p;
  1803. p.f2 = float2(1,2);
  1804. DispatchMesh(1, 1, 1, p);
  1805. }
  1806. )";
  1807. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1808. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1809. VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1810. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1811. VERIFY_ARE_EQUAL(32 + 32, Testables.OffsetAndSizes[0].size);
  1812. bool IsOptimized = (wcscmp(optimization, L"-Od") != 0);
  1813. VERIFY_ARE_EQUAL(2, Testables.AllocaWrites.size());
  1814. ValidateAllocaWrite(Testables.AllocaWrites, 0, (IsOptimized ? "" : "member0")); // "memberN" until dbg.declare works
  1815. ValidateAllocaWrite(Testables.AllocaWrites, 1, (IsOptimized ? "" : "member1")); // "memberN" until dbg.declare works
  1816. break; // don't run -O1 test until pointer types are dealt with by value-to-declare pass
  1817. }
  1818. }
  1819. TEST_F(PixTest, PixStructAnnotation_SequentialFloatN) {
  1820. if (m_ver.SkipDxilVersion(1, 5)) return;
  1821. for (auto const* optimization : OptimizationChoices) {
  1822. const char* hlsl = R"(
  1823. struct smallPayload
  1824. {
  1825. float3 color;
  1826. float3 dir;
  1827. };
  1828. [numthreads(1, 1, 1)]
  1829. void main()
  1830. {
  1831. smallPayload p;
  1832. p.color = float3(1,2,3);
  1833. p.dir = float3(4,5,6);
  1834. DispatchMesh(1, 1, 1, p);
  1835. }
  1836. )";
  1837. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1838. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1839. VERIFY_ARE_EQUAL(6, Testables.OffsetAndSizes[0].countOfMembers);
  1840. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1841. VERIFY_ARE_EQUAL(32 * 6, Testables.OffsetAndSizes[0].size);
  1842. VERIFY_ARE_EQUAL(6, Testables.AllocaWrites.size());
  1843. bool IsOptimized = (wcscmp(optimization, L"-Od") != 0);
  1844. ValidateAllocaWrite(Testables.AllocaWrites, 0, (IsOptimized ? "" : "member0") ); // "memberN" until dbg.declare works
  1845. ValidateAllocaWrite(Testables.AllocaWrites, 1, (IsOptimized ? "" : "member1") ); // "memberN" until dbg.declare works
  1846. ValidateAllocaWrite(Testables.AllocaWrites, 2, (IsOptimized ? "" : "member2") ); // "memberN" until dbg.declare works
  1847. ValidateAllocaWrite(Testables.AllocaWrites, 3, (IsOptimized ? "" : "member0") ); // "memberN" until dbg.declare works
  1848. ValidateAllocaWrite(Testables.AllocaWrites, 4, (IsOptimized ? "" : "member1") ); // "memberN" until dbg.declare works
  1849. ValidateAllocaWrite(Testables.AllocaWrites, 5, (IsOptimized ? "" : "member2") ); // "memberN" until dbg.declare works
  1850. break; // don't run -O1 test until pointer types are dealt with by
  1851. // value-to-declare pass
  1852. }
  1853. }
  1854. TEST_F(PixTest, PixStructAnnotation_EmbeddedFloatN) {
  1855. if (m_ver.SkipDxilVersion(1, 5)) return;
  1856. for (auto const* optimization : OptimizationChoices) {
  1857. const char* hlsl = R"(
  1858. struct Embedded
  1859. {
  1860. float2 f2;
  1861. };
  1862. struct smallPayload
  1863. {
  1864. uint32_t i32;
  1865. Embedded e;
  1866. };
  1867. [numthreads(1, 1, 1)]
  1868. void main()
  1869. {
  1870. smallPayload p;
  1871. p.i32 = 32;
  1872. p.e.f2 = float2(1,2);
  1873. DispatchMesh(1, 1, 1, p);
  1874. }
  1875. )";
  1876. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1877. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1878. VERIFY_ARE_EQUAL(3, Testables.OffsetAndSizes[0].countOfMembers);
  1879. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1880. VERIFY_ARE_EQUAL(32 * 3, Testables.OffsetAndSizes[0].size);
  1881. VERIFY_ARE_EQUAL(3, Testables.AllocaWrites.size());
  1882. bool IsOptimized = (wcscmp(optimization, L"-Od") != 0);
  1883. ValidateAllocaWrite(Testables.AllocaWrites, 0, "");
  1884. ValidateAllocaWrite(Testables.AllocaWrites, 1, (IsOptimized ? "" : "member0"));
  1885. ValidateAllocaWrite(Testables.AllocaWrites, 2, (IsOptimized ? "" : "member1"));
  1886. break; // don't run -O1 test until pointer types are dealt with by
  1887. // value-to-declare pass
  1888. }
  1889. }
  1890. TEST_F(PixTest, PixStructAnnotation_Matrix) {
  1891. if (m_ver.SkipDxilVersion(1, 5)) return;
  1892. for (auto const* optimization : OptimizationChoices) {
  1893. const char* hlsl = R"(
  1894. struct smallPayload
  1895. {
  1896. float4x4 mat;
  1897. };
  1898. [numthreads(1, 1, 1)]
  1899. void main()
  1900. {
  1901. smallPayload p;
  1902. p.mat = float4x4( 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15, 16);
  1903. DispatchMesh(1, 1, 1, p);
  1904. }
  1905. )";
  1906. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  1907. // Can't test member iterator until dbg.declare instructions are emitted when structs
  1908. // contain pointers-to-pointers
  1909. VERIFY_ARE_EQUAL(16, Testables.AllocaWrites.size());
  1910. for (int i = 0; i < 16; ++i)
  1911. {
  1912. ValidateAllocaWrite(Testables.AllocaWrites, i, "");
  1913. }
  1914. }
  1915. }
  1916. TEST_F(PixTest, PixStructAnnotation_MemberFunction) {
  1917. if (m_ver.SkipDxilVersion(1, 5))
  1918. return;
  1919. for (auto const* optimization : OptimizationChoices) {
  1920. const char* hlsl = R"(
  1921. RWStructuredBuffer<float> floatRWUAV: register(u0);
  1922. struct smallPayload
  1923. {
  1924. int i;
  1925. };
  1926. float2 signNotZero(float2 v)
  1927. {
  1928. return (v > 0.0f ? float(1).xx : float(-1).xx);
  1929. }
  1930. float2 unpackUnorm2(uint packed)
  1931. {
  1932. return (1.0 / 65535.0) * float2((packed >> 16) & 0xffff, packed & 0xffff);
  1933. }
  1934. float3 unpackOctahedralSnorm(float2 e)
  1935. {
  1936. float3 v = float3(e.xy, 1.0f - abs(e.x) - abs(e.y));
  1937. if (v.z < 0.0f) v.xy = (1.0f - abs(v.yx)) * signNotZero(v.xy);
  1938. return normalize(v);
  1939. }
  1940. float3 unpackOctahedralUnorm(float2 e)
  1941. {
  1942. return unpackOctahedralSnorm(e * 2.0f - 1.0f);
  1943. }
  1944. float2 unpackHalf2(uint packed)
  1945. {
  1946. return float2(f16tof32(packed >> 16), f16tof32(packed & 0xffff));
  1947. }
  1948. struct Gbuffer
  1949. {
  1950. float3 worldNormal;
  1951. float3 objectNormal; //offset:12
  1952. float linearZ; //24
  1953. float prevLinearZ; //28
  1954. float fwidthLinearZ; //32
  1955. float fwidthObjectNormal; //36
  1956. uint materialType; //40
  1957. uint2 materialParams0; //44
  1958. uint4 materialParams1; //52 <--------- this is the variable that's being covered twice (52*8 = 416 416)
  1959. uint instanceId; //68 <------- and there's one dword left over, as expected
  1960. void load(int2 pixelPos, Texture2DArray<uint4> gbTex)
  1961. {
  1962. uint4 data0 = gbTex.Load(int4(pixelPos, 0, 0));
  1963. uint4 data1 = gbTex.Load(int4(pixelPos, 1, 0));
  1964. uint4 data2 = gbTex.Load(int4(pixelPos, 2, 0));
  1965. worldNormal = unpackOctahedralUnorm(unpackUnorm2(data0.x));
  1966. linearZ = f16tof32((data0.y >> 8) & 0xffff);
  1967. materialType = (data0.y & 0xff);
  1968. materialParams0 = data0.zw;
  1969. materialParams1 = data1.xyzw;
  1970. instanceId = data2.x;
  1971. prevLinearZ = asfloat(data2.y);
  1972. objectNormal = unpackOctahedralUnorm(unpackUnorm2(data2.z));
  1973. float2 fwidth = unpackHalf2(data2.w);
  1974. fwidthLinearZ = fwidth.x;
  1975. fwidthObjectNormal = fwidth.y;
  1976. }
  1977. };
  1978. Gbuffer loadGbuffer(int2 pixelPos, Texture2DArray<uint4> gbTex)
  1979. {
  1980. Gbuffer output;
  1981. output.load(pixelPos, gbTex);
  1982. return output;
  1983. }
  1984. Texture2DArray<uint4> g_gbuffer : register(t0, space0);
  1985. [numthreads(1, 1, 1)]
  1986. void main()
  1987. {
  1988. const Gbuffer gbuffer = loadGbuffer(int2(0,0), g_gbuffer);
  1989. smallPayload p;
  1990. p.i = gbuffer.materialParams1.x + gbuffer.materialParams1.y + gbuffer.materialParams1.z + gbuffer.materialParams1.w;
  1991. DispatchMesh(1, 1, 1, p);
  1992. }
  1993. )";
  1994. // Probably related to PIX bug #29512388. Coverage validation awaiting that fix for optimized shaders
  1995. bool validateCoverage = (wcscmp(optimization, L"-Od") == 0);
  1996. auto Testables = TestStructAnnotationCase(hlsl, optimization, validateCoverage);
  1997. // Can't test member iterator until dbg.declare instructions are emitted when structs
  1998. // contain pointers-to-pointers
  1999. // Can't validate # of writes: rel and dbg are different
  2000. //VERIFY_ARE_EQUAL(43, Testables.AllocaWrites.size());
  2001. // Can't test individual writes until struct member names are returned:
  2002. //for (int i = 0; i < 51; ++i)
  2003. //{
  2004. // ValidateAllocaWrite(Testables.AllocaWrites, i, "");
  2005. //}
  2006. }
  2007. }
  2008. TEST_F(PixTest, PixStructAnnotation_BigMess) {
  2009. if (m_ver.SkipDxilVersion(1, 5)) return;
  2010. for (auto const* optimization : OptimizationChoices) {
  2011. const char* hlsl = R"(
  2012. struct BigStruct
  2013. {
  2014. uint64_t bigInt;
  2015. double bigDouble;
  2016. };
  2017. struct EmbeddedStruct
  2018. {
  2019. uint32_t OneInt;
  2020. uint32_t TwoDArray[2][2];
  2021. };
  2022. struct smallPayload
  2023. {
  2024. uint dummy;
  2025. uint vertexCount;
  2026. uint primitiveCount;
  2027. EmbeddedStruct embeddedStruct;
  2028. #ifdef PAYLOAD_MATRICES
  2029. float4x4 mat;
  2030. #endif
  2031. uint64_t bigOne;
  2032. half littleOne;
  2033. BigStruct bigStruct[2];
  2034. uint lastCheck;
  2035. };
  2036. [numthreads(1, 1, 1)]
  2037. void main()
  2038. {
  2039. smallPayload p;
  2040. // Adding enough instructions to make the shader interesting to debug:
  2041. p.dummy = 42;
  2042. p.vertexCount = 3;
  2043. p.primitiveCount = 1;
  2044. p.embeddedStruct.OneInt = 123;
  2045. p.embeddedStruct.TwoDArray[0][0] = 252;
  2046. p.embeddedStruct.TwoDArray[0][1] = 253;
  2047. p.embeddedStruct.TwoDArray[1][0] = 254;
  2048. p.embeddedStruct.TwoDArray[1][1] = 255;
  2049. #ifdef PAYLOAD_MATRICES
  2050. p.mat = float4x4( 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15, 16);
  2051. #endif
  2052. p.bigOne = 123456789;
  2053. p.littleOne = 1.0;
  2054. p.bigStruct[0].bigInt = 10;
  2055. p.bigStruct[0].bigDouble = 2.0;
  2056. p.bigStruct[1].bigInt = 20;
  2057. p.bigStruct[1].bigDouble = 4.0;
  2058. p.lastCheck = 27;
  2059. DispatchMesh(1, 1, 1, p);
  2060. }
  2061. )";
  2062. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  2063. if (!Testables.OffsetAndSizes.empty()) {
  2064. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  2065. VERIFY_ARE_EQUAL(15, Testables.OffsetAndSizes[0].countOfMembers);
  2066. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  2067. constexpr uint32_t BigStructBitSize = 64 * 2;
  2068. constexpr uint32_t EmbeddedStructBitSize = 32 * 5;
  2069. VERIFY_ARE_EQUAL(3 * 32 + EmbeddedStructBitSize + 64 + 16 + 16/*alignment for next field*/ + BigStructBitSize * 2 + 32 + 32/*align to max align*/, Testables.OffsetAndSizes[0].size);
  2070. }
  2071. VERIFY_ARE_EQUAL(15, Testables.AllocaWrites.size());
  2072. }
  2073. }
  2074. TEST_F(PixTest, PixStructAnnotation_AlignedFloat4Arrays) {
  2075. if (m_ver.SkipDxilVersion(1, 5)) return;
  2076. for (auto const* optimization : OptimizationChoices) {
  2077. const char* hlsl = R"(
  2078. struct LinearSHSampleData
  2079. {
  2080. float4 linearTerms[3];
  2081. float4 hdrColorAO;
  2082. float4 visibilitySH;
  2083. } g_lhSampleData;
  2084. struct smallPayload
  2085. {
  2086. LinearSHSampleData lhSampleData;
  2087. };
  2088. [numthreads(1, 1, 1)]
  2089. void main()
  2090. {
  2091. smallPayload p;
  2092. p.lhSampleData.linearTerms[0].x = g_lhSampleData.linearTerms[0].x;
  2093. DispatchMesh(1, 1, 1, p);
  2094. }
  2095. )";
  2096. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  2097. // Can't test offsets and sizes until dbg.declare instructions are emitted when floatn is used (https://github.com/microsoft/DirectXShaderCompiler/issues/2920)
  2098. //VERIFY_ARE_EQUAL(20, Testables.AllocaWrites.size());
  2099. }
  2100. }
  2101. TEST_F(PixTest, PixStructAnnotation_Inheritance) {
  2102. if (m_ver.SkipDxilVersion(1, 5)) return;
  2103. for (auto const* optimization : OptimizationChoices) {
  2104. // don't run -Od test until -Od inheritance is fixed (#3274:
  2105. // https://github.com/microsoft/DirectXShaderCompiler/issues/3274)
  2106. bool IsOptimized = (wcscmp(optimization, L"-Od") != 0);
  2107. if (!IsOptimized)
  2108. continue;
  2109. const char* hlsl = R"(
  2110. struct Base
  2111. {
  2112. float floatValue;
  2113. };
  2114. struct Derived : Base
  2115. {
  2116. int intValue;
  2117. };
  2118. [numthreads(1, 1, 1)]
  2119. void main()
  2120. {
  2121. Derived p;
  2122. p.floatValue = 1.;
  2123. p.intValue = 2;
  2124. DispatchMesh(1, 1, 1, p);
  2125. }
  2126. )";
  2127. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  2128. // Can't test offsets and sizes until dbg.declare instructions are emitted when floatn is used (https://github.com/microsoft/DirectXShaderCompiler/issues/2920)
  2129. //VERIFY_ARE_EQUAL(20, Testables.AllocaWrites.size());
  2130. }
  2131. }
  2132. TEST_F(PixTest, PixStructAnnotation_ResourceAsMember) {
  2133. if (m_ver.SkipDxilVersion(1, 5)) return;
  2134. for (auto const* optimization : OptimizationChoices) {
  2135. const char* hlsl = R"(
  2136. Buffer g_texture;
  2137. struct smallPayload
  2138. {
  2139. float value;
  2140. };
  2141. struct WithEmbeddedObject
  2142. {
  2143. Buffer texture;
  2144. };
  2145. void DispatchIt(WithEmbeddedObject eo)
  2146. {
  2147. smallPayload p;
  2148. p.value = eo.texture.Load(0);
  2149. DispatchMesh(1, 1, 1, p);
  2150. }
  2151. [numthreads(1, 1, 1)]
  2152. void main()
  2153. {
  2154. WithEmbeddedObject eo;
  2155. eo.texture = g_texture;
  2156. DispatchIt(eo);
  2157. }
  2158. )";
  2159. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  2160. // Can't test offsets and sizes until dbg.declare instructions are emitted when floatn is used (https://github.com/microsoft/DirectXShaderCompiler/issues/2920)
  2161. //VERIFY_ARE_EQUAL(20, Testables.AllocaWrites.size());
  2162. }
  2163. }
  2164. TEST_F(PixTest, PixStructAnnotation_WheresMyDbgValue) {
  2165. if (m_ver.SkipDxilVersion(1, 5)) return;
  2166. for (auto const* optimization : OptimizationChoices) {
  2167. const char* hlsl = R"(
  2168. struct smallPayload
  2169. {
  2170. float f1;
  2171. float2 f2;
  2172. };
  2173. [numthreads(1, 1, 1)]
  2174. void main()
  2175. {
  2176. smallPayload p;
  2177. p.f1 = 1;
  2178. p.f2 = float2(2,3);
  2179. DispatchMesh(1, 1, 1, p);
  2180. }
  2181. )";
  2182. auto Testables = TestStructAnnotationCase(hlsl, optimization);
  2183. // Can't test offsets and sizes until dbg.declare instructions are emitted when floatn is used (https://github.com/microsoft/DirectXShaderCompiler/issues/2920)
  2184. VERIFY_ARE_EQUAL(3, Testables.AllocaWrites.size());
  2185. }
  2186. }
  2187. #endif