BsGLSLGpuProgram.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #pragma once
  2. #include "BsGLSLGpuProgram.h"
  3. #include "BsRenderAPI.h"
  4. #include "BsException.h"
  5. #include "BsGLSLParamParser.h"
  6. #include "BsHardwareBufferManager.h"
  7. #include "BsRenderStats.h"
  8. #include "BsGpuParams.h"
  9. namespace BansheeEngine
  10. {
  11. UINT32 GLSLGpuProgramCore::mVertexShaderCount = 0;
  12. UINT32 GLSLGpuProgramCore::mFragmentShaderCount = 0;
  13. UINT32 GLSLGpuProgramCore::mGeometryShaderCount = 0;
  14. UINT32 GLSLGpuProgramCore::mDomainShaderCount = 0;
  15. UINT32 GLSLGpuProgramCore::mHullShaderCount = 0;
  16. bool checkForGLSLError(const GLuint programObj, String& outErrorMsg)
  17. {
  18. StringStream stream;
  19. GLint linkCompileSuccess = 0;
  20. glGetProgramiv(programObj, GL_LINK_STATUS, &linkCompileSuccess);
  21. GLenum glErr;
  22. bool errorsFound = false;
  23. glErr = glGetError();
  24. while (glErr != GL_NO_ERROR)
  25. {
  26. const char* glerrStr = (const char*)gluErrorString(glErr);
  27. if (glerrStr)
  28. {
  29. if (errorsFound)
  30. stream << "\nPrevious errors: \n";
  31. stream << String(glerrStr) << std::endl;;
  32. }
  33. glErr = glGetError();
  34. errorsFound = true;
  35. }
  36. if ((errorsFound || !linkCompileSuccess) && programObj > 0)
  37. {
  38. GLint infologLength = 0;
  39. glGetProgramiv(programObj, GL_INFO_LOG_LENGTH, &infologLength);
  40. if (infologLength > 0)
  41. {
  42. GLint charsWritten = 0;
  43. GLchar* infoLog = (GLchar*)bs_alloc<ScratchAlloc>(sizeof(GLchar)* infologLength);
  44. glGetProgramInfoLog(programObj, infologLength, &charsWritten, infoLog);
  45. stream << "Compile and linker info log: \n";
  46. stream << String(infoLog);
  47. bs_free<ScratchAlloc>(infoLog);
  48. }
  49. }
  50. outErrorMsg = stream.str();
  51. return errorsFound || !linkCompileSuccess;
  52. }
  53. GLSLGpuProgramCore::GLSLGpuProgramCore(const String& source, const String& entryPoint, GpuProgramType gptype,
  54. GpuProgramProfile profile, bool isAdjacencyInfoRequired)
  55. :GpuProgramCore(source, entryPoint, gptype, profile, isAdjacencyInfoRequired),
  56. mProgramID(0), mGLHandle(0)
  57. { }
  58. GLSLGpuProgramCore::~GLSLGpuProgramCore()
  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 GLSLGpuProgramCore::initialize()
  68. {
  69. static const char GLSL_VERSION_LINE[] = "#version 430\n";
  70. if (!isSupported())
  71. {
  72. mIsCompiled = false;
  73. mCompileError = "Specified program is not supported by the current render system.";
  74. GpuProgramCore::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. }
  101. // Add preprocessor extras and main source
  102. const String& source = mProperties.getSource();
  103. if (!source.empty())
  104. {
  105. Vector<GLchar*> lines;
  106. GLchar* firstLineData = (GLchar*)stackAlloc(sizeof(GLSL_VERSION_LINE));
  107. memcpy(firstLineData, GLSL_VERSION_LINE, sizeof(GLSL_VERSION_LINE));
  108. lines.push_back(firstLineData);
  109. UINT32 lineLength = 0;
  110. for (UINT32 i = 0; i < source.size(); i++)
  111. {
  112. if (source[i] == '\n' || source[i] == '\r')
  113. {
  114. if (lineLength > 0)
  115. {
  116. assert(sizeof(source[i]) == sizeof(GLchar));
  117. bool isDefine = source[i - lineLength] == '#';
  118. GLchar* lineData = (GLchar*)stackAlloc(sizeof(GLchar) * (lineLength + 1 + (isDefine ? 1 : 0)));
  119. memcpy(lineData, &source[i - lineLength], sizeof(GLchar) * lineLength);
  120. if (isDefine) // Defines require a newline as well as a null terminator, otherwise it doesn't compile properly
  121. {
  122. lineData[lineLength] = '\n';
  123. lineData[lineLength + 1] = '\0';
  124. }
  125. else
  126. lineData[lineLength] = '\0';
  127. lines.push_back(lineData);
  128. lineLength = 0;
  129. }
  130. }
  131. else
  132. {
  133. lineLength++;
  134. }
  135. }
  136. if (lineLength > 0)
  137. {
  138. UINT32 end = (UINT32)source.size() - 1;
  139. assert(sizeof(source[end]) == sizeof(GLchar));
  140. GLchar* lineData = (GLchar*)stackAlloc(sizeof(GLchar) * (lineLength + 1));
  141. memcpy(lineData, &source[source.size() - lineLength], sizeof(GLchar) * lineLength);
  142. lineData[lineLength] = '\0';
  143. lines.push_back(lineData);
  144. lineLength = 0;
  145. }
  146. mGLHandle = glCreateShaderProgramv(shaderType, (GLsizei)lines.size(), (const GLchar**)lines.data());
  147. for (auto iter = lines.rbegin(); iter != lines.rend(); ++iter)
  148. {
  149. stackDeallocLast(*iter);
  150. }
  151. mCompileError = "";
  152. mIsCompiled = !checkForGLSLError(mGLHandle, mCompileError);
  153. }
  154. if (mIsCompiled)
  155. {
  156. GLSLParamParser paramParser;
  157. paramParser.buildUniformDescriptions(mGLHandle, *mParametersDesc);
  158. if (mProperties.getType() == GPT_VERTEX_PROGRAM)
  159. {
  160. List<VertexElement> elementList = paramParser.buildVertexDeclaration(mGLHandle);
  161. mVertexDeclaration = HardwareBufferCoreManager::instance().createVertexDeclaration(elementList);
  162. }
  163. }
  164. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  165. GpuProgramCore::initialize();
  166. }
  167. bool GLSLGpuProgramCore::isSupported() const
  168. {
  169. if (!isRequiredCapabilitiesSupported())
  170. return false;
  171. RenderAPICore* rs = BansheeEngine::RenderAPICore::instancePtr();
  172. return rs->getCapabilities()->isShaderProfileSupported("glsl");
  173. }
  174. }