DxilConvTests.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilConvTest.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 dxilconv.dll 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 <cassert>
  19. #include <sstream>
  20. #include <algorithm>
  21. #include <cfloat>
  22. #include "dxc/DxilContainer/DxilContainer.h"
  23. #include "dxc/Support/WinIncludes.h"
  24. #include "dxc/dxcapi.h"
  25. #include <atlfile.h>
  26. #include "dxc/test/HLSLTestData.h"
  27. #define HLSLDATAFILEPARAM L"DxilConvDataDir"
  28. #include "dxc/test/HlslTestUtils.h"
  29. #include "dxc/test/DxcTestUtils.h"
  30. #include "llvm/Support/raw_os_ostream.h"
  31. #include "dxc/Support/Global.h"
  32. #include "dxc/Support/dxcapi.use.h"
  33. #include "dxc/Support/microcom.h"
  34. #include "dxc/Support/HLSLOptions.h"
  35. #include "dxc/Support/Unicode.h"
  36. #include <fstream>
  37. #include "llvm/Support/FileSystem.h"
  38. #include "llvm/Support/MSFileSystem.h"
  39. #include "llvm/Support/Path.h"
  40. #include "llvm/ADT/SmallString.h"
  41. #include "llvm/ADT/StringSwitch.h"
  42. using namespace std;
  43. class DxilConvTest {
  44. public:
  45. BEGIN_TEST_CLASS(DxilConvTest)
  46. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  47. TEST_METHOD_PROPERTY(L"Priority", L"0")
  48. END_TEST_CLASS()
  49. TEST_CLASS_SETUP(InitSupport);
  50. TEST_METHOD(BatchDxbc2dxil);
  51. TEST_METHOD(BatchDxbc2dxilAsm);
  52. TEST_METHOD(BatchDxilCleanup);
  53. TEST_METHOD(BatchNormalizeDxil);
  54. TEST_METHOD(BatchScopeNestIterator);
  55. TEST_METHOD(RegressionTests);
  56. BEGIN_TEST_METHOD(ManualFileCheckTest)
  57. TEST_METHOD_PROPERTY(L"Ignore", L"true")
  58. END_TEST_METHOD()
  59. private:
  60. dxc::DxcDllSupport m_dllSupport;
  61. PluginToolsPaths m_TestToolPaths;
  62. void DxilConvTestCheckFile(LPCWSTR path) {
  63. FileRunTestResult t = FileRunTestResult::RunFromFileCommands(path, m_dllSupport, &m_TestToolPaths);
  64. if (t.RunResult != 0) {
  65. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  66. WEX::Logging::Log::Comment(commentWide);
  67. WEX::Logging::Log::Error(L"Run result is not zero");
  68. }
  69. }
  70. void DxilConvTestCheckBatchDir(std::wstring suitePath, std::string fileExt = ".hlsl", bool useRelativeFilename = false) {
  71. using namespace llvm;
  72. using namespace WEX::TestExecution;
  73. ::llvm::sys::fs::MSFileSystem *msfPtr;
  74. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  75. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  76. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  77. IFTLLVM(pts.error_code());
  78. if (!useRelativeFilename) {
  79. CW2A pUtf8Filename(suitePath.c_str());
  80. if (!llvm::sys::path::is_absolute(pUtf8Filename.m_psz)) {
  81. suitePath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str());
  82. }
  83. }
  84. CW2A utf8SuitePath(suitePath.c_str());
  85. unsigned numTestsRun = 0;
  86. std::error_code EC;
  87. llvm::SmallString<128> DirNative;
  88. llvm::StringRef filterExt(fileExt);
  89. llvm::sys::path::native(utf8SuitePath.m_psz, DirNative);
  90. for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd;
  91. Dir != DirEnd && !EC; Dir.increment(EC)) {
  92. if (!llvm::sys::path::extension(Dir->path()).equals(filterExt)) {
  93. continue;
  94. }
  95. StringRef filename = Dir->path();
  96. CA2W wRelPath(filename.data());
  97. WEX::Logging::Log::StartGroup(wRelPath);
  98. DxilConvTestCheckFile(wRelPath);
  99. WEX::Logging::Log::EndGroup(wRelPath);
  100. numTestsRun++;
  101. }
  102. VERIFY_IS_GREATER_THAN(numTestsRun, (unsigned)0, L"No test files found in batch directory.");
  103. }
  104. bool GetCurrentBinDir(std::string &binDir) {
  105. // get the test dll directory
  106. HMODULE hModule;
  107. if ((hModule = ::GetModuleHandleA("dxilconv-tests.dll")) == 0) {
  108. hlsl_test::LogErrorFmt(L"GetModuleHandle failed.");
  109. return false;
  110. }
  111. // get the path
  112. char buffer[MAX_PATH];
  113. DWORD size = sizeof(buffer);
  114. if ((size = ::GetModuleFileNameA(hModule, buffer, size)) == 0) {
  115. hlsl_test::LogErrorFmt(L"GetModuleFileName failed.");
  116. return false;
  117. }
  118. std::string str = std::string(buffer, size);
  119. DWORD pos;
  120. if ((pos = str.find_last_of("\\")) != std::string::npos) {
  121. str = str.substr(0, pos + 1);
  122. }
  123. binDir.assign(str);
  124. return true;
  125. }
  126. // Find fxc.exe in current bin dir or via WIN10_SDK_PATH environment variable or in the currently installed Windows SDK.
  127. // Add it to m_TestToolPaths so it can be invoked from RUN: lines by the ref name %fxc
  128. bool FindFxc() {
  129. // Find fxc.exe
  130. // 1. in current bin dir
  131. std::string binDir;
  132. if (!GetCurrentBinDir(binDir)) {
  133. return false;
  134. }
  135. std::string fxcLoc = binDir + "fxc.exe";
  136. if (::PathFileExistsA(fxcLoc.c_str())) {
  137. m_TestToolPaths.emplace("%fxc", fxcLoc);
  138. }
  139. else {
  140. std::string sdkPath;
  141. // 2. based on WIN10_SDK_PATH environment variable
  142. char win10SdkPath[MAX_PATH];
  143. size_t win10SdkPathLen = ::GetEnvironmentVariableA("WIN10_SDK_PATH", win10SdkPath, MAX_PATH);
  144. if (win10SdkPathLen > 0) {
  145. sdkPath = std::string(win10SdkPath, win10SdkPathLen);
  146. }
  147. else {
  148. // 3. get current SDK version from registry
  149. LPCSTR szRegSdkVerLoc = "SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0";
  150. std::string szInstallFolder, szVersion;
  151. char buffer[512];
  152. DWORD size = sizeof(buffer);
  153. if (SUCCEEDED(::RegGetValueA(HKEY_LOCAL_MACHINE, szRegSdkVerLoc, "InstallationFolder", RRF_RT_REG_SZ, nullptr, (PVOID)buffer, &size))) {
  154. szInstallFolder = std::string(buffer, size - 1); // skip trailing 0
  155. if (SUCCEEDED(::RegGetValueA(HKEY_LOCAL_MACHINE, szRegSdkVerLoc, "ProductVersion", RRF_RT_REG_SZ, nullptr, (PVOID)buffer, &size))) {
  156. szVersion = std::string(buffer, size - 1); // skip trailing 0
  157. sdkPath = szInstallFolder + "bin\\" + szVersion;
  158. // ProductVersion will be something like 10.0.18362 or 10.0.18362.0; we need the one that matches the directory name
  159. std::string sdkPathDot0 = sdkPath + ".0";
  160. if (::PathFileExistsA(sdkPathDot0.c_str())) {
  161. sdkPath = sdkPathDot0;
  162. }
  163. }
  164. }
  165. }
  166. if (sdkPath.size() > 0) {
  167. fxcLoc = sdkPath + std::string("\\x64\\fxc.exe");
  168. }
  169. if (::PathFileExistsA(fxcLoc.c_str())) {
  170. m_TestToolPaths.emplace("%fxc", fxcLoc);
  171. }
  172. else {
  173. CA2W fxcLocW(fxcLoc.c_str(), CP_UTF8);
  174. hlsl_test::LogErrorFmt(L"Cannot find %s.", fxcLocW.m_psz);
  175. return false;
  176. }
  177. }
  178. return true;
  179. }
  180. // Find the binary in current bin dir and add it to m_TestToolPaths
  181. // so that it can be invoked from RUN: lines by the refName
  182. bool FindToolInBinDir(std::string refName, std::string binaryName) {
  183. std::string binDir;
  184. if (!GetCurrentBinDir(binDir)) {
  185. return false;
  186. }
  187. std::string loc = binDir + binaryName;
  188. if (::PathFileExistsA(loc.c_str())) {
  189. m_TestToolPaths.emplace(refName, loc);
  190. }
  191. else {
  192. CA2W locW(loc.c_str(), CP_UTF8);
  193. hlsl_test::LogErrorFmt(L"Cannot find %s.", locW.m_psz);
  194. return false;
  195. }
  196. return true;
  197. }
  198. };
  199. bool DxilConvTest::InitSupport() {
  200. if (!m_dllSupport.IsEnabled()) {
  201. VERIFY_SUCCEEDED(m_dllSupport.InitializeForDll(L"dxilconv.dll", "DxcCreateInstance"));
  202. }
  203. if (!FindFxc()) {
  204. return false;
  205. }
  206. if (!FindToolInBinDir("%dxbc2dxil", "dxbc2dxil.exe")) {
  207. return false;
  208. }
  209. if (!FindToolInBinDir("%opt-exe", "opt.exe")) {
  210. return false;
  211. }
  212. return true;
  213. }
  214. TEST_F(DxilConvTest, ManualFileCheckTest) {
  215. using namespace llvm;
  216. using namespace WEX::TestExecution;
  217. WEX::Common::String value;
  218. VERIFY_SUCCEEDED(RuntimeParameters::TryGetValue(L"InputPath", value));
  219. std::wstring path = value;
  220. if (!llvm::sys::path::is_absolute(CW2A(path.c_str()).m_psz)) {
  221. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  222. }
  223. bool isDirectory;
  224. {
  225. // Temporarily setup the filesystem for testing whether the path is a directory.
  226. // If it is, CodeGenTestCheckBatchDir will create its own instance.
  227. llvm::sys::fs::MSFileSystem *msfPtr;
  228. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  229. std::unique_ptr<llvm::sys::fs::MSFileSystem> msf(msfPtr);
  230. llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  231. IFTLLVM(pts.error_code());
  232. isDirectory = llvm::sys::fs::is_directory(CW2A(path.c_str()).m_psz);
  233. }
  234. if (isDirectory) {
  235. DxilConvTestCheckBatchDir(path);
  236. } else {
  237. DxilConvTestCheckFile(path.c_str() );
  238. }
  239. }
  240. TEST_F(DxilConvTest, BatchDxbc2dxil) {
  241. DxilConvTestCheckBatchDir(L"dxbc2dxil", ".hlsl");
  242. }
  243. TEST_F(DxilConvTest, BatchDxbc2dxilAsm) {
  244. DxilConvTestCheckBatchDir(L"dxbc2dxil-asm", ".asm");
  245. }
  246. TEST_F(DxilConvTest, BatchDxilCleanup) {
  247. // switch current directory to directory with test files and use relative paths
  248. // because the reference files contain file path as ModuleID
  249. wchar_t curDir[MAX_PATH];
  250. IFT(GetCurrentDirectoryW(sizeof(curDir), curDir) == 0);
  251. wstring testFilesPath = hlsl_test::GetPathToHlslDataFile(L"");
  252. IFT(::SetCurrentDirectory(testFilesPath.c_str()));
  253. DxilConvTestCheckBatchDir(L"dxil_cleanup", ".ll", true);
  254. IFT(::SetCurrentDirectory(curDir));
  255. }
  256. TEST_F(DxilConvTest, BatchNormalizeDxil) {
  257. DxilConvTestCheckBatchDir(L"normalize_dxil", ".ll");
  258. }
  259. TEST_F(DxilConvTest, BatchScopeNestIterator) {
  260. DxilConvTestCheckBatchDir(L"scope_nest_iterator", ".ll");
  261. }
  262. TEST_F(DxilConvTest, RegressionTests) {
  263. DxilConvTestCheckBatchDir(L"regression_tests", ".hlsl");
  264. }