ShaderProgramPrePreprocessor.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include "anki/resource/ShaderProgramPrePreprocessor.h"
  2. #include "anki/misc/Parser.h"
  3. #include "anki/util/Filesystem.h"
  4. #include "anki/util/Exception.h"
  5. #include <iomanip>
  6. #include <cstring>
  7. #include <iostream>
  8. namespace anki {
  9. //==============================================================================
  10. static Array<const char*, 3> commands = {{
  11. "#pragma anki start",
  12. "#pragma anki include",
  13. "#pragma anki transformFeedbackVaryings"}};
  14. Array<const char*, ST_NUM> startTokens = {{
  15. "vertexShader",
  16. "tcShader",
  17. "teShader",
  18. "geometryShader",
  19. "fragmentShader"}};
  20. static const char* MULTIPLE_DEF_MSG = " already defined in the same place. "
  21. "Check for circular or multiple includance";
  22. static const char* ENTRY_POINT_DOT_DEFINED = "Entry point not defined: ";
  23. const U32 MAX_DEPTH = 99;
  24. //==============================================================================
  25. void ShaderProgramPrePreprocessor::printSourceLines() const
  26. {
  27. for(U32 i = 0; i < sourceLines.size(); ++i)
  28. {
  29. std::cout << std::setw(3) << (i + 1) << ": "
  30. << sourceLines[i] << std::endl;
  31. }
  32. }
  33. //==============================================================================
  34. void ShaderProgramPrePreprocessor::parseFileForPragmas(
  35. const std::string& filename, int depth)
  36. {
  37. // first check the depth
  38. if(depth > MAX_DEPTH)
  39. {
  40. throw ANKI_EXCEPTION("The include depth is too high. "
  41. "Probably circular includance: " + filename);
  42. }
  43. // load file in lines
  44. StringList lines = readFileLines(filename.c_str());
  45. if(lines.size() < 1)
  46. {
  47. throw ANKI_EXCEPTION("Cannot open file or empty: " + filename);
  48. }
  49. for(const std::string& line : lines)
  50. {
  51. if(line.find_first_of(commands[0]) != std::string::npos)
  52. {
  53. }
  54. else if(line.find_first_of(commands[1]) != std::string::npos)
  55. {
  56. }
  57. else if(line.find_first_of(commands[2]) != std::string::npos)
  58. {
  59. }
  60. else
  61. {
  62. sourceLines.push_back(line);
  63. }
  64. }
  65. #if 0
  66. scanner::Scanner scanner(filename.c_str(), false);
  67. const scanner::Token* token;
  68. while(true)
  69. {
  70. token = &scanner.getNextToken();
  71. // #
  72. if(token->getCode() == scanner::TC_SHARP)
  73. {
  74. token = &scanner.getNextToken();
  75. // pragma
  76. if(parser::isIdentifier(*token, "pragma"))
  77. {
  78. token = &scanner.getNextToken();
  79. // anki
  80. if(parser::isIdentifier(*token, "anki"))
  81. {
  82. // start
  83. token = &scanner.getNextToken();
  84. if(parser::isIdentifier(*token, "start"))
  85. {
  86. parseStartPragma(scanner, filename, depth, lines);
  87. }
  88. // include
  89. else if(parser::isIdentifier(*token, "include"))
  90. {
  91. parseIncludePragma(scanner, filename, depth, lines);
  92. }
  93. // transformFeedbackVarying
  94. else if(parser::isIdentifier(*token,
  95. "transformFeedbackVarying"))
  96. {
  97. parseTrffbVarying(scanner, filename, depth, lines);
  98. }
  99. // error
  100. else
  101. {
  102. throw PARSER_EXCEPTION(
  103. "#pragma anki followed by incorrect " +
  104. token->getInfoString());
  105. }
  106. } // end if anki
  107. token = &scanner.getNextToken();
  108. if(token->getCode()!=scanner::TC_NEWLINE &&
  109. token->getCode()!=scanner::TC_END)
  110. {
  111. throw PARSER_EXCEPTION_EXPECTED("newline or end of file");
  112. }
  113. if(token->getCode() == scanner::TC_END)
  114. {
  115. break;
  116. }
  117. } // end if pragma
  118. } // end if #
  119. //
  120. // newline
  121. //
  122. else if(token->getCode() == scanner::TC_NEWLINE)
  123. {
  124. sourceLines.push_back(lines[scanner.getLineNumber() - 2]);
  125. //PRINT(lines[scanner.getLineNmbr() - 2])
  126. }
  127. //
  128. // EOF
  129. //
  130. else if(token->getCode() == scanner::TC_END)
  131. {
  132. sourceLines.push_back(lines[scanner.getLineNumber() - 1]);
  133. //PRINT(lines[scanner.getLineNmbr() - 1])
  134. break;
  135. }
  136. //
  137. // error
  138. //
  139. else if(token->getCode() == scanner::TC_ERROR)
  140. {
  141. // It will never get here
  142. }
  143. } // end while
  144. #endif
  145. }
  146. //==============================================================================
  147. void ShaderProgramPrePreprocessor::parseFile(const char* filename)
  148. {
  149. try
  150. {
  151. // parse master file
  152. parseFileForPragmas(filename);
  153. // sanity checks
  154. if(!shaderStarts[ST_VERTEX].isDefined())
  155. {
  156. throw ANKI_EXCEPTION(ENTRY_POINT_DOT_DEFINED
  157. + startTokens[ST_VERTEX]);
  158. }
  159. if(!shaderStarts[ST_FRAGMENT].isDefined())
  160. {
  161. throw ANKI_EXCEPTION(ENTRY_POINT_DOT_DEFINED
  162. + startTokens[ST_FRAGMENT]);
  163. }
  164. // construct each shaders' source code
  165. for(U i = 0; i < ST_NUM; i++)
  166. {
  167. std::string& src = output.shaderSources[i];
  168. src = "";
  169. // If not defined bb
  170. if(!shaderStarts[i].isDefined())
  171. {
  172. continue;
  173. }
  174. // Sanity check: Check the correct order of i
  175. I32 k = (I32)i - 1;
  176. while(k > -1)
  177. {
  178. if(shaderStarts[k].isDefined()
  179. && shaderStarts[k].globalLine >= shaderStarts[i].globalLine)
  180. {
  181. throw ANKI_EXCEPTION(startTokens[i] + " must be after "
  182. + startTokens[k]);
  183. }
  184. --k;
  185. }
  186. k = (I32)i + 1;
  187. while(k < ST_NUM)
  188. {
  189. if(shaderStarts[k].isDefined()
  190. && shaderStarts[k].globalLine <= shaderStarts[i].globalLine)
  191. {
  192. throw ANKI_EXCEPTION(startTokens[k] + " must be after "
  193. + startTokens[i]);
  194. }
  195. ++k;
  196. }
  197. // put global source code
  198. for(I32 j = 0; j < shaderStarts[ST_VERTEX].globalLine - 1; ++j)
  199. {
  200. src += sourceLines[j] + "\n";
  201. }
  202. // put the actual code
  203. U32 from = i;
  204. U32 to;
  205. for(to = i + 1; to < ST_NUM; to++)
  206. {
  207. if(shaderStarts[to].definedInLine != -1)
  208. {
  209. break;
  210. }
  211. }
  212. I32 toLine = (to == ST_NUM) ? sourceLines.size()
  213. : shaderStarts[to].globalLine - 1;
  214. for(I32 j = shaderStarts[from].globalLine - 1; j < toLine; ++j)
  215. {
  216. src += sourceLines[j] + "\n";
  217. }
  218. }
  219. //PRINT("vertShaderBegins.globalLine: " << vertShaderBegins.globalLine)
  220. //PRINT("fragShaderBegins.globalLine: " << fragShaderBegins.globalLine)
  221. //printSourceLines();
  222. //printShaderVars();
  223. }
  224. catch(Exception& e)
  225. {
  226. throw ANKI_EXCEPTION("Loading file failed: " + filename) << e;
  227. }
  228. }
  229. //==============================================================================
  230. void ShaderProgramPrePreprocessor::parseStartPragma(scanner::Scanner& scanner,
  231. const std::string& filename, uint depth,
  232. const Vector<std::string>& lines)
  233. {
  234. const scanner::Token* token = &scanner.getNextToken();
  235. // Chose the correct pragma
  236. CodeBeginningPragma* cbp = NULL;
  237. const char* name = NULL;
  238. for(uint i = 0; i < ST_NUM; i++)
  239. {
  240. if(parser::isIdentifier(*token, startTokens[i]))
  241. {
  242. cbp = &shaderStarts[i];
  243. name = startTokens[i];
  244. break;
  245. }
  246. }
  247. if(name == NULL)
  248. {
  249. throw PARSER_EXCEPTION_UNEXPECTED();
  250. }
  251. // its defined in same place so there is probable circular includance
  252. if(cbp->definedInLine == scanner.getLineNumber() &&
  253. cbp->definedInFile == filename)
  254. {
  255. throw PARSER_EXCEPTION(name + MULTIPLE_DEF_MSG);
  256. }
  257. // already defined elsewhere => error
  258. if(cbp->definedInLine != -1)
  259. {
  260. throw PARSER_EXCEPTION( name + " already defined at " +
  261. cbp->definedInFile + ":" +
  262. boost::lexical_cast<std::string>(cbp->definedInLine));
  263. }
  264. cbp->definedInFile = filename;
  265. cbp->definedInLine = scanner.getLineNumber();
  266. cbp->globalLine = sourceLines.size() + 1;
  267. addLinePreProcExpression(scanner.getLineNumber(), depth,
  268. lines[scanner.getLineNumber() - 1].c_str());
  269. }
  270. //==============================================================================
  271. // parseIncludePragma =
  272. //==============================================================================
  273. void ShaderProgramPrePreprocessor::parseIncludePragma(
  274. scanner::Scanner& scanner, const std::string& /*filename*/, uint depth,
  275. const Vector<std::string>& lines)
  276. {
  277. const scanner::Token* token = &scanner.getNextToken();
  278. if(token->getCode() == scanner::TC_STRING)
  279. {
  280. std::string filename = token->getValue().getString();
  281. //int line = sourceLines.size();
  282. addLinePreProcExpression(0, depth + 1,
  283. lines[scanner.getLineNumber() - 1].c_str());
  284. parseFileForPragmas(filename.c_str(), depth + 1);
  285. addLinePreProcExpression(scanner.getLineNumber(), depth,
  286. (" // end of " + lines[scanner.getLineNumber() - 1]).c_str());
  287. }
  288. else
  289. {
  290. throw PARSER_EXCEPTION_EXPECTED("string");
  291. }
  292. }
  293. //==============================================================================
  294. // parseTrffbVarying =
  295. //==============================================================================
  296. void ShaderProgramPrePreprocessor::parseTrffbVarying(scanner::Scanner& scanner,
  297. const std::string& filename, uint /*depth*/,
  298. const Vector<std::string>& lines)
  299. {
  300. const scanner::Token* token = &scanner.getNextToken();
  301. if(token->getCode() == scanner::TC_IDENTIFIER)
  302. {
  303. std::string varName = token->getValue().getString();
  304. // check if already defined and for circular includance
  305. Vector<TrffbVaryingPragma>::const_iterator var =
  306. findNamed(output.trffbVaryings, varName);
  307. // Throw the correct exception
  308. if(var != output.trffbVaryings.end())
  309. {
  310. if(var->definedInLine == scanner.getLineNumber() &&
  311. var->definedInFile == filename)
  312. {
  313. throw PARSER_EXCEPTION("\"" + varName +
  314. "\"" + MULTIPLE_DEF_MSG);
  315. }
  316. else
  317. {
  318. throw PARSER_EXCEPTION("Varying \"" + varName +
  319. "\" already defined at " + var->definedInFile + ":" +
  320. boost::lexical_cast<std::string>(var->definedInLine));
  321. }
  322. }
  323. // all ok, push it back
  324. output.trffbVaryings.push_back(TrffbVaryingPragma(filename,
  325. scanner.getLineNumber(), varName));
  326. sourceLines.push_back(lines[scanner.getLineNumber() - 1]);
  327. }
  328. else
  329. {
  330. throw PARSER_EXCEPTION_EXPECTED("identifier");
  331. }
  332. }
  333. //==============================================================================
  334. // addLinePreProcExpression =
  335. //==============================================================================
  336. void ShaderProgramPrePreprocessor::addLinePreProcExpression(
  337. uint /*line*/, uint /*depth*/, const char* /*cmnt*/)
  338. {
  339. /*sourceLines.push_back("#line " +
  340. boost::lexical_cast<std::string>(line) +
  341. ' ' +
  342. boost::lexical_cast<std::string>(depth) +
  343. " // " +
  344. cmnt);*/
  345. }
  346. } // end namespace