ShaderProgram.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. #ifndef ANKI_GL_SHADER_PROGRAM_H
  2. #define ANKI_GL_SHADER_PROGRAM_H
  3. #include "anki/util/ConstCharPtrHashMap.h"
  4. #include "anki/util/Assert.h"
  5. #include "anki/util/Flags.h"
  6. #include "anki/math/Forward.h"
  7. #include "anki/gl/Ogl.h"
  8. #include "anki/util/Vector.h"
  9. #include "anki/util/StdTypes.h"
  10. #include "anki/util/NonCopyable.h"
  11. #include <string>
  12. #include <memory>
  13. namespace anki {
  14. class ShaderProgram;
  15. class ShaderProgramUniformBlock;
  16. class Texture;
  17. /// @addtogroup OpenGL
  18. /// @{
  19. /// Shader program variable. The type is attribute or uniform
  20. class ShaderProgramVariable
  21. {
  22. friend class ShaderProgram;
  23. public:
  24. /// Shader var types
  25. enum ShaderProgramVariableType
  26. {
  27. SPVT_ATTRIBUTE,
  28. SPVT_UNIFORM
  29. };
  30. ShaderProgramVariable(ShaderProgramVariableType type_)
  31. : type(type_)
  32. {}
  33. virtual ~ShaderProgramVariable()
  34. {}
  35. /// @name Accessors
  36. /// @{
  37. const ShaderProgram& getFatherShaderProgram() const
  38. {
  39. return *fatherSProg;
  40. }
  41. GLint getLocation() const
  42. {
  43. return loc;
  44. }
  45. const std::string& getName() const
  46. {
  47. return name;
  48. }
  49. GLenum getGlDataType() const
  50. {
  51. return glDataType;
  52. }
  53. ShaderProgramVariableType getType() const
  54. {
  55. return type;
  56. }
  57. PtrSize getSize() const
  58. {
  59. return size;
  60. }
  61. /// @}
  62. ShaderProgramVariable& operator=(const ShaderProgramVariable& b)
  63. {
  64. ANKI_ASSERT(type == b.type);
  65. loc = b.loc;
  66. name = b.name;
  67. glDataType = b.glDataType;
  68. size = b.size;
  69. fatherSProg = b.fatherSProg;
  70. return *this;
  71. }
  72. private:
  73. GLint loc; ///< GL location
  74. std::string name; ///< The name inside the shader program
  75. /// GL_FLOAT, GL_FLOAT_VEC2 etc. See
  76. /// http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml
  77. GLenum glDataType;
  78. PtrSize size; ///< Its 1 if it is a single or >1 if it is an array
  79. ShaderProgramVariableType type;
  80. /// We need the ShaderProg of this variable mainly for sanity checks
  81. const ShaderProgram* fatherSProg;
  82. };
  83. /// Uniform shader variable
  84. class ShaderProgramUniformVariable: public ShaderProgramVariable
  85. {
  86. friend class ShaderProgramUniformBlock;
  87. friend class ShaderProgram;
  88. public:
  89. ShaderProgramUniformVariable()
  90. : ShaderProgramVariable(SPVT_UNIFORM)
  91. {}
  92. ShaderProgramUniformVariable& operator=(
  93. const ShaderProgramUniformVariable& b)
  94. {
  95. ShaderProgramVariable::operator=(b);
  96. index = b.index;
  97. offset = b.offset;
  98. arrayStride = b.arrayStride;
  99. return *this;
  100. }
  101. const ShaderProgramUniformBlock* getUniformBlock() const
  102. {
  103. return block;
  104. }
  105. /// @name Set the var
  106. /// @{
  107. void set(const F32 x) const;
  108. void set(const Vec2& x) const;
  109. void set(const Vec3& x) const
  110. {
  111. set(&x, 1);
  112. }
  113. void set(const Vec4& x) const
  114. {
  115. set(&x, 1);
  116. }
  117. void set(const Mat3& x) const
  118. {
  119. set(&x, 1);
  120. }
  121. void set(const Mat4& x) const
  122. {
  123. set(&x, 1);
  124. }
  125. void set(const Texture& tex) const;
  126. void set(const Texture* const texes[], const U32 count) const;
  127. void set(const F32 x[], uint size) const;
  128. void set(const Vec2 x[], uint size) const;
  129. void set(const Vec3 x[], uint size) const;
  130. void set(const Vec4 x[], uint size) const;
  131. void set(const Mat3 x[], uint size) const;
  132. void set(const Mat4 x[], uint size) const;
  133. /// @tparam Container It could be something like array<F32, X> or
  134. /// vector<Vec2> etc
  135. template<typename Container>
  136. void setContainer(const Container& c) const
  137. {
  138. set(&c[0], c.size());
  139. }
  140. /// @}
  141. void setClientMemory(void* buff, U32 buffSize,
  142. const F32 arr[], U32 size) const;
  143. void setClientMemory(void* buff, U32 buffSize,
  144. const Vec2 arr[], U32 size) const;
  145. void setClientMemory(void* buff, U32 buffSize,
  146. const Vec3 arr[], U32 size) const;
  147. void setClientMemory(void* buff, U32 buffSize,
  148. const Vec4 arr[], U32 size) const;
  149. void setClientMemory(void* buff, U32 buffSize,
  150. const Mat3 arr[], U32 size) const;
  151. void setClientMemory(void* buff, U32 buffSize,
  152. const Mat4 arr[], U32 size) const;
  153. private:
  154. GLuint index;
  155. ShaderProgramUniformBlock* block = nullptr;
  156. /// Offset inside the uniform block. -1 if it's inside the default uniform
  157. /// block
  158. GLint offset = -1;
  159. /// "An array identifying the stride between elements, in basic machine
  160. /// units, of each of the uniforms specified by the corresponding array of
  161. /// uniformIndices is returned. The stride of a uniform associated with
  162. /// the default uniform block is -1. Note that this information only makes
  163. /// sense for uniforms that are arrays. For uniforms that are not arrays,
  164. /// but are declared in a named uniform block, an array stride of zero is
  165. /// returned"
  166. GLint arrayStride = -1;
  167. /// Identifying the stride between columns of a column-major matrix or rows
  168. /// of a row-major matrix
  169. GLint matrixStride = -1;
  170. /// Standard set uniform checks
  171. /// - Check if initialized
  172. /// - if the current shader program is the var's shader program
  173. /// - if the GL driver gives the same location as the one the var has
  174. void doCommonSetCode() const;
  175. /// Do common checks
  176. template<typename T>
  177. void setClientMemorySanityChecks(U32 buffSize, U32 size) const;
  178. /// Do the actual job of setClientMemory
  179. template<typename T>
  180. void setClientMemoryInternal(void* buff_, U32 buffSize,
  181. const T arr[], U32 size) const;
  182. /// Do the actual job of setClientMemory for matrices
  183. template<typename Mat, typename Vec>
  184. void setClientMemoryInternalMatrix(void* buff_, U32 buffSize,
  185. const Mat arr[], U32 size) const;
  186. };
  187. /// Attribute shader program variable
  188. class ShaderProgramAttributeVariable: public ShaderProgramVariable
  189. {
  190. friend class ShaderProgram;
  191. public:
  192. ShaderProgramAttributeVariable()
  193. : ShaderProgramVariable(SPVT_ATTRIBUTE)
  194. {}
  195. };
  196. /// Uniform shader block
  197. class ShaderProgramUniformBlock
  198. {
  199. friend class ShaderProgram;
  200. public:
  201. ShaderProgramUniformBlock()
  202. {}
  203. ShaderProgramUniformBlock(const ShaderProgramUniformBlock& b)
  204. {
  205. operator=(b);
  206. }
  207. ~ShaderProgramUniformBlock()
  208. {}
  209. /// @name Accessors
  210. /// @{
  211. GLuint getIndex() const
  212. {
  213. return index;
  214. }
  215. U32 getSize() const
  216. {
  217. return size;
  218. }
  219. const std::string& getName() const
  220. {
  221. return name;
  222. }
  223. GLuint getBinding() const
  224. {
  225. return bindingPoint;
  226. }
  227. void setBinding(GLuint bp) const
  228. {
  229. // Don't try any opts with existing binding point. Binding points
  230. // should break
  231. glUniformBlockBinding(progId, index, bp);
  232. bindingPoint = bp;
  233. }
  234. /// @}
  235. ShaderProgramUniformBlock& operator=(const ShaderProgramUniformBlock& b);
  236. private:
  237. Vector<ShaderProgramUniformVariable*> uniforms;
  238. GLuint index = GL_INVALID_INDEX;
  239. U32 size = 0; ///< In bytes
  240. std::string name;
  241. /// Ask the program to get you the binding point
  242. mutable GLuint bindingPoint;
  243. GLuint progId; ///< Needed for binding
  244. };
  245. /// Shader program object
  246. class ShaderProgram: public NonCopyable
  247. {
  248. public:
  249. typedef Vector<ShaderProgramUniformVariable>
  250. UniformVariablesContainer;
  251. typedef Vector<ShaderProgramAttributeVariable>
  252. AttributeVariablesContainer;
  253. typedef Vector<ShaderProgramUniformBlock>
  254. UniformBlocksContainer;
  255. /// @name Constructors/Destructor
  256. /// @{
  257. ShaderProgram()
  258. {
  259. init();
  260. }
  261. ShaderProgram(const char* vertSource, const char* tcSource,
  262. const char* teSource, const char* geomSource, const char* fragSource,
  263. const char* transformFeedbackVaryings[],
  264. const GLenum xfbBufferMode = GL_SEPARATE_ATTRIBS)
  265. {
  266. init();
  267. create(vertSource, tcSource, teSource, geomSource, fragSource,
  268. transformFeedbackVaryings, xfbBufferMode);
  269. }
  270. ~ShaderProgram()
  271. {
  272. if(isCreated())
  273. {
  274. destroy();
  275. }
  276. }
  277. /// @}
  278. /// @name Accessors
  279. /// @{
  280. GLuint getGlId() const
  281. {
  282. ANKI_ASSERT(isCreated());
  283. return glId;
  284. }
  285. const UniformVariablesContainer& getUniformVariables() const
  286. {
  287. return unis;
  288. }
  289. const AttributeVariablesContainer& getAttributeVariables() const
  290. {
  291. return attribs;
  292. }
  293. /// @}
  294. /// Create the program
  295. /// @param vertSource Vertex shader source
  296. /// @param tcSource Tessellation control shader source. Can be nullptr
  297. /// @param teSource Tessellation evaluation shader source. Can be nullptr
  298. /// @param geomSource Geometry shader source. Can be nullptr
  299. /// @param fragSource Fragment shader source. Can be nullptr
  300. /// @param xfbVaryings An array of varyings names. Eg
  301. /// {"var0", "var1", nullptr}. Can be nullptr
  302. /// @param xfbBufferMode GL_SEPARATE_ATTRIBS or GL_INTERLEAVED_ATTRIBS
  303. void create(const char* vertSource, const char* tcSource,
  304. const char* teSource, const char* geomSource, const char* fragSource,
  305. const char* xfbVaryings[],
  306. const GLenum xfbBufferMode = GL_SEPARATE_ATTRIBS);
  307. /// Bind the shader program
  308. void bind() const
  309. {
  310. ANKI_ASSERT(isCreated());
  311. if(current != this)
  312. {
  313. glUseProgram(glId);
  314. current = this;
  315. }
  316. }
  317. // Unbinds only @a this if its binded
  318. void unbind() const
  319. {
  320. ANKI_ASSERT(isCreated());
  321. if(current == this)
  322. {
  323. glUseProgram(0);
  324. current = nullptr;
  325. }
  326. }
  327. /// @name Variable finders
  328. /// Used to find and return the variable. They return nullptr if the
  329. /// variable is not found
  330. /// @{
  331. const ShaderProgramUniformVariable* tryFindUniformVariable(
  332. const char* varName) const;
  333. const ShaderProgramUniformVariable& findUniformVariable(
  334. const char* varName) const;
  335. const ShaderProgramAttributeVariable* tryFindAttributeVariable(
  336. const char* varName) const;
  337. const ShaderProgramAttributeVariable& findAttributeVariable(
  338. const char* varName) const;
  339. const ShaderProgramUniformBlock* tryFindUniformBlock(
  340. const char* name) const;
  341. const ShaderProgramUniformBlock& findUniformBlock(const char* name) const;
  342. /// @}
  343. static GLuint getCurrentProgramGlId()
  344. {
  345. int i;
  346. glGetIntegerv(GL_CURRENT_PROGRAM, &i);
  347. return i;
  348. }
  349. /// For debugging
  350. friend std::ostream& operator<<(std::ostream& s,
  351. const ShaderProgram& x);
  352. private:
  353. typedef ConstCharPtrHashMap<ShaderProgramUniformVariable*>::Type
  354. NameToUniVarHashMap;
  355. typedef ConstCharPtrHashMap<ShaderProgramAttributeVariable*>::Type
  356. NameToAttribVarHashMap;
  357. typedef ConstCharPtrHashMap<ShaderProgramUniformBlock*>::Type
  358. NameToUniformBlockHashMap;
  359. static thread_local const ShaderProgram* current;
  360. GLuint glId; ///< The OpenGL ID of the shader program
  361. GLuint vertShaderGlId; ///< Vertex shader OpenGL id
  362. GLuint tcShaderGlId; ///< Tessellation control shader OpenGL id
  363. GLuint teShaderGlId; ///< Tessellation eval shader OpenGL id
  364. GLuint geomShaderGlId; ///< Geometry shader OpenGL id
  365. GLuint fragShaderGlId; ///< Fragment shader OpenGL id
  366. /// @name Containers
  367. /// @{
  368. UniformVariablesContainer unis;
  369. AttributeVariablesContainer attribs;
  370. NameToUniVarHashMap nameToUniVar; ///< Uniform searching
  371. NameToAttribVarHashMap nameToAttribVar; ///< Attribute searching
  372. UniformBlocksContainer blocks;
  373. NameToUniformBlockHashMap nameToBlock;
  374. /// @}
  375. /// Query the driver to get the vars. After the linking of the shader
  376. /// prog is done gather all the vars in custom containers
  377. void initUniAndAttribVars();
  378. /// Get info about the uniform blocks
  379. void initUniformBlocks();
  380. /// Create and compile shader
  381. /// @return The shader's OpenGL id
  382. /// @exception Exception
  383. static GLuint createAndCompileShader(const char* sourceCode,
  384. const char* preproc, GLenum type);
  385. /// Link the shader program
  386. /// @exception Exception
  387. void link() const;
  388. /// Returns true if the class points to a valid GL ID
  389. bool isCreated() const
  390. {
  391. return glId != 0;
  392. }
  393. /// Common construction code
  394. void init()
  395. {
  396. glId = vertShaderGlId = tcShaderGlId = teShaderGlId =
  397. geomShaderGlId = fragShaderGlId = 0;
  398. }
  399. void destroy();
  400. };
  401. /// @}
  402. } // end namespace anki
  403. #endif