ShaderProgramImpl.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright (C) 2009-2018, 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/ShaderProgramImpl.h>
  6. #include <anki/gr/Shader.h>
  7. #include <anki/gr/gl/ShaderImpl.h>
  8. namespace anki
  9. {
  10. static void deletePrograms(GLsizei n, const GLuint* progs)
  11. {
  12. ANKI_ASSERT(n == 1);
  13. ANKI_ASSERT(progs);
  14. glDeleteProgram(*progs);
  15. }
  16. ShaderProgramImpl::~ShaderProgramImpl()
  17. {
  18. destroyDeferred(getManager(), deletePrograms);
  19. m_refl.m_uniforms.destroy(getAllocator());
  20. }
  21. Error ShaderProgramImpl::initGraphics(ShaderPtr vert, ShaderPtr tessc, ShaderPtr tesse, ShaderPtr geom, ShaderPtr frag)
  22. {
  23. m_glName = glCreateProgram();
  24. ANKI_ASSERT(m_glName != 0);
  25. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*vert).getGlName());
  26. m_shaders[ShaderType::VERTEX] = vert;
  27. if(tessc)
  28. {
  29. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*tessc).getGlName());
  30. m_shaders[ShaderType::TESSELLATION_CONTROL] = tessc;
  31. }
  32. if(tesse)
  33. {
  34. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*tesse).getGlName());
  35. m_shaders[ShaderType::TESSELLATION_EVALUATION] = tesse;
  36. }
  37. if(geom)
  38. {
  39. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*geom).getGlName());
  40. m_shaders[ShaderType::GEOMETRY] = geom;
  41. }
  42. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*frag).getGlName());
  43. m_shaders[ShaderType::FRAGMENT] = frag;
  44. return link(static_cast<const ShaderImpl&>(*vert).getGlName(), static_cast<const ShaderImpl&>(*frag).getGlName());
  45. }
  46. Error ShaderProgramImpl::initCompute(ShaderPtr comp)
  47. {
  48. m_glName = glCreateProgram();
  49. ANKI_ASSERT(m_glName != 0);
  50. glAttachShader(m_glName, static_cast<const ShaderImpl&>(*comp).getGlName());
  51. m_shaders[ShaderType::COMPUTE] = comp;
  52. return link(0, 0);
  53. }
  54. Error ShaderProgramImpl::link(GLuint vert, GLuint frag)
  55. {
  56. Error err = Error::NONE;
  57. glLinkProgram(m_glName);
  58. GLint status = 0;
  59. glGetProgramiv(m_glName, GL_LINK_STATUS, &status);
  60. if(!status)
  61. {
  62. GLint infoLen = 0;
  63. GLint charsWritten = 0;
  64. DynamicArrayAuto<char> infoLogTxt(getAllocator());
  65. glGetProgramiv(m_glName, GL_INFO_LOG_LENGTH, &infoLen);
  66. infoLogTxt.create(infoLen + 1);
  67. glGetProgramInfoLog(m_glName, infoLen, &charsWritten, &infoLogTxt[0]);
  68. ANKI_GL_LOGE("Link error log follows (vs:%u, fs:%u):\n%s", vert, frag, &infoLogTxt[0]);
  69. err = Error::USER_DATA;
  70. }
  71. return err;
  72. }
  73. const ShaderProgramImplReflection& ShaderProgramImpl::getReflection()
  74. {
  75. if(m_reflInitialized)
  76. {
  77. return m_refl;
  78. }
  79. GLint uniformCount = 0;
  80. glGetProgramiv(getGlName(), GL_ACTIVE_UNIFORMS, &uniformCount);
  81. if(uniformCount)
  82. {
  83. for(U i = 0; i < U(uniformCount); ++i)
  84. {
  85. // Get uniform info
  86. GLsizei len;
  87. GLenum type;
  88. GLint size;
  89. Array<char, 128> name;
  90. glGetActiveUniform(getGlName(), i, sizeof(name), &len, &size, &type, &name[0]);
  91. name[len] = '\0';
  92. if(CString(&name[0]).find("gl_") == 0)
  93. {
  94. // Builtin, skip
  95. continue;
  96. }
  97. // Set type
  98. ShaderVariableDataType akType = ShaderVariableDataType::NONE;
  99. switch(type)
  100. {
  101. case GL_FLOAT_VEC4:
  102. akType = ShaderVariableDataType::VEC4;
  103. break;
  104. case GL_INT_VEC4:
  105. akType = ShaderVariableDataType::IVEC4;
  106. break;
  107. case GL_UNSIGNED_INT_VEC4:
  108. akType = ShaderVariableDataType::UVEC4;
  109. break;
  110. case GL_FLOAT_MAT4:
  111. akType = ShaderVariableDataType::MAT4;
  112. break;
  113. case GL_FLOAT_MAT3:
  114. akType = ShaderVariableDataType::MAT3;
  115. break;
  116. default:
  117. // Unsupported type, skip as well
  118. continue;
  119. }
  120. const GLint location = glGetUniformLocation(getGlName(), &name[0]);
  121. if(location < 0)
  122. {
  123. // Uniform block maybe, skip
  124. continue;
  125. }
  126. // Store
  127. ShaderProgramImplReflection::Uniform uni;
  128. uni.m_location = location;
  129. uni.m_type = akType;
  130. uni.m_arrSize = size;
  131. m_refl.m_uniforms.emplaceBack(getAllocator(), uni);
  132. }
  133. // Sort the uniforms
  134. std::sort(m_refl.m_uniforms.getBegin(),
  135. m_refl.m_uniforms.getEnd(),
  136. [](const ShaderProgramImplReflection::Uniform& a, const ShaderProgramImplReflection::Uniform& b) {
  137. return a.m_location < b.m_location;
  138. });
  139. // Now calculate the offset inside the push constant buffer
  140. m_refl.m_uniformDataSize = 0;
  141. for(ShaderProgramImplReflection::Uniform& uni : m_refl.m_uniforms)
  142. {
  143. U32 dataSize = 0;
  144. switch(uni.m_type)
  145. {
  146. case ShaderVariableDataType::VEC4:
  147. case ShaderVariableDataType::IVEC4:
  148. case ShaderVariableDataType::UVEC4:
  149. dataSize = sizeof(F32) * 4;
  150. break;
  151. case ShaderVariableDataType::MAT4:
  152. dataSize = sizeof(F32) * 16;
  153. break;
  154. case ShaderVariableDataType::MAT3:
  155. dataSize = sizeof(F32) * 12;
  156. break;
  157. default:
  158. ANKI_ASSERT(!"Unsupported type");
  159. }
  160. uni.m_pushConstantOffset = m_refl.m_uniformDataSize;
  161. m_refl.m_uniformDataSize += dataSize * uni.m_arrSize;
  162. }
  163. }
  164. m_reflInitialized = true;
  165. return m_refl;
  166. }
  167. } // end namespace anki