DxilConvTests.cpp 9.9 KB

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