ShaderCompiler.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. // Copyright (C) 2009-2019, 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/gr/ShaderCompiler.h>
  6. #include <anki/gr/GrManager.h>
  7. #include <anki/core/Trace.h>
  8. #include <anki/util/StringList.h>
  9. #include <anki/util/Filesystem.h>
  10. #include <anki/core/Trace.h>
  11. #if defined(__GNUC__)
  12. # pragma GCC diagnostic push
  13. # pragma GCC diagnostic ignored "-Wundef"
  14. #endif
  15. #include <glslang/Public/ShaderLang.h>
  16. #include <glslang/SPIRV/GlslangToSpv.h>
  17. #include <glslang/StandAlone/DirStackFileIncluder.h>
  18. #include <SPIRV-Cross/spirv_glsl.hpp>
  19. #if defined(__GNUC__)
  20. # pragma GCC diagnostic pop
  21. #endif
  22. namespace anki
  23. {
  24. void ShaderCompilerOptions::setFromGrManager(const GrManager& gr)
  25. {
  26. #if ANKI_GR_BACKEND == ANKI_GR_BACKEND_VULKAN
  27. m_outLanguage = ShaderLanguage::SPIRV;
  28. #else
  29. m_outLanguage = ShaderLanguage::GLSL;
  30. #endif
  31. m_gpuCapabilities = gr.getDeviceCapabilities();
  32. }
  33. static const Array<const char*, U(ShaderType::COUNT)> SHADER_NAME = {
  34. {"VERTEX", "TESSELATION_CONTROL", "TESSELATION_EVALUATION", "GEOMETRY", "FRAGMENT", "COMPUTE"}};
  35. static const char* SHADER_HEADER = R"(#version 450 core
  36. #define ANKI_BACKEND_%s 1
  37. #define ANKI_BACKEND_MINOR %u
  38. #define ANKI_BACKEND_MAJOR %u
  39. #define ANKI_VENDOR_%s 1
  40. #define ANKI_%s_SHADER 1
  41. #if defined(ANKI_BACKEND_GL)
  42. # error GL is Deprecated
  43. #else
  44. # define gl_VertexID gl_VertexIndex
  45. # define gl_InstanceID gl_InstanceIndex
  46. #
  47. # extension GL_EXT_control_flow_attributes : require
  48. # define ANKI_UNROLL [[unroll]]
  49. # define ANKI_LOOP [[dont_unroll]]
  50. # define ANKI_BRANCH [[branch]]
  51. # define ANKI_FLATTEN [[flatten]]
  52. #
  53. # if ANKI_BACKEND_MAJOR == 1 && ANKI_BACKEND_MINOR >= 1
  54. # extension GL_KHR_shader_subgroup_vote : require
  55. # extension GL_KHR_shader_subgroup_ballot : require
  56. # extension GL_KHR_shader_subgroup_shuffle : require
  57. # extension GL_KHR_shader_subgroup_arithmetic : require
  58. # endif
  59. # extension GL_EXT_samplerless_texture_functions : require
  60. # extension GL_EXT_shader_image_load_formatted : require
  61. # extension GL_EXT_nonuniform_qualifier : enable
  62. #
  63. # define ANKI_MAX_BINDLESS_TEXTURES %u
  64. # define ANKI_MAX_BINDLESS_IMAGES %u
  65. #endif
  66. #define F32 float
  67. #define Vec2 vec2
  68. #define Vec3 vec3
  69. #define Vec4 vec4
  70. #define U32 uint
  71. #define UVec2 uvec2
  72. #define UVec3 uvec3
  73. #define UVec4 uvec4
  74. #define I32 int
  75. #define IVec2 ivec2
  76. #define IVec3 ivec3
  77. #define IVec4 ivec4
  78. #define Mat3 mat3
  79. #define Mat4 mat4
  80. #define Mat3x4 mat3x4
  81. #define Bool bool
  82. %s)";
  83. static EShLanguage ankiToGlslangShaderType(ShaderType shaderType)
  84. {
  85. EShLanguage gslangShader;
  86. switch(shaderType)
  87. {
  88. case ShaderType::VERTEX:
  89. gslangShader = EShLangVertex;
  90. break;
  91. case ShaderType::FRAGMENT:
  92. gslangShader = EShLangFragment;
  93. break;
  94. case ShaderType::TESSELLATION_EVALUATION:
  95. gslangShader = EShLangTessEvaluation;
  96. break;
  97. case ShaderType::TESSELLATION_CONTROL:
  98. gslangShader = EShLangTessControl;
  99. break;
  100. case ShaderType::GEOMETRY:
  101. gslangShader = EShLangGeometry;
  102. break;
  103. case ShaderType::COMPUTE:
  104. gslangShader = EShLangCompute;
  105. break;
  106. default:
  107. ANKI_ASSERT(0);
  108. gslangShader = EShLangCount;
  109. };
  110. return gslangShader;
  111. }
  112. static TBuiltInResource setLimits()
  113. {
  114. TBuiltInResource c = {};
  115. c.maxLights = 32;
  116. c.maxClipPlanes = 6;
  117. c.maxTextureUnits = 32;
  118. c.maxTextureCoords = 32;
  119. c.maxVertexAttribs = 64;
  120. c.maxVertexUniformComponents = 4096;
  121. c.maxVaryingFloats = 64;
  122. c.maxVertexTextureImageUnits = 32;
  123. c.maxCombinedTextureImageUnits = 80;
  124. c.maxTextureImageUnits = 32;
  125. c.maxFragmentUniformComponents = 4096;
  126. c.maxDrawBuffers = 32;
  127. c.maxVertexUniformVectors = 128;
  128. c.maxVaryingVectors = 8;
  129. c.maxFragmentUniformVectors = 16;
  130. c.maxVertexOutputVectors = 16;
  131. c.maxFragmentInputVectors = 15;
  132. c.minProgramTexelOffset = -8;
  133. c.maxProgramTexelOffset = 7;
  134. c.maxClipDistances = 8;
  135. c.maxComputeWorkGroupCountX = 65535;
  136. c.maxComputeWorkGroupCountY = 65535;
  137. c.maxComputeWorkGroupCountZ = 65535;
  138. c.maxComputeWorkGroupSizeX = 1024;
  139. c.maxComputeWorkGroupSizeY = 1024;
  140. c.maxComputeWorkGroupSizeZ = 64;
  141. c.maxComputeUniformComponents = 1024;
  142. c.maxComputeTextureImageUnits = 16;
  143. c.maxComputeImageUniforms = 8;
  144. c.maxComputeAtomicCounters = 8;
  145. c.maxComputeAtomicCounterBuffers = 1;
  146. c.maxVaryingComponents = 60;
  147. c.maxVertexOutputComponents = 64;
  148. c.maxGeometryInputComponents = 64;
  149. c.maxGeometryOutputComponents = 128;
  150. c.maxFragmentInputComponents = 128;
  151. c.maxImageUnits = 8;
  152. c.maxCombinedImageUnitsAndFragmentOutputs = 8;
  153. c.maxCombinedShaderOutputResources = 8;
  154. c.maxImageSamples = 0;
  155. c.maxVertexImageUniforms = 0;
  156. c.maxTessControlImageUniforms = 0;
  157. c.maxTessEvaluationImageUniforms = 0;
  158. c.maxGeometryImageUniforms = 0;
  159. c.maxFragmentImageUniforms = 8;
  160. c.maxCombinedImageUniforms = 8;
  161. c.maxGeometryTextureImageUnits = 16;
  162. c.maxGeometryOutputVertices = 256;
  163. c.maxGeometryTotalOutputComponents = 1024;
  164. c.maxGeometryUniformComponents = 1024;
  165. c.maxGeometryVaryingComponents = 64;
  166. c.maxTessControlInputComponents = 128;
  167. c.maxTessControlOutputComponents = 128;
  168. c.maxTessControlTextureImageUnits = 16;
  169. c.maxTessControlUniformComponents = 1024;
  170. c.maxTessControlTotalOutputComponents = 4096;
  171. c.maxTessEvaluationInputComponents = 128;
  172. c.maxTessEvaluationOutputComponents = 128;
  173. c.maxTessEvaluationTextureImageUnits = 16;
  174. c.maxTessEvaluationUniformComponents = 1024;
  175. c.maxTessPatchComponents = 120;
  176. c.maxPatchVertices = 32;
  177. c.maxTessGenLevel = 64;
  178. c.maxViewports = 16;
  179. c.maxVertexAtomicCounters = 0;
  180. c.maxTessControlAtomicCounters = 0;
  181. c.maxTessEvaluationAtomicCounters = 0;
  182. c.maxGeometryAtomicCounters = 0;
  183. c.maxFragmentAtomicCounters = 8;
  184. c.maxCombinedAtomicCounters = 8;
  185. c.maxAtomicCounterBindings = 1;
  186. c.maxVertexAtomicCounterBuffers = 0;
  187. c.maxTessControlAtomicCounterBuffers = 0;
  188. c.maxTessEvaluationAtomicCounterBuffers = 0;
  189. c.maxGeometryAtomicCounterBuffers = 0;
  190. c.maxFragmentAtomicCounterBuffers = 1;
  191. c.maxCombinedAtomicCounterBuffers = 1;
  192. c.maxAtomicCounterBufferSize = 16384;
  193. c.maxTransformFeedbackBuffers = 4;
  194. c.maxTransformFeedbackInterleavedComponents = 64;
  195. c.maxCullDistances = 8;
  196. c.maxCombinedClipAndCullDistances = 8;
  197. c.maxSamples = 4;
  198. c.limits.nonInductiveForLoops = 1;
  199. c.limits.whileLoops = 1;
  200. c.limits.doWhileLoops = 1;
  201. c.limits.generalUniformIndexing = 1;
  202. c.limits.generalAttributeMatrixVectorIndexing = 1;
  203. c.limits.generalVaryingIndexing = 1;
  204. c.limits.generalSamplerIndexing = 1;
  205. c.limits.generalVariableIndexing = 1;
  206. c.limits.generalConstantMatrixVectorIndexing = 1;
  207. return c;
  208. }
  209. static const TBuiltInResource GLSLANG_LIMITS = setLimits();
  210. static void preappendAnkiSpecific(CString source, const ShaderCompilerOptions& options, StringAuto& out)
  211. {
  212. // Gen the new source
  213. out.sprintf(SHADER_HEADER,
  214. (options.m_outLanguage == ShaderLanguage::GLSL) ? "GL" : "VULKAN",
  215. options.m_gpuCapabilities.m_minorApiVersion,
  216. options.m_gpuCapabilities.m_majorApiVersion,
  217. &GPU_VENDOR_STR[options.m_gpuCapabilities.m_gpuVendor][0],
  218. SHADER_NAME[options.m_shaderType],
  219. MAX_BINDLESS_TEXTURES,
  220. MAX_BINDLESS_IMAGES,
  221. &source[0]);
  222. }
  223. I32 ShaderCompiler::m_refcount = {0};
  224. Mutex ShaderCompiler::m_refcountMtx;
  225. ShaderCompiler::ShaderCompiler(GenericMemoryPoolAllocator<U8> alloc)
  226. : m_alloc(alloc)
  227. {
  228. LockGuard<Mutex> lock(m_refcountMtx);
  229. const I32 refcount = m_refcount++;
  230. ANKI_ASSERT(refcount >= 0);
  231. if(refcount == 0)
  232. {
  233. glslang::InitializeProcess();
  234. }
  235. }
  236. ShaderCompiler::~ShaderCompiler()
  237. {
  238. LockGuard<Mutex> lock(m_refcountMtx);
  239. const I32 refcount = m_refcount--;
  240. ANKI_ASSERT(refcount >= 0);
  241. if(refcount == 1)
  242. {
  243. glslang::FinalizeProcess();
  244. }
  245. }
  246. Error ShaderCompiler::preprocessCommon(CString in, const ShaderCompilerOptions& options, StringAuto& out) const
  247. {
  248. const EShLanguage stage = ankiToGlslangShaderType(options.m_shaderType);
  249. glslang::TShader shader(stage);
  250. Array<const char*, 1> csrc = {{&in[0]}};
  251. shader.setStrings(&csrc[0], 1);
  252. DirStackFileIncluder includer;
  253. EShMessages messages = EShMsgDefault;
  254. std::string glslangOut;
  255. if(!shader.preprocess(&GLSLANG_LIMITS, 450, ENoProfile, false, false, messages, &glslangOut, includer))
  256. {
  257. ShaderCompiler::logShaderErrorCode(shader.getInfoLog(), in, m_alloc);
  258. return Error::USER_DATA;
  259. }
  260. out.append(glslangOut.c_str());
  261. return Error::NONE;
  262. }
  263. Error ShaderCompiler::genSpirv(CString src, const ShaderCompilerOptions& options, DynamicArrayAuto<U8>& spirv) const
  264. {
  265. const EShLanguage stage = ankiToGlslangShaderType(options.m_shaderType);
  266. EShMessages messages = EShMsgSpvRules;
  267. if(options.m_outLanguage == ShaderLanguage::SPIRV)
  268. {
  269. messages = static_cast<EShMessages>(messages | EShMsgVulkanRules);
  270. }
  271. // Setup the shader
  272. glslang::EShTargetLanguageVersion langVersion;
  273. if(options.m_outLanguage == ShaderLanguage::SPIRV && options.m_gpuCapabilities.m_minorApiVersion > 0)
  274. {
  275. langVersion = glslang::EShTargetSpv_1_3;
  276. }
  277. else
  278. {
  279. langVersion = glslang::EShTargetSpv_1_0;
  280. }
  281. glslang::TShader shader(stage);
  282. Array<const char*, 1> csrc = {{&src[0]}};
  283. shader.setStrings(&csrc[0], 1);
  284. shader.setEnvTarget(glslang::EShTargetSpv, langVersion);
  285. if(!shader.parse(&GLSLANG_LIMITS, 100, false, messages))
  286. {
  287. ShaderCompiler::logShaderErrorCode(shader.getInfoLog(), src, m_alloc);
  288. return Error::USER_DATA;
  289. }
  290. // Setup the program
  291. glslang::TProgram program;
  292. program.addShader(&shader);
  293. if(!program.link(messages))
  294. {
  295. ANKI_GR_LOGE("glslang failed to link a shader");
  296. return Error::USER_DATA;
  297. }
  298. // Gen SPIRV
  299. glslang::SpvOptions spvOptions;
  300. spvOptions.optimizeSize = true;
  301. spvOptions.disableOptimizer = false;
  302. std::vector<unsigned int> glslangSpirv;
  303. glslang::GlslangToSpv(*program.getIntermediate(stage), glslangSpirv, &spvOptions);
  304. // Store
  305. spirv.resize(glslangSpirv.size() * sizeof(unsigned int));
  306. memcpy(&spirv[0], &glslangSpirv[0], spirv.getSizeInBytes());
  307. return Error::NONE;
  308. }
  309. Error ShaderCompiler::preprocess(
  310. CString source, const ShaderCompilerOptions& options, const StringList& defines, StringAuto& out) const
  311. {
  312. ANKI_ASSERT(!source.isEmpty() && source.getLength() > 0);
  313. ANKI_TRACE_SCOPED_EVENT(GR_SHADER_COMPILE);
  314. // Append defines
  315. StringAuto newSource(m_alloc);
  316. auto it = defines.getBegin();
  317. auto end = defines.getEnd();
  318. while(it != end)
  319. {
  320. newSource.append("#define ");
  321. newSource.append(it->toCString());
  322. newSource.append(" = (");
  323. ++it;
  324. ANKI_ASSERT(it != end);
  325. newSource.append(it->toCString());
  326. newSource.append(")\n");
  327. }
  328. newSource.append(source);
  329. // Add the extra code
  330. StringAuto fullSrc(m_alloc);
  331. preappendAnkiSpecific(newSource.toCString(), options, fullSrc);
  332. // Do the work
  333. ANKI_CHECK(preprocessCommon(fullSrc.toCString(), options, out));
  334. return Error::NONE;
  335. }
  336. Error ShaderCompiler::compile(CString source, const ShaderCompilerOptions& options, DynamicArrayAuto<U8>& bin) const
  337. {
  338. ANKI_ASSERT(!source.isEmpty() && source.getLength() > 0);
  339. Error err = Error::NONE;
  340. ANKI_TRACE_SCOPED_EVENT(GR_SHADER_COMPILE);
  341. // Create the context
  342. StringAuto finalSrc(m_alloc);
  343. preappendAnkiSpecific(source, options, finalSrc);
  344. // Compile
  345. if(options.m_outLanguage == ShaderLanguage::GLSL)
  346. {
  347. #if 0
  348. std::vector<unsigned int> spv;
  349. err = genSpirv(ctx, spv);
  350. if(!err)
  351. {
  352. spirv_cross::CompilerGLSL cross(spv);
  353. std::string newSrc = cross.compile();
  354. bin.resize(newSrc.length() + 1);
  355. memcpy(&bin[0], &newSrc[0], bin.getSize());
  356. }
  357. #else
  358. // Preprocess the source because MESA sucks and can't do it
  359. StringAuto out(m_alloc);
  360. ANKI_CHECK(preprocessCommon(finalSrc.toCString(), options, out));
  361. bin.resize(out.getLength() + 1);
  362. memcpy(&bin[0], &out[0], bin.getSizeInBytes());
  363. #endif
  364. }
  365. else
  366. {
  367. ANKI_CHECK(genSpirv(finalSrc.toCString(), options, bin));
  368. }
  369. #if 0
  370. // Dump
  371. {
  372. static I id = 0;
  373. String homeDir;
  374. ANKI_CHECK(getHomeDirectory(m_alloc, homeDir));
  375. File file;
  376. ANKI_CHECK(
  377. file.open(StringAuto(m_alloc).sprintf("%s/.anki/cache/%d.dump.glsl", homeDir.cstr(), id++).toCString(),
  378. FileOpenFlag::WRITE));
  379. ANKI_CHECK(file.write(finalSrc.cstr(), finalSrc.getLength() + 1));
  380. homeDir.destroy(m_alloc);
  381. }
  382. #endif
  383. return err;
  384. }
  385. void ShaderCompiler::logShaderErrorCode(CString error, CString source, GenericMemoryPoolAllocator<U8> alloc)
  386. {
  387. StringAuto prettySrc(alloc);
  388. StringListAuto lines(alloc);
  389. static const char* padding = "==============================================================================";
  390. lines.splitString(source, '\n', true);
  391. I lineno = 0;
  392. for(auto it = lines.getBegin(); it != lines.getEnd(); ++it)
  393. {
  394. ++lineno;
  395. StringAuto tmp(alloc);
  396. if(!it->isEmpty())
  397. {
  398. tmp.sprintf("%8d: %s\n", lineno, &(*it)[0]);
  399. }
  400. else
  401. {
  402. tmp.sprintf("%8d:\n", lineno);
  403. }
  404. prettySrc.append(tmp);
  405. }
  406. ANKI_GR_LOGE("Shader compilation failed:\n%s\n%s\n%s\n%s\n%s\n%s",
  407. padding,
  408. &error[0],
  409. padding,
  410. &prettySrc[0],
  411. padding,
  412. &error[0]);
  413. }
  414. Error ShaderCompilerCache::compile(
  415. CString source, U64* hash, const ShaderCompilerOptions& options, DynamicArrayAuto<U8>& bin) const
  416. {
  417. Error err = compileInternal(source, hash, options, bin);
  418. if(err)
  419. {
  420. ANKI_GR_LOGE("Failed to compile or retrieve shader from the cache");
  421. }
  422. return err;
  423. }
  424. Error ShaderCompilerCache::compileInternal(
  425. CString source, U64* hash, const ShaderCompilerOptions& options, DynamicArrayAuto<U8>& bin) const
  426. {
  427. ANKI_ASSERT(!source.isEmpty() && source.getLength() > 0);
  428. // Compute hash
  429. U64 fhash;
  430. if(hash)
  431. {
  432. fhash = *hash;
  433. ANKI_ASSERT(fhash != 0);
  434. }
  435. else
  436. {
  437. fhash = computeHash(&source[0], source.getLength());
  438. }
  439. fhash = appendHash(&options, sizeof(options), fhash);
  440. // Search the cache
  441. StringAuto fname(m_alloc);
  442. fname.sprintf("%s/%llu.shdrbin", m_cacheDir.cstr(), fhash);
  443. if(fileExists(fname.toCString()))
  444. {
  445. File file;
  446. ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::READ | FileOpenFlag::BINARY));
  447. PtrSize size = file.getSize();
  448. bin.resize(size);
  449. ANKI_CHECK(file.read(&bin[0], bin.getSize()));
  450. }
  451. else
  452. {
  453. ANKI_GR_LOGI("%s not found in cache. Will compile", fname.cstr());
  454. ANKI_CHECK(m_compiler.compile(source, options, bin));
  455. File file;
  456. ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::WRITE | FileOpenFlag::BINARY));
  457. ANKI_CHECK(file.write(&bin[0], bin.getSize()));
  458. }
  459. return Error::NONE;
  460. }
  461. } // end namespace anki