BsGLSLGpuProgram.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. GLenum glErr;
  24. bool errorsFound = false;
  25. glErr = glGetError();
  26. while (glErr != GL_NO_ERROR)
  27. {
  28. const char* glerrStr = (const char*)gluErrorString(glErr);
  29. if (glerrStr)
  30. {
  31. if (errorsFound)
  32. stream << "\nPrevious errors: \n";
  33. stream << String(glerrStr) << std::endl;;
  34. }
  35. glErr = glGetError();
  36. errorsFound = true;
  37. }
  38. if ((errorsFound || !linkCompileSuccess) && programObj > 0)
  39. {
  40. GLint infologLength = 0;
  41. glGetProgramiv(programObj, GL_INFO_LOG_LENGTH, &infologLength);
  42. if (infologLength > 0)
  43. {
  44. GLint charsWritten = 0;
  45. GLchar* infoLog = (GLchar*)bs_alloc(sizeof(GLchar)* infologLength);
  46. glGetProgramInfoLog(programObj, infologLength, &charsWritten, infoLog);
  47. stream << "Compile and linker info log: \n";
  48. stream << String(infoLog);
  49. bs_free(infoLog);
  50. }
  51. }
  52. outErrorMsg = stream.str();
  53. return errorsFound || !linkCompileSuccess;
  54. }
  55. GLSLGpuProgram::GLSLGpuProgram(const GPU_PROGRAM_DESC& desc, GpuDeviceFlags deviceMask)
  56. :GpuProgram(desc, deviceMask), mProgramID(0), mGLHandle(0)
  57. { }
  58. GLSLGpuProgram::~GLSLGpuProgram()
  59. {
  60. if (mIsCompiled && mGLHandle != 0)
  61. {
  62. glDeleteProgram(mGLHandle);
  63. mGLHandle = 0;
  64. }
  65. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  66. }
  67. void GLSLGpuProgram::initialize()
  68. {
  69. static const char* VERSION_LINE = "#version 450\n";
  70. if (!isSupported())
  71. {
  72. mIsCompiled = false;
  73. mCompileError = "Specified program is not supported by the current render system.";
  74. GpuProgram::initialize();
  75. return;
  76. }
  77. GLenum shaderType = 0x0000;
  78. switch (mProperties.getType())
  79. {
  80. case GPT_VERTEX_PROGRAM:
  81. shaderType = GL_VERTEX_SHADER;
  82. mProgramID = ++mVertexShaderCount;
  83. break;
  84. case GPT_FRAGMENT_PROGRAM:
  85. shaderType = GL_FRAGMENT_SHADER;
  86. mProgramID = ++mFragmentShaderCount;
  87. break;
  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. case GPT_COMPUTE_PROGRAM:
  101. shaderType = GL_COMPUTE_SHADER;
  102. mProgramID = ++mComputeShaderCount;
  103. break;
  104. }
  105. // Add preprocessor extras and main source
  106. const String& source = mProperties.getSource();
  107. if (!source.empty())
  108. {
  109. Vector<GLchar*> lines;
  110. const char* versionStr = "#version ";
  111. UINT32 versionStrLen = (UINT32)strlen(versionStr);
  112. UINT32 lineLength = 0;
  113. INT32 versionLine = -1;
  114. for (UINT32 i = 0; i < source.size(); i++)
  115. {
  116. if (source[i] == '\n' || source[i] == '\r')
  117. {
  118. assert(sizeof(source[i]) == sizeof(GLchar));
  119. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 2));
  120. memcpy(lineData, &source[i - lineLength], sizeof(GLchar) * lineLength);
  121. lineData[lineLength] = '\n';
  122. lineData[lineLength + 1] = '\0';
  123. if(versionLine == -1 && lineLength >= versionStrLen)
  124. {
  125. bool isEqual = true;
  126. for (UINT32 j = 0; j < versionStrLen; ++j)
  127. {
  128. if(lineData[j] != versionStr[j])
  129. {
  130. isEqual = false;
  131. break;
  132. }
  133. }
  134. if (isEqual)
  135. versionLine = (INT32)lines.size();
  136. }
  137. lines.push_back(lineData);
  138. lineLength = 0;
  139. }
  140. else
  141. {
  142. lineLength++;
  143. }
  144. }
  145. if (lineLength > 0)
  146. {
  147. UINT32 end = (UINT32)source.size() - 1;
  148. assert(sizeof(source[end]) == sizeof(GLchar));
  149. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 1));
  150. memcpy(lineData, &source[source.size() - lineLength], sizeof(GLchar) * lineLength);
  151. lineData[lineLength] = '\0';
  152. lines.push_back(lineData);
  153. lineLength = 0;
  154. }
  155. int numInsertedLines = 0;
  156. if(versionLine == -1)
  157. {
  158. UINT32 length = (UINT32)strlen(VERSION_LINE) + 1;
  159. GLchar* extraLineData = (GLchar*)bs_stack_alloc(length);
  160. memcpy(extraLineData, VERSION_LINE, length);
  161. lines.insert(lines.begin(), extraLineData);
  162. numInsertedLines++;
  163. }
  164. static const char* EXTRA_LINES[] = { "#define OPENGL\n" };
  165. UINT32 numExtraLines = sizeof(EXTRA_LINES) / sizeof(EXTRA_LINES[0]);
  166. UINT32 extraLineOffset = versionLine != -1 ? versionLine + 1 : 0;
  167. for (UINT32 i = 0; i < numExtraLines; i++)
  168. {
  169. UINT32 length = (UINT32)strlen(EXTRA_LINES[i]) + 1;
  170. GLchar* extraLineData = (GLchar*)bs_stack_alloc(length);
  171. memcpy(extraLineData, EXTRA_LINES[i], length);
  172. lines.insert(lines.begin() + extraLineOffset + numInsertedLines, extraLineData);
  173. numInsertedLines++;
  174. }
  175. mGLHandle = glCreateShaderProgramv(shaderType, (GLsizei)lines.size(), (const GLchar**)lines.data());
  176. for (INT32 i = numInsertedLines - 1; i >= 0; i--)
  177. bs_stack_free(lines[extraLineOffset + i]);
  178. if (numInsertedLines > 0)
  179. lines.erase(lines.begin() + extraLineOffset, lines.begin() + extraLineOffset + numInsertedLines);
  180. for (auto iter = lines.rbegin(); iter != lines.rend(); ++iter)
  181. bs_stack_free(*iter);
  182. mCompileError = "";
  183. mIsCompiled = !checkForGLSLError(mGLHandle, mCompileError);
  184. }
  185. if (mIsCompiled)
  186. {
  187. GLSLParamParser paramParser;
  188. paramParser.buildUniformDescriptions(mGLHandle, mProperties.getType(), *mParametersDesc);
  189. if (mProperties.getType() == GPT_VERTEX_PROGRAM)
  190. {
  191. List<VertexElement> elementList = paramParser.buildVertexDeclaration(mGLHandle);
  192. mInputDeclaration = HardwareBufferManager::instance().createVertexDeclaration(elementList);
  193. }
  194. }
  195. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  196. GpuProgram::initialize();
  197. }
  198. bool GLSLGpuProgram::isSupported() const
  199. {
  200. if (!isRequiredCapabilitiesSupported())
  201. return false;
  202. RenderAPI* rapi = RenderAPI::instancePtr();
  203. return rapi->getCapabilities(0).isShaderProfileSupported("glsl");
  204. }
  205. }}