Glslang.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright (C) 2009-2021, 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/Glslang.h>
  6. #include <AnKi/Util/StringList.h>
  7. #include <AnKi/Util/File.h>
  8. #include <AnKi/Util/Filesystem.h>
  9. #if ANKI_COMPILER_GCC_COMPATIBLE
  10. # pragma GCC diagnostic push
  11. # pragma GCC diagnostic ignored "-Wundef"
  12. # pragma GCC diagnostic ignored "-Wconversion"
  13. #endif
  14. #define ENABLE_OPT 0
  15. #include <Glslang/glslang/Public/ShaderLang.h>
  16. #include <Glslang/SPIRV/GlslangToSpv.h>
  17. #include <Glslang/StandAlone/DirStackFileIncluder.h>
  18. #if ANKI_COMPILER_GCC_COMPATIBLE
  19. # pragma GCC diagnostic pop
  20. #endif
  21. #define ANKI_GLSLANG_DUMP 0
  22. namespace anki {
  23. #if ANKI_GLSLANG_DUMP
  24. static Atomic<U32> g_dumpFileCount;
  25. #endif
  26. class GlslangCtx
  27. {
  28. public:
  29. GlslangCtx()
  30. {
  31. glslang::InitializeProcess();
  32. }
  33. ~GlslangCtx()
  34. {
  35. glslang::FinalizeProcess();
  36. }
  37. };
  38. GlslangCtx g_glslangCtx;
  39. static TBuiltInResource setGlslangLimits()
  40. {
  41. TBuiltInResource c = {};
  42. c.maxLights = 32;
  43. c.maxClipPlanes = 6;
  44. c.maxTextureUnits = 32;
  45. c.maxTextureCoords = 32;
  46. c.maxVertexAttribs = 64;
  47. c.maxVertexUniformComponents = 4096;
  48. c.maxVaryingFloats = 64;
  49. c.maxVertexTextureImageUnits = 32;
  50. c.maxCombinedTextureImageUnits = 80;
  51. c.maxTextureImageUnits = 32;
  52. c.maxFragmentUniformComponents = 4096;
  53. c.maxDrawBuffers = 32;
  54. c.maxVertexUniformVectors = 128;
  55. c.maxVaryingVectors = 8;
  56. c.maxFragmentUniformVectors = 16;
  57. c.maxVertexOutputVectors = 16;
  58. c.maxFragmentInputVectors = 15;
  59. c.minProgramTexelOffset = -8;
  60. c.maxProgramTexelOffset = 7;
  61. c.maxClipDistances = 8;
  62. c.maxComputeWorkGroupCountX = 65535;
  63. c.maxComputeWorkGroupCountY = 65535;
  64. c.maxComputeWorkGroupCountZ = 65535;
  65. c.maxComputeWorkGroupSizeX = 1024;
  66. c.maxComputeWorkGroupSizeY = 1024;
  67. c.maxComputeWorkGroupSizeZ = 64;
  68. c.maxComputeUniformComponents = 1024;
  69. c.maxComputeTextureImageUnits = 16;
  70. c.maxComputeImageUniforms = 8;
  71. c.maxComputeAtomicCounters = 8;
  72. c.maxComputeAtomicCounterBuffers = 1;
  73. c.maxVaryingComponents = 60;
  74. c.maxVertexOutputComponents = 64;
  75. c.maxGeometryInputComponents = 64;
  76. c.maxGeometryOutputComponents = 128;
  77. c.maxFragmentInputComponents = 128;
  78. c.maxImageUnits = 8;
  79. c.maxCombinedImageUnitsAndFragmentOutputs = 8;
  80. c.maxCombinedShaderOutputResources = 8;
  81. c.maxImageSamples = 0;
  82. c.maxVertexImageUniforms = 0;
  83. c.maxTessControlImageUniforms = 0;
  84. c.maxTessEvaluationImageUniforms = 0;
  85. c.maxGeometryImageUniforms = 0;
  86. c.maxFragmentImageUniforms = 8;
  87. c.maxCombinedImageUniforms = 8;
  88. c.maxGeometryTextureImageUnits = 16;
  89. c.maxGeometryOutputVertices = 256;
  90. c.maxGeometryTotalOutputComponents = 1024;
  91. c.maxGeometryUniformComponents = 1024;
  92. c.maxGeometryVaryingComponents = 64;
  93. c.maxTessControlInputComponents = 128;
  94. c.maxTessControlOutputComponents = 128;
  95. c.maxTessControlTextureImageUnits = 16;
  96. c.maxTessControlUniformComponents = 1024;
  97. c.maxTessControlTotalOutputComponents = 4096;
  98. c.maxTessEvaluationInputComponents = 128;
  99. c.maxTessEvaluationOutputComponents = 128;
  100. c.maxTessEvaluationTextureImageUnits = 16;
  101. c.maxTessEvaluationUniformComponents = 1024;
  102. c.maxTessPatchComponents = 120;
  103. c.maxPatchVertices = 32;
  104. c.maxTessGenLevel = 64;
  105. c.maxViewports = 16;
  106. c.maxVertexAtomicCounters = 0;
  107. c.maxTessControlAtomicCounters = 0;
  108. c.maxTessEvaluationAtomicCounters = 0;
  109. c.maxGeometryAtomicCounters = 0;
  110. c.maxFragmentAtomicCounters = 8;
  111. c.maxCombinedAtomicCounters = 8;
  112. c.maxAtomicCounterBindings = 1;
  113. c.maxVertexAtomicCounterBuffers = 0;
  114. c.maxTessControlAtomicCounterBuffers = 0;
  115. c.maxTessEvaluationAtomicCounterBuffers = 0;
  116. c.maxGeometryAtomicCounterBuffers = 0;
  117. c.maxFragmentAtomicCounterBuffers = 1;
  118. c.maxCombinedAtomicCounterBuffers = 1;
  119. c.maxAtomicCounterBufferSize = 16384;
  120. c.maxTransformFeedbackBuffers = 4;
  121. c.maxTransformFeedbackInterleavedComponents = 64;
  122. c.maxCullDistances = 8;
  123. c.maxCombinedClipAndCullDistances = 8;
  124. c.maxSamples = 4;
  125. c.limits.nonInductiveForLoops = 1;
  126. c.limits.whileLoops = 1;
  127. c.limits.doWhileLoops = 1;
  128. c.limits.generalUniformIndexing = 1;
  129. c.limits.generalAttributeMatrixVectorIndexing = 1;
  130. c.limits.generalVaryingIndexing = 1;
  131. c.limits.generalSamplerIndexing = 1;
  132. c.limits.generalVariableIndexing = 1;
  133. c.limits.generalConstantMatrixVectorIndexing = 1;
  134. return c;
  135. }
  136. static TBuiltInResource GLSLANG_LIMITS = setGlslangLimits();
  137. static EShLanguage ankiToGlslangShaderType(ShaderType shaderType)
  138. {
  139. EShLanguage gslangShader;
  140. switch(shaderType)
  141. {
  142. case ShaderType::VERTEX:
  143. gslangShader = EShLangVertex;
  144. break;
  145. case ShaderType::FRAGMENT:
  146. gslangShader = EShLangFragment;
  147. break;
  148. case ShaderType::TESSELLATION_EVALUATION:
  149. gslangShader = EShLangTessEvaluation;
  150. break;
  151. case ShaderType::TESSELLATION_CONTROL:
  152. gslangShader = EShLangTessControl;
  153. break;
  154. case ShaderType::GEOMETRY:
  155. gslangShader = EShLangGeometry;
  156. break;
  157. case ShaderType::COMPUTE:
  158. gslangShader = EShLangCompute;
  159. break;
  160. case ShaderType::RAY_GEN:
  161. gslangShader = EShLangRayGen;
  162. break;
  163. case ShaderType::ANY_HIT:
  164. gslangShader = EShLangAnyHit;
  165. break;
  166. case ShaderType::CLOSEST_HIT:
  167. gslangShader = EShLangClosestHit;
  168. break;
  169. case ShaderType::MISS:
  170. gslangShader = EShLangMiss;
  171. break;
  172. case ShaderType::INTERSECTION:
  173. gslangShader = EShLangIntersect;
  174. break;
  175. case ShaderType::CALLABLE:
  176. gslangShader = EShLangCallable;
  177. break;
  178. default:
  179. ANKI_ASSERT(0);
  180. gslangShader = EShLangCount;
  181. };
  182. return gslangShader;
  183. }
  184. /// Parse Glslang's error message for the line of the error.
  185. static ANKI_USE_RESULT Error parseErrorLine(CString error, GenericMemoryPoolAllocator<U8> alloc, U32& lineNumber)
  186. {
  187. lineNumber = MAX_U32;
  188. StringListAuto lines(alloc);
  189. lines.splitString(error, '\n');
  190. for(String& line : lines)
  191. {
  192. if(line.find("ERROR: ") == 0)
  193. {
  194. StringListAuto tokens(alloc);
  195. tokens.splitString(line, ':');
  196. if(tokens.getSize() < 3 || (tokens.getBegin() + 2)->toNumber(lineNumber) != Error::NONE)
  197. {
  198. ANKI_SHADER_COMPILER_LOGE("Failed to parse the error message: %s", error.cstr());
  199. return Error::FUNCTION_FAILED;
  200. }
  201. else
  202. {
  203. break;
  204. }
  205. }
  206. }
  207. return Error::NONE;
  208. }
  209. static ANKI_USE_RESULT Error logShaderErrorCode(CString error, CString source, GenericMemoryPoolAllocator<U8> alloc)
  210. {
  211. U32 errorLineNumber = 0;
  212. ANKI_CHECK(parseErrorLine(error, alloc, errorLineNumber));
  213. StringAuto prettySrc(alloc);
  214. StringListAuto lines(alloc);
  215. StringAuto errorLineTxt(alloc);
  216. static const char* padding = "==============================================================================";
  217. lines.splitString(source, '\n', true);
  218. U32 lineno = 0;
  219. for(auto it = lines.getBegin(); it != lines.getEnd(); ++it)
  220. {
  221. ++lineno;
  222. StringAuto tmp(alloc);
  223. if(!it->isEmpty() && lineno == errorLineNumber)
  224. {
  225. tmp.sprintf(">>%8u: %s\n", lineno, &(*it)[0]);
  226. errorLineTxt.sprintf("%s", &(*it)[0]);
  227. }
  228. else if(!it->isEmpty())
  229. {
  230. tmp.sprintf(" %8u: %s\n", lineno, &(*it)[0]);
  231. }
  232. else
  233. {
  234. tmp.sprintf(" %8u:\n", lineno);
  235. }
  236. prettySrc.append(tmp);
  237. }
  238. ANKI_SHADER_COMPILER_LOGE("Shader compilation failed:\n%s\n%s\nIn: %s\n%s\n%s\n%s\n%s\nIn: %s\n", padding,
  239. &error[0], errorLineTxt.cstr(), padding, &prettySrc[0], padding, &error[0],
  240. errorLineTxt.cstr());
  241. return Error::NONE;
  242. }
  243. Error preprocessGlsl(CString in, StringAuto& out)
  244. {
  245. glslang::TShader shader(EShLangVertex);
  246. Array<const char*, 1> csrc = {&in[0]};
  247. shader.setStrings(&csrc[0], 1);
  248. DirStackFileIncluder includer;
  249. EShMessages messages = EShMsgDefault;
  250. std::string glslangOut;
  251. if(!shader.preprocess(&GLSLANG_LIMITS, 450, ENoProfile, false, false, messages, &glslangOut, includer))
  252. {
  253. ANKI_SHADER_COMPILER_LOGE("Preprocessing failed:\n%s", shader.getInfoLog());
  254. return Error::USER_DATA;
  255. }
  256. out.append(glslangOut.c_str());
  257. return Error::NONE;
  258. }
  259. Error compilerGlslToSpirv(CString src, ShaderType shaderType, GenericMemoryPoolAllocator<U8> tmpAlloc,
  260. DynamicArrayAuto<U8>& spirv)
  261. {
  262. #if ANKI_GLSLANG_DUMP
  263. // Dump it
  264. {
  265. const U32 count = g_dumpFileCount.fetchAdd(1) / 2;
  266. if(count == 0)
  267. {
  268. ANKI_SHADER_COMPILER_LOGW("GLSL dumping is enabled");
  269. }
  270. File file;
  271. StringAuto tmpDir(tmpAlloc);
  272. ANKI_CHECK(getTempDirectory(tmpDir));
  273. StringAuto fname(tmpAlloc);
  274. fname.sprintf("%s/%u.glsl", tmpDir.cstr(), count);
  275. ANKI_CHECK(file.open(fname, FileOpenFlag::WRITE));
  276. ANKI_CHECK(file.writeText("%s", src.cstr()));
  277. }
  278. #endif
  279. const EShLanguage stage = ankiToGlslangShaderType(shaderType);
  280. const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules);
  281. glslang::TShader shader(stage);
  282. Array<const char*, 1> csrc = {&src[0]};
  283. shader.setStrings(&csrc[0], 1);
  284. shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
  285. shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4);
  286. if(!shader.parse(&GLSLANG_LIMITS, 100, false, messages))
  287. {
  288. ANKI_CHECK(logShaderErrorCode(shader.getInfoLog(), src, tmpAlloc));
  289. return Error::USER_DATA;
  290. }
  291. // Setup the program
  292. glslang::TProgram program;
  293. program.addShader(&shader);
  294. if(!program.link(messages))
  295. {
  296. ANKI_SHADER_COMPILER_LOGE("glslang failed to link a shader");
  297. return Error::USER_DATA;
  298. }
  299. // Gen SPIRV
  300. glslang::SpvOptions spvOptions;
  301. spvOptions.optimizeSize = true;
  302. spvOptions.disableOptimizer = false;
  303. std::vector<unsigned int> glslangSpirv;
  304. glslang::GlslangToSpv(*program.getIntermediate(stage), glslangSpirv, &spvOptions);
  305. // Store
  306. spirv.resize(U32(glslangSpirv.size() * sizeof(unsigned int)));
  307. memcpy(&spirv[0], &glslangSpirv[0], spirv.getSizeInBytes());
  308. #if ANKI_GLSLANG_DUMP
  309. // Dump it
  310. {
  311. const U32 count = g_dumpFileCount.fetchAdd(1) / 2;
  312. if(count == 0)
  313. {
  314. ANKI_SHADER_COMPILER_LOGW("SPIR-V dumping is enabled");
  315. }
  316. File file;
  317. StringAuto tmpDir(tmpAlloc);
  318. ANKI_CHECK(getTempDirectory(tmpDir));
  319. StringAuto fname(tmpAlloc);
  320. fname.sprintf("%s/%u.spv", tmpDir.cstr(), count);
  321. ANKI_CHECK(file.open(fname, FileOpenFlag::WRITE | FileOpenFlag::BINARY));
  322. ANKI_CHECK(file.write(spirv.getBegin(), spirv.getSizeInBytes()));
  323. }
  324. #endif
  325. return Error::NONE;
  326. }
  327. } // end namespace anki