BsGLSLGpuProgram.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "GLSL/BsGLSLGpuProgram.h"
  4. #include "RenderAPI/BsRenderAPI.h"
  5. #include "Error/BsException.h"
  6. #include "GLSL/BsGLSLParamParser.h"
  7. #include "Managers/BsHardwareBufferManager.h"
  8. #include "Profiling/BsRenderStats.h"
  9. #include "RenderAPI/BsGpuParams.h"
  10. namespace bs { namespace ct
  11. {
  12. UINT32 GLSLGpuProgram::mVertexShaderCount = 0;
  13. UINT32 GLSLGpuProgram::mFragmentShaderCount = 0;
  14. UINT32 GLSLGpuProgram::mGeometryShaderCount = 0;
  15. UINT32 GLSLGpuProgram::mDomainShaderCount = 0;
  16. UINT32 GLSLGpuProgram::mHullShaderCount = 0;
  17. UINT32 GLSLGpuProgram::mComputeShaderCount = 0;
  18. bool checkForGLSLError(const GLuint programObj, String& outErrorMsg)
  19. {
  20. StringStream stream;
  21. GLint linkCompileSuccess = 0;
  22. glGetProgramiv(programObj, GL_LINK_STATUS, &linkCompileSuccess);
  23. BS_CHECK_GL_ERROR();
  24. if (!linkCompileSuccess && programObj > 0)
  25. {
  26. GLint infologLength = 0;
  27. glGetProgramiv(programObj, GL_INFO_LOG_LENGTH, &infologLength);
  28. BS_CHECK_GL_ERROR();
  29. if (infologLength > 0)
  30. {
  31. GLint charsWritten = 0;
  32. GLchar* infoLog = (GLchar*)bs_alloc(sizeof(GLchar)* infologLength);
  33. glGetProgramInfoLog(programObj, infologLength, &charsWritten, infoLog);
  34. BS_CHECK_GL_ERROR();
  35. stream << "Compile and linker info log: \n";
  36. stream << String(infoLog);
  37. bs_free(infoLog);
  38. }
  39. }
  40. outErrorMsg = stream.str();
  41. return !linkCompileSuccess;
  42. }
  43. GLSLGpuProgram::GLSLGpuProgram(const GPU_PROGRAM_DESC& desc, GpuDeviceFlags deviceMask)
  44. :GpuProgram(desc, deviceMask), mProgramID(0), mGLHandle(0)
  45. { }
  46. GLSLGpuProgram::~GLSLGpuProgram()
  47. {
  48. if (mIsCompiled && mGLHandle != 0)
  49. {
  50. glDeleteProgram(mGLHandle);
  51. BS_CHECK_GL_ERROR();
  52. mGLHandle = 0;
  53. }
  54. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  55. }
  56. void GLSLGpuProgram::initialize()
  57. {
  58. #if BS_OPENGL_4_5
  59. static const char* VERSION_CHARS = "450";
  60. #elif BS_OPENGL_4_4
  61. static const char* VERSION_CHARS = "440";
  62. #elif BS_OPENGL_4_3
  63. static const char* VERSION_CHARS = "430";
  64. #elif BS_OPENGL_4_2
  65. static const char* VERSION_CHARS = "420";
  66. #else
  67. static const char* VERSION_CHARS = "410";
  68. #endif
  69. if (!isSupported())
  70. {
  71. mIsCompiled = false;
  72. mCompileError = "Specified GPU program type is not supported by the current render system.";
  73. GpuProgram::initialize();
  74. return;
  75. }
  76. GLenum shaderType = 0x0000;
  77. switch (mProperties.getType())
  78. {
  79. case GPT_VERTEX_PROGRAM:
  80. shaderType = GL_VERTEX_SHADER;
  81. mProgramID = ++mVertexShaderCount;
  82. break;
  83. case GPT_FRAGMENT_PROGRAM:
  84. shaderType = GL_FRAGMENT_SHADER;
  85. mProgramID = ++mFragmentShaderCount;
  86. break;
  87. #if BS_OPENGL_4_1 || BS_OPENGLES_3_2
  88. case GPT_GEOMETRY_PROGRAM:
  89. shaderType = GL_GEOMETRY_SHADER;
  90. mProgramID = ++mGeometryShaderCount;
  91. break;
  92. case GPT_HULL_PROGRAM:
  93. shaderType = GL_TESS_CONTROL_SHADER;
  94. mProgramID = ++mDomainShaderCount;
  95. break;
  96. case GPT_DOMAIN_PROGRAM:
  97. shaderType = GL_TESS_EVALUATION_SHADER;
  98. mProgramID = ++mHullShaderCount;
  99. break;
  100. #endif
  101. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  102. case GPT_COMPUTE_PROGRAM:
  103. shaderType = GL_COMPUTE_SHADER;
  104. mProgramID = ++mComputeShaderCount;
  105. break;
  106. #endif
  107. default:
  108. break;
  109. }
  110. // Add preprocessor extras and main source
  111. const String& source = mProperties.getSource();
  112. if (!source.empty())
  113. {
  114. Vector<GLchar*> lines;
  115. const char* versionStr = "#version ";
  116. UINT32 versionStrLen = (UINT32)strlen(versionStr);
  117. UINT32 lineLength = 0;
  118. INT32 versionLineNum = -1;
  119. for (UINT32 i = 0; i < source.size(); i++)
  120. {
  121. if (source[i] == '\n' || source[i] == '\r')
  122. {
  123. assert(sizeof(source[i]) == sizeof(GLchar));
  124. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 2));
  125. memcpy(lineData, &source[i - lineLength], sizeof(GLchar) * lineLength);
  126. lineData[lineLength] = '\n';
  127. lineData[lineLength + 1] = '\0';
  128. if(versionLineNum == -1 && lineLength >= versionStrLen)
  129. {
  130. bool isEqual = true;
  131. for (UINT32 j = 0; j < versionStrLen; ++j)
  132. {
  133. if(lineData[j] != versionStr[j])
  134. {
  135. isEqual = false;
  136. break;
  137. }
  138. }
  139. if (isEqual)
  140. versionLineNum = (INT32)lines.size();
  141. }
  142. lines.push_back(lineData);
  143. lineLength = 0;
  144. }
  145. else
  146. {
  147. lineLength++;
  148. }
  149. }
  150. if (lineLength > 0)
  151. {
  152. UINT32 end = (UINT32)source.size() - 1;
  153. assert(sizeof(source[end]) == sizeof(GLchar));
  154. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 1));
  155. memcpy(lineData, &source[source.size() - lineLength], sizeof(GLchar) * lineLength);
  156. lineData[lineLength] = '\0';
  157. lines.push_back(lineData);
  158. lineLength = 0;
  159. }
  160. int numInsertedLines = 0;
  161. if(versionLineNum == -1)
  162. {
  163. char versionLine[50];
  164. strcpy(versionLine, "#version ");
  165. strcat(versionLine, VERSION_CHARS);
  166. strcat(versionLine, "\n");
  167. UINT32 length = (UINT32)strlen(versionLine) + 1;
  168. GLchar* extraLineData = (GLchar*)bs_stack_alloc(length);
  169. memcpy(extraLineData, versionLine, length);
  170. lines.insert(lines.begin(), extraLineData);
  171. numInsertedLines++;
  172. }
  173. char versionDefine[50];
  174. strcpy(versionDefine, "#define OPENGL");
  175. strcat(versionDefine, VERSION_CHARS);
  176. strcat(versionDefine, "\n");
  177. static const char* EXTRA_LINES[] =
  178. {
  179. "#define OPENGL\n",
  180. versionDefine
  181. };
  182. UINT32 numExtraLines = sizeof(EXTRA_LINES) / sizeof(EXTRA_LINES[0]);
  183. UINT32 extraLineOffset = versionLineNum != -1 ? versionLineNum + 1 : 0;
  184. for (UINT32 i = 0; i < numExtraLines; i++)
  185. {
  186. UINT32 length = (UINT32)strlen(EXTRA_LINES[i]) + 1;
  187. GLchar* extraLineData = (GLchar*)bs_stack_alloc(length);
  188. memcpy(extraLineData, EXTRA_LINES[i], length);
  189. lines.insert(lines.begin() + extraLineOffset + numInsertedLines, extraLineData);
  190. numInsertedLines++;
  191. }
  192. StringStream codeStream;
  193. for(auto& entry : lines)
  194. codeStream << entry;
  195. for (INT32 i = numInsertedLines - 1; i >= 0; i--)
  196. bs_stack_free(lines[extraLineOffset + i]);
  197. if (numInsertedLines > 0)
  198. lines.erase(lines.begin() + extraLineOffset, lines.begin() + extraLineOffset + numInsertedLines);
  199. for (auto iter = lines.rbegin(); iter != lines.rend(); ++iter)
  200. bs_stack_free(*iter);
  201. String code = codeStream.str();
  202. const char* codeRaw = code.c_str();
  203. mGLHandle = glCreateShaderProgramv(shaderType, 1, (const GLchar**)&codeRaw);
  204. BS_CHECK_GL_ERROR();
  205. mCompileError = "";
  206. mIsCompiled = !checkForGLSLError(mGLHandle, mCompileError);
  207. // DEBUG ONLY
  208. if(!mIsCompiled)
  209. {
  210. LOGWRN(mCompileError);
  211. }
  212. }
  213. if (mIsCompiled)
  214. {
  215. GLSLParamParser paramParser;
  216. paramParser.buildUniformDescriptions(mGLHandle, mProperties.getType(), *mParametersDesc);
  217. if (mProperties.getType() == GPT_VERTEX_PROGRAM)
  218. {
  219. List<VertexElement> elementList = paramParser.buildVertexDeclaration(mGLHandle);
  220. mInputDeclaration = HardwareBufferManager::instance().createVertexDeclaration(elementList);
  221. }
  222. }
  223. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  224. GpuProgram::initialize();
  225. }
  226. bool GLSLGpuProgram::isSupported() const
  227. {
  228. RenderAPI* rapi = RenderAPI::instancePtr();
  229. const RenderAPICapabilities& caps = rapi->getCapabilities(0);
  230. switch (mProperties.getType())
  231. {
  232. case GPT_GEOMETRY_PROGRAM:
  233. #if BS_OPENGL_4_1 || BS_OPENGLES_3_2
  234. return caps.hasCapability(RSC_GEOMETRY_PROGRAM);
  235. #else
  236. return false;
  237. #endif
  238. case GPT_HULL_PROGRAM:
  239. case GPT_DOMAIN_PROGRAM:
  240. #if BS_OPENGL_4_1 || BS_OPENGLES_3_2
  241. return caps.hasCapability(RSC_TESSELLATION_PROGRAM);
  242. #else
  243. return false;
  244. #endif
  245. case GPT_COMPUTE_PROGRAM:
  246. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  247. return caps.hasCapability(RSC_COMPUTE_PROGRAM);
  248. #else
  249. return false;
  250. #endif
  251. default:
  252. return true;
  253. }
  254. }
  255. }}