PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ShaderAttribArray.cpp

https://gitlab.com/hamsham/LightDraw
C++ | 367 lines | 235 code | 67 blank | 65 comment | 36 complexity | ef2320d2fdd32ef966bbfdd943fcdd10 MD5 | raw file
  1. /*
  2. * @file: ShaderAttribArray.cpp
  3. * @author geeds
  4. *
  5. * @date June 30, 2016 4:38 PM
  6. */
  7. #include "lightsky/draw/ShaderAttribArray.h"
  8. #include "lightsky/draw/ShaderObject.h" // shader_stage_t
  9. #include "lightsky/draw/ShaderProgram.h"
  10. #include "lightsky/draw/VAOAttrib.h" // vertex_attrib_t
  11. namespace ls
  12. {
  13. namespace draw
  14. {
  15. /*-----------------------------------------------------------------------------
  16. * Shader Attrib Array
  17. -----------------------------------------------------------------------------*/
  18. /*-------------------------------------
  19. * Destructor
  20. -------------------------------------*/
  21. ShaderAttribArray::~ShaderAttribArray() noexcept
  22. {
  23. }
  24. /*-------------------------------------
  25. * Constructor
  26. -------------------------------------*/
  27. ShaderAttribArray::ShaderAttribArray() noexcept :
  28. attribs{nullptr},
  29. numAttribs{0}
  30. {
  31. }
  32. /*-------------------------------------
  33. * Preallocation Constructor
  34. -------------------------------------*/
  35. ShaderAttribArray::ShaderAttribArray(const unsigned allocCount) noexcept :
  36. // Delegated constructor
  37. ShaderAttribArray::ShaderAttribArray{
  38. allocCount, utils::Pointer<ShaderAttrib[]>{allocCount ? new(std::nothrow) ShaderAttrib[allocCount] : nullptr}
  39. }
  40. {
  41. }
  42. /*-------------------------------------
  43. * Allocation & Fill Constructor
  44. -------------------------------------*/
  45. ShaderAttribArray::ShaderAttribArray(
  46. const unsigned preallocCount,
  47. utils::Pointer<ShaderAttrib[]>&& preallocAttribs
  48. ) noexcept :
  49. attribs{nullptr},
  50. numAttribs{0}
  51. {
  52. if (preallocCount)
  53. {
  54. if (!preallocAttribs)
  55. {
  56. constexpr char errMsg[] = "Unable to allocate memory to copy VAO Attributes.";
  57. utils::runtime_assert(false, utils::error_t::LS_ERROR, errMsg);
  58. }
  59. attribs = std::move(preallocAttribs);
  60. numAttribs = preallocCount;
  61. }
  62. }
  63. /*-------------------------------------
  64. * Copy constructor
  65. -------------------------------------*/
  66. ShaderAttribArray::ShaderAttribArray(const ShaderAttribArray& shaderAttrib) noexcept
  67. {
  68. *this = shaderAttrib;
  69. }
  70. /*-------------------------------------
  71. * Move Constructor
  72. -------------------------------------*/
  73. ShaderAttribArray::ShaderAttribArray(ShaderAttribArray&& shaderAttrib) noexcept
  74. {
  75. *this = std::move(shaderAttrib);
  76. }
  77. /*-------------------------------------
  78. * Copy Operator
  79. -------------------------------------*/
  80. ShaderAttribArray& ShaderAttribArray::operator=(const ShaderAttribArray& shaderAttrib) noexcept
  81. {
  82. // Check for an early exit by querying for 0 attributes
  83. if (!shaderAttrib.numAttribs)
  84. {
  85. if (this->numAttribs)
  86. {
  87. attribs.reset();
  88. numAttribs = 0;
  89. }
  90. return *this;
  91. }
  92. // Determine if a reallocation is necessary
  93. if (shaderAttrib.numAttribs != this->numAttribs)
  94. {
  95. const unsigned allocCount = shaderAttrib.numAttribs;
  96. attribs.reset(new(std::nothrow) ShaderAttrib[allocCount]);
  97. if (allocCount && !attribs)
  98. {
  99. numAttribs = 0;
  100. // Assertion goes here for reentrancy.
  101. constexpr char errMsg[] = "Unable to allocate memory to copy VAO Attributes.";
  102. utils::runtime_assert(false, utils::error_t::LS_ERROR, errMsg);
  103. }
  104. else
  105. {
  106. numAttribs = allocCount;
  107. }
  108. }
  109. // COPY!
  110. for (unsigned i = 0; i < numAttribs; ++i)
  111. {
  112. attribs[i] = shaderAttrib.attribs[i];
  113. }
  114. return *this;
  115. }
  116. /*-------------------------------------
  117. * Move Operator
  118. -------------------------------------*/
  119. ShaderAttribArray& ShaderAttribArray::operator=(ShaderAttribArray&& shaderAttrib) noexcept
  120. {
  121. attribs = std::move(shaderAttrib.attribs);
  122. numAttribs = shaderAttrib.numAttribs;
  123. shaderAttrib.numAttribs = 0;
  124. return *this;
  125. }
  126. /*-------------------------------------
  127. * Attribute Reallocation
  128. -------------------------------------*/
  129. bool ShaderAttribArray::set_num_attribs(const unsigned attribCount) noexcept
  130. {
  131. if (attribCount == numAttribs)
  132. {
  133. return true;
  134. }
  135. if (!attribCount)
  136. {
  137. attribs.reset();
  138. numAttribs = 0;
  139. return true;
  140. }
  141. ShaderAttribArray tempAttrib{attribCount, std::move(attribs)};
  142. *this = ShaderAttribArray{attribCount};
  143. // noexcept guarantee
  144. if (!this->numAttribs)
  145. {
  146. *this = std::move(tempAttrib);
  147. return false;
  148. }
  149. // Keep track of the number of attribs to copy over
  150. const unsigned maxAttribCount = this->numAttribs < tempAttrib.numAttribs
  151. ? this->numAttribs
  152. : tempAttrib.numAttribs;
  153. // Move old attribs into *this
  154. for (unsigned i = 0; i < maxAttribCount; ++i)
  155. {
  156. attribs[i] = std::move(tempAttrib.attribs[i]);
  157. }
  158. return true;
  159. }
  160. /*-------------------------------------
  161. * Reallocation & Invalidation
  162. -------------------------------------*/
  163. bool ShaderAttribArray::reset_num_attribs(const unsigned attribCount) noexcept
  164. {
  165. if (attribCount == this->numAttribs)
  166. {
  167. for (unsigned i = 0; i < attribCount; ++i)
  168. {
  169. this->attribs[i] = ShaderAttrib{};
  170. }
  171. }
  172. else
  173. {
  174. ShaderAttribArray tempAttrib{attribCount};
  175. if (tempAttrib.numAttribs != attribCount)
  176. {
  177. return false;
  178. }
  179. *this = std::move(tempAttrib);
  180. }
  181. return true;
  182. }
  183. /*-----------------------------------------------------------------------------
  184. * Utility functions for Shader Attributes
  185. -----------------------------------------------------------------------------*/
  186. } // end draw namespace
  187. /*-------------------------------------
  188. * Get all shader attrib/uniform names
  189. -------------------------------------*/
  190. draw::ShaderAttribArray draw::get_shader_attribs(
  191. const ShaderProgram& prog,
  192. const vertex_attrib_t attribType
  193. ) noexcept
  194. {
  195. LS_DEBUG_ASSERT(
  196. attribType == vertex_attrib_t::UNIFORM_ATTRIB ||
  197. attribType == vertex_attrib_t::VERTEX_ATTRIB
  198. );
  199. const GLenum paramType = (attribType == vertex_attrib_t::UNIFORM_ATTRIB)
  200. ? GL_ACTIVE_UNIFORMS
  201. : GL_ACTIVE_ATTRIBUTES;
  202. GLint totalAttribs = 0;
  203. glGetProgramiv(prog.gpu_id(), paramType, &totalAttribs);
  204. LS_LOG_GL_ERR();
  205. ShaderAttribArray ret{(unsigned)totalAttribs};
  206. for (int i = 0; i < totalAttribs; ++i)
  207. {
  208. GLint outVarSize = 0;
  209. GLenum outVarType = 0;
  210. ShaderAttrib& attrib = ret.get_attrib(i);
  211. const int inAttribType = attribType == vertex_attrib_t::UNIFORM_ATTRIB
  212. ? GL_ACTIVE_UNIFORM_MAX_LENGTH
  213. : GL_ACTIVE_ATTRIBUTE_MAX_LENGTH;
  214. utils::Pointer<GLchar[]>&& attribName = draw::get_attrib_name(prog, i, outVarSize, outVarType, inAttribType);
  215. attrib.set_name(std::move(attribName));
  216. if (attribType == vertex_attrib_t::UNIFORM_ATTRIB)
  217. {
  218. attrib.set_location(glGetUniformLocation(prog.gpu_id(), attribName.get()));
  219. }
  220. else
  221. {
  222. attrib.set_location(glGetAttribLocation(prog.gpu_id(), attribName.get()));
  223. }
  224. attrib.set_type((vertex_data_t)outVarType);
  225. }
  226. return ret;
  227. }
  228. /*-------------------------------------
  229. * Perform introspection to retrieve all current vertex attributes.
  230. -------------------------------------*/
  231. draw::ShaderAttribArray draw::get_linked_shader_attribs(
  232. const ShaderProgram& prog,
  233. const shader_stage_t shaderType
  234. ) noexcept
  235. {
  236. // Vertex shader introspection can be run through routines shared with
  237. // uniform introspection routines.
  238. if (shaderType != shader_stage_t::SHADER_STAGE_FRAGMENT)
  239. {
  240. return draw::get_shader_attribs(prog, vertex_attrib_t::VERTEX_ATTRIB);
  241. }
  242. const GLint shaderId = prog.get_attached_shader_id(shaderType);
  243. LS_LOG_MSG("Attempting to introspect a fragment shader.");
  244. if (!shaderId)
  245. {
  246. LS_LOG_ERR("\tFailed introspect a fragment shader. No ID available.\n");
  247. return false;
  248. }
  249. ShaderObject shaderObj{};
  250. if (!shaderObj.recreate_from_id(shaderId))
  251. {
  252. LS_LOG_ERR("\tFailed recreate a fragment shader.\n");
  253. return false;
  254. }
  255. // Begin the introspection
  256. const ShaderAttribArray& shaderAttribs = shaderObj.get_attribs();
  257. unsigned numCurrentAttribs = 0;
  258. // determine how many attributes currently exist in *this.
  259. for (unsigned i = 0; i < shaderAttribs.get_num_attribs(); ++i)
  260. {
  261. const utils::Pointer<GLchar[]>& attribName = shaderAttribs.get_attrib_name(i);
  262. if (glGetFragDataLocation(prog.gpu_id(), attribName.get()) >= 0)
  263. {
  264. ++numCurrentAttribs;
  265. }
  266. LS_LOG_GL_ERR();
  267. }
  268. LS_LOG_MSG("\tFound ", numCurrentAttribs, " attributes in the recreated fragment shader.");
  269. // preallocate some space
  270. ShaderAttribArray outAttribs;
  271. if (!outAttribs.reset_num_attribs(numCurrentAttribs))
  272. {
  273. LS_LOG_ERR("\tFailed to preallocate room in a ShaderAttribArray for ", numCurrentAttribs, " attributes.\n");
  274. return false;
  275. }
  276. // fill the current attribute list
  277. for (unsigned i = 0; i < numCurrentAttribs; ++i)
  278. {
  279. ShaderAttrib& outAttrib = outAttribs.get_attrib(i);
  280. // Fragment shader attributes require special care
  281. for (unsigned j = 0; j < shaderAttribs.get_num_attribs(); ++j)
  282. {
  283. // Check if an output attribute made it past the linking/optimizing
  284. // stage of the GLSL compiler.
  285. const utils::Pointer<GLchar[]>& attribName = shaderAttribs.get_attrib_name(j);
  286. const GLint attribLoc = glGetFragDataLocation(prog.gpu_id(), attribName.get());
  287. LS_LOG_GL_ERR();
  288. if (attribLoc < 0)
  289. {
  290. continue;
  291. }
  292. outAttrib.set_name(shaderAttribs.get_attrib_name(j));
  293. outAttrib.set_location(attribLoc);
  294. outAttrib.set_type(shaderAttribs.get_attrib(j).get_type());
  295. }
  296. }
  297. LS_LOG_MSG("\tSuccessfully found ", numCurrentAttribs, " linked attributes.\n");
  298. return outAttribs;
  299. }
  300. } // end ls namespace