BsGLSLGpuProgram.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsGLSLGpuProgram.h"
  5. #include "BsRenderAPI.h"
  6. #include "BsException.h"
  7. #include "BsGLSLParamParser.h"
  8. #include "BsHardwareBufferManager.h"
  9. #include "BsRenderStats.h"
  10. #include "BsGpuParams.h"
  11. namespace BansheeEngine
  12. {
  13. UINT32 GLSLGpuProgramCore::mVertexShaderCount = 0;
  14. UINT32 GLSLGpuProgramCore::mFragmentShaderCount = 0;
  15. UINT32 GLSLGpuProgramCore::mGeometryShaderCount = 0;
  16. UINT32 GLSLGpuProgramCore::mDomainShaderCount = 0;
  17. UINT32 GLSLGpuProgramCore::mHullShaderCount = 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. GLSLGpuProgramCore::GLSLGpuProgramCore(const String& source, const String& entryPoint, GpuProgramType gptype,
  56. GpuProgramProfile profile, bool isAdjacencyInfoRequired)
  57. :GpuProgramCore(source, entryPoint, gptype, profile, isAdjacencyInfoRequired),
  58. mProgramID(0), mGLHandle(0)
  59. { }
  60. GLSLGpuProgramCore::~GLSLGpuProgramCore()
  61. {
  62. if (mIsCompiled && mGLHandle != 0)
  63. {
  64. glDeleteProgram(mGLHandle);
  65. mGLHandle = 0;
  66. }
  67. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
  68. }
  69. void GLSLGpuProgramCore::initialize()
  70. {
  71. static const char GLSL_VERSION_LINE[] = "#version 430\n";
  72. if (!isSupported())
  73. {
  74. mIsCompiled = false;
  75. mCompileError = "Specified program is not supported by the current render system.";
  76. GpuProgramCore::initialize();
  77. return;
  78. }
  79. GLenum shaderType = 0x0000;
  80. switch (mProperties.getType())
  81. {
  82. case GPT_VERTEX_PROGRAM:
  83. shaderType = GL_VERTEX_SHADER;
  84. mProgramID = ++mVertexShaderCount;
  85. break;
  86. case GPT_FRAGMENT_PROGRAM:
  87. shaderType = GL_FRAGMENT_SHADER;
  88. mProgramID = ++mFragmentShaderCount;
  89. break;
  90. case GPT_GEOMETRY_PROGRAM:
  91. shaderType = GL_GEOMETRY_SHADER;
  92. mProgramID = ++mGeometryShaderCount;
  93. break;
  94. case GPT_HULL_PROGRAM:
  95. shaderType = GL_TESS_CONTROL_SHADER;
  96. mProgramID = ++mDomainShaderCount;
  97. break;
  98. case GPT_DOMAIN_PROGRAM:
  99. shaderType = GL_TESS_EVALUATION_SHADER;
  100. mProgramID = ++mHullShaderCount;
  101. break;
  102. }
  103. // Add preprocessor extras and main source
  104. const String& source = mProperties.getSource();
  105. if (!source.empty())
  106. {
  107. Vector<GLchar*> lines;
  108. GLchar* firstLineData = (GLchar*)bs_stack_alloc(sizeof(GLSL_VERSION_LINE));
  109. memcpy(firstLineData, GLSL_VERSION_LINE, sizeof(GLSL_VERSION_LINE));
  110. lines.push_back(firstLineData);
  111. UINT32 lineLength = 0;
  112. for (UINT32 i = 0; i < source.size(); i++)
  113. {
  114. if (source[i] == '\n' || source[i] == '\r')
  115. {
  116. if (lineLength > 0)
  117. {
  118. assert(sizeof(source[i]) == sizeof(GLchar));
  119. bool isDefine = source[i - lineLength] == '#';
  120. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 1 + (isDefine ? 1 : 0)));
  121. memcpy(lineData, &source[i - lineLength], sizeof(GLchar) * lineLength);
  122. if (isDefine) // Defines require a newline as well as a null terminator, otherwise it doesn't compile properly
  123. {
  124. lineData[lineLength] = '\n';
  125. lineData[lineLength + 1] = '\0';
  126. }
  127. else
  128. lineData[lineLength] = '\0';
  129. lines.push_back(lineData);
  130. lineLength = 0;
  131. }
  132. }
  133. else
  134. {
  135. lineLength++;
  136. }
  137. }
  138. if (lineLength > 0)
  139. {
  140. UINT32 end = (UINT32)source.size() - 1;
  141. assert(sizeof(source[end]) == sizeof(GLchar));
  142. GLchar* lineData = (GLchar*)bs_stack_alloc(sizeof(GLchar) * (lineLength + 1));
  143. memcpy(lineData, &source[source.size() - lineLength], sizeof(GLchar) * lineLength);
  144. lineData[lineLength] = '\0';
  145. lines.push_back(lineData);
  146. lineLength = 0;
  147. }
  148. mGLHandle = glCreateShaderProgramv(shaderType, (GLsizei)lines.size(), (const GLchar**)lines.data());
  149. for (auto iter = lines.rbegin(); iter != lines.rend(); ++iter)
  150. {
  151. bs_stack_free(*iter);
  152. }
  153. mCompileError = "";
  154. mIsCompiled = !checkForGLSLError(mGLHandle, mCompileError);
  155. }
  156. if (mIsCompiled)
  157. {
  158. GLSLParamParser paramParser;
  159. paramParser.buildUniformDescriptions(mGLHandle, *mParametersDesc);
  160. if (mProperties.getType() == GPT_VERTEX_PROGRAM)
  161. {
  162. List<VertexElement> elementList = paramParser.buildVertexDeclaration(mGLHandle);
  163. mInputDeclaration = HardwareBufferCoreManager::instance().createVertexDeclaration(elementList);
  164. }
  165. }
  166. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
  167. GpuProgramCore::initialize();
  168. }
  169. bool GLSLGpuProgramCore::isSupported() const
  170. {
  171. if (!isRequiredCapabilitiesSupported())
  172. return false;
  173. RenderAPICore* rs = BansheeEngine::RenderAPICore::instancePtr();
  174. return rs->getCapabilities()->isShaderProfileSupported("glsl");
  175. }
  176. }