ShaderProgramPrePreprocessor.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include "anki/resource/ShaderProgramPrePreprocessor.h"
  2. #include "anki/util/Filesystem.h"
  3. #include "anki/util/Exception.h"
  4. #include "anki/util/Functions.h"
  5. #include <iomanip>
  6. #include <cstring>
  7. #include <iostream>
  8. namespace anki {
  9. //==============================================================================
  10. // Keep the strings in that order so that the start pragmas will match to the
  11. // ShaderType enums
  12. static Array<const char*, 8> commands = {{
  13. "#pragma anki start vertexShader",
  14. "#pragma anki start teShader",
  15. "#pragma anki start tcShader",
  16. "#pragma anki start geometryShader",
  17. "#pragma anki start fragmentShader",
  18. "#pragma anki include",
  19. "#pragma anki transformFeedbackVaryings separate",
  20. "#pragma anki transformFeedbackVaryings interleaved"}};
  21. static_assert(ST_VERTEX == 0 && ST_FRAGMENT == 4, "See file");
  22. static const char* ENTRYPOINT_NOT_DEFINED = "Entry point not defined: ";
  23. const U32 MAX_DEPTH = 8;
  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, U32 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. Last: " + filename);
  42. }
  43. // load file in lines
  44. StringList lines = readFileLines(filename.c_str());
  45. if(lines.size() < 1)
  46. {
  47. throw ANKI_EXCEPTION("File is empty: " + filename);
  48. }
  49. for(const std::string& line : lines)
  50. {
  51. std::string::size_type npos = 0;
  52. Bool expectPragmaAnki = false;
  53. Bool gotPragmaAnki = true;
  54. if(line.find("#pragma anki") == 0)
  55. {
  56. expectPragmaAnki = true;
  57. }
  58. if(line.find(commands[ST_VERTEX]) == 0)
  59. {
  60. parseStartPragma(ST_VERTEX, line);
  61. }
  62. else if(line.find(commands[ST_TC]) == 0)
  63. {
  64. parseStartPragma(ST_TC, line);
  65. }
  66. else if(line.find(commands[ST_TE]) == 0)
  67. {
  68. parseStartPragma(ST_TE, line);
  69. }
  70. else if(line.find(commands[ST_GEOMETRY]) == 0)
  71. {
  72. parseStartPragma(ST_GEOMETRY, line);
  73. }
  74. else if(line.find(commands[ST_FRAGMENT]) == 0)
  75. {
  76. parseStartPragma(ST_FRAGMENT, line);
  77. }
  78. else if((npos = line.find(commands[5])) == 0)
  79. {
  80. std::string filen = {line, strlen(commands[5]), std::string::npos};
  81. filen = trimString(filen, " \"");
  82. parseFileForPragmas(filen, depth + 1);
  83. }
  84. else if((npos = line.find(commands[6])) == 0)
  85. {
  86. std::string slist = {line, strlen(commands[6]), std::string::npos};
  87. trffbVaryings = StringList::splitString(slist.c_str(), ' ');
  88. xfbBufferMode = XFBBM_SEPARATE;
  89. }
  90. else if((npos = line.find(commands[7])) == 0)
  91. {
  92. std::string slist = {line, strlen(commands[7]), std::string::npos};
  93. trffbVaryings = StringList::splitString(slist.c_str(), ' ');
  94. xfbBufferMode = XFBBM_INTERLEAVED;
  95. }
  96. else
  97. {
  98. gotPragmaAnki = false;
  99. sourceLines.push_back(line);
  100. }
  101. // Sanity check
  102. if(expectPragmaAnki && !gotPragmaAnki)
  103. {
  104. throw ANKI_EXCEPTION("Malformed pragma anki: " + line);
  105. }
  106. }
  107. }
  108. //==============================================================================
  109. void ShaderProgramPrePreprocessor::parseFile(const char* filename)
  110. {
  111. try
  112. {
  113. parseFileInternal(filename);
  114. }
  115. catch(Exception& e)
  116. {
  117. throw ANKI_EXCEPTION("Loading file failed: " + filename) << e;
  118. }
  119. }
  120. //==============================================================================
  121. void ShaderProgramPrePreprocessor::parseFileInternal(const char* filename)
  122. {
  123. // parse master file
  124. parseFileForPragmas(filename);
  125. // sanity checks
  126. if(!shaderStarts[ST_VERTEX].isDefined())
  127. {
  128. throw ANKI_EXCEPTION(ENTRYPOINT_NOT_DEFINED
  129. + commands[ST_VERTEX]);
  130. }
  131. if(!shaderStarts[ST_FRAGMENT].isDefined())
  132. {
  133. throw ANKI_EXCEPTION(ENTRYPOINT_NOT_DEFINED
  134. + commands[ST_FRAGMENT]);
  135. }
  136. // construct each shaders' source code
  137. for(U i = 0; i < ST_NUM; i++)
  138. {
  139. // If not defined bb
  140. if(!shaderStarts[i].isDefined())
  141. {
  142. continue;
  143. }
  144. std::string& src = shaderSources[i];
  145. src = "";
  146. // Sanity check: Check the correct order of i
  147. I32 k = (I32)i - 1;
  148. while(k > -1)
  149. {
  150. if(shaderStarts[k].isDefined()
  151. && shaderStarts[k].definedLine >= shaderStarts[i].definedLine)
  152. {
  153. throw ANKI_EXCEPTION(commands[i] + " must be after "
  154. + commands[k]);
  155. }
  156. --k;
  157. }
  158. k = (I32)i + 1;
  159. while(k < ST_NUM)
  160. {
  161. if(shaderStarts[k].isDefined()
  162. && shaderStarts[k].definedLine <= shaderStarts[i].definedLine)
  163. {
  164. throw ANKI_EXCEPTION(commands[k] + " must be after "
  165. + commands[i]);
  166. }
  167. ++k;
  168. }
  169. // put global source code
  170. for(I32 j = 0; j < shaderStarts[ST_VERTEX].definedLine; ++j)
  171. {
  172. src += sourceLines[j] + "\n";
  173. }
  174. // put the actual code
  175. U32 from = i;
  176. U32 to;
  177. for(to = i + 1; to < ST_NUM; to++)
  178. {
  179. if(shaderStarts[to].definedLine != -1)
  180. {
  181. break;
  182. }
  183. }
  184. I32 toLine = (to == ST_NUM) ? sourceLines.size()
  185. : shaderStarts[to].definedLine;
  186. for(I32 j = shaderStarts[from].definedLine; j < toLine; ++j)
  187. {
  188. src += sourceLines[j] + "\n";
  189. }
  190. }
  191. //PRINT("vertShaderBegins.globalLine: " << vertShaderBegins.globalLine)
  192. //PRINT("fragShaderBegins.globalLine: " << fragShaderBegins.globalLine)
  193. //printSourceLines();
  194. //printShaderVars();
  195. }
  196. //==============================================================================
  197. void ShaderProgramPrePreprocessor::parseStartPragma(U32 shaderType,
  198. const std::string& line)
  199. {
  200. CodeBeginningPragma& pragma = shaderStarts[shaderType];
  201. if(pragma.definedLine != -1)
  202. {
  203. throw ANKI_EXCEPTION("Redefinition of: " + commands[shaderType]);
  204. }
  205. pragma.definedLine = sourceLines.size();
  206. sourceLines.push_back("//" + line);
  207. }
  208. } // end namespace anki