You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ShaderLoader.cpp 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include "ShaderLoader.h"
  2. #include <fstream>
  3. #include <iostream>
  4. #include <memory>
  5. #include "Shader.h"
  6. #include "../../Log.h"
  7. static constexpr GLint maxLogSize = 1024 * 1024 * 2; //2 MiB
  8. ShaderLoader::ShaderCache ShaderLoader::shaderCache;
  9. GLuint ShaderLoader::loadShader(const std::string &shaderSource, Shader::Type type) {
  10. GLenum glType = getGlShaderType(type);
  11. if (!glType) {
  12. logError() << "Unknown shader type: " << type << std::endl;
  13. return 0;
  14. }
  15. GLuint shader = glCreateShader(glType);
  16. const char *source = shaderSource.c_str();
  17. glShaderSource(shader, 1, &source, NULL);
  18. glCompileShader(shader);
  19. if(checkShader(shader, shaderSource, type))
  20. return 0;
  21. return shader;
  22. }
  23. GLuint ShaderLoader::createProgram(const std::string &shader1Source, Shader::Type shader1Type,
  24. const std::string &shader2Source, Shader::Type shader2Type) {
  25. GLuint shader1 = loadShader(shader1Source, shader1Type);
  26. GLuint shader2 = loadShader(shader2Source, shader2Type);
  27. if (!shader1 || !shader2)
  28. return 0;
  29. GLuint program = glCreateProgram();
  30. glAttachShader(program, shader1);
  31. glAttachShader(program, shader2);
  32. glLinkProgram(program);
  33. if (checkProgram(program, GL_LINK_STATUS, shader1Source))
  34. return 0;
  35. glValidateProgram(program);
  36. if (checkProgram(program, GL_VALIDATE_STATUS, shader1Source))
  37. return 0;
  38. return program;
  39. }
  40. Shader *ShaderLoader::getShader(VertexShader vertexShader, FragmentShader fragmentShader) {
  41. // concatenate strings to create unique key for the shader
  42. std::string key = vertexShader.source + fragmentShader.source;
  43. // has the shader been cached?
  44. auto it = shaderCache.find(key);
  45. if (it != shaderCache.end())
  46. return it->second;
  47. // Ok. It isn't. Let's create the shader Q.Q
  48. GLuint program = createProgram(vertexShader.source, Shader::Type::Vertex,
  49. fragmentShader.source, Shader::Type::Fragment);
  50. if (!program) //reee it failed
  51. return NULL;
  52. Shader *shader = new Shader(program);
  53. shaderCache.insert(std::make_pair(key, shader));
  54. return shader;
  55. }
  56. int ShaderLoader::checkShader(GLuint shader, const std::string &source, Shader::Type type) {
  57. GLint success = 0;
  58. glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
  59. if (success == GL_TRUE) {
  60. logDebug() << "Shader " << source << " compiled successfully!" << std::endl;
  61. } else {
  62. GLint logSize = 0;
  63. glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
  64. if (logSize > maxLogSize) {
  65. logError() << "Shader " << source << " failed to compile but \
  66. the log is too long to show." << std::endl;
  67. return 1;
  68. }
  69. char log[logSize];
  70. glGetShaderInfoLog(shader, logSize, &logSize, &log[0]);
  71. logError() << "Shader " << source << " failed to compile. GL log output: "
  72. << log << std::endl;
  73. glDeleteShader(shader);
  74. return 1;
  75. }
  76. return 0;
  77. }
  78. int ShaderLoader::checkProgram(GLuint program, GLenum pname, const std::string &source) {
  79. GLint success = 0;
  80. glGetProgramiv(program, pname, &success);
  81. if (success == GL_TRUE) {
  82. logDebug() << "Program with shader1 " << source << " " << getProgramStatusString(pname)
  83. << std::endl;
  84. } else {
  85. GLint logSize = 0;
  86. glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logSize);
  87. if (logSize > maxLogSize) {
  88. logError() << "Program with shader1 " << source << " failed to be "
  89. << getProgramStatusString(pname) << " but the log is too long to show" << std::endl;
  90. return 1;
  91. }
  92. char log[logSize];
  93. glGetProgramInfoLog(program, logSize, &logSize, &log[0]);
  94. logError() << "Program with shader1 " << source << " failed to be "
  95. << getProgramStatusString(pname) << ". GL log output: " << log << std::endl;
  96. glDeleteProgram(program);
  97. return 1;
  98. }
  99. return 0;
  100. }
  101. constexpr const char *ShaderLoader::getProgramStatusString(GLenum pname) {
  102. switch (pname) {
  103. case GL_LINK_STATUS:
  104. return "linked";
  105. case GL_VALIDATE_STATUS:
  106. return "validated";
  107. }
  108. return "";
  109. }
  110. constexpr GLenum ShaderLoader::getGlShaderType(const Shader::Type type) {
  111. switch (type) {
  112. case Shader::Vertex:
  113. return GL_VERTEX_SHADER;
  114. case Shader::Fragment:
  115. return GL_FRAGMENT_SHADER;
  116. }
  117. return 0;
  118. }