ShaderImpl.cpp 3.8 KB

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