Glslang.cpp 9.9 KB

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