CompilerTest.cpp 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // CompilerTest.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 compiler API. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #ifndef UNICODE
  12. #define UNICODE
  13. #endif
  14. #include <memory>
  15. #include <vector>
  16. #include <string>
  17. #include <map>
  18. #include <set>
  19. #include <cassert>
  20. #include <sstream>
  21. #include <algorithm>
  22. #include <cfloat>
  23. #include "dxc/DxilContainer/DxilContainer.h"
  24. #include "dxc/Support/WinIncludes.h"
  25. #include "dxc/dxcapi.h"
  26. #include "dxc/dxcpix.h"
  27. #ifdef _WIN32
  28. #include <atlfile.h>
  29. #include <d3dcompiler.h>
  30. #include "dia2.h"
  31. #endif
  32. #include "dxc/Test/HLSLTestData.h"
  33. #include "dxc/Test/HlslTestUtils.h"
  34. #include "dxc/Test/DxcTestUtils.h"
  35. #include "llvm/Support/raw_os_ostream.h"
  36. #include "dxc/Support/Global.h"
  37. #include "dxc/Support/dxcapi.use.h"
  38. #include "dxc/Support/microcom.h"
  39. #include "dxc/Support/HLSLOptions.h"
  40. #include "dxc/Support/Unicode.h"
  41. #include <fstream>
  42. #include "llvm/Support/FileSystem.h"
  43. #include "llvm/Support/MSFileSystem.h"
  44. #include "llvm/Support/Path.h"
  45. #include "llvm/ADT/SmallString.h"
  46. #include "llvm/ADT/StringSwitch.h"
  47. using namespace std;
  48. using namespace hlsl_test;
  49. class TestIncludeHandler : public IDxcIncludeHandler {
  50. DXC_MICROCOM_REF_FIELD(m_dwRef)
  51. public:
  52. DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
  53. dxc::DxcDllSupport &m_dllSupport;
  54. HRESULT m_defaultErrorCode = E_FAIL;
  55. TestIncludeHandler(dxc::DxcDllSupport &dllSupport) : m_dwRef(0), m_dllSupport(dllSupport), callIndex(0) { }
  56. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) override {
  57. return DoBasicQueryInterface<IDxcIncludeHandler>(this, iid, ppvObject);
  58. }
  59. struct LoadSourceCallInfo {
  60. std::wstring Filename; // Filename as written in #include statement
  61. LoadSourceCallInfo(LPCWSTR pFilename) :
  62. Filename(pFilename) { }
  63. };
  64. std::vector<LoadSourceCallInfo> CallInfos;
  65. std::wstring GetAllFileNames() const {
  66. std::wstringstream s;
  67. for (size_t i = 0; i < CallInfos.size(); ++i) {
  68. s << CallInfos[i].Filename << ';';
  69. }
  70. return s.str();
  71. }
  72. struct LoadSourceCallResult {
  73. HRESULT hr;
  74. std::string source;
  75. UINT32 codePage;
  76. LoadSourceCallResult() : hr(E_FAIL), codePage(0) { }
  77. LoadSourceCallResult(const char *pSource, UINT32 codePage = CP_UTF8) : hr(S_OK), source(pSource), codePage(codePage) { }
  78. };
  79. std::vector<LoadSourceCallResult> CallResults;
  80. size_t callIndex;
  81. HRESULT STDMETHODCALLTYPE LoadSource(
  82. _In_ LPCWSTR pFilename, // Filename as written in #include statement
  83. _COM_Outptr_ IDxcBlob **ppIncludeSource // Resultant source object for included file
  84. ) override {
  85. CallInfos.push_back(LoadSourceCallInfo(pFilename));
  86. *ppIncludeSource = nullptr;
  87. if (callIndex >= CallResults.size()) {
  88. return m_defaultErrorCode;
  89. }
  90. if (FAILED(CallResults[callIndex].hr)) {
  91. return CallResults[callIndex++].hr;
  92. }
  93. MultiByteStringToBlob(m_dllSupport, CallResults[callIndex].source,
  94. CallResults[callIndex].codePage, ppIncludeSource);
  95. return CallResults[callIndex++].hr;
  96. }
  97. };
  98. #ifdef _WIN32
  99. class CompilerTest {
  100. #else
  101. class CompilerTest : public ::testing::Test {
  102. #endif
  103. public:
  104. BEGIN_TEST_CLASS(CompilerTest)
  105. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  106. TEST_METHOD_PROPERTY(L"Priority", L"0")
  107. END_TEST_CLASS()
  108. TEST_CLASS_SETUP(InitSupport);
  109. TEST_METHOD(CompileWhenDefinesThenApplied)
  110. TEST_METHOD(CompileWhenDefinesManyThenApplied)
  111. TEST_METHOD(CompileWhenEmptyThenFails)
  112. TEST_METHOD(CompileWhenIncorrectThenFails)
  113. TEST_METHOD(CompileWhenWorksThenDisassembleWorks)
  114. TEST_METHOD(CompileWhenDebugWorksThenStripDebug)
  115. TEST_METHOD(CompileWhenWorksThenAddRemovePrivate)
  116. TEST_METHOD(CompileThenAddCustomDebugName)
  117. TEST_METHOD(CompileThenTestPdbUtils)
  118. TEST_METHOD(CompileThenTestPdbInPrivate)
  119. TEST_METHOD(CompileThenTestPdbUtilsStripped)
  120. TEST_METHOD(CompileThenTestPdbUtilsEmptyEntry)
  121. TEST_METHOD(CompileThenTestPdbUtilsRelativePath)
  122. TEST_METHOD(CompileWithRootSignatureThenStripRootSignature)
  123. TEST_METHOD(CompileWhenIncludeThenLoadInvoked)
  124. TEST_METHOD(CompileWhenIncludeThenLoadUsed)
  125. TEST_METHOD(CompileWhenIncludeAbsoluteThenLoadAbsolute)
  126. TEST_METHOD(CompileWhenIncludeLocalThenLoadRelative)
  127. TEST_METHOD(CompileWhenIncludeSystemThenLoadNotRelative)
  128. TEST_METHOD(CompileWhenIncludeSystemMissingThenLoadAttempt)
  129. TEST_METHOD(CompileWhenIncludeFlagsThenIncludeUsed)
  130. TEST_METHOD(CompileWhenIncludeMissingThenFail)
  131. TEST_METHOD(CompileWhenIncludeHasPathThenOK)
  132. TEST_METHOD(CompileWhenIncludeEmptyThenOK)
  133. TEST_METHOD(CompileWhenODumpThenPassConfig)
  134. TEST_METHOD(CompileWhenODumpThenOptimizerMatch)
  135. TEST_METHOD(CompileWhenVdThenProducesDxilContainer)
  136. #if _ITERATOR_DEBUG_LEVEL==0
  137. // CompileWhenNoMemThenOOM can properly detect leaks only when debug iterators are disabled
  138. BEGIN_TEST_METHOD(CompileWhenNoMemThenOOM)
  139. // Disabled because there are problems where we try to allocate memory in destructors,
  140. // which causes more bad_alloc() throws while unwinding bad_alloc(), which asserts
  141. // If only failing one allocation, there are allocations where failing them is lost,
  142. // such as in ~raw_string_ostream(), where it flushes, then eats bad_alloc(), if thrown.
  143. TEST_METHOD_PROPERTY(L"Ignore", L"true")
  144. END_TEST_METHOD()
  145. #endif
  146. TEST_METHOD(CompileWhenShaderModelMismatchAttributeThenFail)
  147. TEST_METHOD(CompileBadHlslThenFail)
  148. TEST_METHOD(CompileLegacyShaderModelThenFail)
  149. TEST_METHOD(CompileWhenRecursiveAlbeitStaticTermThenFail)
  150. TEST_METHOD(CompileWhenRecursiveThenFail)
  151. TEST_METHOD(CompileHlsl2015ThenFail)
  152. TEST_METHOD(CompileHlsl2016ThenOK)
  153. TEST_METHOD(CompileHlsl2017ThenOK)
  154. TEST_METHOD(CompileHlsl2018ThenOK)
  155. TEST_METHOD(CompileHlsl2019ThenFail)
  156. TEST_METHOD(CodeGenFloatingPointEnvironment)
  157. TEST_METHOD(CodeGenInclude)
  158. TEST_METHOD(CodeGenLibCsEntry)
  159. TEST_METHOD(CodeGenLibCsEntry2)
  160. TEST_METHOD(CodeGenLibCsEntry3)
  161. TEST_METHOD(CodeGenLibEntries)
  162. TEST_METHOD(CodeGenLibEntries2)
  163. TEST_METHOD(CodeGenLibNoAlias)
  164. TEST_METHOD(CodeGenLibResource)
  165. TEST_METHOD(CodeGenLibUnusedFunc)
  166. TEST_METHOD(CodeGenRootSigProfile)
  167. TEST_METHOD(CodeGenRootSigProfile2)
  168. TEST_METHOD(CodeGenRootSigProfile5)
  169. TEST_METHOD(CodeGenWaveSize)
  170. TEST_METHOD(PreprocessWhenValidThenOK)
  171. TEST_METHOD(LibGVStore)
  172. TEST_METHOD(PreprocessWhenExpandTokenPastingOperandThenAccept)
  173. TEST_METHOD(PreprocessWithDebugOptsThenOk)
  174. TEST_METHOD(WhenSigMismatchPCFunctionThenFail)
  175. TEST_METHOD(CompileOtherModesWithDebugOptsThenOk)
  176. TEST_METHOD(BatchSamples)
  177. TEST_METHOD(BatchD3DReflect)
  178. TEST_METHOD(BatchDxil)
  179. TEST_METHOD(BatchHLSL)
  180. TEST_METHOD(BatchInfra)
  181. TEST_METHOD(BatchPasses)
  182. TEST_METHOD(BatchShaderTargets)
  183. TEST_METHOD(BatchValidation)
  184. TEST_METHOD(SubobjectCodeGenErrors)
  185. BEGIN_TEST_METHOD(ManualFileCheckTest)
  186. TEST_METHOD_PROPERTY(L"Ignore", L"true")
  187. END_TEST_METHOD()
  188. // Batch directories
  189. BEGIN_TEST_METHOD(CodeGenHashStability)
  190. TEST_METHOD_PROPERTY(L"Priority", L"2")
  191. END_TEST_METHOD()
  192. dxc::DxcDllSupport m_dllSupport;
  193. VersionSupportInfo m_ver;
  194. void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
  195. UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
  196. CComPtr<IDxcLibrary> library;
  197. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  198. IFT(library->CreateBlobWithEncodingFromPinned(data, size, codePage,
  199. ppBlob));
  200. }
  201. void CreateBlobFromFile(LPCWSTR name, _Outptr_ IDxcBlobEncoding **ppBlob) {
  202. CComPtr<IDxcLibrary> library;
  203. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  204. const std::wstring path = hlsl_test::GetPathToHlslDataFile(name);
  205. IFT(library->CreateBlobFromFile(path.c_str(), nullptr, ppBlob));
  206. }
  207. void CreateBlobFromText(_In_z_ const char *pText,
  208. _Outptr_ IDxcBlobEncoding **ppBlob) {
  209. CreateBlobPinned(pText, strlen(pText) + 1, CP_UTF8, ppBlob);
  210. }
  211. HRESULT CreateCompiler(IDxcCompiler **ppResult) {
  212. return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
  213. }
  214. void TestPdbUtils(bool bSlim, bool bLegacy, bool bStrip);
  215. #ifdef _WIN32 // No ContainerBuilder support yet
  216. HRESULT CreateContainerBuilder(IDxcContainerBuilder **ppResult) {
  217. return m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, ppResult);
  218. }
  219. #endif
  220. template <typename T, typename TDefault, typename TIface>
  221. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  222. TDefault defaultValue, LPCWSTR valueLabel,
  223. HRESULT (__stdcall TIface::*pFn)(T *)) {
  224. T value;
  225. HRESULT hr = (pSymbol->*(pFn))(&value);
  226. if (SUCCEEDED(hr) && value != defaultValue) {
  227. o << L", " << valueLabel << L": " << value;
  228. }
  229. }
  230. std::string GetOption(std::string &cmd, char *opt) {
  231. std::string option = cmd.substr(cmd.find(opt));
  232. option = option.substr(option.find_first_of(' '));
  233. option = option.substr(option.find_first_not_of(' '));
  234. return option.substr(0, option.find_first_of(' '));
  235. }
  236. void CodeGenTest(std::wstring name) {
  237. CComPtr<IDxcCompiler> pCompiler;
  238. CComPtr<IDxcOperationResult> pResult;
  239. CComPtr<IDxcBlobEncoding> pSource;
  240. name.insert(0, L"..\\CodeGenHLSL\\");
  241. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  242. CreateBlobFromFile(name.c_str(), &pSource);
  243. std::string cmdLine = GetFirstLine(name.c_str());
  244. llvm::StringRef argsRef = cmdLine;
  245. llvm::SmallVector<llvm::StringRef, 8> splitArgs;
  246. argsRef.split(splitArgs, " ");
  247. hlsl::options::MainArgs argStrings(splitArgs);
  248. std::string errorString;
  249. llvm::raw_string_ostream errorStream(errorString);
  250. hlsl::options::DxcOpts opts;
  251. IFT(ReadDxcOpts(hlsl::options::getHlslOptTable(), /*flagsToInclude*/ 0,
  252. argStrings, opts, errorStream));
  253. std::wstring entry =
  254. Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
  255. std::wstring profile =
  256. Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
  257. std::vector<std::wstring> argLists;
  258. CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argLists);
  259. std::vector<LPCWSTR> args;
  260. args.reserve(argLists.size());
  261. for (const std::wstring &a : argLists)
  262. args.push_back(a.data());
  263. VERIFY_SUCCEEDED(pCompiler->Compile(
  264. pSource, name.c_str(), entry.c_str(), profile.c_str(), args.data(), args.size(),
  265. opts.Defines.data(), opts.Defines.size(), nullptr, &pResult));
  266. VERIFY_IS_NOT_NULL(pResult, L"Failed to compile - pResult NULL");
  267. HRESULT result;
  268. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  269. if (FAILED(result)) {
  270. CComPtr<IDxcBlobEncoding> pErr;
  271. IFT(pResult->GetErrorBuffer(&pErr));
  272. std::string errString(BlobToUtf8(pErr));
  273. CA2W errStringW(errString.c_str(), CP_UTF8);
  274. WEX::Logging::Log::Comment(L"Failed to compile - errors follow");
  275. WEX::Logging::Log::Comment(errStringW);
  276. }
  277. VERIFY_SUCCEEDED(result);
  278. CComPtr<IDxcBlob> pProgram;
  279. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  280. if (opts.IsRootSignatureProfile())
  281. return;
  282. CComPtr<IDxcBlobEncoding> pDisassembleBlob;
  283. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembleBlob));
  284. std::string disassembleString(BlobToUtf8(pDisassembleBlob));
  285. VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
  286. }
  287. void CodeGenTestHashFullPath(LPCWSTR fullPath) {
  288. FileRunTestResult t = FileRunTestResult::RunHashTestFromFileCommands(fullPath);
  289. if (t.RunResult != 0) {
  290. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  291. WEX::Logging::Log::Comment(commentWide);
  292. WEX::Logging::Log::Error(L"Run result is not zero");
  293. }
  294. }
  295. void CodeGenTestHash(LPCWSTR name, bool implicitDir) {
  296. std::wstring path = name;
  297. if (implicitDir) {
  298. path.insert(0, L"..\\CodeGenHLSL\\");
  299. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  300. }
  301. CodeGenTestHashFullPath(path.c_str());
  302. }
  303. void CodeGenTestCheckBatchHash(std::wstring suitePath, bool implicitDir = true) {
  304. using namespace llvm;
  305. using namespace WEX::TestExecution;
  306. if (implicitDir) suitePath.insert(0, L"..\\HLSLFileCheck\\");
  307. ::llvm::sys::fs::MSFileSystem *msfPtr;
  308. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  309. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  310. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  311. IFTLLVM(pts.error_code());
  312. CW2A pUtf8Filename(suitePath.c_str());
  313. if (!llvm::sys::path::is_absolute(pUtf8Filename.m_psz)) {
  314. suitePath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str());
  315. }
  316. CW2A utf8SuitePath(suitePath.c_str());
  317. unsigned numTestsRun = 0;
  318. std::error_code EC;
  319. llvm::SmallString<128> DirNative;
  320. llvm::sys::path::native(utf8SuitePath.m_psz, DirNative);
  321. for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd;
  322. Dir != DirEnd && !EC; Dir.increment(EC)) {
  323. // Check whether this entry has an extension typically associated with
  324. // headers.
  325. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
  326. .Cases(".hlsl", ".ll", true).Default(false))
  327. continue;
  328. StringRef filename = Dir->path();
  329. std::string filetag = Dir->path();
  330. filetag += "<HASH>";
  331. CA2W wRelTag(filetag.data());
  332. CA2W wRelPath(filename.data());
  333. WEX::Logging::Log::StartGroup(wRelTag);
  334. CodeGenTestHash(wRelPath, /*implicitDir*/ false);
  335. WEX::Logging::Log::EndGroup(wRelTag);
  336. numTestsRun++;
  337. }
  338. VERIFY_IS_GREATER_THAN(numTestsRun, (unsigned)0, L"No test files found in batch directory.");
  339. }
  340. void CodeGenTestCheckFullPath(LPCWSTR fullPath, LPCWSTR dumpPath = nullptr) {
  341. // Create file system if needed
  342. llvm::sys::fs::MSFileSystem *msfPtr = llvm::sys::fs::GetCurrentThreadFileSystem();
  343. std::unique_ptr<llvm::sys::fs::MSFileSystem> msf;
  344. if (!msfPtr) {
  345. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  346. msf.reset(msfPtr);
  347. }
  348. llvm::sys::fs::AutoPerThreadSystem pts(msfPtr);
  349. IFTLLVM(pts.error_code());
  350. FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath,
  351. /*pPluginToolsPaths*/nullptr, dumpPath);
  352. if (t.RunResult != 0) {
  353. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  354. WEX::Logging::Log::Comment(commentWide);
  355. WEX::Logging::Log::Error(L"Run result is not zero");
  356. }
  357. }
  358. void CodeGenTestCheck(LPCWSTR name, bool implicitDir = true, LPCWSTR dumpPath = nullptr) {
  359. std::wstring path = name;
  360. std::wstring dumpStr;
  361. if (implicitDir) {
  362. path.insert(0, L"..\\CodeGenHLSL\\");
  363. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  364. if (!dumpPath) {
  365. dumpStr = hlsl_test::GetPathToHlslDataFile(path.c_str(), FILECHECKDUMPDIRPARAM);
  366. dumpPath = dumpStr.empty() ? nullptr : dumpStr.c_str();
  367. }
  368. }
  369. CodeGenTestCheckFullPath(path.c_str(), dumpPath);
  370. }
  371. void CodeGenTestCheckBatchDir(std::wstring suitePath, bool implicitDir = true) {
  372. using namespace llvm;
  373. using namespace WEX::TestExecution;
  374. if (implicitDir) suitePath.insert(0, L"..\\HLSLFileCheck\\");
  375. ::llvm::sys::fs::MSFileSystem *msfPtr;
  376. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  377. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  378. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  379. IFTLLVM(pts.error_code());
  380. std::wstring dumpPath;
  381. CW2A pUtf8Filename(suitePath.c_str());
  382. if (!llvm::sys::path::is_absolute(pUtf8Filename.m_psz)) {
  383. dumpPath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str(), FILECHECKDUMPDIRPARAM);
  384. suitePath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str());
  385. }
  386. CW2A utf8SuitePath(suitePath.c_str());
  387. unsigned numTestsRun = 0;
  388. std::error_code EC;
  389. llvm::SmallString<128> DirNative;
  390. llvm::sys::path::native(utf8SuitePath.m_psz, DirNative);
  391. for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd;
  392. Dir != DirEnd && !EC; Dir.increment(EC)) {
  393. // Check whether this entry has an extension typically associated with
  394. // headers.
  395. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
  396. .Cases(".hlsl", ".ll", true).Default(false))
  397. continue;
  398. StringRef filename = Dir->path();
  399. CA2W wRelPath(filename.data());
  400. std::wstring dumpStr;
  401. if (!dumpPath.empty() && suitePath.compare(0, suitePath.size(), wRelPath.m_psz, suitePath.size()) == 0) {
  402. dumpStr = dumpPath + (wRelPath.m_psz + suitePath.size());
  403. }
  404. WEX::Logging::Log::StartGroup(wRelPath);
  405. CodeGenTestCheck(wRelPath, /*implicitDir*/ false,
  406. dumpStr.empty() ? nullptr : dumpStr.c_str());
  407. WEX::Logging::Log::EndGroup(wRelPath);
  408. numTestsRun++;
  409. }
  410. VERIFY_IS_GREATER_THAN(numTestsRun, (unsigned)0, L"No test files found in batch directory.");
  411. }
  412. std::string VerifyCompileFailed(LPCSTR pText, LPCWSTR pTargetProfile, LPCSTR pErrorMsg) {
  413. return VerifyCompileFailed(pText, pTargetProfile, pErrorMsg, L"main");
  414. }
  415. std::string VerifyCompileFailed(LPCSTR pText, LPCWSTR pTargetProfile, LPCSTR pErrorMsg, LPCWSTR pEntryPoint) {
  416. CComPtr<IDxcCompiler> pCompiler;
  417. CComPtr<IDxcOperationResult> pResult;
  418. CComPtr<IDxcBlobEncoding> pSource;
  419. CComPtr<IDxcBlobEncoding> pErrors;
  420. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  421. CreateBlobFromText(pText, &pSource);
  422. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  423. pTargetProfile, nullptr, 0, nullptr, 0, nullptr, &pResult));
  424. HRESULT status;
  425. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  426. VERIFY_FAILED(status);
  427. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  428. if (pErrorMsg && *pErrorMsg) {
  429. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  430. }
  431. return BlobToUtf8(pErrors);
  432. }
  433. void VerifyOperationSucceeded(IDxcOperationResult *pResult) {
  434. HRESULT result;
  435. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  436. if (FAILED(result)) {
  437. CComPtr<IDxcBlobEncoding> pErrors;
  438. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  439. CA2W errorsWide(BlobToUtf8(pErrors).c_str(), CP_UTF8);
  440. WEX::Logging::Log::Comment(errorsWide);
  441. }
  442. VERIFY_SUCCEEDED(result);
  443. }
  444. std::string VerifyOperationFailed(IDxcOperationResult *pResult) {
  445. HRESULT result;
  446. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  447. VERIFY_FAILED(result);
  448. CComPtr<IDxcBlobEncoding> pErrors;
  449. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  450. return BlobToUtf8(pErrors);
  451. }
  452. #ifdef _WIN32 // - exclude dia stuff
  453. HRESULT CreateDiaSourceForCompile(const char *hlsl, IDiaDataSource **ppDiaSource)
  454. {
  455. if (!ppDiaSource)
  456. return E_POINTER;
  457. CComPtr<IDxcCompiler> pCompiler;
  458. CComPtr<IDxcOperationResult> pResult;
  459. CComPtr<IDxcBlobEncoding> pSource;
  460. CComPtr<IDxcBlob> pProgram;
  461. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  462. CreateBlobFromText(hlsl, &pSource);
  463. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  464. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  465. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult));
  466. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  467. // Disassemble the compiled (stripped) program.
  468. {
  469. CComPtr<IDxcBlobEncoding> pDisassembly;
  470. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  471. std::string disText = BlobToUtf8(pDisassembly);
  472. CA2W disTextW(disText.c_str(), CP_UTF8);
  473. //WEX::Logging::Log::Comment(disTextW);
  474. }
  475. // CONSIDER: have the dia data source look for the part if passed a whole container.
  476. CComPtr<IDiaDataSource> pDiaSource;
  477. CComPtr<IStream> pProgramStream;
  478. CComPtr<IDxcLibrary> pLib;
  479. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  480. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  481. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  482. VERIFY_IS_NOT_NULL(pContainer);
  483. hlsl::DxilPartIterator partIter =
  484. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  485. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  486. const hlsl::DxilProgramHeader *pProgramHeader =
  487. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  488. uint32_t bitcodeLength;
  489. const char *pBitcode;
  490. CComPtr<IDxcBlob> pProgramPdb;
  491. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  492. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  493. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(), bitcodeLength,
  494. &pProgramPdb));
  495. // Disassemble the program with debug information.
  496. {
  497. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  498. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  499. std::string disText = BlobToUtf8(pDbgDisassembly);
  500. CA2W disTextW(disText.c_str(), CP_UTF8);
  501. //WEX::Logging::Log::Comment(disTextW);
  502. }
  503. // Create a short text dump of debug information.
  504. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pProgramPdb, &pProgramStream));
  505. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  506. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  507. *ppDiaSource = pDiaSource.Detach();
  508. return S_OK;
  509. }
  510. #endif // _WIN32 - exclude dia stuff
  511. };
  512. // Useful for debugging.
  513. #if SUPPORT_FXC_PDB
  514. #include <d3dcompiler.h>
  515. #pragma comment(lib, "d3dcompiler.lib")
  516. HRESULT GetBlobPdb(IDxcBlob *pBlob, IDxcBlob **ppDebugInfo) {
  517. return D3DGetBlobPart(pBlob->GetBufferPointer(), pBlob->GetBufferSize(),
  518. D3D_BLOB_PDB, 0, (ID3DBlob **)ppDebugInfo);
  519. }
  520. std::string FourCCStr(uint32_t val) {
  521. std::stringstream o;
  522. char c[5];
  523. c[0] = val & 0xFF;
  524. c[1] = (val & 0xFF00) >> 8;
  525. c[2] = (val & 0xFF0000) >> 16;
  526. c[3] = (val & 0xFF000000) >> 24;
  527. c[4] = '\0';
  528. o << c << " (" << std::hex << val << std::dec << ")";
  529. return o.str();
  530. }
  531. std::string DumpParts(IDxcBlob *pBlob) {
  532. std::stringstream o;
  533. hlsl::DxilContainerHeader *pContainer = (hlsl::DxilContainerHeader *)pBlob->GetBufferPointer();
  534. o << "Container:" << std::endl
  535. << " Size: " << pContainer->ContainerSizeInBytes << std::endl
  536. << " FourCC: " << FourCCStr(pContainer->HeaderFourCC) << std::endl
  537. << " Part count: " << pContainer->PartCount << std::endl;
  538. for (uint32_t i = 0; i < pContainer->PartCount; ++i) {
  539. hlsl::DxilPartHeader *pPart = hlsl::GetDxilContainerPart(pContainer, i);
  540. o << "Part " << i << std::endl
  541. << " FourCC: " << FourCCStr(pPart->PartFourCC) << std::endl
  542. << " Size: " << pPart->PartSize << std::endl;
  543. }
  544. return o.str();
  545. }
  546. HRESULT CreateDiaSourceFromDxbcBlob(IDxcLibrary *pLib, IDxcBlob *pDxbcBlob,
  547. IDiaDataSource **ppDiaSource) {
  548. HRESULT hr = S_OK;
  549. CComPtr<IDxcBlob> pdbBlob;
  550. CComPtr<IStream> pPdbStream;
  551. CComPtr<IDiaDataSource> pDiaSource;
  552. IFR(GetBlobPdb(pDxbcBlob, &pdbBlob));
  553. IFR(pLib->CreateStreamFromBlobReadOnly(pdbBlob, &pPdbStream));
  554. IFR(CoCreateInstance(CLSID_DiaSource, NULL, CLSCTX_INPROC_SERVER,
  555. __uuidof(IDiaDataSource), (void **)&pDiaSource));
  556. IFR(pDiaSource->loadDataFromIStream(pPdbStream));
  557. *ppDiaSource = pDiaSource.Detach();
  558. return hr;
  559. }
  560. #endif
  561. bool CompilerTest::InitSupport() {
  562. if (!m_dllSupport.IsEnabled()) {
  563. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  564. m_ver.Initialize(m_dllSupport);
  565. }
  566. return true;
  567. }
  568. TEST_F(CompilerTest, CompileWhenDefinesThenApplied) {
  569. CComPtr<IDxcCompiler> pCompiler;
  570. CComPtr<IDxcOperationResult> pResult;
  571. CComPtr<IDxcBlobEncoding> pSource;
  572. DxcDefine defines[] = {{L"F4", L"float4"}};
  573. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  574. CreateBlobFromText("F4 main() : SV_Target { return 0; }", &pSource);
  575. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  576. L"ps_6_0", nullptr, 0, defines,
  577. _countof(defines), nullptr, &pResult));
  578. }
  579. TEST_F(CompilerTest, CompileWhenDefinesManyThenApplied) {
  580. CComPtr<IDxcCompiler> pCompiler;
  581. CComPtr<IDxcOperationResult> pResult;
  582. CComPtr<IDxcBlobEncoding> pSource;
  583. LPCWSTR args[] = {L"/DVAL1=1", L"/DVAL2=2", L"/DVAL3=3", L"/DVAL4=2",
  584. L"/DVAL5=4", L"/DNVAL1", L"/DNVAL2", L"/DNVAL3",
  585. L"/DNVAL4", L"/DNVAL5", L"/DCVAL1=1", L"/DCVAL2=2",
  586. L"/DCVAL3=3", L"/DCVAL4=2", L"/DCVAL5=4", L"/DCVALNONE="};
  587. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  588. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  589. "#ifndef VAL1\r\n"
  590. "#error VAL1 not defined\r\n"
  591. "#endif\r\n"
  592. "#ifndef NVAL5\r\n"
  593. "#error NVAL5 not defined\r\n"
  594. "#endif\r\n"
  595. "#ifndef CVALNONE\r\n"
  596. "#error CVALNONE not defined\r\n"
  597. "#endif\r\n"
  598. "return 0; }",
  599. &pSource);
  600. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  601. L"ps_6_0", args, _countof(args), nullptr,
  602. 0, nullptr, &pResult));
  603. HRESULT compileStatus;
  604. VERIFY_SUCCEEDED(pResult->GetStatus(&compileStatus));
  605. if (FAILED(compileStatus)) {
  606. CComPtr<IDxcBlobEncoding> pErrors;
  607. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  608. OutputDebugStringA((LPCSTR)pErrors->GetBufferPointer());
  609. }
  610. VERIFY_SUCCEEDED(compileStatus);
  611. }
  612. TEST_F(CompilerTest, CompileWhenEmptyThenFails) {
  613. CComPtr<IDxcCompiler> pCompiler;
  614. CComPtr<IDxcOperationResult> pResult;
  615. CComPtr<IDxcBlobEncoding> pSource;
  616. CComPtr<IDxcBlobEncoding> pSourceBad;
  617. LPCWSTR pProfile = L"ps_6_0";
  618. LPCWSTR pEntryPoint = L"main";
  619. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  620. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  621. CreateBlobFromText("float4 main() : SV_Target { return undef; }", &pSourceBad);
  622. // correct version
  623. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  624. pProfile, nullptr, 0, nullptr, 0, nullptr,
  625. &pResult));
  626. pResult.Release();
  627. // correct version with compilation errors
  628. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, L"source.hlsl", pEntryPoint,
  629. pProfile, nullptr, 0, nullptr, 0, nullptr,
  630. &pResult));
  631. pResult.Release();
  632. // null source
  633. VERIFY_FAILED(pCompiler->Compile(nullptr, L"source.hlsl", pEntryPoint, pProfile,
  634. nullptr, 0, nullptr, 0, nullptr, &pResult));
  635. // null profile
  636. VERIFY_FAILED(pCompiler->Compile(pSourceBad, L"source.hlsl", pEntryPoint,
  637. nullptr, nullptr, 0, nullptr, 0, nullptr,
  638. &pResult));
  639. // null source name succeeds
  640. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, nullptr, pEntryPoint, pProfile,
  641. nullptr, 0, nullptr, 0, nullptr, &pResult));
  642. pResult.Release();
  643. // empty source name (as opposed to null) also suceeds
  644. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, L"", pEntryPoint, pProfile,
  645. nullptr, 0, nullptr, 0, nullptr,
  646. &pResult));
  647. pResult.Release();
  648. // null result
  649. VERIFY_FAILED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  650. pProfile, nullptr, 0, nullptr, 0, nullptr,
  651. nullptr));
  652. }
  653. TEST_F(CompilerTest, CompileWhenIncorrectThenFails) {
  654. CComPtr<IDxcCompiler> pCompiler;
  655. CComPtr<IDxcOperationResult> pResult;
  656. CComPtr<IDxcBlobEncoding> pSource;
  657. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  658. CreateBlobFromText("float4_undefined main() : SV_Target { return 0; }",
  659. &pSource);
  660. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main", L"ps_6_0",
  661. nullptr, 0, nullptr, 0, nullptr,
  662. &pResult));
  663. HRESULT result;
  664. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  665. VERIFY_FAILED(result);
  666. CComPtr<IDxcBlobEncoding> pErrorBuffer;
  667. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrorBuffer));
  668. std::string errorString(BlobToUtf8(pErrorBuffer));
  669. VERIFY_ARE_NOT_EQUAL(0U, errorString.size());
  670. // Useful for examining actual error message:
  671. // CA2W errorStringW(errorString.c_str(), CP_UTF8);
  672. // WEX::Logging::Log::Comment(errorStringW.m_psz);
  673. }
  674. TEST_F(CompilerTest, CompileWhenWorksThenDisassembleWorks) {
  675. CComPtr<IDxcCompiler> pCompiler;
  676. CComPtr<IDxcOperationResult> pResult;
  677. CComPtr<IDxcBlobEncoding> pSource;
  678. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  679. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  680. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  681. L"ps_6_0", nullptr, 0, nullptr, 0,
  682. nullptr, &pResult));
  683. HRESULT result;
  684. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  685. VERIFY_SUCCEEDED(result);
  686. CComPtr<IDxcBlob> pProgram;
  687. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  688. CComPtr<IDxcBlobEncoding> pDisassembleBlob;
  689. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembleBlob));
  690. std::string disassembleString(BlobToUtf8(pDisassembleBlob));
  691. VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
  692. // Useful for examining disassembly:
  693. // CA2W disassembleStringW(disassembleString.c_str(), CP_UTF8);
  694. // WEX::Logging::Log::Comment(disassembleStringW.m_psz);
  695. }
  696. #ifdef _WIN32 // Container builder unsupported
  697. TEST_F(CompilerTest, CompileWhenDebugWorksThenStripDebug) {
  698. CComPtr<IDxcCompiler> pCompiler;
  699. CComPtr<IDxcOperationResult> pResult;
  700. CComPtr<IDxcBlobEncoding> pSource;
  701. CComPtr<IDxcBlob> pProgram;
  702. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  703. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
  704. " float4 local = abs(pos);\r\n"
  705. " return local;\r\n"
  706. "}",
  707. &pSource);
  708. LPCWSTR args[] = {L"/Zi", L"/Qembed_debug"};
  709. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  710. L"ps_6_0", args, _countof(args), nullptr,
  711. 0, nullptr, &pResult));
  712. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  713. // Check if it contains debug blob
  714. hlsl::DxilContainerHeader *pHeader =
  715. hlsl::IsDxilContainerLike(pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  716. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pHeader, pProgram->GetBufferSize()));
  717. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  718. pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
  719. VERIFY_IS_NOT_NULL(pPartHeader);
  720. // Check debug info part does not exist after strip debug info
  721. CComPtr<IDxcBlob> pNewProgram;
  722. CComPtr<IDxcContainerBuilder> pBuilder;
  723. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  724. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  725. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  726. pResult.Release();
  727. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  728. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  729. pHeader = hlsl::IsDxilContainerLike(pNewProgram->GetBufferPointer(), pNewProgram->GetBufferSize());
  730. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pHeader, pNewProgram->GetBufferSize()));
  731. pPartHeader = hlsl::GetDxilPartByType(
  732. pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
  733. VERIFY_IS_NULL(pPartHeader);
  734. }
  735. TEST_F(CompilerTest, CompileWhenWorksThenAddRemovePrivate) {
  736. CComPtr<IDxcCompiler> pCompiler;
  737. CComPtr<IDxcOperationResult> pResult;
  738. CComPtr<IDxcBlobEncoding> pSource;
  739. CComPtr<IDxcBlob> pProgram;
  740. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  741. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  742. " return 0;\r\n"
  743. "}",
  744. &pSource);
  745. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  746. L"ps_6_0", nullptr, 0, nullptr, 0,
  747. nullptr, &pResult));
  748. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  749. // Append private data blob
  750. CComPtr<IDxcContainerBuilder> pBuilder;
  751. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  752. std::string privateTxt("private data");
  753. CComPtr<IDxcBlobEncoding> pPrivate;
  754. CreateBlobFromText(privateTxt.c_str(), &pPrivate);
  755. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  756. VERIFY_SUCCEEDED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_PrivateData, pPrivate));
  757. pResult.Release();
  758. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  759. CComPtr<IDxcBlob> pNewProgram;
  760. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  761. hlsl::DxilContainerHeader *pContainerHeader = hlsl::IsDxilContainerLike(pNewProgram->GetBufferPointer(), pNewProgram->GetBufferSize());
  762. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pNewProgram->GetBufferSize()));
  763. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  764. pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
  765. VERIFY_IS_NOT_NULL(pPartHeader);
  766. // compare data
  767. std::string privatePart((const char *)(pPartHeader + 1), privateTxt.size());
  768. VERIFY_IS_TRUE(strcmp(privatePart.c_str(), privateTxt.c_str()) == 0);
  769. // Remove private data blob
  770. pBuilder.Release();
  771. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  772. VERIFY_SUCCEEDED(pBuilder->Load(pNewProgram));
  773. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_PrivateData));
  774. pResult.Release();
  775. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  776. pNewProgram.Release();
  777. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  778. pContainerHeader = hlsl::IsDxilContainerLike(pNewProgram->GetBufferPointer(), pNewProgram->GetBufferSize());
  779. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pNewProgram->GetBufferSize()));
  780. pPartHeader = hlsl::GetDxilPartByType(
  781. pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
  782. VERIFY_IS_NULL(pPartHeader);
  783. }
  784. TEST_F(CompilerTest, CompileThenAddCustomDebugName) {
  785. // container builders prior to 1.3 did not support adding debug name parts
  786. if (m_ver.SkipDxilVersion(1, 3)) return;
  787. CComPtr<IDxcCompiler> pCompiler;
  788. CComPtr<IDxcOperationResult> pResult;
  789. CComPtr<IDxcBlobEncoding> pSource;
  790. CComPtr<IDxcBlob> pProgram;
  791. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  792. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  793. " return 0;\r\n"
  794. "}",
  795. &pSource);
  796. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug", L"/Zss" };
  797. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  798. L"ps_6_0", args, _countof(args), nullptr, 0,
  799. nullptr, &pResult));
  800. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  801. // Append private data blob
  802. CComPtr<IDxcContainerBuilder> pBuilder;
  803. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  804. const char pNewName[] = "MyOwnUniqueName.lld";
  805. //include null terminator:
  806. size_t nameBlobPartSize = sizeof(hlsl::DxilShaderDebugName) + _countof(pNewName);
  807. // round up to four-byte size:
  808. size_t allocatedSize = (nameBlobPartSize + 3) & ~3;
  809. auto pNameBlobContent = reinterpret_cast<hlsl::DxilShaderDebugName*>(malloc(allocatedSize));
  810. ZeroMemory(pNameBlobContent, allocatedSize); //just to make sure trailing nulls are nulls.
  811. pNameBlobContent->Flags = 0;
  812. pNameBlobContent->NameLength = _countof(pNewName) - 1; //this is not supposed to include null terminator
  813. memcpy(pNameBlobContent + 1, pNewName, _countof(pNewName));
  814. CComPtr<IDxcBlobEncoding> pDebugName;
  815. CreateBlobPinned(pNameBlobContent, allocatedSize, CP_UTF8, &pDebugName);
  816. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  817. // should fail since it already exists:
  818. VERIFY_FAILED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_ShaderDebugName, pDebugName));
  819. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugName));
  820. VERIFY_SUCCEEDED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_ShaderDebugName, pDebugName));
  821. pResult.Release();
  822. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  823. CComPtr<IDxcBlob> pNewProgram;
  824. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  825. hlsl::DxilContainerHeader *pContainerHeader = hlsl::IsDxilContainerLike(pNewProgram->GetBufferPointer(), pNewProgram->GetBufferSize());
  826. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pNewProgram->GetBufferSize()));
  827. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  828. pContainerHeader, hlsl::DxilFourCC::DFCC_ShaderDebugName);
  829. VERIFY_IS_NOT_NULL(pPartHeader);
  830. // compare data
  831. VERIFY_IS_TRUE(memcmp(pPartHeader + 1, pNameBlobContent, allocatedSize) == 0);
  832. free(pNameBlobContent);
  833. // Remove private data blob
  834. pBuilder.Release();
  835. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  836. VERIFY_SUCCEEDED(pBuilder->Load(pNewProgram));
  837. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugName));
  838. pResult.Release();
  839. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  840. pNewProgram.Release();
  841. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  842. pContainerHeader = hlsl::IsDxilContainerLike(pNewProgram->GetBufferPointer(), pNewProgram->GetBufferSize());
  843. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pNewProgram->GetBufferSize()));
  844. pPartHeader = hlsl::GetDxilPartByType(
  845. pContainerHeader, hlsl::DxilFourCC::DFCC_ShaderDebugName);
  846. VERIFY_IS_NULL(pPartHeader);
  847. }
  848. static void VerifyPdbUtil(dxc::DxcDllSupport &dllSupport,
  849. IDxcBlob *pBlob, IDxcPdbUtils *pPdbUtils,
  850. const WCHAR *pMainFileName,
  851. llvm::ArrayRef<std::pair<const WCHAR *, const WCHAR *> > ExpectedArgs,
  852. llvm::ArrayRef<std::pair<const WCHAR *, const WCHAR *> > ExpectedFlags,
  853. llvm::ArrayRef<const WCHAR *> ExpectedDefines,
  854. IDxcCompiler *pCompiler,
  855. bool HasVersion,
  856. bool IsFullPDB,
  857. bool HasHashAndPdbName,
  858. bool TestReflection,
  859. const std::string &MainSource,
  860. const std::string &IncludedFile)
  861. {
  862. VERIFY_SUCCEEDED(pPdbUtils->Load(pBlob));
  863. // Compiler version comparison
  864. if (!HasVersion) {
  865. CComPtr<IDxcVersionInfo> pVersion;
  866. VERIFY_FAILED(pPdbUtils->GetVersionInfo(&pVersion));
  867. }
  868. else {
  869. CComPtr<IDxcVersionInfo> pVersion;
  870. VERIFY_SUCCEEDED(pPdbUtils->GetVersionInfo(&pVersion));
  871. CComPtr<IDxcVersionInfo2> pVersion2;
  872. VERIFY_IS_NOT_NULL(pVersion);
  873. VERIFY_SUCCEEDED(pVersion.QueryInterface(&pVersion2));
  874. CComPtr<IDxcVersionInfo3> pVersion3;
  875. VERIFY_SUCCEEDED(pVersion.QueryInterface(&pVersion3));
  876. CComPtr<IDxcVersionInfo> pCompilerVersion;
  877. pCompiler->QueryInterface(&pCompilerVersion);
  878. if (pCompilerVersion) {
  879. UINT32 uCompilerMajor = 0;
  880. UINT32 uCompilerMinor = 0;
  881. UINT32 uCompilerFlags = 0;
  882. VERIFY_SUCCEEDED(pCompilerVersion->GetVersion(&uCompilerMajor, &uCompilerMinor));
  883. VERIFY_SUCCEEDED(pCompilerVersion->GetFlags(&uCompilerFlags));
  884. UINT32 uMajor = 0;
  885. UINT32 uMinor = 0;
  886. UINT32 uFlags = 0;
  887. VERIFY_SUCCEEDED(pVersion->GetVersion(&uMajor, &uMinor));
  888. VERIFY_SUCCEEDED(pVersion->GetFlags(&uFlags));
  889. VERIFY_ARE_EQUAL(uMajor, uCompilerMajor);
  890. VERIFY_ARE_EQUAL(uMinor, uCompilerMinor);
  891. VERIFY_ARE_EQUAL(uFlags, uCompilerFlags);
  892. // IDxcVersionInfo2
  893. UINT32 uCommitCount = 0;
  894. CComHeapPtr<char> CommitVersionHash;
  895. VERIFY_SUCCEEDED(pVersion2->GetCommitInfo(&uCommitCount, &CommitVersionHash));
  896. CComPtr<IDxcVersionInfo2> pCompilerVersion2;
  897. if (SUCCEEDED(pCompiler->QueryInterface(&pCompilerVersion2))) {
  898. UINT32 uCompilerCommitCount = 0;
  899. CComHeapPtr<char> CompilerCommitVersionHash;
  900. VERIFY_SUCCEEDED(pCompilerVersion2->GetCommitInfo(&uCompilerCommitCount, &CompilerCommitVersionHash));
  901. VERIFY_IS_TRUE(0 == strcmp(CommitVersionHash, CompilerCommitVersionHash));
  902. VERIFY_ARE_EQUAL(uCommitCount, uCompilerCommitCount);
  903. }
  904. // IDxcVersionInfo3
  905. CComHeapPtr<char> VersionString;
  906. VERIFY_SUCCEEDED(pVersion3->GetCustomVersionString(&VersionString));
  907. VERIFY_IS_TRUE(VersionString && strlen(VersionString) != 0);
  908. {
  909. CComPtr<IDxcVersionInfo3> pCompilerVersion3;
  910. VERIFY_SUCCEEDED(pCompiler->QueryInterface(&pCompilerVersion3));
  911. CComHeapPtr<char> CompilerVersionString;
  912. VERIFY_SUCCEEDED(pCompilerVersion3->GetCustomVersionString(&CompilerVersionString));
  913. VERIFY_IS_TRUE(0 == strcmp(CompilerVersionString, VersionString));
  914. }
  915. }
  916. }
  917. // Target profile
  918. {
  919. CComBSTR str;
  920. VERIFY_SUCCEEDED(pPdbUtils->GetTargetProfile(&str));
  921. VERIFY_ARE_EQUAL(str, L"ps_6_0");
  922. }
  923. // Entry point
  924. {
  925. CComBSTR str;
  926. VERIFY_SUCCEEDED(pPdbUtils->GetEntryPoint(&str));
  927. VERIFY_ARE_EQUAL(str, L"PSMain");
  928. }
  929. // PDB file path
  930. if (HasHashAndPdbName) {
  931. CComBSTR pName;
  932. VERIFY_SUCCEEDED(pPdbUtils->GetName(&pName));
  933. std::wstring suffix = L".pdb";
  934. VERIFY_IS_TRUE(pName.Length() >= suffix.size());
  935. VERIFY_IS_TRUE(
  936. 0 == std::memcmp(suffix.c_str(), &pName[pName.Length() - suffix.size()], suffix.size()));
  937. }
  938. // Main file name
  939. {
  940. CComBSTR pMainFileName;
  941. VERIFY_SUCCEEDED(pPdbUtils->GetMainFileName(&pMainFileName));
  942. VERIFY_ARE_EQUAL(pMainFileName, pMainFileName);
  943. }
  944. // There is hash and hash is not empty
  945. if (HasHashAndPdbName) {
  946. CComPtr<IDxcBlob> pHash;
  947. VERIFY_SUCCEEDED(pPdbUtils->GetHash(&pHash));
  948. hlsl::DxilShaderHash EmptyHash = {};
  949. VERIFY_ARE_EQUAL(pHash->GetBufferSize(), sizeof(EmptyHash));
  950. VERIFY_IS_FALSE(0 == std::memcmp(pHash->GetBufferPointer(), &EmptyHash, sizeof(EmptyHash)));
  951. }
  952. // Source files
  953. {
  954. UINT32 uSourceCount = 0;
  955. VERIFY_SUCCEEDED(pPdbUtils->GetSourceCount(&uSourceCount));
  956. for (UINT32 i = 0; i < uSourceCount; i++) {
  957. CComBSTR pFileName;
  958. CComPtr<IDxcBlobEncoding> pFileContent;
  959. VERIFY_SUCCEEDED(pPdbUtils->GetSourceName(i, &pFileName));
  960. VERIFY_SUCCEEDED(pPdbUtils->GetSource(i, &pFileContent));
  961. if (0 == wcscmp(pFileName, pMainFileName)) {
  962. VERIFY_IS_TRUE(pFileContent->GetBufferSize() == MainSource.size());
  963. VERIFY_IS_TRUE(0 == std::memcmp(pFileContent->GetBufferPointer(), MainSource.data(), MainSource.size()));
  964. }
  965. else {
  966. VERIFY_IS_TRUE(0 == std::memcmp(pFileContent->GetBufferPointer(), IncludedFile.data(), IncludedFile.size()));
  967. }
  968. }
  969. }
  970. // Defines
  971. {
  972. UINT32 uDefineCount = 0;
  973. std::map<std::wstring, int> tally;
  974. VERIFY_SUCCEEDED(pPdbUtils->GetDefineCount(&uDefineCount));
  975. VERIFY_IS_TRUE(uDefineCount == 2);
  976. for (UINT32 i = 0; i < uDefineCount; i++) {
  977. CComBSTR def;
  978. VERIFY_SUCCEEDED(pPdbUtils->GetDefine(i, &def));
  979. tally[std::wstring(def)]++;
  980. }
  981. auto Expected = ExpectedDefines;
  982. for (size_t i = 0; i < Expected.size(); i++) {
  983. auto it = tally.find(Expected[i]);
  984. VERIFY_IS_TRUE(it != tally.end() && it->second == 1);
  985. tally.erase(it);
  986. }
  987. VERIFY_IS_TRUE(tally.size() == 0);
  988. }
  989. // Arg pairs
  990. {
  991. std::vector<std::pair< std::wstring, std::wstring > > ArgPairs;
  992. UINT32 uCount = 0;
  993. VERIFY_SUCCEEDED(pPdbUtils->GetArgPairCount(&uCount));
  994. for (unsigned i = 0; i < uCount; i++) {
  995. CComBSTR pName;
  996. CComBSTR pValue;
  997. VERIFY_SUCCEEDED(pPdbUtils->GetArgPair(i, &pName, &pValue));
  998. VERIFY_IS_TRUE(pName || pValue);
  999. std::pair<std::wstring, std::wstring> NewPair;
  1000. if (pName)
  1001. NewPair.first = std::wstring(pName);
  1002. if (pValue)
  1003. NewPair.second = std::wstring(pValue);
  1004. ArgPairs.push_back(std::move(NewPair));
  1005. }
  1006. for (size_t i = 0; i < ExpectedArgs.size(); i++) {
  1007. auto ExpectedPair = ExpectedArgs[i];
  1008. bool Found = false;
  1009. for (size_t j = 0; j < ArgPairs.size(); j++) {
  1010. auto Pair = ArgPairs[j];
  1011. if ((!ExpectedPair.first || Pair.first == ExpectedPair.first) &&
  1012. (!ExpectedPair.second || Pair.second == ExpectedPair.second))
  1013. {
  1014. Found = true;
  1015. break;
  1016. }
  1017. }
  1018. VERIFY_SUCCEEDED(Found);
  1019. }
  1020. }
  1021. auto TestArgumentPair = [](llvm::ArrayRef<std::wstring> Args, llvm::ArrayRef<std::pair<const WCHAR *, const WCHAR *> > Expected) {
  1022. for (size_t i = 0; i < Expected.size(); i++) {
  1023. auto Pair = Expected[i];
  1024. bool found = false;
  1025. for (size_t j = 0; j < Args.size(); j++) {
  1026. if (!Pair.second && Args[j] == Pair.first) {
  1027. found = true;
  1028. break;
  1029. }
  1030. else if (!Pair.first && Args[j] == Pair.second) {
  1031. found = true;
  1032. break;
  1033. }
  1034. else if (Pair.first && Pair.second &&
  1035. Args[j] == Pair.first &&
  1036. j+1 < Args.size() &&
  1037. Args[j+1] == Pair.second)
  1038. {
  1039. found = true;
  1040. break;
  1041. }
  1042. }
  1043. VERIFY_IS_TRUE(found);
  1044. }
  1045. };
  1046. // Flags
  1047. {
  1048. UINT32 uCount = 0;
  1049. std::vector<std::wstring> Flags;
  1050. VERIFY_SUCCEEDED(pPdbUtils->GetFlagCount(&uCount));
  1051. VERIFY_IS_TRUE(uCount == ExpectedFlags.size());
  1052. for (UINT32 i = 0; i < uCount; i++) {
  1053. CComBSTR item;
  1054. VERIFY_SUCCEEDED(pPdbUtils->GetFlag(i, &item));
  1055. Flags.push_back(std::wstring(item));
  1056. }
  1057. TestArgumentPair(Flags, ExpectedFlags);
  1058. }
  1059. // Args
  1060. {
  1061. UINT32 uCount = 0;
  1062. std::vector<std::wstring> Args;
  1063. VERIFY_SUCCEEDED(pPdbUtils->GetArgCount(&uCount));
  1064. for (UINT32 i = 0; i < uCount; i++) {
  1065. CComBSTR item;
  1066. VERIFY_SUCCEEDED(pPdbUtils->GetArg(i, &item));
  1067. Args.push_back( std::wstring(item) );
  1068. }
  1069. TestArgumentPair(Args, ExpectedArgs);
  1070. }
  1071. // Shader reflection
  1072. if (TestReflection) {
  1073. CComPtr<IDxcUtils> pUtils;
  1074. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcUtils, &pUtils));
  1075. DxcBuffer buf = {};
  1076. buf.Ptr = pBlob->GetBufferPointer();
  1077. buf.Size = pBlob->GetBufferSize();
  1078. buf.Encoding = CP_ACP;
  1079. CComPtr<ID3D12ShaderReflection> pRefl;
  1080. VERIFY_SUCCEEDED(pUtils->CreateReflection(&buf, IID_PPV_ARGS(&pRefl)));
  1081. D3D12_SHADER_DESC desc = {};
  1082. VERIFY_SUCCEEDED(pRefl->GetDesc(&desc));
  1083. VERIFY_ARE_EQUAL(desc.ConstantBuffers, 1);
  1084. ID3D12ShaderReflectionConstantBuffer *pCB = pRefl->GetConstantBufferByIndex(0);
  1085. D3D12_SHADER_BUFFER_DESC cbDesc = {};
  1086. VERIFY_SUCCEEDED(pCB->GetDesc(&cbDesc));
  1087. VERIFY_IS_TRUE(0 == strcmp(cbDesc.Name, "MyCbuffer"));
  1088. VERIFY_ARE_EQUAL(cbDesc.Variables, 1);
  1089. ID3D12ShaderReflectionVariable *pVar = pCB->GetVariableByIndex(0);
  1090. D3D12_SHADER_VARIABLE_DESC varDesc = {};
  1091. VERIFY_SUCCEEDED(pVar->GetDesc(&varDesc));
  1092. VERIFY_ARE_EQUAL(varDesc.uFlags, D3D_SVF_USED);
  1093. VERIFY_IS_TRUE(0 == strcmp(varDesc.Name, "my_cbuf_foo"));
  1094. VERIFY_ARE_EQUAL(varDesc.Size, sizeof(float) * 4);
  1095. }
  1096. // Make the pix debug info
  1097. if (IsFullPDB) {
  1098. VERIFY_IS_TRUE(pPdbUtils->IsFullPDB());
  1099. CComPtr<IDxcBlob> pPDBBlob;
  1100. VERIFY_SUCCEEDED(pPdbUtils->GetFullPDB(&pPDBBlob));
  1101. CComPtr<IDxcPixDxilDebugInfoFactory> pFactory;
  1102. VERIFY_SUCCEEDED(pPdbUtils->QueryInterface(&pFactory));
  1103. CComPtr<IDxcPixCompilationInfo> pCompInfo;
  1104. VERIFY_ARE_EQUAL(E_NOTIMPL, pFactory->NewDxcPixCompilationInfo(&pCompInfo));
  1105. CComPtr<IDxcPixDxilDebugInfo> pDebugInfo;
  1106. VERIFY_SUCCEEDED(pFactory->NewDxcPixDxilDebugInfo(&pDebugInfo));
  1107. VERIFY_ARE_NOT_EQUAL(pDebugInfo, nullptr);
  1108. }
  1109. else {
  1110. VERIFY_IS_FALSE(pPdbUtils->IsFullPDB());
  1111. CComPtr<IDxcBlob> pFullPdb;
  1112. VERIFY_SUCCEEDED(pPdbUtils->GetFullPDB(&pFullPdb));
  1113. // Save a copy of the arg pairs
  1114. std::vector<std::pair< std::wstring, std::wstring> > pairsStorage;
  1115. UINT32 uNumArgsPairs = 0;
  1116. VERIFY_SUCCEEDED(pPdbUtils->GetArgPairCount(&uNumArgsPairs));
  1117. for (UINT32 i = 0; i < uNumArgsPairs; i++) {
  1118. CComBSTR pName, pValue;
  1119. VERIFY_SUCCEEDED(pPdbUtils->GetArgPair(i, &pName, &pValue));
  1120. std::pair< std::wstring, std::wstring> pairStorage;
  1121. pairStorage.first = pName ? pName : L"";
  1122. pairStorage.second = pValue ? pValue : L"";
  1123. pairsStorage.push_back(pairStorage);
  1124. }
  1125. // Set an obviously wrong RS and verify compilation fails
  1126. {
  1127. VERIFY_SUCCEEDED(pPdbUtils->OverrideRootSignature(L""));
  1128. CComPtr<IDxcResult> pResult;
  1129. VERIFY_SUCCEEDED(pPdbUtils->CompileForFullPDB(&pResult));
  1130. HRESULT result = S_OK;
  1131. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  1132. VERIFY_FAILED(result);
  1133. CComPtr<IDxcBlobEncoding> pErr;
  1134. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErr));
  1135. }
  1136. // Set an obviously wrong set of args and verify compilation fails
  1137. {
  1138. std::vector<DxcArgPair> pairs;
  1139. for (auto &p : pairsStorage) {
  1140. DxcArgPair pair = {};
  1141. pair.pName = p.first.c_str();
  1142. pair.pValue = p.second.c_str();
  1143. pairs.push_back(pair);
  1144. }
  1145. VERIFY_SUCCEEDED(pPdbUtils->OverrideArgs(pairs.data(), pairs.size()));
  1146. CComPtr<IDxcResult> pResult;
  1147. VERIFY_SUCCEEDED(pPdbUtils->CompileForFullPDB(&pResult));
  1148. HRESULT result = S_OK;
  1149. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  1150. VERIFY_SUCCEEDED(result);
  1151. }
  1152. auto ReplaceDebugFlagPair = [](const std::vector<std::pair<const WCHAR *, const WCHAR *> > &List) -> std::vector<std::pair<const WCHAR *, const WCHAR *> > {
  1153. std::vector<std::pair<const WCHAR *, const WCHAR *> > ret;
  1154. for (unsigned i = 0; i < List.size(); i++) {
  1155. if (!wcscmp(List[i].first, L"/Zs") || !wcscmp(List[i].first, L"-Zs"))
  1156. ret.push_back(std::pair<const WCHAR *, const WCHAR *>(L"-Zi", nullptr));
  1157. else
  1158. ret.push_back(List[i]);
  1159. }
  1160. return ret;
  1161. };
  1162. auto NewExpectedFlags = ReplaceDebugFlagPair(ExpectedFlags);
  1163. auto NewExpectedArgs = ReplaceDebugFlagPair(ExpectedArgs);
  1164. VerifyPdbUtil(dllSupport, pFullPdb, pPdbUtils,
  1165. pMainFileName,
  1166. NewExpectedArgs, NewExpectedFlags, ExpectedDefines,
  1167. pCompiler, HasVersion, /*IsFullPDB*/true,
  1168. /*TestReflection*/true,
  1169. HasHashAndPdbName, MainSource, IncludedFile);
  1170. }
  1171. // Now, test that dia interface doesn't crash (even if it fails).
  1172. {
  1173. CComPtr<IDiaDataSource> pDataSource;
  1174. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDataSource));
  1175. CComPtr<IDxcLibrary> pLib;
  1176. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1177. CComPtr<IStream> pStream;
  1178. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pBlob, &pStream));
  1179. if (SUCCEEDED(pDataSource->loadDataFromIStream(pStream))) {
  1180. CComPtr<IDiaSession> pSession;
  1181. if (SUCCEEDED(pDataSource->openSession(&pSession))) {
  1182. CComPtr<IDxcPixDxilDebugInfoFactory> pFactory;
  1183. VERIFY_SUCCEEDED(pSession->QueryInterface(&pFactory));
  1184. CComPtr<IDxcPixCompilationInfo> pCompilationInfo;
  1185. if (SUCCEEDED(pFactory->NewDxcPixCompilationInfo(&pCompilationInfo))) {
  1186. CComBSTR args;
  1187. CComBSTR defs;
  1188. CComBSTR mainName;
  1189. CComBSTR entryPoint;
  1190. CComBSTR entryPointFile;
  1191. CComBSTR target;
  1192. pCompilationInfo->GetArguments(&args);
  1193. pCompilationInfo->GetMacroDefinitions(&defs);
  1194. pCompilationInfo->GetEntryPoint(&entryPoint);
  1195. pCompilationInfo->GetEntryPointFile(&entryPointFile);
  1196. pCompilationInfo->GetHlslTarget(&target);
  1197. for (DWORD i = 0;;i++) {
  1198. CComBSTR sourceName;
  1199. CComBSTR sourceContent;
  1200. if (FAILED(pCompilationInfo->GetSourceFile(i, &sourceName, &sourceContent)))
  1201. break;
  1202. }
  1203. }
  1204. CComPtr<IDxcPixDxilDebugInfo> pDebugInfo;
  1205. pFactory->NewDxcPixDxilDebugInfo(&pDebugInfo);
  1206. }
  1207. }
  1208. }
  1209. }
  1210. #ifdef _WIN32
  1211. TEST_F(CompilerTest, CompileThenTestPdbUtilsStripped) {
  1212. CComPtr<TestIncludeHandler> pInclude;
  1213. CComPtr<IDxcCompiler> pCompiler;
  1214. CComPtr<IDxcBlobEncoding> pSource;
  1215. CComPtr<IDxcOperationResult> pOperationResult;
  1216. std::string main_source = "#include \"helper.h\"\r\n"
  1217. "float4 PSMain() : SV_Target { return ZERO; }";
  1218. std::string included_File = "#define ZERO 0";
  1219. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1220. CreateBlobFromText(main_source.c_str(), &pSource);
  1221. pInclude = new TestIncludeHandler(m_dllSupport);
  1222. pInclude->CallResults.emplace_back(included_File.c_str());
  1223. const WCHAR *pArgs[] = { L"/Zi", L"/Od", L"-flegacy-macro-expansion", L"-Qstrip_debug", L"/DTHIS_IS_A_DEFINE=HELLO" };
  1224. const DxcDefine pDefines[] = { L"THIS_IS_ANOTHER_DEFINE", L"1" };
  1225. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"PSMain",
  1226. L"ps_6_0", pArgs, _countof(pArgs), pDefines, _countof(pDefines), pInclude, &pOperationResult));
  1227. CComPtr<IDxcBlob> pCompiledBlob;
  1228. VERIFY_SUCCEEDED(pOperationResult->GetResult(&pCompiledBlob));
  1229. CComPtr<IDxcPdbUtils> pPdbUtils;
  1230. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcPdbUtils, &pPdbUtils));
  1231. VERIFY_SUCCEEDED(pPdbUtils->Load(pCompiledBlob));
  1232. // PDB file path
  1233. {
  1234. CComBSTR pName;
  1235. VERIFY_SUCCEEDED(pPdbUtils->GetName(&pName));
  1236. std::wstring suffix = L".pdb";
  1237. VERIFY_IS_TRUE(pName.Length() >= suffix.size());
  1238. VERIFY_IS_TRUE(
  1239. 0 == std::memcmp(suffix.c_str(), &pName[pName.Length() - suffix.size()], suffix.size()));
  1240. }
  1241. // There is hash and hash is not empty
  1242. {
  1243. CComPtr<IDxcBlob> pHash;
  1244. VERIFY_SUCCEEDED(pPdbUtils->GetHash(&pHash));
  1245. hlsl::DxilShaderHash EmptyHash = {};
  1246. VERIFY_ARE_EQUAL(pHash->GetBufferSize(), sizeof(EmptyHash));
  1247. VERIFY_IS_FALSE(0 == std::memcmp(pHash->GetBufferPointer(), &EmptyHash, sizeof(EmptyHash)));
  1248. }
  1249. {
  1250. VERIFY_IS_FALSE(pPdbUtils->IsFullPDB());
  1251. UINT32 uSourceCount = 0;
  1252. VERIFY_SUCCEEDED(pPdbUtils->GetSourceCount(&uSourceCount));
  1253. VERIFY_ARE_EQUAL(uSourceCount, 0);
  1254. }
  1255. }
  1256. void CompilerTest::TestPdbUtils(bool bSlim, bool bSourceInDebugModule, bool bStrip) {
  1257. CComPtr<TestIncludeHandler> pInclude;
  1258. CComPtr<IDxcCompiler> pCompiler;
  1259. CComPtr<IDxcBlobEncoding> pSource;
  1260. CComPtr<IDxcOperationResult> pOperationResult;
  1261. std::string main_source = R"x(
  1262. #include "helper.h"
  1263. cbuffer MyCbuffer : register(b1) {
  1264. float4 my_cbuf_foo;
  1265. }
  1266. [RootSignature("CBV(b1)")]
  1267. float4 PSMain() : SV_Target {
  1268. return ZERO + my_cbuf_foo;
  1269. }
  1270. )x";
  1271. std::string included_File = "#define ZERO 0";
  1272. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1273. CreateBlobFromText(main_source.c_str(), &pSource);
  1274. pInclude = new TestIncludeHandler(m_dllSupport);
  1275. pInclude->CallResults.emplace_back(included_File.c_str());
  1276. std::vector<const WCHAR *> args;
  1277. std::vector<std::pair<const WCHAR *, const WCHAR *> > expectedArgs;
  1278. std::vector<std::pair<const WCHAR *, const WCHAR *> > expectedFlags;
  1279. std::vector<const WCHAR *> expectedDefines;
  1280. auto AddArg = [&args, &expectedFlags, &expectedArgs](const WCHAR *arg, const WCHAR *value, bool isDefine) {
  1281. args.push_back(arg);
  1282. if (value)
  1283. args.push_back(value);
  1284. std::pair<const WCHAR *, const WCHAR *> pair(arg, value);
  1285. expectedArgs.push_back(pair);
  1286. if (!isDefine) {
  1287. expectedFlags.push_back(pair);
  1288. }
  1289. };
  1290. AddArg(L"-Od", nullptr, false);
  1291. AddArg(L"-flegacy-macro-expansion", nullptr, false);
  1292. if (bStrip) {
  1293. AddArg(L"-Qstrip_debug", nullptr, false);
  1294. }
  1295. else {
  1296. AddArg(L"-Qembed_debug", nullptr, false);
  1297. }
  1298. if (bSourceInDebugModule) {
  1299. AddArg(L"-Qsource_in_debug_module", nullptr, false);
  1300. }
  1301. if (bSlim) {
  1302. AddArg(L"-Zs", nullptr, false);
  1303. }
  1304. else {
  1305. AddArg(L"-Zi", nullptr, false);
  1306. }
  1307. AddArg(L"-D", L"THIS_IS_A_DEFINE=HELLO", true);
  1308. const DxcDefine pDefines[] = { L"THIS_IS_ANOTHER_DEFINE", L"1" };
  1309. expectedDefines.push_back(L"THIS_IS_ANOTHER_DEFINE=1");
  1310. expectedDefines.push_back(L"THIS_IS_A_DEFINE=HELLO");
  1311. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"PSMain",
  1312. L"ps_6_0", args.data(), args.size(), pDefines, _countof(pDefines), pInclude, &pOperationResult));
  1313. HRESULT CompileStatus = S_OK;
  1314. VERIFY_SUCCEEDED(pOperationResult->GetStatus(&CompileStatus));
  1315. VERIFY_SUCCEEDED(CompileStatus);
  1316. CComPtr<IDxcBlob> pCompiledBlob;
  1317. VERIFY_SUCCEEDED(pOperationResult->GetResult(&pCompiledBlob));
  1318. CComPtr<IDxcResult> pResult;
  1319. VERIFY_SUCCEEDED(pOperationResult.QueryInterface(&pResult));
  1320. CComPtr<IDxcBlob> pPdbBlob;
  1321. VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPdbBlob), nullptr));
  1322. CComPtr<IDxcPdbUtils> pPdbUtils;
  1323. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcPdbUtils, &pPdbUtils));
  1324. CComPtr<IDxcBlob> pProgramHeaderBlob;
  1325. if (bSourceInDebugModule) {
  1326. CComPtr<IDxcContainerReflection> pRef;
  1327. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pRef));
  1328. VERIFY_SUCCEEDED(pRef->Load(pPdbBlob));
  1329. UINT32 uIndex = 0;
  1330. VERIFY_SUCCEEDED(pRef->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &uIndex));
  1331. VERIFY_SUCCEEDED(pRef->GetPartContent(uIndex, &pProgramHeaderBlob));
  1332. VerifyPdbUtil(m_dllSupport,
  1333. pProgramHeaderBlob, pPdbUtils,
  1334. L"source.hlsl",
  1335. expectedArgs, expectedFlags, expectedDefines,
  1336. pCompiler,
  1337. /*HasVersion*/ false,
  1338. /*IsFullPDB*/ true,
  1339. /*HasHashAndPdbName*/false,
  1340. /*TestReflection*/false, // Reflection creation interface doesn't support just the DxilProgramHeader.
  1341. main_source, included_File);
  1342. }
  1343. VerifyPdbUtil(m_dllSupport,
  1344. pPdbBlob, pPdbUtils,
  1345. L"source.hlsl",
  1346. expectedArgs, expectedFlags, expectedDefines,
  1347. pCompiler,
  1348. /*HasVersion*/ true,
  1349. /*IsFullPDB*/ !bSlim,
  1350. /*HasHashAndPdbName*/true,
  1351. /*TestReflection*/true,
  1352. main_source, included_File);
  1353. if (!bStrip) {
  1354. VerifyPdbUtil(m_dllSupport,
  1355. pCompiledBlob, pPdbUtils,
  1356. L"source.hlsl",
  1357. expectedArgs, expectedFlags, expectedDefines,
  1358. pCompiler,
  1359. /*HasVersion*/ false,
  1360. /*IsFullPDB*/ true,
  1361. /*HasHashAndPdbName*/true,
  1362. /*TestReflection*/true,
  1363. main_source, included_File);
  1364. }
  1365. }
  1366. TEST_F(CompilerTest, CompileThenTestPdbUtils) {
  1367. TestPdbUtils(/*bSlim*/true, /*bSourceInDebugModule*/false, /*strip*/true); // Slim PDB, where source info is stored in its own part, and debug module is NOT present
  1368. TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/true, /*strip*/false); // Old PDB format, where source info is embedded in the module
  1369. TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/false, /*strip*/false); // Full PDB, where source info is stored in its own part, and a debug module which is present
  1370. TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/true, /*strip*/true); // Legacy PDB, where source info is embedded in the module
  1371. TestPdbUtils(/*bSlim*/false, /*bSourceInDebugModule*/false, /*strip*/true); // Full PDB, where source info is stored in its own part, and debug module is present
  1372. }
  1373. TEST_F(CompilerTest, CompileThenTestPdbInPrivate) {
  1374. CComPtr<IDxcCompiler> pCompiler;
  1375. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1376. std::string main_source = R"x(
  1377. cbuffer MyCbuffer : register(b1) {
  1378. float4 my_cbuf_foo;
  1379. }
  1380. [RootSignature("CBV(b1)")]
  1381. float4 main() : SV_Target {
  1382. return my_cbuf_foo;
  1383. }
  1384. )x";
  1385. CComPtr<IDxcUtils> pUtils;
  1386. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcUtils, &pUtils));
  1387. CComPtr<IDxcBlobEncoding> pSource;
  1388. VERIFY_SUCCEEDED(pUtils->CreateBlobFromPinned(main_source.c_str(), main_source.size(), CP_UTF8, &pSource));
  1389. const WCHAR *args[] = {
  1390. L"/Zs",
  1391. L"/Qpdb_in_private",
  1392. };
  1393. CComPtr<IDxcOperationResult> pOpResult;
  1394. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main", L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pOpResult));
  1395. CComPtr<IDxcResult> pResult;
  1396. VERIFY_SUCCEEDED(pOpResult.QueryInterface(&pResult));
  1397. CComPtr<IDxcBlob> pShader;
  1398. VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&pShader), nullptr));
  1399. CComPtr<IDxcContainerReflection> pRefl;
  1400. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pRefl));
  1401. VERIFY_SUCCEEDED(pRefl->Load(pShader));
  1402. UINT32 uIndex = 0;
  1403. VERIFY_SUCCEEDED(pRefl->FindFirstPartKind(hlsl::DFCC_PrivateData, &uIndex));
  1404. CComPtr<IDxcBlob> pPdbBlob;
  1405. VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPdbBlob), nullptr));
  1406. CComPtr<IDxcBlob> pPrivatePdbBlob;
  1407. VERIFY_SUCCEEDED(pRefl->GetPartContent(uIndex, &pPrivatePdbBlob));
  1408. VERIFY_ARE_EQUAL(pPdbBlob->GetBufferSize(), pPrivatePdbBlob->GetBufferSize());
  1409. VERIFY_ARE_EQUAL(0, memcmp(pPdbBlob->GetBufferPointer(), pPrivatePdbBlob->GetBufferPointer(), pPdbBlob->GetBufferSize()));
  1410. }
  1411. TEST_F(CompilerTest, CompileThenTestPdbUtilsRelativePath) {
  1412. std::string main_source = R"x(
  1413. #include "helper.h"
  1414. cbuffer MyCbuffer : register(b1) {
  1415. float4 my_cbuf_foo;
  1416. }
  1417. [RootSignature("CBV(b1)")]
  1418. float4 main() : SV_Target {
  1419. return my_cbuf_foo;
  1420. }
  1421. )x";
  1422. CComPtr<IDxcCompiler3> pCompiler;
  1423. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  1424. DxcBuffer SourceBuf = {};
  1425. SourceBuf.Ptr = main_source.c_str();
  1426. SourceBuf.Size = main_source.size();
  1427. SourceBuf.Encoding = CP_UTF8;
  1428. std::vector<const WCHAR *> args;
  1429. args.push_back(L"/Tps_6_0");
  1430. args.push_back(L"/Zs");
  1431. args.push_back(L"shaders/Shader.hlsl");
  1432. CComPtr<TestIncludeHandler> pInclude;
  1433. std::string included_File = "#define ZERO 0";
  1434. pInclude = new TestIncludeHandler(m_dllSupport);
  1435. pInclude->CallResults.emplace_back(included_File.c_str());
  1436. CComPtr<IDxcResult> pResult;
  1437. VERIFY_SUCCEEDED(pCompiler->Compile(&SourceBuf, args.data(), args.size(), pInclude, IID_PPV_ARGS(&pResult)));
  1438. CComPtr<IDxcBlob> pPdb;
  1439. CComPtr<IDxcBlobUtf16> pPdbName;
  1440. VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPdb), &pPdbName));
  1441. CComPtr<IDxcPdbUtils> pPdbUtils;
  1442. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcPdbUtils, &pPdbUtils));
  1443. VERIFY_SUCCEEDED(pPdbUtils->Load(pPdb));
  1444. CComPtr<IDxcBlob> pFullPdb;
  1445. VERIFY_SUCCEEDED(pPdbUtils->GetFullPDB(&pFullPdb));
  1446. VERIFY_SUCCEEDED(pPdbUtils->Load(pFullPdb));
  1447. VERIFY_IS_TRUE(pPdbUtils->IsFullPDB());
  1448. }
  1449. TEST_F(CompilerTest, CompileThenTestPdbUtilsEmptyEntry) {
  1450. std::string main_source = R"x(
  1451. cbuffer MyCbuffer : register(b1) {
  1452. float4 my_cbuf_foo;
  1453. }
  1454. [RootSignature("CBV(b1)")]
  1455. float4 main() : SV_Target {
  1456. return my_cbuf_foo;
  1457. }
  1458. )x";
  1459. CComPtr<IDxcCompiler3> pCompiler;
  1460. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  1461. DxcBuffer SourceBuf = {};
  1462. SourceBuf.Ptr = main_source.c_str();
  1463. SourceBuf.Size = main_source.size();
  1464. SourceBuf.Encoding = CP_UTF8;
  1465. std::vector<const WCHAR *> args;
  1466. args.push_back(L"/Tps_6_0");
  1467. args.push_back(L"/Zi");
  1468. CComPtr<IDxcResult> pResult;
  1469. VERIFY_SUCCEEDED(pCompiler->Compile(&SourceBuf, args.data(), args.size(), nullptr, IID_PPV_ARGS(&pResult)));
  1470. CComPtr<IDxcBlob> pPdb;
  1471. CComPtr<IDxcBlobUtf16> pPdbName;
  1472. VERIFY_SUCCEEDED(pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPdb), &pPdbName));
  1473. CComPtr<IDxcPdbUtils> pPdbUtils;
  1474. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcPdbUtils, &pPdbUtils));
  1475. VERIFY_SUCCEEDED(pPdbUtils->Load(pPdb));
  1476. CComBSTR pEntryName;
  1477. VERIFY_SUCCEEDED(pPdbUtils->GetEntryPoint(&pEntryName));
  1478. VERIFY_ARE_EQUAL(pEntryName, L"main");
  1479. }
  1480. #endif
  1481. TEST_F(CompilerTest, CompileWithRootSignatureThenStripRootSignature) {
  1482. CComPtr<IDxcCompiler> pCompiler;
  1483. CComPtr<IDxcOperationResult> pResult;
  1484. CComPtr<IDxcBlobEncoding> pSource;
  1485. CComPtr<IDxcBlob> pProgram;
  1486. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1487. CreateBlobFromText("[RootSignature(\"\")] \r\n"
  1488. "float4 main(float a : A) : SV_Target {\r\n"
  1489. " return a;\r\n"
  1490. "}",
  1491. &pSource);
  1492. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1493. L"ps_6_0", nullptr, 0, nullptr,
  1494. 0, nullptr, &pResult));
  1495. VERIFY_IS_NOT_NULL(pResult);
  1496. HRESULT status;
  1497. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1498. VERIFY_SUCCEEDED(status);
  1499. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1500. VERIFY_IS_NOT_NULL(pProgram);
  1501. hlsl::DxilContainerHeader *pContainerHeader = hlsl::IsDxilContainerLike(pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  1502. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pProgram->GetBufferSize()));
  1503. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  1504. pContainerHeader, hlsl::DxilFourCC::DFCC_RootSignature);
  1505. VERIFY_IS_NOT_NULL(pPartHeader);
  1506. pResult.Release();
  1507. // Remove root signature
  1508. CComPtr<IDxcBlob> pProgramRootSigRemoved;
  1509. CComPtr<IDxcContainerBuilder> pBuilder;
  1510. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1511. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  1512. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature));
  1513. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1514. VERIFY_SUCCEEDED(pResult->GetResult(&pProgramRootSigRemoved));
  1515. pContainerHeader = hlsl::IsDxilContainerLike(pProgramRootSigRemoved->GetBufferPointer(), pProgramRootSigRemoved->GetBufferSize());
  1516. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pProgramRootSigRemoved->GetBufferSize()));
  1517. hlsl::DxilPartHeader *pPartHeaderShouldBeNull = hlsl::GetDxilPartByType(pContainerHeader,
  1518. hlsl::DxilFourCC::DFCC_RootSignature);
  1519. VERIFY_IS_NULL(pPartHeaderShouldBeNull);
  1520. pBuilder.Release();
  1521. pResult.Release();
  1522. // Add root signature back
  1523. CComPtr<IDxcBlobEncoding> pRootSignatureBlob;
  1524. CComPtr<IDxcLibrary> pLibrary;
  1525. CComPtr<IDxcBlob> pProgramRootSigAdded;
  1526. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  1527. VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned(
  1528. hlsl::GetDxilPartData(pPartHeader), pPartHeader->PartSize, 0, &pRootSignatureBlob));
  1529. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1530. VERIFY_SUCCEEDED(pBuilder->Load(pProgramRootSigRemoved));
  1531. pBuilder->AddPart(hlsl::DxilFourCC::DFCC_RootSignature, pRootSignatureBlob);
  1532. pBuilder->SerializeContainer(&pResult);
  1533. VERIFY_SUCCEEDED(pResult->GetResult(&pProgramRootSigAdded));
  1534. pContainerHeader = hlsl::IsDxilContainerLike(pProgramRootSigAdded->GetBufferPointer(), pProgramRootSigAdded->GetBufferSize());
  1535. VERIFY_SUCCEEDED(hlsl::IsValidDxilContainer(pContainerHeader, pProgramRootSigAdded->GetBufferSize()));
  1536. pPartHeader = hlsl::GetDxilPartByType(pContainerHeader,
  1537. hlsl::DxilFourCC::DFCC_RootSignature);
  1538. VERIFY_IS_NOT_NULL(pPartHeader);
  1539. }
  1540. #endif // Container builder unsupported
  1541. TEST_F(CompilerTest, CompileWhenIncludeThenLoadInvoked) {
  1542. CComPtr<IDxcCompiler> pCompiler;
  1543. CComPtr<IDxcOperationResult> pResult;
  1544. CComPtr<IDxcBlobEncoding> pSource;
  1545. CComPtr<TestIncludeHandler> pInclude;
  1546. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1547. CreateBlobFromText(
  1548. "#include \"helper.h\"\r\n"
  1549. "float4 main() : SV_Target { return 0; }", &pSource);
  1550. pInclude = new TestIncludeHandler(m_dllSupport);
  1551. pInclude->CallResults.emplace_back("");
  1552. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1553. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1554. VerifyOperationSucceeded(pResult);
  1555. VERIFY_ARE_EQUAL_WSTR(L"./helper.h;", pInclude->GetAllFileNames().c_str());
  1556. }
  1557. TEST_F(CompilerTest, CompileWhenIncludeThenLoadUsed) {
  1558. CComPtr<IDxcCompiler> pCompiler;
  1559. CComPtr<IDxcOperationResult> pResult;
  1560. CComPtr<IDxcBlobEncoding> pSource;
  1561. CComPtr<TestIncludeHandler> pInclude;
  1562. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1563. CreateBlobFromText(
  1564. "#include \"helper.h\"\r\n"
  1565. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1566. pInclude = new TestIncludeHandler(m_dllSupport);
  1567. pInclude->CallResults.emplace_back("#define ZERO 0");
  1568. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1569. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1570. VerifyOperationSucceeded(pResult);
  1571. VERIFY_ARE_EQUAL_WSTR(L"./helper.h;", pInclude->GetAllFileNames().c_str());
  1572. }
  1573. TEST_F(CompilerTest, CompileWhenIncludeAbsoluteThenLoadAbsolute) {
  1574. CComPtr<IDxcCompiler> pCompiler;
  1575. CComPtr<IDxcOperationResult> pResult;
  1576. CComPtr<IDxcBlobEncoding> pSource;
  1577. CComPtr<TestIncludeHandler> pInclude;
  1578. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1579. #ifdef _WIN32 // OS-specific root
  1580. CreateBlobFromText(
  1581. "#include \"C:\\helper.h\"\r\n"
  1582. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1583. #else
  1584. CreateBlobFromText(
  1585. "#include \"/helper.h\"\n"
  1586. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1587. #endif
  1588. pInclude = new TestIncludeHandler(m_dllSupport);
  1589. pInclude->CallResults.emplace_back("#define ZERO 0");
  1590. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1591. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1592. VerifyOperationSucceeded(pResult);
  1593. #ifdef _WIN32 // OS-specific root
  1594. VERIFY_ARE_EQUAL_WSTR(L"C:\\helper.h;", pInclude->GetAllFileNames().c_str());
  1595. #else
  1596. VERIFY_ARE_EQUAL_WSTR(L"/helper.h;", pInclude->GetAllFileNames().c_str());
  1597. #endif
  1598. }
  1599. TEST_F(CompilerTest, CompileWhenIncludeLocalThenLoadRelative) {
  1600. CComPtr<IDxcCompiler> pCompiler;
  1601. CComPtr<IDxcOperationResult> pResult;
  1602. CComPtr<IDxcBlobEncoding> pSource;
  1603. CComPtr<TestIncludeHandler> pInclude;
  1604. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1605. CreateBlobFromText(
  1606. "#include \"..\\helper.h\"\r\n"
  1607. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1608. pInclude = new TestIncludeHandler(m_dllSupport);
  1609. pInclude->CallResults.emplace_back("#define ZERO 0");
  1610. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1611. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1612. VerifyOperationSucceeded(pResult);
  1613. #ifdef _WIN32 // OS-specific directory dividers
  1614. VERIFY_ARE_EQUAL_WSTR(L"./..\\helper.h;", pInclude->GetAllFileNames().c_str());
  1615. #else
  1616. VERIFY_ARE_EQUAL_WSTR(L"./../helper.h;", pInclude->GetAllFileNames().c_str());
  1617. #endif
  1618. }
  1619. TEST_F(CompilerTest, CompileWhenIncludeSystemThenLoadNotRelative) {
  1620. CComPtr<IDxcCompiler> pCompiler;
  1621. CComPtr<IDxcOperationResult> pResult;
  1622. CComPtr<IDxcBlobEncoding> pSource;
  1623. CComPtr<TestIncludeHandler> pInclude;
  1624. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1625. CreateBlobFromText(
  1626. "#include \"subdir/other/file.h\"\r\n"
  1627. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1628. LPCWSTR args[] = {
  1629. L"-Ifoo"
  1630. };
  1631. pInclude = new TestIncludeHandler(m_dllSupport);
  1632. pInclude->CallResults.emplace_back("#include <helper.h>");
  1633. pInclude->CallResults.emplace_back("#define ZERO 0");
  1634. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1635. L"ps_6_0", args, _countof(args), nullptr, 0, pInclude, &pResult));
  1636. VerifyOperationSucceeded(pResult);
  1637. #ifdef _WIN32 // OS-specific directory dividers
  1638. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./foo\\helper.h;", pInclude->GetAllFileNames().c_str());
  1639. #else
  1640. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./foo/helper.h;", pInclude->GetAllFileNames().c_str());
  1641. #endif
  1642. }
  1643. TEST_F(CompilerTest, CompileWhenIncludeSystemMissingThenLoadAttempt) {
  1644. CComPtr<IDxcCompiler> pCompiler;
  1645. CComPtr<IDxcOperationResult> pResult;
  1646. CComPtr<IDxcBlobEncoding> pSource;
  1647. CComPtr<TestIncludeHandler> pInclude;
  1648. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1649. CreateBlobFromText(
  1650. "#include \"subdir/other/file.h\"\r\n"
  1651. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1652. pInclude = new TestIncludeHandler(m_dllSupport);
  1653. pInclude->CallResults.emplace_back("#include <helper.h>");
  1654. pInclude->CallResults.emplace_back("#define ZERO 0");
  1655. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1656. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1657. std::string failLog(VerifyOperationFailed(pResult));
  1658. VERIFY_ARE_NOT_EQUAL(std::string::npos, failLog.find("<angled>")); // error message should prompt to use <angled> rather than "quotes"
  1659. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./subdir/other/helper.h;", pInclude->GetAllFileNames().c_str());
  1660. }
  1661. TEST_F(CompilerTest, CompileWhenIncludeFlagsThenIncludeUsed) {
  1662. CComPtr<IDxcCompiler> pCompiler;
  1663. CComPtr<IDxcOperationResult> pResult;
  1664. CComPtr<IDxcBlobEncoding> pSource;
  1665. CComPtr<TestIncludeHandler> pInclude;
  1666. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1667. CreateBlobFromText(
  1668. "#include <helper.h>\r\n"
  1669. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1670. pInclude = new TestIncludeHandler(m_dllSupport);
  1671. pInclude->CallResults.emplace_back("#define ZERO 0");
  1672. #ifdef _WIN32 // OS-specific root
  1673. LPCWSTR args[] = { L"-I\\\\server\\share" };
  1674. #else
  1675. LPCWSTR args[] = { L"-I/server/share" };
  1676. #endif
  1677. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1678. L"ps_6_0", args, _countof(args), nullptr, 0, pInclude, &pResult));
  1679. VerifyOperationSucceeded(pResult);
  1680. #ifdef _WIN32 // OS-specific root
  1681. VERIFY_ARE_EQUAL_WSTR(L"\\\\server\\share\\helper.h;", pInclude->GetAllFileNames().c_str());
  1682. #else
  1683. VERIFY_ARE_EQUAL_WSTR(L"/server/share/helper.h;", pInclude->GetAllFileNames().c_str());
  1684. #endif
  1685. }
  1686. TEST_F(CompilerTest, CompileWhenIncludeMissingThenFail) {
  1687. CComPtr<IDxcCompiler> pCompiler;
  1688. CComPtr<IDxcOperationResult> pResult;
  1689. CComPtr<IDxcBlobEncoding> pSource;
  1690. CComPtr<TestIncludeHandler> pInclude;
  1691. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1692. CreateBlobFromText(
  1693. "#include \"file.h\"\r\n"
  1694. "float4 main() : SV_Target { return 0; }", &pSource);
  1695. pInclude = new TestIncludeHandler(m_dllSupport);
  1696. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1697. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1698. HRESULT hr;
  1699. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1700. VERIFY_FAILED(hr);
  1701. }
  1702. TEST_F(CompilerTest, CompileWhenIncludeHasPathThenOK) {
  1703. CComPtr<IDxcCompiler> pCompiler;
  1704. LPCWSTR Source = L"c:\\temp\\OddIncludes\\main.hlsl";
  1705. LPCWSTR Args[] = { L"/I", L"c:\\temp" };
  1706. LPCWSTR ArgsUp[] = { L"/I", L"c:\\Temp" };
  1707. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1708. bool useUpValues[] = { false, true };
  1709. for (bool useUp : useUpValues) {
  1710. CComPtr<IDxcOperationResult> pResult;
  1711. CComPtr<IDxcBlobEncoding> pSource;
  1712. #if TEST_ON_DISK
  1713. CComPtr<IDxcLibrary> pLibrary;
  1714. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  1715. VERIFY_SUCCEEDED(pLibrary->CreateIncludeHandler(&pInclude));
  1716. VERIFY_SUCCEEDED(pLibrary->CreateBlobFromFile(Source, nullptr, &pSource));
  1717. #else
  1718. CComPtr<TestIncludeHandler> pInclude;
  1719. pInclude = new TestIncludeHandler(m_dllSupport);
  1720. pInclude->CallResults.emplace_back("// Empty");
  1721. CreateBlobFromText("#include \"include.hlsl\"\r\n"
  1722. "float4 main() : SV_Target { return 0; }",
  1723. &pSource);
  1724. #endif
  1725. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, Source, L"main",
  1726. L"ps_6_0", useUp ? ArgsUp : Args, _countof(Args), nullptr, 0, pInclude, &pResult));
  1727. HRESULT hr;
  1728. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1729. VERIFY_SUCCEEDED(hr);
  1730. }
  1731. }
  1732. TEST_F(CompilerTest, CompileWhenIncludeEmptyThenOK) {
  1733. CComPtr<IDxcCompiler> pCompiler;
  1734. CComPtr<IDxcOperationResult> pResult;
  1735. CComPtr<IDxcBlobEncoding> pSource;
  1736. CComPtr<TestIncludeHandler> pInclude;
  1737. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1738. CreateBlobFromText("#include \"empty.h\"\r\n"
  1739. "float4 main() : SV_Target { return 0; }",
  1740. &pSource);
  1741. pInclude = new TestIncludeHandler(m_dllSupport);
  1742. pInclude->CallResults.emplace_back("", CP_ACP); // An empty file would get detected as ACP code page
  1743. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1744. L"ps_6_0", nullptr, 0, nullptr, 0,
  1745. pInclude, &pResult));
  1746. VerifyOperationSucceeded(pResult);
  1747. VERIFY_ARE_EQUAL_WSTR(L"./empty.h;", pInclude->GetAllFileNames().c_str());
  1748. }
  1749. static const char EmptyCompute[] = "[numthreads(8,8,1)] void main() { }";
  1750. TEST_F(CompilerTest, CompileWhenODumpThenPassConfig) {
  1751. CComPtr<IDxcCompiler> pCompiler;
  1752. CComPtr<IDxcOperationResult> pResult;
  1753. CComPtr<IDxcBlobEncoding> pSource;
  1754. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1755. CreateBlobFromText(EmptyCompute, &pSource);
  1756. LPCWSTR Args[] = { L"/Odump" };
  1757. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1758. L"cs_6_0", Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1759. VerifyOperationSucceeded(pResult);
  1760. CComPtr<IDxcBlob> pResultBlob;
  1761. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1762. wstring passes = BlobToUtf16(pResultBlob);
  1763. VERIFY_ARE_NOT_EQUAL(wstring::npos, passes.find(L"inline"));
  1764. }
  1765. TEST_F(CompilerTest, CompileWhenVdThenProducesDxilContainer) {
  1766. CComPtr<IDxcCompiler> pCompiler;
  1767. CComPtr<IDxcOperationResult> pResult;
  1768. CComPtr<IDxcBlobEncoding> pSource;
  1769. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1770. CreateBlobFromText(EmptyCompute, &pSource);
  1771. LPCWSTR Args[] = { L"/Vd" };
  1772. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1773. L"cs_6_0", Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1774. VerifyOperationSucceeded(pResult);
  1775. CComPtr<IDxcBlob> pResultBlob;
  1776. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1777. VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(reinterpret_cast<hlsl::DxilContainerHeader *>(pResultBlob->GetBufferPointer()), pResultBlob->GetBufferSize()));
  1778. }
  1779. TEST_F(CompilerTest, CompileWhenODumpThenOptimizerMatch) {
  1780. LPCWSTR OptLevels[] = { L"/Od", L"/O1", L"/O2" };
  1781. CComPtr<IDxcCompiler> pCompiler;
  1782. CComPtr<IDxcOptimizer> pOptimizer;
  1783. CComPtr<IDxcAssembler> pAssembler;
  1784. CComPtr<IDxcValidator> pValidator;
  1785. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  1786. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  1787. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  1788. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
  1789. for (LPCWSTR OptLevel : OptLevels) {
  1790. CComPtr<IDxcOperationResult> pResult;
  1791. CComPtr<IDxcBlobEncoding> pSource;
  1792. CComPtr<IDxcBlob> pHighLevelBlob;
  1793. CComPtr<IDxcBlob> pOptimizedModule;
  1794. CComPtr<IDxcBlob> pAssembledBlob;
  1795. // Could use EmptyCompute and cs_6_0, but there is an issue where properties
  1796. // don't round-trip properly at high-level, so validation fails because
  1797. // dimensions are set to zero. Workaround by using pixel shader instead.
  1798. LPCWSTR Target = L"ps_6_0";
  1799. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1800. LPCWSTR Args[2] = { OptLevel, L"/Odump" };
  1801. // Get the passes for this optimization level.
  1802. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1803. Target, Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1804. VerifyOperationSucceeded(pResult);
  1805. CComPtr<IDxcBlob> pResultBlob;
  1806. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1807. wstring passes = BlobToUtf16(pResultBlob);
  1808. // Get wchar_t version and prepend hlsl-hlensure, to do a split high-level/opt compilation pass.
  1809. std::vector<LPCWSTR> Options;
  1810. SplitPassList(const_cast<LPWSTR>(passes.data()), Options);
  1811. // Now compile directly.
  1812. pResult.Release();
  1813. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1814. Target, Args, 1, nullptr, 0, nullptr, &pResult));
  1815. VerifyOperationSucceeded(pResult);
  1816. // Now compile via a high-level compile followed by the optimization passes.
  1817. pResult.Release();
  1818. Args[_countof(Args)-1] = L"/fcgl";
  1819. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1820. Target, Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1821. VerifyOperationSucceeded(pResult);
  1822. VERIFY_SUCCEEDED(pResult->GetResult(&pHighLevelBlob));
  1823. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(pHighLevelBlob, Options.data(),
  1824. Options.size(), &pOptimizedModule,
  1825. nullptr));
  1826. string text = DisassembleProgram(m_dllSupport, pOptimizedModule);
  1827. WEX::Logging::Log::Comment(L"Final program:");
  1828. WEX::Logging::Log::Comment(CA2W(text.c_str()));
  1829. // At the very least, the module should be valid.
  1830. pResult.Release();
  1831. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pOptimizedModule, &pResult));
  1832. VerifyOperationSucceeded(pResult);
  1833. VERIFY_SUCCEEDED(pResult->GetResult(&pAssembledBlob));
  1834. pResult.Release();
  1835. VERIFY_SUCCEEDED(pValidator->Validate(pAssembledBlob, DxcValidatorFlags_Default, &pResult));
  1836. VerifyOperationSucceeded(pResult);
  1837. }
  1838. }
  1839. static const UINT CaptureStacks = 0; // Set to 1 to enable captures
  1840. static const UINT StackFrameCount = 12;
  1841. struct InstrumentedHeapMalloc : public IMalloc {
  1842. private:
  1843. HANDLE m_Handle; // Heap handle.
  1844. ULONG m_RefCount = 0; // Reference count. Used for reference leaks, not for lifetime.
  1845. ULONG m_AllocCount = 0; // Total # of alloc and realloc requests.
  1846. ULONG m_AllocSize = 0; // Total # of alloc and realloc bytes.
  1847. ULONG m_Size = 0; // Current # of alloc'ed bytes.
  1848. ULONG m_FailAlloc = 0; // If nonzero, the alloc/realloc call to fail.
  1849. // Each allocation also tracks the following information:
  1850. // - allocation callstack
  1851. // - deallocation callstack
  1852. // - prior/next blocks in a list of allocated blocks
  1853. LIST_ENTRY AllocList;
  1854. struct PtrData {
  1855. LIST_ENTRY Entry;
  1856. LPVOID AllocFrames[CaptureStacks ? StackFrameCount * CaptureStacks : 1];
  1857. LPVOID FreeFrames[CaptureStacks ? StackFrameCount * CaptureStacks : 1];
  1858. UINT64 AllocAtCount;
  1859. DWORD AllocFrameCount;
  1860. DWORD FreeFrameCount;
  1861. SIZE_T Size;
  1862. PtrData *Self;
  1863. };
  1864. PtrData *DataFromPtr(void *p) {
  1865. if (p == nullptr) return nullptr;
  1866. PtrData *R = ((PtrData *)p) - 1;
  1867. if (R != R->Self) {
  1868. VERIFY_FAIL(); // p is invalid or underrun
  1869. }
  1870. return R;
  1871. }
  1872. public:
  1873. InstrumentedHeapMalloc() : m_Handle(nullptr) {
  1874. ResetCounts();
  1875. }
  1876. ~InstrumentedHeapMalloc() {
  1877. if (m_Handle)
  1878. HeapDestroy(m_Handle);
  1879. }
  1880. void ResetHeap() {
  1881. if (m_Handle) {
  1882. HeapDestroy(m_Handle);
  1883. m_Handle = nullptr;
  1884. }
  1885. m_Handle = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  1886. }
  1887. ULONG GetRefCount() const { return m_RefCount; }
  1888. ULONG GetAllocCount() const { return m_AllocCount; }
  1889. ULONG GetAllocSize() const { return m_AllocSize; }
  1890. ULONG GetSize() const { return m_Size; }
  1891. void ResetCounts() {
  1892. m_RefCount = m_AllocCount = m_AllocSize = m_Size = 0;
  1893. AllocList.Blink = AllocList.Flink = &AllocList;
  1894. }
  1895. void SetFailAlloc(ULONG index) {
  1896. m_FailAlloc = index;
  1897. }
  1898. ULONG STDMETHODCALLTYPE AddRef() {
  1899. return ++m_RefCount;
  1900. }
  1901. ULONG STDMETHODCALLTYPE Release() {
  1902. if (m_RefCount == 0) VERIFY_FAIL();
  1903. return --m_RefCount;
  1904. }
  1905. STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) {
  1906. return DoBasicQueryInterface<IMalloc>(this, iid, ppvObject);
  1907. }
  1908. virtual void *STDMETHODCALLTYPE Alloc(_In_ SIZE_T cb) {
  1909. ++m_AllocCount;
  1910. if (m_FailAlloc && m_AllocCount >= m_FailAlloc) {
  1911. return nullptr; // breakpoint for i failure - m_FailAlloc == 1+VAL
  1912. }
  1913. m_AllocSize += cb;
  1914. m_Size += cb;
  1915. PtrData *P = (PtrData *)HeapAlloc(m_Handle, HEAP_ZERO_MEMORY, sizeof(PtrData) + cb);
  1916. P->Entry.Flink = AllocList.Flink;
  1917. P->Entry.Blink = &AllocList;
  1918. AllocList.Flink->Blink = &(P->Entry);
  1919. AllocList.Flink = &(P->Entry);
  1920. // breakpoint for i failure on NN alloc - m_FailAlloc == 1+VAL && m_AllocCount == NN
  1921. // breakpoint for happy path for NN alloc - m_AllocCount == NN
  1922. P->AllocAtCount = m_AllocCount;
  1923. if (CaptureStacks)
  1924. P->AllocFrameCount = CaptureStackBackTrace(1, StackFrameCount, P->AllocFrames, nullptr);
  1925. P->Size = cb;
  1926. P->Self = P;
  1927. return P + 1;
  1928. }
  1929. virtual void *STDMETHODCALLTYPE Realloc(_In_opt_ void *pv, _In_ SIZE_T cb) {
  1930. SIZE_T priorSize = pv == nullptr ? (SIZE_T)0 : GetSize(pv);
  1931. void *R = Alloc(cb);
  1932. if (!R)
  1933. return nullptr;
  1934. SIZE_T copySize = std::min(cb, priorSize);
  1935. memcpy(R, pv, copySize);
  1936. Free(pv);
  1937. return R;
  1938. }
  1939. virtual void STDMETHODCALLTYPE Free(_In_opt_ void *pv) {
  1940. if (!pv)
  1941. return;
  1942. PtrData *P = DataFromPtr(pv);
  1943. if (P->FreeFrameCount)
  1944. VERIFY_FAIL(); // double-free detected
  1945. m_Size -= P->Size;
  1946. P->Entry.Flink->Blink = P->Entry.Blink;
  1947. P->Entry.Blink->Flink = P->Entry.Flink;
  1948. if (CaptureStacks)
  1949. P->FreeFrameCount =
  1950. CaptureStackBackTrace(1, StackFrameCount, P->FreeFrames, nullptr);
  1951. }
  1952. virtual SIZE_T STDMETHODCALLTYPE GetSize(
  1953. /* [annotation][in] */
  1954. _In_opt_ _Post_writable_byte_size_(return) void *pv)
  1955. {
  1956. if (pv == nullptr) return 0;
  1957. return DataFromPtr(pv)->Size;
  1958. }
  1959. virtual int STDMETHODCALLTYPE DidAlloc(
  1960. _In_opt_ void *pv) {
  1961. return -1; // don't know
  1962. }
  1963. virtual void STDMETHODCALLTYPE HeapMinimize(void) {}
  1964. void DumpLeaks() {
  1965. PtrData *ptr = (PtrData*)AllocList.Flink;;
  1966. PtrData *end = (PtrData*)AllocList.Blink;;
  1967. WEX::Logging::Log::Comment(FormatToWString(L"Leaks total size: %d", (signed int)m_Size).data());
  1968. while (ptr != end) {
  1969. WEX::Logging::Log::Comment(FormatToWString(L"Memory leak at 0x0%X, size %d, alloc# %d", ptr + 1, ptr->Size, ptr->AllocAtCount).data());
  1970. ptr = (PtrData*)ptr->Entry.Flink;
  1971. }
  1972. }
  1973. };
  1974. #if _ITERATOR_DEBUG_LEVEL==0
  1975. // CompileWhenNoMemThenOOM can properly detect leaks only when debug iterators are disabled
  1976. TEST_F(CompilerTest, CompileWhenNoMemThenOOM) {
  1977. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  1978. CComPtr<IDxcBlobEncoding> pSource;
  1979. CreateBlobFromText(EmptyCompute, &pSource);
  1980. InstrumentedHeapMalloc InstrMalloc;
  1981. CComPtr<IDxcCompiler> pCompiler;
  1982. CComPtr<IDxcOperationResult> pResult;
  1983. ULONG allocCount = 0;
  1984. ULONG allocSize = 0;
  1985. ULONG initialRefCount;
  1986. InstrMalloc.ResetHeap();
  1987. VERIFY_IS_TRUE(m_dllSupport.HasCreateWithMalloc());
  1988. // Verify a simple object creation.
  1989. initialRefCount = InstrMalloc.GetRefCount();
  1990. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler));
  1991. pCompiler.Release();
  1992. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  1993. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  1994. InstrMalloc.ResetCounts();
  1995. InstrMalloc.ResetHeap();
  1996. // First time, run to completion and capture stats.
  1997. initialRefCount = InstrMalloc.GetRefCount();
  1998. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler));
  1999. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2000. L"cs_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2001. allocCount = InstrMalloc.GetAllocCount();
  2002. allocSize = InstrMalloc.GetAllocSize();
  2003. HRESULT hrWithMemory;
  2004. VERIFY_SUCCEEDED(pResult->GetStatus(&hrWithMemory));
  2005. VERIFY_SUCCEEDED(hrWithMemory);
  2006. pCompiler.Release();
  2007. pResult.Release();
  2008. VERIFY_IS_TRUE(allocSize > allocCount);
  2009. // Ensure that after all resources are released, there are no outstanding
  2010. // allocations or references.
  2011. //
  2012. // First leak is in ((InstrumentedHeapMalloc::PtrData *)InstrMalloc.AllocList.Flink)
  2013. if (InstrMalloc.GetSize() != 0) {
  2014. WEX::Logging::Log::Comment(L"Memory leak(s) detected");
  2015. InstrMalloc.DumpLeaks();
  2016. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  2017. }
  2018. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  2019. // In Debug, without /D_ITERATOR_DEBUG_LEVEL=0, debug iterators will be used;
  2020. // this causes a problem where std::string is specified as noexcept, and yet
  2021. // a sentinel is allocated that may fail and throw.
  2022. if (m_ver.SkipOutOfMemoryTest()) return;
  2023. // Now, fail each allocation and make sure we get an error.
  2024. for (ULONG i = 0; i <= allocCount; ++i) {
  2025. // LogCommentFmt(L"alloc fail %u", i);
  2026. bool isLast = i == allocCount;
  2027. InstrMalloc.ResetCounts();
  2028. InstrMalloc.ResetHeap();
  2029. InstrMalloc.SetFailAlloc(i + 1);
  2030. HRESULT hrOp = m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler);
  2031. if (SUCCEEDED(hrOp)) {
  2032. hrOp = pCompiler->Compile(pSource, L"source.hlsl", L"main", L"cs_6_0",
  2033. nullptr, 0, nullptr, 0, nullptr, &pResult);
  2034. if (SUCCEEDED(hrOp)) {
  2035. pResult->GetStatus(&hrOp);
  2036. }
  2037. }
  2038. if (FAILED(hrOp)) {
  2039. // This is true in *almost* every case. When the OOM happens during stream
  2040. // handling, there is no specific error set; by the time it's detected,
  2041. // it propagates as E_FAIL.
  2042. //VERIFY_ARE_EQUAL(hrOp, E_OUTOFMEMORY);
  2043. VERIFY_IS_TRUE(hrOp == E_OUTOFMEMORY || hrOp == E_FAIL);
  2044. }
  2045. if (isLast)
  2046. VERIFY_SUCCEEDED(hrOp);
  2047. else
  2048. VERIFY_FAILED(hrOp);
  2049. pCompiler.Release();
  2050. pResult.Release();
  2051. if (InstrMalloc.GetSize() != 0) {
  2052. WEX::Logging::Log::Comment(FormatToWString(L"Memory leak(s) detected, allocCount = %d", i).data());
  2053. InstrMalloc.DumpLeaks();
  2054. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  2055. }
  2056. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  2057. }
  2058. }
  2059. #endif
  2060. TEST_F(CompilerTest, CompileWhenShaderModelMismatchAttributeThenFail) {
  2061. CComPtr<IDxcCompiler> pCompiler;
  2062. CComPtr<IDxcOperationResult> pResult;
  2063. CComPtr<IDxcBlobEncoding> pSource;
  2064. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2065. CreateBlobFromText(EmptyCompute, &pSource);
  2066. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2067. L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2068. std::string failLog(VerifyOperationFailed(pResult));
  2069. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find("attribute numthreads only valid for CS"));
  2070. }
  2071. TEST_F(CompilerTest, CompileBadHlslThenFail) {
  2072. CComPtr<IDxcCompiler> pCompiler;
  2073. CComPtr<IDxcOperationResult> pResult;
  2074. CComPtr<IDxcBlobEncoding> pSource;
  2075. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2076. CreateBlobFromText(
  2077. "bad hlsl", &pSource);
  2078. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2079. L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2080. HRESULT status;
  2081. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2082. VERIFY_FAILED(status);
  2083. }
  2084. TEST_F(CompilerTest, CompileLegacyShaderModelThenFail) {
  2085. VerifyCompileFailed(
  2086. "float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", L"ps_5_1", nullptr);
  2087. }
  2088. TEST_F(CompilerTest, CompileWhenRecursiveAlbeitStaticTermThenFail) {
  2089. // This shader will compile under fxc because if execution is
  2090. // simulated statically, it does terminate. dxc changes this behavior
  2091. // to avoid imposing the requirement on the compiler.
  2092. const char ShaderText[] =
  2093. "static int i = 10;\r\n"
  2094. "float4 f(); // Forward declaration\r\n"
  2095. "float4 g() { if (i > 10) { i--; return f(); } else return 0; } // Recursive call to 'f'\r\n"
  2096. "float4 f() { return g(); } // First call to 'g'\r\n"
  2097. "float4 VS() : SV_Position{\r\n"
  2098. " return f(); // First call to 'f'\r\n"
  2099. "}\r\n";
  2100. VerifyCompileFailed(ShaderText, L"vs_6_0", "recursive functions not allowed", L"VS");
  2101. }
  2102. TEST_F(CompilerTest, CompileWhenRecursiveThenFail) {
  2103. const char ShaderTextSimple[] =
  2104. "float4 f(); // Forward declaration\r\n"
  2105. "float4 g() { return f(); } // Recursive call to 'f'\r\n"
  2106. "float4 f() { return g(); } // First call to 'g'\r\n"
  2107. "float4 main() : SV_Position{\r\n"
  2108. " return f(); // First call to 'f'\r\n"
  2109. "}\r\n";
  2110. VerifyCompileFailed(ShaderTextSimple, L"vs_6_0", "recursive functions not allowed");
  2111. const char ShaderTextIndirect[] =
  2112. "float4 f(); // Forward declaration\r\n"
  2113. "float4 g() { return f(); } // Recursive call to 'f'\r\n"
  2114. "float4 f() { return g(); } // First call to 'g'\r\n"
  2115. "float4 main() : SV_Position{\r\n"
  2116. " return f(); // First call to 'f'\r\n"
  2117. "}\r\n";
  2118. VerifyCompileFailed(ShaderTextIndirect, L"vs_6_0", "recursive functions not allowed");
  2119. const char ShaderTextSelf[] =
  2120. "float4 main() : SV_Position{\r\n"
  2121. " return main();\r\n"
  2122. "}\r\n";
  2123. VerifyCompileFailed(ShaderTextSelf, L"vs_6_0", "recursive functions not allowed");
  2124. const char ShaderTextMissing[] =
  2125. "float4 mainz() : SV_Position{\r\n"
  2126. " return 1;\r\n"
  2127. "}\r\n";
  2128. VerifyCompileFailed(ShaderTextMissing, L"vs_6_0", "missing entry point definition");
  2129. }
  2130. TEST_F(CompilerTest, CompileHlsl2015ThenFail) {
  2131. CComPtr<IDxcCompiler> pCompiler;
  2132. CComPtr<IDxcOperationResult> pResult;
  2133. CComPtr<IDxcBlobEncoding> pSource;
  2134. CComPtr<IDxcBlobEncoding> pErrors;
  2135. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2136. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  2137. LPCWSTR args[2] = { L"-HV", L"2015" };
  2138. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2139. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  2140. HRESULT status;
  2141. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2142. VERIFY_ARE_EQUAL(status, E_INVALIDARG);
  2143. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  2144. LPCSTR pErrorMsg = "HLSL Version 2015 is only supported for language services";
  2145. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  2146. }
  2147. TEST_F(CompilerTest, CompileHlsl2016ThenOK) {
  2148. CComPtr<IDxcCompiler> pCompiler;
  2149. CComPtr<IDxcOperationResult> pResult;
  2150. CComPtr<IDxcBlobEncoding> pSource;
  2151. CComPtr<IDxcBlobEncoding> pErrors;
  2152. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2153. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  2154. LPCWSTR args[2] = { L"-HV", L"2016" };
  2155. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2156. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  2157. HRESULT status;
  2158. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2159. VERIFY_SUCCEEDED(status);
  2160. }
  2161. TEST_F(CompilerTest, CompileHlsl2017ThenOK) {
  2162. CComPtr<IDxcCompiler> pCompiler;
  2163. CComPtr<IDxcOperationResult> pResult;
  2164. CComPtr<IDxcBlobEncoding> pSource;
  2165. CComPtr<IDxcBlobEncoding> pErrors;
  2166. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2167. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  2168. LPCWSTR args[2] = { L"-HV", L"2017" };
  2169. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2170. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  2171. HRESULT status;
  2172. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2173. VERIFY_SUCCEEDED(status);
  2174. }
  2175. TEST_F(CompilerTest, CompileHlsl2018ThenOK) {
  2176. CComPtr<IDxcCompiler> pCompiler;
  2177. CComPtr<IDxcOperationResult> pResult;
  2178. CComPtr<IDxcBlobEncoding> pSource;
  2179. CComPtr<IDxcBlobEncoding> pErrors;
  2180. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2181. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  2182. LPCWSTR args[2] = { L"-HV", L"2018" };
  2183. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2184. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  2185. HRESULT status;
  2186. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2187. VERIFY_SUCCEEDED(status);
  2188. }
  2189. TEST_F(CompilerTest, CompileHlsl2019ThenFail) {
  2190. CComPtr<IDxcCompiler> pCompiler;
  2191. CComPtr<IDxcOperationResult> pResult;
  2192. CComPtr<IDxcBlobEncoding> pSource;
  2193. CComPtr<IDxcBlobEncoding> pErrors;
  2194. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2195. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  2196. LPCWSTR args[2] = { L"-HV", L"2019" };
  2197. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2198. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  2199. HRESULT status;
  2200. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  2201. VERIFY_ARE_EQUAL(status, E_INVALIDARG);
  2202. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  2203. LPCSTR pErrorMsg = "Unknown HLSL version";
  2204. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  2205. }
  2206. #ifdef _WIN32
  2207. #pragma fenv_access(on)
  2208. #pragma optimize("", off)
  2209. #pragma warning(disable : 4723)
  2210. // Define test state as something weird that we can verify was restored
  2211. static const unsigned int fpTestState =
  2212. (_MCW_EM & (~_EM_ZERODIVIDE)) | // throw on div by zero
  2213. _DN_FLUSH_OPERANDS_SAVE_RESULTS | // denorm flush operands & save results
  2214. _RC_UP; // round up
  2215. static const unsigned int fpTestMask = _MCW_EM | _MCW_DN | _MCW_RC;
  2216. struct FPTestScope
  2217. {
  2218. // _controlfp_s is non-standard and <cfenv> doesn't have a function to enable exceptions
  2219. unsigned int fpSavedState;
  2220. FPTestScope() {
  2221. VERIFY_IS_TRUE(_controlfp_s(&fpSavedState, 0, 0) == 0);
  2222. unsigned int newValue;
  2223. VERIFY_IS_TRUE(_controlfp_s(&newValue, fpTestState, fpTestMask) == 0);
  2224. }
  2225. ~FPTestScope() {
  2226. unsigned int newValue;
  2227. errno_t error = _controlfp_s(&newValue, fpSavedState, fpTestMask);
  2228. DXASSERT_LOCALVAR(error, error == 0, "Failed to restore floating-point environment.");
  2229. }
  2230. };
  2231. void VerifyDivByZeroThrows() {
  2232. bool bCaughtExpectedException = false;
  2233. __try {
  2234. float one = 1.0;
  2235. float zero = 0.0;
  2236. float val = one / zero;
  2237. (void)val;
  2238. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2239. bCaughtExpectedException = true;
  2240. }
  2241. VERIFY_IS_TRUE(bCaughtExpectedException);
  2242. }
  2243. TEST_F(CompilerTest, CodeGenFloatingPointEnvironment) {
  2244. unsigned int fpOriginal;
  2245. VERIFY_IS_TRUE(_controlfp_s(&fpOriginal, 0, 0) == 0);
  2246. {
  2247. FPTestScope fpTestScope;
  2248. // Get state before/after compilation, making sure it's our test state,
  2249. // and that it is restored after the compile.
  2250. unsigned int fpBeforeCompile;
  2251. VERIFY_IS_TRUE(_controlfp_s(&fpBeforeCompile, 0, 0) == 0);
  2252. VERIFY_ARE_EQUAL((fpBeforeCompile & fpTestMask), fpTestState);
  2253. CodeGenTestCheck(L"fpexcept.hlsl");
  2254. // Verify excpetion environment was restored
  2255. unsigned int fpAfterCompile;
  2256. VERIFY_IS_TRUE(_controlfp_s(&fpAfterCompile, 0, 0) == 0);
  2257. VERIFY_ARE_EQUAL((fpBeforeCompile & fpTestMask), (fpAfterCompile & fpTestMask));
  2258. // Make sure round up is set
  2259. VERIFY_ARE_EQUAL(rint(12.25), 13);
  2260. // Make sure we actually enabled div-by-zero exception
  2261. VerifyDivByZeroThrows();
  2262. }
  2263. // Verify original state has been restored
  2264. unsigned int fpLocal;
  2265. VERIFY_IS_TRUE(_controlfp_s(&fpLocal, 0, 0) == 0);
  2266. VERIFY_ARE_EQUAL(fpLocal, fpOriginal);
  2267. }
  2268. #pragma optimize("", on)
  2269. #else // _WIN32
  2270. // Only implemented on Win32
  2271. TEST_F(CompilerTest, CodeGenFloatingPointEnvironment) {
  2272. VERIFY_IS_TRUE(true);
  2273. }
  2274. #endif // _WIN32
  2275. TEST_F(CompilerTest, CodeGenInclude) {
  2276. CodeGenTestCheck(L"Include.hlsl");
  2277. }
  2278. TEST_F(CompilerTest, CodeGenLibCsEntry) {
  2279. CodeGenTestCheck(L"lib_cs_entry.hlsl");
  2280. }
  2281. TEST_F(CompilerTest, CodeGenLibCsEntry2) {
  2282. CodeGenTestCheck(L"lib_cs_entry2.hlsl");
  2283. }
  2284. TEST_F(CompilerTest, CodeGenLibCsEntry3) {
  2285. CodeGenTestCheck(L"lib_cs_entry3.hlsl");
  2286. }
  2287. TEST_F(CompilerTest, CodeGenLibEntries) {
  2288. CodeGenTestCheck(L"lib_entries.hlsl");
  2289. }
  2290. TEST_F(CompilerTest, CodeGenLibEntries2) {
  2291. CodeGenTestCheck(L"lib_entries2.hlsl");
  2292. }
  2293. TEST_F(CompilerTest, CodeGenLibNoAlias) {
  2294. CodeGenTestCheck(L"lib_no_alias.hlsl");
  2295. }
  2296. TEST_F(CompilerTest, CodeGenLibResource) {
  2297. CodeGenTestCheck(L"lib_resource.hlsl");
  2298. }
  2299. TEST_F(CompilerTest, CodeGenLibUnusedFunc) {
  2300. CodeGenTestCheck(L"lib_unused_func.hlsl");
  2301. }
  2302. TEST_F(CompilerTest, CodeGenRootSigProfile) {
  2303. if (m_ver.SkipDxilVersion(1, 5)) return;
  2304. CodeGenTest(L"rootSigProfile.hlsl");
  2305. }
  2306. TEST_F(CompilerTest, CodeGenRootSigProfile2) {
  2307. if (m_ver.SkipDxilVersion(1, 5)) return;
  2308. // TODO: Verify the result when reflect the structures.
  2309. CodeGenTest(L"rootSigProfile2.hlsl");
  2310. }
  2311. TEST_F(CompilerTest, CodeGenRootSigProfile5) {
  2312. if (m_ver.SkipDxilVersion(1, 5)) return;
  2313. CodeGenTest(L"rootSigProfile5.hlsl");
  2314. }
  2315. TEST_F(CompilerTest, CodeGenWaveSize) {
  2316. CodeGenTestCheck(L"attributes_wavesize.hlsl");
  2317. }
  2318. TEST_F(CompilerTest, LibGVStore) {
  2319. CComPtr<IDxcCompiler> pCompiler;
  2320. CComPtr<IDxcOperationResult> pResult;
  2321. CComPtr<IDxcBlobEncoding> pSource;
  2322. CComPtr<IDxcContainerReflection> pReflection;
  2323. CComPtr<IDxcAssembler> pAssembler;
  2324. VERIFY_SUCCEEDED(this->m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  2325. VERIFY_SUCCEEDED(this->m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  2326. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2327. CreateBlobFromText(
  2328. R"(
  2329. struct T {
  2330. RWByteAddressBuffer outputBuffer;
  2331. RWByteAddressBuffer outputBuffer2;
  2332. };
  2333. struct D {
  2334. float4 a;
  2335. int4 b;
  2336. };
  2337. struct T2 {
  2338. RWStructuredBuffer<D> uav;
  2339. };
  2340. T2 resStruct(T t, uint2 id);
  2341. RWByteAddressBuffer outputBuffer;
  2342. RWByteAddressBuffer outputBuffer2;
  2343. [numthreads(8, 8, 1)]
  2344. void main( uint2 id : SV_DispatchThreadID )
  2345. {
  2346. T t = {outputBuffer,outputBuffer2};
  2347. T2 t2 = resStruct(t, id);
  2348. uint counter = t2.uav.IncrementCounter();
  2349. t2.uav[counter].b.xy = id;
  2350. }
  2351. )", &pSource);
  2352. const WCHAR *pArgs[] = {
  2353. L"/Zi",
  2354. };
  2355. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"file.hlsl", L"", L"lib_6_x",
  2356. pArgs, _countof(pArgs), nullptr, 0, nullptr,
  2357. &pResult));
  2358. CComPtr<IDxcBlob> pShader;
  2359. VERIFY_SUCCEEDED(pResult->GetResult(&pShader));
  2360. VERIFY_SUCCEEDED(pReflection->Load(pShader));
  2361. UINT32 index = 0;
  2362. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_DXIL, &index));
  2363. CComPtr<IDxcBlob> pBitcode;
  2364. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, &pBitcode));
  2365. const char *bitcode = hlsl::GetDxilBitcodeData((hlsl::DxilProgramHeader *)pBitcode->GetBufferPointer());
  2366. unsigned bitcode_size = hlsl::GetDxilBitcodeSize((hlsl::DxilProgramHeader *)pBitcode->GetBufferPointer());
  2367. CComPtr<IDxcBlobEncoding> pBitcodeBlob;
  2368. CreateBlobPinned(bitcode, bitcode_size, CP_UTF8, &pBitcodeBlob);
  2369. CComPtr<IDxcBlob> pReassembled;
  2370. CComPtr<IDxcOperationResult> pReassembleResult;
  2371. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pBitcodeBlob, &pReassembleResult));
  2372. VERIFY_SUCCEEDED(pReassembleResult->GetResult(&pReassembled));
  2373. CComPtr<IDxcBlobEncoding> pTextBlob;
  2374. VERIFY_SUCCEEDED(pCompiler->Disassemble(pReassembled, &pTextBlob));
  2375. std::wstring Text = BlobToUtf16(pTextBlob);
  2376. VERIFY_ARE_NOT_EQUAL(std::wstring::npos, Text.find(L"store"));
  2377. }
  2378. TEST_F(CompilerTest, PreprocessWhenValidThenOK) {
  2379. CComPtr<IDxcCompiler> pCompiler;
  2380. CComPtr<IDxcOperationResult> pResult;
  2381. CComPtr<IDxcBlobEncoding> pSource;
  2382. DxcDefine defines[2];
  2383. defines[0].Name = L"MYDEF";
  2384. defines[0].Value = L"int";
  2385. defines[1].Name = L"MYOTHERDEF";
  2386. defines[1].Value = L"123";
  2387. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2388. CreateBlobFromText(
  2389. "// First line\r\n"
  2390. "MYDEF g_int = MYOTHERDEF;\r\n"
  2391. "#define FOO BAR\r\n"
  2392. "int FOO;", &pSource);
  2393. VERIFY_SUCCEEDED(pCompiler->Preprocess(pSource, L"file.hlsl", nullptr, 0,
  2394. defines, _countof(defines), nullptr,
  2395. &pResult));
  2396. HRESULT hrOp;
  2397. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2398. VERIFY_SUCCEEDED(hrOp);
  2399. CComPtr<IDxcBlob> pOutText;
  2400. VERIFY_SUCCEEDED(pResult->GetResult(&pOutText));
  2401. std::string text(BlobToUtf8(pOutText));
  2402. VERIFY_ARE_EQUAL_STR(
  2403. "#line 1 \"file.hlsl\"\n"
  2404. "\n"
  2405. "int g_int = 123;\n"
  2406. "\n"
  2407. "int BAR;\n", text.c_str());
  2408. }
  2409. TEST_F(CompilerTest, PreprocessWhenExpandTokenPastingOperandThenAccept) {
  2410. // Tests that we can turn on fxc's behavior (pre-expanding operands before
  2411. // performing token-pasting) using -flegacy-macro-expansion
  2412. CComPtr<IDxcCompiler> pCompiler;
  2413. CComPtr<IDxcOperationResult> pResult;
  2414. CComPtr<IDxcBlobEncoding> pSource;
  2415. LPCWSTR expandOption = L"-flegacy-macro-expansion";
  2416. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2417. CreateBlobFromText(R"(
  2418. #define SET_INDEX0 10
  2419. #define BINDING_INDEX0 5
  2420. #define SET(INDEX) SET_INDEX##INDEX
  2421. #define BINDING(INDEX) BINDING_INDEX##INDEX
  2422. #define SET_BIND(NAME,SET,BIND) resource_set_##SET##_bind_##BIND##_##NAME
  2423. #define RESOURCE(NAME,INDEX) SET_BIND(NAME, SET(INDEX), BINDING(INDEX))
  2424. Texture2D<float4> resource_set_10_bind_5_tex;
  2425. float4 main() : SV_Target{
  2426. return RESOURCE(tex, 0)[uint2(1, 2)];
  2427. }
  2428. )",
  2429. &pSource);
  2430. VERIFY_SUCCEEDED(pCompiler->Preprocess(pSource, L"file.hlsl", &expandOption,
  2431. 1, nullptr, 0, nullptr, &pResult));
  2432. HRESULT hrOp;
  2433. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2434. VERIFY_SUCCEEDED(hrOp);
  2435. CComPtr<IDxcBlob> pOutText;
  2436. VERIFY_SUCCEEDED(pResult->GetResult(&pOutText));
  2437. std::string text(BlobToUtf8(pOutText));
  2438. VERIFY_ARE_EQUAL_STR(R"(#line 1 "file.hlsl"
  2439. #line 12 "file.hlsl"
  2440. Texture2D<float4> resource_set_10_bind_5_tex;
  2441. float4 main() : SV_Target{
  2442. return resource_set_10_bind_5_tex[uint2(1, 2)];
  2443. }
  2444. )",
  2445. text.c_str());
  2446. }
  2447. TEST_F(CompilerTest, PreprocessWithDebugOptsThenOk) {
  2448. // Make sure debug options, such as -Zi and -Fd,
  2449. // are simply ignored when preprocessing
  2450. CComPtr<IDxcCompiler> pCompiler;
  2451. CComPtr<IDxcOperationResult> pResult;
  2452. CComPtr<IDxcBlobEncoding> pSource;
  2453. DxcDefine defines[2];
  2454. defines[0].Name = L"MYDEF";
  2455. defines[0].Value = L"int";
  2456. defines[1].Name = L"MYOTHERDEF";
  2457. defines[1].Value = L"123";
  2458. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2459. CreateBlobFromText(
  2460. "// First line\r\n"
  2461. "MYDEF g_int = MYOTHERDEF;\r\n"
  2462. "#define FOO BAR\r\n"
  2463. "int FOO;", &pSource);
  2464. LPCWSTR extraOptions[] = {L"-Zi", L"-Fd", L"file.pdb", L"-Qembed_debug"};
  2465. VERIFY_SUCCEEDED(pCompiler->Preprocess(pSource, L"file.hlsl",
  2466. extraOptions, _countof(extraOptions),
  2467. defines, _countof(defines), nullptr,
  2468. &pResult));
  2469. HRESULT hrOp;
  2470. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2471. VERIFY_SUCCEEDED(hrOp);
  2472. CComPtr<IDxcBlob> pOutText;
  2473. VERIFY_SUCCEEDED(pResult->GetResult(&pOutText));
  2474. std::string text(BlobToUtf8(pOutText));
  2475. VERIFY_ARE_EQUAL_STR(
  2476. "#line 1 \"file.hlsl\"\n"
  2477. "\n"
  2478. "int g_int = 123;\n"
  2479. "\n"
  2480. "int BAR;\n", text.c_str());
  2481. }
  2482. TEST_F(CompilerTest, CompileOtherModesWithDebugOptsThenOk) {
  2483. // Make sure debug options, such as -Zi and -Fd,
  2484. // are simply ignored when compiling in modes:
  2485. // /Odump -ast-dump -fcgl -rootsig_1_0
  2486. CComPtr<IDxcCompiler> pCompiler;
  2487. CComPtr<IDxcBlobEncoding> pSource;
  2488. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2489. CreateBlobFromText(
  2490. "#define RS \"CBV(b0)\"\n"
  2491. "[RootSignature(RS)]\n"
  2492. "float main(float i : IN) : OUT { return i * 2.0F; }",
  2493. &pSource);
  2494. auto testWithOpts = [&](LPCWSTR entry, LPCWSTR target, llvm::ArrayRef<LPCWSTR> mainOpts) -> HRESULT {
  2495. std::vector<LPCWSTR> opts(mainOpts);
  2496. opts.insert(opts.end(), {L"-Zi", L"-Fd", L"file.pdb"});
  2497. CComPtr<IDxcOperationResult> pResult;
  2498. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"file.hlsl",
  2499. entry, target, opts.data(), opts.size(),
  2500. nullptr, 0, nullptr, &pResult));
  2501. HRESULT hrOp;
  2502. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2503. return hrOp;
  2504. };
  2505. VERIFY_SUCCEEDED(testWithOpts(L"main", L"vs_6_0", {L"/Odump"}));
  2506. VERIFY_SUCCEEDED(testWithOpts(L"main", L"vs_6_0", {L"-ast-dump"}));
  2507. VERIFY_SUCCEEDED(testWithOpts(L"main", L"vs_6_0", {L"-fcgl"}));
  2508. VERIFY_SUCCEEDED(testWithOpts(L"RS", L"rootsig_1_0", {}));
  2509. }
  2510. TEST_F(CompilerTest, WhenSigMismatchPCFunctionThenFail) {
  2511. CComPtr<IDxcCompiler> pCompiler;
  2512. CComPtr<IDxcOperationResult> pResult;
  2513. CComPtr<IDxcBlobEncoding> pSource;
  2514. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2515. CreateBlobFromText(
  2516. "struct PSSceneIn \n\
  2517. { \n\
  2518. float4 pos : SV_Position; \n\
  2519. float2 tex : TEXCOORD0; \n\
  2520. float3 norm : NORMAL; \n\
  2521. }; \n"
  2522. "struct HSPerPatchData { \n\
  2523. float edges[ 3 ] : SV_TessFactor; \n\
  2524. float inside : SV_InsideTessFactor; \n\
  2525. float foo : FOO; \n\
  2526. }; \n"
  2527. "HSPerPatchData HSPerPatchFunc( InputPatch< PSSceneIn, 3 > points, \n\
  2528. OutputPatch<PSSceneIn, 3> outpoints) { \n\
  2529. HSPerPatchData d = (HSPerPatchData)0; \n\
  2530. d.edges[ 0 ] = points[0].tex.x + outpoints[0].tex.x; \n\
  2531. d.edges[ 1 ] = 1; \n\
  2532. d.edges[ 2 ] = 1; \n\
  2533. d.inside = 1; \n\
  2534. return d; \n\
  2535. } \n"
  2536. "[domain(\"tri\")] \n\
  2537. [partitioning(\"fractional_odd\")] \n\
  2538. [outputtopology(\"triangle_cw\")] \n\
  2539. [patchconstantfunc(\"HSPerPatchFunc\")] \n\
  2540. [outputcontrolpoints(3)] \n"
  2541. "void main(const uint id : SV_OutputControlPointID, \n\
  2542. const InputPatch< PSSceneIn, 3 > points ) { \n\
  2543. } \n"
  2544. , &pSource);
  2545. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2546. L"hs_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2547. std::string failLog(VerifyOperationFailed(pResult));
  2548. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find(
  2549. "Signature element SV_Position, referred to by patch constant function, is not found in corresponding hull shader output."));
  2550. }
  2551. TEST_F(CompilerTest, SubobjectCodeGenErrors) {
  2552. struct SubobjectErrorTestCase {
  2553. const char *shaderText;
  2554. const char *expectedError;
  2555. };
  2556. SubobjectErrorTestCase testCases[] = {
  2557. { "GlobalRootSignature grs;", "1:1: error: subobject needs to be initialized" },
  2558. { "StateObjectConfig soc;", "1:1: error: subobject needs to be initialized" },
  2559. { "LocalRootSignature lrs;", "1:1: error: subobject needs to be initialized" },
  2560. { "SubobjectToExportsAssociation sea;", "1:1: error: subobject needs to be initialized" },
  2561. { "RaytracingShaderConfig rsc;", "1:1: error: subobject needs to be initialized" },
  2562. { "RaytracingPipelineConfig rpc;", "1:1: error: subobject needs to be initialized" },
  2563. { "RaytracingPipelineConfig1 rpc1;", "1:1: error: subobject needs to be initialized" },
  2564. { "TriangleHitGroup hitGt;", "1:1: error: subobject needs to be initialized" },
  2565. { "ProceduralPrimitiveHitGroup hitGt;", "1:1: error: subobject needs to be initialized" },
  2566. { "GlobalRootSignature grs2 = {\"\"};", "1:29: error: empty string not expected here" },
  2567. { "LocalRootSignature lrs2 = {\"\"};", "1:28: error: empty string not expected here" },
  2568. { "SubobjectToExportsAssociation sea2 = { \"\", \"x\" };", "1:40: error: empty string not expected here" },
  2569. { "string s; SubobjectToExportsAssociation sea4 = { \"x\", s };", "1:55: error: cannot convert to constant string" },
  2570. { "extern int v; RaytracingPipelineConfig rpc2 = { v + 16 };", "1:49: error: cannot convert to constant unsigned int" },
  2571. { "string s; TriangleHitGroup trHitGt2_8 = { s, \"foo\" };", "1:43: error: cannot convert to constant string" },
  2572. { "string s; ProceduralPrimitiveHitGroup ppHitGt2_8 = { s, \"\", s };", "1:54: error: cannot convert to constant string" },
  2573. { "ProceduralPrimitiveHitGroup ppHitGt2_9 = { \"a\", \"b\", \"\"};", "1:54: error: empty string not expected here" }
  2574. };
  2575. for (unsigned i = 0; i < _countof(testCases); i++) {
  2576. CComPtr<IDxcCompiler> pCompiler;
  2577. CComPtr<IDxcOperationResult> pResult;
  2578. CComPtr<IDxcBlobEncoding> pSource;
  2579. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2580. CreateBlobFromText(testCases[i].shaderText, &pSource);
  2581. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"", L"lib_6_4", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2582. std::string failLog(VerifyOperationFailed(pResult));
  2583. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find(testCases[i].expectedError));
  2584. }
  2585. }
  2586. #ifdef _WIN32
  2587. TEST_F(CompilerTest, ManualFileCheckTest) {
  2588. #else
  2589. TEST_F(CompilerTest, DISABLED_ManualFileCheckTest) {
  2590. #endif
  2591. using namespace llvm;
  2592. using namespace WEX::TestExecution;
  2593. WEX::Common::String value;
  2594. VERIFY_SUCCEEDED(RuntimeParameters::TryGetValue(L"InputPath", value));
  2595. std::wstring path = value;
  2596. if (!llvm::sys::path::is_absolute(CW2A(path.c_str()).m_psz)) {
  2597. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  2598. }
  2599. bool isDirectory;
  2600. {
  2601. // Temporarily setup the filesystem for testing whether the path is a directory.
  2602. // If it is, CodeGenTestCheckBatchDir will create its own instance.
  2603. llvm::sys::fs::MSFileSystem *msfPtr;
  2604. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  2605. std::unique_ptr<llvm::sys::fs::MSFileSystem> msf(msfPtr);
  2606. llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  2607. IFTLLVM(pts.error_code());
  2608. isDirectory = llvm::sys::fs::is_directory(CW2A(path.c_str()).m_psz);
  2609. }
  2610. if (isDirectory) {
  2611. CodeGenTestCheckBatchDir(path, /*implicitDir*/ false);
  2612. } else {
  2613. CodeGenTestCheck(path.c_str(), /*implicitDir*/ false);
  2614. }
  2615. }
  2616. TEST_F(CompilerTest, CodeGenHashStability) {
  2617. CodeGenTestCheckBatchHash(L"");
  2618. }
  2619. TEST_F(CompilerTest, BatchD3DReflect) {
  2620. CodeGenTestCheckBatchDir(L"d3dreflect");
  2621. }
  2622. TEST_F(CompilerTest, BatchDxil) {
  2623. CodeGenTestCheckBatchDir(L"dxil");
  2624. }
  2625. TEST_F(CompilerTest, BatchHLSL) {
  2626. CodeGenTestCheckBatchDir(L"hlsl");
  2627. }
  2628. TEST_F(CompilerTest, BatchInfra) {
  2629. CodeGenTestCheckBatchDir(L"infra");
  2630. }
  2631. TEST_F(CompilerTest, BatchPasses) {
  2632. CodeGenTestCheckBatchDir(L"passes");
  2633. }
  2634. TEST_F(CompilerTest, BatchShaderTargets) {
  2635. CodeGenTestCheckBatchDir(L"shader_targets");
  2636. }
  2637. TEST_F(CompilerTest, BatchValidation) {
  2638. CodeGenTestCheckBatchDir(L"validation");
  2639. }
  2640. TEST_F(CompilerTest, BatchSamples) {
  2641. CodeGenTestCheckBatchDir(L"samples");
  2642. }