ShaderProgram.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #include "Resources/ShaderProgram.h"
  2. #include "ShaderProgramPrePreprocessor.h"
  3. #include "Core/App.h" // To get cache dir
  4. #include "GfxApi/GlException.h"
  5. #include "Core/Logger.h"
  6. #include "Util/Util.h"
  7. #include "Core/Globals.h"
  8. #include "Util/Exception.h"
  9. #include <boost/filesystem.hpp>
  10. #include <boost/lexical_cast.hpp>
  11. #include <boost/foreach.hpp>
  12. #include <boost/functional/hash.hpp>
  13. #include <fstream>
  14. #include <sstream>
  15. #define SHADER_PROGRAM_EXCEPTION(x) EXCEPTION( \
  16. "Shader program \"" + rsrcFilename + \
  17. "\": " + x)
  18. //==============================================================================
  19. // Statics =
  20. //==============================================================================
  21. const char* ShaderProgram::stdSourceCode =
  22. "#version 330 core\n"
  23. "precision lowp float;\n"
  24. "#pragma optimize(on)\n"
  25. "#pragma debug(off)\n";
  26. //==============================================================================
  27. // Destructor =
  28. //==============================================================================
  29. ShaderProgram::~ShaderProgram()
  30. {
  31. /// @todo add code
  32. }
  33. //==============================================================================
  34. // createAndCompileShader =
  35. //==============================================================================
  36. uint ShaderProgram::createAndCompileShader(const char* sourceCode,
  37. const char* preproc, int type) const
  38. {
  39. uint glId = 0;
  40. const char* sourceStrs[2] = {NULL, NULL};
  41. // create the shader
  42. glId = glCreateShader(type);
  43. // attach the source
  44. sourceStrs[1] = sourceCode;
  45. sourceStrs[0] = preproc;
  46. // compile
  47. glShaderSource(glId, 2, sourceStrs, NULL);
  48. glCompileShader(glId);
  49. int success;
  50. glGetShaderiv(glId, GL_COMPILE_STATUS, &success);
  51. if(!success)
  52. {
  53. // print info log
  54. int infoLen = 0;
  55. int charsWritten = 0;
  56. Vec<char> infoLog;
  57. glGetShaderiv(glId, GL_INFO_LOG_LENGTH, &infoLen);
  58. infoLog.resize(infoLen + 1);
  59. glGetShaderInfoLog(glId, infoLen, &charsWritten, &infoLog[0]);
  60. infoLog[charsWritten] = '\0';
  61. const char* shaderType = "*dummy*";
  62. switch(type)
  63. {
  64. case GL_VERTEX_SHADER:
  65. shaderType = "Vertex shader";
  66. break;
  67. case GL_FRAGMENT_SHADER:
  68. shaderType = "Fragment shader";
  69. break;
  70. default:
  71. ASSERT(0); // Not supported
  72. }
  73. throw SHADER_PROGRAM_EXCEPTION(shaderType +
  74. " compiler error log follows:\n"
  75. "===================================\n" +
  76. &infoLog[0] +
  77. "\n===================================\n" + sourceCode);
  78. }
  79. return glId;
  80. }
  81. //==============================================================================
  82. // link =
  83. //==============================================================================
  84. void ShaderProgram::link() const
  85. {
  86. // link
  87. glLinkProgram(glId);
  88. // check if linked correctly
  89. int success;
  90. glGetProgramiv(glId, GL_LINK_STATUS, &success);
  91. if(!success)
  92. {
  93. int info_len = 0;
  94. int charsWritten = 0;
  95. std::string infoLogTxt;
  96. glGetProgramiv(glId, GL_INFO_LOG_LENGTH, &info_len);
  97. infoLogTxt.resize(info_len + 1);
  98. glGetProgramInfoLog(glId, info_len, &charsWritten, &infoLogTxt[0]);
  99. throw SHADER_PROGRAM_EXCEPTION("Link error log follows:\n" +
  100. infoLogTxt);
  101. }
  102. }
  103. //==============================================================================
  104. // getUniAndAttribVars =
  105. //==============================================================================
  106. void ShaderProgram::getUniAndAttribVars()
  107. {
  108. int num;
  109. boost::array<char, 256> name_;
  110. GLsizei length;
  111. GLint size;
  112. GLenum type;
  113. // attrib locations
  114. glGetProgramiv(glId, GL_ACTIVE_ATTRIBUTES, &num);
  115. for(int i = 0; i < num; i++) // loop all attributes
  116. {
  117. glGetActiveAttrib(glId, i, sizeof(name_) / sizeof(char), &length,
  118. &size, &type, &name_[0]);
  119. name_[length] = '\0';
  120. // check if its FFP location
  121. int loc = glGetAttribLocation(glId, &name_[0]);
  122. if(loc == -1) // if -1 it means that its an FFP var
  123. {
  124. WARNING("Shader prog: \"" << rsrcFilename <<
  125. "\": You are using FFP vertex attributes (\"" <<
  126. &name_[0] << "\")");
  127. continue;
  128. }
  129. ShaderProgramAttributeVariable* var =
  130. new ShaderProgramAttributeVariable(loc, &name_[0], type, *this);
  131. vars.push_back(var);
  132. nameToVar[var->getName().c_str()] = var;
  133. nameToAttribVar[var->getName().c_str()] = var;
  134. }
  135. // uni locations
  136. glGetProgramiv(glId, GL_ACTIVE_UNIFORMS, &num);
  137. for(int i = 0; i < num; i++) // loop all uniforms
  138. {
  139. glGetActiveUniform(glId, i, sizeof(name_) / sizeof(char), &length,
  140. &size, &type, &name_[0]);
  141. name_[length] = '\0';
  142. // check if its FFP location
  143. int loc = glGetUniformLocation(glId, &name_[0]);
  144. if(loc == -1) // if -1 it means that its an FFP var
  145. {
  146. WARNING("Shader prog: \"" << rsrcFilename <<
  147. "\": You are using FFP vertex uniforms (\"" <<
  148. &name_[0] << "\")");
  149. continue;
  150. }
  151. ShaderProgramUniformVariable* var =
  152. new ShaderProgramUniformVariable(loc, &name_[0], type, *this);
  153. vars.push_back(var);
  154. nameToVar[var->getName().c_str()] = var;
  155. nameToUniVar[var->getName().c_str()] = var;
  156. }
  157. }
  158. //==============================================================================
  159. // load =
  160. //==============================================================================
  161. void ShaderProgram::load(const char* filename)
  162. {
  163. rsrcFilename = filename;
  164. ASSERT(glId == std::numeric_limits<uint>::max());
  165. ShaderProgramPrePreprocessor pars(filename);
  166. // 1) create and compile the shaders
  167. std::string preprocSource = stdSourceCode;
  168. vertShaderGlId = createAndCompileShader(
  169. pars.getVertexShaderSource().c_str(),
  170. preprocSource.c_str(),
  171. GL_VERTEX_SHADER);
  172. fragShaderGlId = createAndCompileShader(
  173. pars.getFragmentShaderSource().c_str(),
  174. preprocSource.c_str(),
  175. GL_FRAGMENT_SHADER);
  176. // 2) create program and attach shaders
  177. glId = glCreateProgram();
  178. if(glId == 0)
  179. {
  180. throw SHADER_PROGRAM_EXCEPTION("glCreateProgram failed");
  181. }
  182. glAttachShader(glId, vertShaderGlId);
  183. glAttachShader(glId, fragShaderGlId);
  184. // 3) set the TRFFB varyings
  185. if(pars.getTranformFeedbackVaryings().size() > 0)
  186. {
  187. boost::array<const char*, 128> varsArr;
  188. for(uint i = 0; i < pars.getTranformFeedbackVaryings().size(); i++)
  189. {
  190. varsArr[i] = pars.getTranformFeedbackVaryings()[i].c_str();
  191. }
  192. glTransformFeedbackVaryings(glId,
  193. pars.getTranformFeedbackVaryings().size(), &varsArr[0],
  194. GL_SEPARATE_ATTRIBS);
  195. }
  196. // 4) link
  197. link();
  198. // init the rest
  199. getUniAndAttribVars();
  200. }
  201. //==============================================================================
  202. // getVariableByName =
  203. //==============================================================================
  204. const ShaderProgramVariable& ShaderProgram::getVariableByName(
  205. const char* name) const
  206. {
  207. VarsHashMap::const_iterator it = nameToVar.find(name);
  208. if(it == nameToVar.end())
  209. {
  210. throw SHADER_PROGRAM_EXCEPTION("Cannot get variable: " + name);
  211. }
  212. return *(it->second);
  213. }
  214. //==============================================================================
  215. // getAttributeVariableByName =
  216. //==============================================================================
  217. const ShaderProgramAttributeVariable& ShaderProgram::getAttributeVariableByName(
  218. const char* name) const
  219. {
  220. AttribVarsHashMap::const_iterator it = nameToAttribVar.find(name);
  221. if(it == nameToAttribVar.end())
  222. {
  223. throw SHADER_PROGRAM_EXCEPTION("Cannot get attribute loc: " + name);
  224. }
  225. return *(it->second);
  226. }
  227. //==============================================================================
  228. // getUniformVariableByName =
  229. //==============================================================================
  230. const ShaderProgramUniformVariable& ShaderProgram::getUniformVariableByName(
  231. const char* name) const
  232. {
  233. UniVarsHashMap::const_iterator it = nameToUniVar.find(name);
  234. if(it == nameToUniVar.end())
  235. {
  236. throw SHADER_PROGRAM_EXCEPTION("Cannot get uniform loc: " + name);
  237. }
  238. return *(it->second);
  239. }
  240. //==============================================================================
  241. // variableExists =
  242. //==============================================================================
  243. bool ShaderProgram::variableExists(const char* name) const
  244. {
  245. VarsHashMap::const_iterator it = nameToVar.find(name);
  246. return it != nameToVar.end();
  247. }
  248. //==============================================================================
  249. // uniformVariableExists =
  250. //==============================================================================
  251. bool ShaderProgram::uniformVariableExists(const char* name) const
  252. {
  253. UniVarsHashMap::const_iterator it = nameToUniVar.find(name);
  254. return it != nameToUniVar.end();
  255. }
  256. //==============================================================================
  257. // attributeVariableExists =
  258. //==============================================================================
  259. bool ShaderProgram::attributeVariableExists(const char* name) const
  260. {
  261. AttribVarsHashMap::const_iterator it = nameToAttribVar.find(name);
  262. return it != nameToAttribVar.end();
  263. }
  264. //==============================================================================
  265. // createSrcCodeToCache =
  266. //==============================================================================
  267. std::string ShaderProgram::createSrcCodeToCache(const char* sProgFPathName,
  268. const char* preAppendedSrcCode)
  269. {
  270. if(strlen(preAppendedSrcCode) < 1)
  271. {
  272. return sProgFPathName;
  273. }
  274. // Create suffix
  275. boost::hash<std::string> stringHash;
  276. std::size_t h = stringHash(preAppendedSrcCode);
  277. std::string suffix = boost::lexical_cast<std::string>(h);
  278. //
  279. boost::filesystem::path newfPathName =
  280. AppSingleton::getInstance().getCachePath() /
  281. (boost::filesystem::path(sProgFPathName).filename() + "." + suffix);
  282. if(boost::filesystem::exists(newfPathName))
  283. {
  284. return newfPathName.string();
  285. }
  286. std::string src_ = Util::readFile(sProgFPathName);
  287. std::string src = preAppendedSrcCode + src_;
  288. std::ofstream f(newfPathName.string().c_str());
  289. if(!f.is_open())
  290. {
  291. throw EXCEPTION("Cannot open file for writing \"" +
  292. newfPathName.string() + "\"");
  293. }
  294. f.write(src.c_str(), src.length());
  295. return newfPathName.string();
  296. }
  297. //==============================================================================
  298. // getShaderInfoString =
  299. //==============================================================================
  300. std::string ShaderProgram::getShaderInfoString() const
  301. {
  302. std::stringstream ss;
  303. ss << "Variables:\n";
  304. BOOST_FOREACH(const ShaderProgramVariable& var, vars)
  305. {
  306. ss << var.getName() << " " << var.getLoc() << " ";
  307. if(var.getType() == ShaderProgramVariable::T_ATTRIBUTE)
  308. {
  309. ss << "attribute";
  310. }
  311. else
  312. {
  313. ss << "uniform";
  314. }
  315. ss << std::endl;
  316. }
  317. return ss.str();
  318. }