Dxc.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/ShaderCompiler/Dxc.h>
  6. #include <AnKi/Util/Process.h>
  7. #include <AnKi/Util/Filesystem.h>
  8. #include <AnKi/Util/File.h>
  9. #include <AnKi/Util/HighRezTimer.h>
  10. #include <AnKi/Util/StringList.h>
  11. namespace anki {
  12. static Atomic<U32> g_nextFileId = {1};
  13. static CString profile(ShaderType shaderType)
  14. {
  15. switch(shaderType)
  16. {
  17. case ShaderType::kVertex:
  18. return "vs_6_8";
  19. break;
  20. case ShaderType::kFragment:
  21. return "ps_6_8";
  22. break;
  23. case ShaderType::kTessellationEvaluation:
  24. return "ds_6_8";
  25. break;
  26. case ShaderType::kTessellationControl:
  27. return "ds_6_8";
  28. break;
  29. case ShaderType::kGeometry:
  30. return "gs_6_8";
  31. break;
  32. case ShaderType::kTask:
  33. return "as_6_8";
  34. break;
  35. case ShaderType::kMesh:
  36. return "ms_6_8";
  37. break;
  38. case ShaderType::kCompute:
  39. return "cs_6_8";
  40. break;
  41. case ShaderType::kRayGen:
  42. case ShaderType::kAnyHit:
  43. case ShaderType::kClosestHit:
  44. case ShaderType::kMiss:
  45. case ShaderType::kIntersection:
  46. case ShaderType::kCallable:
  47. case ShaderType::kWorkGraph:
  48. return "lib_6_8";
  49. break;
  50. default:
  51. ANKI_ASSERT(0);
  52. };
  53. return "";
  54. }
  55. static Error compileHlsl(CString src, ShaderType shaderType, Bool compileWith16bitTypes, Bool debugInfo, ConstWeakArray<CString> compilerArgs,
  56. Bool spirv, ShaderCompilerDynamicArray<U8>& bin, ShaderCompilerString& errorMessage)
  57. {
  58. Array<U64, 3> toHash = {g_nextFileId.fetchAdd(1), getCurrentProcessId(), getRandom() & kMaxU32};
  59. const U64 rand = computeHash(&toHash[0], sizeof(toHash));
  60. String tmpDir;
  61. ANKI_CHECK(getTempDirectory(tmpDir));
  62. // Store HLSL to a file
  63. ShaderCompilerString hlslFilename;
  64. hlslFilename.sprintf("%s/%" PRIu64 ".hlsl", tmpDir.cstr(), rand);
  65. File hlslFile;
  66. ANKI_CHECK(hlslFile.open(hlslFilename, FileOpenFlag::kWrite));
  67. CleanupFile hlslFileCleanup(hlslFilename);
  68. ANKI_CHECK(hlslFile.writeText(src));
  69. hlslFile.close();
  70. // Call DXC
  71. ShaderCompilerString binFilename;
  72. binFilename.sprintf("%s/%" PRIu64 ".spvdxil", tmpDir.cstr(), rand);
  73. ShaderCompilerStringList dxcArgs;
  74. dxcArgs.emplaceBack("-Fo");
  75. dxcArgs.emplaceBack(binFilename);
  76. dxcArgs.emplaceBack("-Wall");
  77. dxcArgs.emplaceBack("-Wextra");
  78. dxcArgs.emplaceBack("-Wno-conversion");
  79. dxcArgs.emplaceBack("-Werror");
  80. dxcArgs.emplaceBack("-Wfatal-errors");
  81. dxcArgs.emplaceBack("-Wundef");
  82. dxcArgs.emplaceBack("-Wno-unused-const-variable");
  83. dxcArgs.emplaceBack("-Wno-unused-parameter");
  84. dxcArgs.emplaceBack("-Wno-unneeded-internal-declaration");
  85. dxcArgs.emplaceBack("-HV");
  86. dxcArgs.emplaceBack("2021");
  87. dxcArgs.emplaceBack("-E");
  88. dxcArgs.emplaceBack("main");
  89. dxcArgs.emplaceBack("-T");
  90. dxcArgs.emplaceBack(profile(shaderType));
  91. if(ANKI_COMPILER_MSVC)
  92. {
  93. dxcArgs.emplaceBack("-fdiagnostics-format=msvc"); // Make errors clickable in visual studio
  94. }
  95. if(spirv)
  96. {
  97. dxcArgs.emplaceBack("-spirv");
  98. dxcArgs.emplaceBack("-fspv-target-env=vulkan1.1spirv1.4");
  99. // dxcArgs.emplaceBack("-fvk-support-nonzero-base-instance"); // Match DX12's behavior, SV_INSTANCEID starts from zero
  100. // Shift the bindings in order to identify the registers when doing reflection
  101. for(U32 ds = 0; ds < kMaxRegisterSpaces; ++ds)
  102. {
  103. dxcArgs.emplaceBack("-fvk-b-shift");
  104. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", kDxcVkBindingShifts[ds][HlslResourceType::kCbv]));
  105. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", ds));
  106. dxcArgs.emplaceBack("-fvk-t-shift");
  107. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", kDxcVkBindingShifts[ds][HlslResourceType::kSrv]));
  108. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", ds));
  109. dxcArgs.emplaceBack("-fvk-u-shift");
  110. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", kDxcVkBindingShifts[ds][HlslResourceType::kUav]));
  111. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", ds));
  112. dxcArgs.emplaceBack("-fvk-s-shift");
  113. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", kDxcVkBindingShifts[ds][HlslResourceType::kSampler]));
  114. dxcArgs.emplaceBack(ShaderCompilerString().sprintf("%u", ds));
  115. }
  116. }
  117. else
  118. {
  119. dxcArgs.emplaceBack("-Wno-ignored-attributes"); // TODO remove that at some point
  120. dxcArgs.emplaceBack("-Wno-inline-asm"); // Workaround a DXC bug
  121. }
  122. if(debugInfo)
  123. {
  124. dxcArgs.emplaceBack("-Zi");
  125. }
  126. dxcArgs.emplaceBack(hlslFilename);
  127. if(compileWith16bitTypes)
  128. {
  129. dxcArgs.emplaceBack("-enable-16bit-types");
  130. }
  131. for(CString extraArg : compilerArgs)
  132. {
  133. dxcArgs.emplaceBack(extraArg);
  134. }
  135. ShaderCompilerDynamicArray<CString> dxcArgs2;
  136. dxcArgs2.resize(U32(dxcArgs.getSize()));
  137. U32 count = 0;
  138. for(auto& it : dxcArgs)
  139. {
  140. dxcArgs2[count++] = it.cstr();
  141. }
  142. while(true)
  143. {
  144. I32 exitCode;
  145. ShaderCompilerString stdOut;
  146. #if ANKI_OS_WINDOWS
  147. CString dxcBin = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Windows64/dxc.exe";
  148. #elif ANKI_OS_LINUX
  149. CString dxcBin = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Linux64/dxc";
  150. #else
  151. CString dxcBin = "N/A";
  152. #endif
  153. // Run once without stdout or stderr. Because if you do the process library will crap out after a while
  154. ANKI_CHECK(Process::callProcess(dxcBin, dxcArgs2, nullptr, nullptr, exitCode));
  155. if(exitCode != 0)
  156. {
  157. // There was an error, run again just to get the stderr
  158. String errorMessageTmp;
  159. const Error err = Process::callProcess(dxcBin, dxcArgs2, nullptr, &errorMessageTmp, exitCode);
  160. (void)err; // Shoudn't throw an error
  161. errorMessage = errorMessageTmp;
  162. ShaderCompilerString args;
  163. dxcArgs.join(" ", args);
  164. errorMessage += " (";
  165. errorMessage += args;
  166. errorMessage += ")";
  167. if(!errorMessage.isEmpty() && errorMessage.find("The process cannot access the file because") != CString::kNpos)
  168. {
  169. // DXC might fail to read the HLSL because the antivirus might be having a lock on it. Try again
  170. errorMessage.destroy();
  171. HighRezTimer::sleep(1.0_ms);
  172. }
  173. else if(errorMessage.isEmpty())
  174. {
  175. errorMessage = "Unknown error";
  176. return Error::kFunctionFailed;
  177. }
  178. else
  179. {
  180. // printf("%s\n", src.cstr());
  181. return Error::kFunctionFailed;
  182. }
  183. }
  184. else
  185. {
  186. break;
  187. }
  188. }
  189. CleanupFile binFileCleanup(binFilename);
  190. // Read the spirv back
  191. File binFile;
  192. ANKI_CHECK(binFile.open(binFilename, FileOpenFlag::kRead));
  193. bin.resize(U32(binFile.getSize()));
  194. ANKI_CHECK(binFile.read(&bin[0], bin.getSizeInBytes()));
  195. binFile.close();
  196. return Error::kNone;
  197. }
  198. Error compileHlslToSpirv(CString src, ShaderType shaderType, Bool compileWith16bitTypes, Bool debugInfo, ConstWeakArray<CString> compilerArgs,
  199. ShaderCompilerDynamicArray<U8>& spirv, ShaderCompilerString& errorMessage)
  200. {
  201. return compileHlsl(src, shaderType, compileWith16bitTypes, debugInfo, compilerArgs, true, spirv, errorMessage);
  202. }
  203. Error compileHlslToDxil(CString src, ShaderType shaderType, Bool compileWith16bitTypes, Bool debugInfo, ConstWeakArray<CString> compilerArgs,
  204. ShaderCompilerDynamicArray<U8>& dxil, ShaderCompilerString& errorMessage)
  205. {
  206. return compileHlsl(src, shaderType, compileWith16bitTypes, debugInfo, compilerArgs, false, dxil, errorMessage);
  207. }
  208. } // end namespace anki