ShaderImpl.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  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/Gr/gl/GrManagerImpl.h>
  8. #include <AnKi/Gr/gl/GlState.h>
  9. #include <AnKi/Gr/ShaderCompiler.h>
  10. #include <AnKi/Util/StringList.h>
  11. #include <AnKi/Util/Logger.h>
  12. #define ANKI_DUMP_SHADERS ANKI_EXTRA_CHECKS
  13. #if ANKI_DUMP_SHADERS
  14. # include <anki/util/File.h>
  15. #endif
  16. namespace anki {
  17. /// Fake glDeleteShaders because some jenius created a conflicting interface
  18. static void deleteShaders(GLsizei n, const GLuint* names)
  19. {
  20. ANKI_ASSERT(n == 1);
  21. ANKI_ASSERT(names);
  22. glDeleteShader(*names);
  23. }
  24. ShaderImpl::~ShaderImpl()
  25. {
  26. destroyDeferred(getManager(), deleteShaders);
  27. }
  28. Error ShaderImpl::init(CString source, ConstWeakArray<ShaderSpecializationConstValue> constValues)
  29. {
  30. ANKI_ASSERT(source);
  31. ANKI_ASSERT(!isCreated());
  32. static const Array<GLenum, 6> gltype = {{GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER,
  33. GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER, GL_COMPUTE_SHADER}};
  34. m_glType = gltype[U(m_shaderType)];
  35. // Create a new shader with spec consts if needed
  36. StringAuto newSrc(getAllocator());
  37. if(constValues.getSize())
  38. {
  39. // Create const str
  40. StringListAuto constStrLines(getAllocator());
  41. U count = 0;
  42. for(const ShaderSpecializationConstValue& constVal : constValues)
  43. {
  44. if(constVal.m_dataType == ShaderVariableDataType::INT)
  45. {
  46. constStrLines.pushBackSprintf("#define _anki_spec_const_%u %i", count, constVal.m_int);
  47. }
  48. else
  49. {
  50. ANKI_ASSERT(constVal.m_dataType == ShaderVariableDataType::FLOAT);
  51. constStrLines.pushBackSprintf("#define _anki_spec_const_%u %f", count, constVal.m_float);
  52. }
  53. ++count;
  54. }
  55. StringAuto constStr(getAllocator());
  56. constStrLines.join("\n", constStr);
  57. // Break the old source
  58. StringListAuto lines(getAllocator());
  59. lines.splitString(source, '\n');
  60. ANKI_ASSERT(lines.getFront().find("#version") == 0);
  61. lines.popFront();
  62. // Append the const values
  63. lines.pushFront(constStr.toCString());
  64. lines.pushFront("#version 450 core");
  65. // Create the new string
  66. lines.join("\n", newSrc);
  67. source = newSrc.toCString();
  68. }
  69. // Gen name, create and compile
  70. const char* sourceStrs[1] = {nullptr};
  71. sourceStrs[0] = &source[0];
  72. m_glName = glCreateShader(m_glType);
  73. glShaderSource(m_glName, 1, sourceStrs, NULL);
  74. glCompileShader(m_glName);
  75. #if ANKI_DUMP_SHADERS
  76. {
  77. const char* ext;
  78. switch(m_glType)
  79. {
  80. case GL_VERTEX_SHADER:
  81. ext = "vert";
  82. break;
  83. case GL_TESS_CONTROL_SHADER:
  84. ext = "tesc";
  85. break;
  86. case GL_TESS_EVALUATION_SHADER:
  87. ext = "tese";
  88. break;
  89. case GL_GEOMETRY_SHADER:
  90. ext = "geom";
  91. break;
  92. case GL_FRAGMENT_SHADER:
  93. ext = "frag";
  94. break;
  95. case GL_COMPUTE_SHADER:
  96. ext = "comp";
  97. break;
  98. default:
  99. ext = nullptr;
  100. ANKI_ASSERT(0);
  101. }
  102. StringAuto fname(getAllocator());
  103. CString cacheDir = getManager().getCacheDirectory();
  104. fname.sprintf("%s/%05u.%s", &cacheDir[0], static_cast<U32>(m_glName), ext);
  105. File file;
  106. ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::WRITE));
  107. ANKI_CHECK(file.writeText("%s", source.cstr()));
  108. }
  109. #endif
  110. GLint status = GL_FALSE;
  111. glGetShaderiv(m_glName, GL_COMPILE_STATUS, &status);
  112. if(status == GL_FALSE)
  113. {
  114. auto alloc = getAllocator();
  115. StringAuto compilerLog(alloc);
  116. GLint compilerLogLen = 0;
  117. GLint charsWritten = 0;
  118. glGetShaderiv(m_glName, GL_INFO_LOG_LENGTH, &compilerLogLen);
  119. compilerLog.create(' ', compilerLogLen + 1);
  120. glGetShaderInfoLog(m_glName, compilerLogLen, &charsWritten, &compilerLog[0]);
  121. ShaderCompiler::logShaderErrorCode(compilerLog.toCString(), source, alloc);
  122. // Compilation failed, set error anyway
  123. return Error::USER_DATA;
  124. }
  125. return Error::NONE;
  126. }
  127. } // end namespace anki