shaderc_glsl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Copyright 2011-2023 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include "shaderc.h"
  6. #include "glsl_optimizer.h"
  7. namespace bgfx { namespace glsl
  8. {
  9. static bool compile(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
  10. {
  11. bx::ErrorAssert messageErr;
  12. char ch = _options.shaderType;
  13. const glslopt_shader_type type = ch == 'f'
  14. ? kGlslOptShaderFragment
  15. : (ch == 'c' ? kGlslOptShaderCompute : kGlslOptShaderVertex);
  16. glslopt_target target = kGlslTargetOpenGL;
  17. if(_version == BX_MAKEFOURCC('M', 'T', 'L', 0))
  18. {
  19. target = kGlslTargetMetal;
  20. } else if(_version < 0x80000000) {
  21. target = kGlslTargetOpenGL;
  22. }
  23. else {
  24. _version &= ~0x80000000;
  25. target = (_version >= 300) ? kGlslTargetOpenGLES30 : kGlslTargetOpenGLES20;
  26. }
  27. glslopt_ctx* ctx = glslopt_initialize(target);
  28. glslopt_shader* shader = glslopt_optimize(ctx, type, _code.c_str(), 0);
  29. if (!glslopt_get_status(shader) )
  30. {
  31. const char* log = glslopt_get_log(shader);
  32. int32_t source = 0;
  33. int32_t line = 0;
  34. int32_t column = 0;
  35. int32_t start = 0;
  36. int32_t end = INT32_MAX;
  37. bool found = false
  38. || 3 == sscanf(log, "%u:%u(%u):", &source, &line, &column)
  39. || 2 == sscanf(log, "(%u,%u):", &line, &column)
  40. ;
  41. if (found
  42. && 0 != line)
  43. {
  44. start = bx::uint32_imax(1, line-10);
  45. end = start + 20;
  46. }
  47. printCode(_code.c_str(), line, start, end, column);
  48. bx::write(_messageWriter, &messageErr, "Error: %s\n", log);
  49. glslopt_shader_delete(shader);
  50. glslopt_cleanup(ctx);
  51. return false;
  52. }
  53. const char* optimizedShader = glslopt_get_output(shader);
  54. std::string out;
  55. // Trim all directives.
  56. while ('#' == *optimizedShader)
  57. {
  58. optimizedShader = bx::strFindNl(optimizedShader).getPtr();
  59. }
  60. out.append(optimizedShader, strlen(optimizedShader));
  61. optimizedShader = out.c_str();
  62. {
  63. char* code = const_cast<char*>(optimizedShader);
  64. strReplace(code, "gl_FragDepthEXT", "gl_FragDepth");
  65. strReplace(code, "textureLodEXT", "texture2DLod");
  66. strReplace(code, "textureGradEXT", "texture2DGrad");
  67. strReplace(code, "texture2DLodARB", "texture2DLod");
  68. strReplace(code, "texture2DLodEXT", "texture2DLod");
  69. strReplace(code, "texture2DGradARB", "texture2DGrad");
  70. strReplace(code, "texture2DGradEXT", "texture2DGrad");
  71. strReplace(code, "textureCubeLodARB", "textureCubeLod");
  72. strReplace(code, "textureCubeLodEXT", "textureCubeLod");
  73. strReplace(code, "textureCubeGradARB", "textureCubeGrad");
  74. strReplace(code, "textureCubeGradEXT", "textureCubeGrad");
  75. strReplace(code, "texture2DProjLodARB", "texture2DProjLod");
  76. strReplace(code, "texture2DProjLodEXT", "texture2DProjLod");
  77. strReplace(code, "texture2DProjGradARB", "texture2DProjGrad");
  78. strReplace(code, "texture2DProjGradEXT", "texture2DProjGrad");
  79. strReplace(code, "shadow2DARB", "shadow2D");
  80. strReplace(code, "shadow2DEXT", "shadow2D");
  81. strReplace(code, "shadow2DProjARB", "shadow2DProj");
  82. strReplace(code, "shadow2DProjEXT", "shadow2DProj");
  83. }
  84. UniformArray uniforms;
  85. if (target != kGlslTargetMetal)
  86. {
  87. bx::StringView parse(optimizedShader);
  88. while (!parse.isEmpty() )
  89. {
  90. parse = bx::strLTrimSpace(parse);
  91. bx::StringView eol = bx::strFind(parse, ';');
  92. if (!eol.isEmpty() )
  93. {
  94. bx::StringView qualifier = nextWord(parse);
  95. if (0 == bx::strCmp(qualifier, "precision", 9) )
  96. {
  97. // skip precision
  98. parse.set(eol.getPtr() + 1, parse.getTerm() );
  99. continue;
  100. }
  101. if (0 == bx::strCmp(qualifier, "attribute", 9)
  102. || 0 == bx::strCmp(qualifier, "varying", 7)
  103. || 0 == bx::strCmp(qualifier, "in", 2)
  104. || 0 == bx::strCmp(qualifier, "out", 3)
  105. )
  106. {
  107. // skip attributes and varyings.
  108. parse.set(eol.getPtr() + 1, parse.getTerm() );
  109. continue;
  110. }
  111. if (0 == bx::strCmp(qualifier, "flat", 4)
  112. || 0 == bx::strCmp(qualifier, "smooth", 6)
  113. || 0 == bx::strCmp(qualifier, "noperspective", 13)
  114. || 0 == bx::strCmp(qualifier, "centroid", 8)
  115. )
  116. {
  117. // skip interpolation qualifiers
  118. parse.set(eol.getPtr() + 1, parse.getTerm() );
  119. continue;
  120. }
  121. if (0 == bx::strCmp(parse, "tmpvar", 6) )
  122. {
  123. // skip temporaries
  124. parse.set(eol.getPtr() + 1, parse.getTerm() );
  125. continue;
  126. }
  127. if (0 != bx::strCmp(qualifier, "uniform", 7) )
  128. {
  129. // end if there is no uniform keyword.
  130. parse.clear();
  131. continue;
  132. }
  133. bx::StringView precision;
  134. bx::StringView typen = nextWord(parse);
  135. if (0 == bx::strCmp(typen, "lowp", 4)
  136. || 0 == bx::strCmp(typen, "mediump", 7)
  137. || 0 == bx::strCmp(typen, "highp", 5) )
  138. {
  139. precision = typen;
  140. typen = nextWord(parse);
  141. }
  142. BX_UNUSED(precision);
  143. char uniformType[256];
  144. if (0 == bx::strCmp(typen, "sampler", 7)
  145. || 0 == bx::strCmp(typen, "isampler", 8)
  146. || 0 == bx::strCmp(typen, "usampler", 8) )
  147. {
  148. bx::strCopy(uniformType, BX_COUNTOF(uniformType), "int");
  149. }
  150. else
  151. {
  152. bx::strCopy(uniformType, BX_COUNTOF(uniformType), typen);
  153. }
  154. bx::StringView name = nextWord(parse);
  155. uint8_t num = 1;
  156. bx::StringView array = bx::strSubstr(parse, 0, 1);
  157. if (0 == bx::strCmp(array, "[", 1) )
  158. {
  159. parse = bx::strLTrimSpace(bx::StringView(parse.getPtr() + 1, parse.getTerm() ) );
  160. uint32_t tmp;
  161. bx::fromString(&tmp, parse);
  162. num = uint8_t(tmp);
  163. }
  164. Uniform un;
  165. un.type = nameToUniformTypeEnum(uniformType);
  166. if (UniformType::Count != un.type)
  167. {
  168. un.name.assign(name.getPtr(), name.getTerm());
  169. BX_TRACE("name: %s (type %d, num %d)", un.name.c_str(), un.type, num);
  170. un.num = num;
  171. un.regIndex = 0;
  172. un.regCount = num;
  173. switch (un.type)
  174. {
  175. case UniformType::Mat3:
  176. un.regCount *= 3;
  177. break;
  178. case UniformType::Mat4:
  179. un.regCount *= 4;
  180. break;
  181. default:
  182. break;
  183. }
  184. uniforms.push_back(un);
  185. }
  186. parse = bx::strLTrimSpace(bx::strFindNl(bx::StringView(eol.getPtr(), parse.getTerm() ) ) );
  187. }
  188. }
  189. }
  190. else
  191. {
  192. const bx::StringView optShader(optimizedShader);
  193. bx::StringView parse = bx::strFind(optimizedShader, "struct xlatMtlShaderUniform {");
  194. bx::StringView end = parse;
  195. if (!parse.isEmpty() )
  196. {
  197. parse.set(parse.getPtr() + bx::strLen("struct xlatMtlShaderUniform {"), optShader.getTerm() );
  198. end = bx::strFind(parse, "};");
  199. }
  200. while ( parse.getPtr() < end.getPtr()
  201. && !parse.isEmpty() )
  202. {
  203. parse.set(bx::strLTrimSpace(parse).getPtr(), optShader.getTerm() );
  204. const bx::StringView eol = bx::strFind(parse, ';');
  205. if (!eol.isEmpty() )
  206. {
  207. const char* typen = parse.getPtr();
  208. char uniformType[256];
  209. parse = bx::strWord(parse);
  210. bx::strCopy(uniformType, parse.getLength()+1, typen);
  211. parse.set(parse.getPtr()+parse.getLength(),optShader.getTerm());
  212. const char* name = bx::strLTrimSpace(parse).getPtr();
  213. parse.set(name, optShader.getTerm() );
  214. char uniformName[256];
  215. uint8_t num = 1;
  216. bx::StringView array = bx::strFind(bx::StringView(name, int32_t(eol.getPtr()-parse.getPtr() ) ), "[");
  217. if (!array.isEmpty() )
  218. {
  219. bx::strCopy(uniformName, int32_t(array.getPtr()-name+1), name);
  220. char arraySize[32];
  221. bx::StringView arrayEnd = bx::strFind(bx::StringView(array.getPtr(), int32_t(eol.getPtr()-array.getPtr() ) ), "]");
  222. bx::strCopy(arraySize, int32_t(arrayEnd.getPtr()-array.getPtr() ), array.getPtr()+1);
  223. uint32_t tmp;
  224. bx::fromString(&tmp, arraySize);
  225. num = uint8_t(tmp);
  226. }
  227. else
  228. {
  229. bx::strCopy(uniformName, int32_t(eol.getPtr()-name+1), name);
  230. }
  231. Uniform un;
  232. un.type = nameToUniformTypeEnum(uniformType);
  233. if (UniformType::Count != un.type)
  234. {
  235. BX_TRACE("name: %s (type %d, num %d)", uniformName, un.type, num);
  236. un.name = uniformName;
  237. un.num = num;
  238. un.regIndex = 0;
  239. un.regCount = num;
  240. uniforms.push_back(un);
  241. }
  242. parse = eol.getPtr() + 1;
  243. }
  244. }
  245. bx::StringView mainEntry("xlatMtlShaderOutput xlatMtlMain (");
  246. parse = bx::strFind(optimizedShader, mainEntry);
  247. end = parse;
  248. if (!parse.isEmpty())
  249. {
  250. parse.set(parse.getPtr() + mainEntry.getLength(), optShader.getTerm());
  251. end = bx::strFind(parse, "{");
  252. }
  253. while (parse.getPtr() < end.getPtr()
  254. && !parse.isEmpty())
  255. {
  256. parse.set(bx::strLTrimSpace(parse).getPtr(), optShader.getTerm());
  257. const bx::StringView textureNameMark("[[texture(");
  258. const bx::StringView textureName = bx::strFind(parse, textureNameMark);
  259. if (!textureName.isEmpty())
  260. {
  261. Uniform un;
  262. un.type = nameToUniformTypeEnum("int"); // int for sampler
  263. const char* varNameEnd = textureName.getPtr() - 1;
  264. parse.set(parse.getPtr(), varNameEnd - 1);
  265. const char* varNameBeg = parse.getPtr();
  266. for (int ii = parse.getLength() - 1; 0 <= ii; --ii)
  267. {
  268. if (varNameBeg[ii] == ' ')
  269. {
  270. parse.set(varNameBeg + ii + 1, varNameEnd);
  271. break;
  272. }
  273. }
  274. char uniformName[256];
  275. bx::strCopy(uniformName, parse.getLength() + 1, parse);
  276. un.name = uniformName;
  277. const char* regIndexBeg = textureName.getPtr() + textureNameMark.getLength();
  278. bx::StringView regIndex = bx::strFind(regIndexBeg, ")");
  279. regIndex.set(regIndexBeg, regIndex.getPtr());
  280. uint32_t tmp;
  281. bx::fromString(&tmp, regIndex);
  282. un.regIndex = uint16_t(tmp);
  283. un.num = 1;
  284. un.regCount = 1;
  285. uniforms.push_back(un);
  286. parse = regIndex.getPtr() + 1;
  287. }
  288. else
  289. {
  290. parse = textureName;
  291. }
  292. }
  293. }
  294. bx::ErrorAssert err;
  295. uint16_t count = (uint16_t)uniforms.size();
  296. bx::write(_shaderWriter, count, &err);
  297. for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it)
  298. {
  299. const Uniform& un = *it;
  300. uint8_t nameSize = (uint8_t)un.name.size();
  301. bx::write(_shaderWriter, nameSize, &err);
  302. bx::write(_shaderWriter, un.name.c_str(), nameSize, &err);
  303. uint8_t uniformType = uint8_t(un.type);
  304. bx::write(_shaderWriter, uniformType, &err);
  305. bx::write(_shaderWriter, un.num, &err);
  306. bx::write(_shaderWriter, un.regIndex, &err);
  307. bx::write(_shaderWriter, un.regCount, &err);
  308. bx::write(_shaderWriter, un.texComponent, &err);
  309. bx::write(_shaderWriter, un.texDimension, &err);
  310. bx::write(_shaderWriter, un.texFormat, &err);
  311. BX_TRACE("%s, %s, %d, %d, %d"
  312. , un.name.c_str()
  313. , getUniformTypeName(un.type)
  314. , un.num
  315. , un.regIndex
  316. , un.regCount
  317. );
  318. }
  319. uint32_t shaderSize = (uint32_t)bx::strLen(optimizedShader);
  320. bx::write(_shaderWriter, shaderSize, &err);
  321. bx::write(_shaderWriter, optimizedShader, shaderSize, &err);
  322. uint8_t nul = 0;
  323. bx::write(_shaderWriter, nul, &err);
  324. if (_options.disasm )
  325. {
  326. std::string disasmfp = _options.outputFilePath + ".disasm";
  327. writeFile(disasmfp.c_str(), optimizedShader, shaderSize);
  328. }
  329. glslopt_shader_delete(shader);
  330. glslopt_cleanup(ctx);
  331. return true;
  332. }
  333. } // namespace glsl
  334. bool compileGLSLShader(const Options& _options, uint32_t _version, const std::string& _code, bx::WriterI* _shaderWriter, bx::WriterI* _messageWriter)
  335. {
  336. return glsl::compile(_options, _version, _code, _shaderWriter, _messageWriter);
  337. }
  338. } // namespace bgfx