ShaderImpl.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include "anki/gr/gl/ShaderImpl.h"
  6. #include "anki/gr/GrManager.h"
  7. #include "anki/util/StringList.h"
  8. #include "anki/util/Logger.h"
  9. #define ANKI_DUMP_SHADERS ANKI_DEBUG
  10. #if ANKI_DUMP_SHADERS
  11. # include "anki/util/File.h"
  12. #endif
  13. namespace anki {
  14. //==============================================================================
  15. Error ShaderImpl::create(GLenum type, const CString& source)
  16. {
  17. ANKI_ASSERT(source);
  18. ANKI_ASSERT(!isCreated());
  19. Error err = ErrorCode::NONE;
  20. m_type = type;
  21. // 1) Append some things in the source string
  22. //
  23. U32 version;
  24. {
  25. GLint major, minor;
  26. glGetIntegerv(GL_MAJOR_VERSION, &major);
  27. glGetIntegerv(GL_MINOR_VERSION, &minor);
  28. version = major * 100 + minor * 10;
  29. }
  30. auto alloc = getAllocator();
  31. String fullSrc;
  32. String::ScopeDestroyer fullSrcd(&fullSrc, alloc);
  33. #if ANKI_GL == ANKI_GL_DESKTOP
  34. err = fullSrc.sprintf(alloc, "#version %d core\n%s\n", version, &source[0]);
  35. #else
  36. err = fullSrc.sprintf(alloc, "#version %d es\n%s\n", version, &source[0]);
  37. #endif
  38. // 2) Gen name, create, compile and link
  39. //
  40. if(!err)
  41. {
  42. const char* sourceStrs[1] = {nullptr};
  43. sourceStrs[0] = &fullSrc[0];
  44. m_glName = glCreateShaderProgramv(m_type, 1, sourceStrs);
  45. if(m_glName == 0)
  46. {
  47. err = ErrorCode::FUNCTION_FAILED;
  48. }
  49. }
  50. #if ANKI_DUMP_SHADERS
  51. if(!err)
  52. {
  53. const char* ext;
  54. switch(m_type)
  55. {
  56. case GL_VERTEX_SHADER:
  57. ext = "vert";
  58. break;
  59. case GL_TESS_CONTROL_SHADER:
  60. ext = "tesc";
  61. break;
  62. case GL_TESS_EVALUATION_SHADER:
  63. ext = "tese";
  64. break;
  65. case GL_GEOMETRY_SHADER:
  66. ext = "geom";
  67. break;
  68. case GL_FRAGMENT_SHADER:
  69. ext = "frag";
  70. break;
  71. case GL_COMPUTE_SHADER:
  72. ext = "comp";
  73. break;
  74. default:
  75. ext = nullptr;
  76. ANKI_ASSERT(0);
  77. }
  78. String fname;
  79. CString cacheDir = getManager().getCacheDirectory();
  80. err = fname.sprintf(alloc,
  81. "%s/%05u.%s", &cacheDir[0], static_cast<U32>(m_glName), ext);
  82. if(!err)
  83. {
  84. File file;
  85. err = file.open(fname.toCString(), File::OpenFlag::WRITE);
  86. }
  87. fname.destroy(alloc);
  88. }
  89. #endif
  90. if(!err)
  91. {
  92. GLint status = GL_FALSE;
  93. glGetProgramiv(m_glName, GL_LINK_STATUS, &status);
  94. if(status == GL_FALSE)
  95. {
  96. err = handleError(fullSrc);
  97. if(!err)
  98. {
  99. // Compilation failed, set error anyway
  100. err = ErrorCode::USER_DATA;
  101. }
  102. }
  103. }
  104. return err;
  105. }
  106. //==============================================================================
  107. Error ShaderImpl::handleError(String& src)
  108. {
  109. Error err = ErrorCode::NONE;
  110. auto alloc = getAllocator();
  111. GLint compilerLogLen = 0;
  112. GLint charsWritten = 0;
  113. String compilerLog;
  114. String prettySrc;
  115. StringList lines;
  116. static const char* padding =
  117. "======================================="
  118. "=======================================";
  119. glGetProgramiv(m_glName, GL_INFO_LOG_LENGTH, &compilerLogLen);
  120. err = compilerLog.create(alloc, ' ', compilerLogLen + 1);
  121. if(!err)
  122. {
  123. glGetProgramInfoLog(
  124. m_glName, compilerLogLen, &charsWritten, &compilerLog[0]);
  125. err = lines.splitString(alloc, src.toCString(), '\n');
  126. }
  127. I lineno = 0;
  128. for(auto it = lines.getBegin(); it != lines.getEnd() && !err; ++it)
  129. {
  130. String tmp;
  131. err = tmp.sprintf(alloc, "%4d: %s\n", ++lineno, &(*it)[0]);
  132. if(!err)
  133. {
  134. err = prettySrc.append(alloc, tmp);
  135. }
  136. tmp.destroy(alloc);
  137. }
  138. if(!err)
  139. {
  140. ANKI_LOGE("Shader compilation failed (type %x):\n%s\n%s\n%s\n%s",
  141. m_type, padding, &compilerLog[0], padding, &prettySrc[0]);
  142. }
  143. lines.destroy(alloc);
  144. prettySrc.destroy(alloc);
  145. compilerLog.destroy(alloc);
  146. return err;
  147. }
  148. //==============================================================================
  149. void ShaderImpl::destroy()
  150. {
  151. if(m_glName != 0)
  152. {
  153. glDeleteProgram(m_glName);
  154. m_glName = 0;
  155. }
  156. }
  157. } // end namespace anki