BsGLVertexArrayObjectManager.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #include "BsGLVertexArrayObjectManager.h"
  5. #include "BsGLVertexBuffer.h"
  6. #include "BsVertexDeclaration.h"
  7. #include "BsGLSLGpuProgram.h"
  8. #include "BsGLHardwareBufferManager.h"
  9. #include "BsUtil.h"
  10. #include "BsRenderStats.h"
  11. #define VBO_BUFFER_OFFSET(i) ((char *)NULL + (i))
  12. namespace BansheeEngine
  13. {
  14. GLVertexArrayObject::GLVertexArrayObject()
  15. :mHandle(0), mVertProgId(0), mAttachedBuffers(nullptr), mNumBuffers(0)
  16. { }
  17. GLVertexArrayObject::GLVertexArrayObject(GLuint handle, UINT64 vertexProgramId,
  18. GLVertexBuffer** attachedBuffers, UINT32 numBuffers)
  19. :mHandle(handle), mVertProgId(vertexProgramId), mAttachedBuffers(attachedBuffers), mNumBuffers(numBuffers)
  20. { }
  21. ::std::size_t GLVertexArrayObject::Hash::operator()(const GLVertexArrayObject &vao) const
  22. {
  23. std::size_t seed = 0;
  24. hash_combine(seed, vao.mVertProgId);
  25. for (UINT32 i = 0; i < vao.mNumBuffers; i++)
  26. hash_combine(seed, vao.mAttachedBuffers[i]->getInternalID());
  27. return seed;
  28. }
  29. bool GLVertexArrayObject::Equal::operator()(const GLVertexArrayObject &a, const GLVertexArrayObject &b) const
  30. {
  31. if (a.mVertProgId != b.mVertProgId)
  32. return false;
  33. if (a.mNumBuffers != b.mNumBuffers)
  34. return false;
  35. for (UINT32 i = 0; i < a.mNumBuffers; i++)
  36. {
  37. if (a.mAttachedBuffers[i]->getInternalID() != b.mAttachedBuffers[i]->getInternalID())
  38. return false;
  39. }
  40. return true;
  41. }
  42. bool GLVertexArrayObject::operator== (const GLVertexArrayObject& obj)
  43. {
  44. if (mVertProgId != obj.mVertProgId)
  45. return false;
  46. if (mNumBuffers != obj.mNumBuffers)
  47. return false;
  48. for (UINT32 i = 0; i < mNumBuffers; i++)
  49. {
  50. if (mAttachedBuffers[i]->getInternalID() != obj.mAttachedBuffers[i]->getInternalID())
  51. return false;
  52. }
  53. return true;
  54. }
  55. bool GLVertexArrayObject::operator!= (const GLVertexArrayObject& obj)
  56. {
  57. return !operator==(obj);
  58. }
  59. GLVertexArrayObjectManager::~GLVertexArrayObjectManager()
  60. {
  61. assert(mVAObjects.size() == 0 && "VertexArrayObjectManager getting shut down but not all VA objects were released.");
  62. }
  63. const GLVertexArrayObject& GLVertexArrayObjectManager::getVAO(const GLSLGpuProgramPtr& vertexProgram,
  64. const VertexDeclarationPtr& vertexDecl, const Vector<VertexBufferPtr>& boundBuffers)
  65. {
  66. UINT32 numUsedBuffers = 0;
  67. INT32* streamToSeqIdx = stackAllocN<INT32>((UINT32)boundBuffers.size());
  68. GLVertexBuffer** usedBuffers = stackAllocN<GLVertexBuffer*>((UINT32)boundBuffers.size());
  69. const VertexDeclaration::VertexElementList& decl = vertexDecl->getElements();
  70. for (auto& elem : decl)
  71. {
  72. UINT16 streamIdx = elem.getStreamIdx();
  73. if (streamIdx >= (UINT32)boundBuffers.size())
  74. {
  75. streamToSeqIdx[streamIdx] = -1;
  76. continue;
  77. }
  78. VertexBufferPtr vertexBuffer = boundBuffers[streamIdx];
  79. if (vertexBuffer == nullptr)
  80. continue; // Skip unbound elements
  81. streamToSeqIdx[streamIdx] = (INT32)numUsedBuffers;
  82. usedBuffers[numUsedBuffers++] = static_cast<GLVertexBuffer*>(vertexBuffer.get());
  83. }
  84. GLVertexArrayObject wantedVAO(0, vertexProgram->getInternalID(), usedBuffers, numUsedBuffers);
  85. auto findIter = mVAObjects.find(wantedVAO);
  86. if (findIter != mVAObjects.end())
  87. {
  88. stackDeallocLast(usedBuffers);
  89. stackDeallocLast(streamToSeqIdx);
  90. return *findIter; // Found existing, return that
  91. }
  92. // Need to create new VAO
  93. const VertexDeclaration::VertexElementList& inputAttributes = vertexProgram->getInputAttributes().getElements();
  94. glGenVertexArrays(1, &wantedVAO.mHandle);
  95. glBindVertexArray(wantedVAO.mHandle);
  96. for (auto& elem : decl)
  97. {
  98. UINT16 streamIdx = elem.getStreamIdx();
  99. INT32 seqIdx = streamToSeqIdx[streamIdx];
  100. if (seqIdx == -1)
  101. continue;
  102. bool foundSemantic = false;
  103. GLint attribLocation = 0;
  104. for (auto iter = inputAttributes.begin(); iter != inputAttributes.end(); ++iter)
  105. {
  106. if (iter->getSemantic() == elem.getSemantic() && iter->getSemanticIdx() == elem.getSemanticIdx())
  107. {
  108. foundSemantic = true;
  109. attribLocation = iter->getOffset();
  110. break;
  111. }
  112. }
  113. if (!foundSemantic) // Shader needs to have a matching input attribute, otherwise we skip it
  114. continue;
  115. // TODO - We might also want to check the size of input and buffer, and make sure they match? Or does OpenGL handle that internally?
  116. GLVertexBuffer* vertexBuffer = usedBuffers[seqIdx];
  117. glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->getGLBufferId());
  118. void* bufferData = VBO_BUFFER_OFFSET(elem.getOffset());
  119. GLboolean normalized = GL_FALSE;
  120. switch (elem.getType())
  121. {
  122. case VET_COLOR:
  123. case VET_COLOR_ABGR:
  124. case VET_COLOR_ARGB:
  125. normalized = GL_TRUE;
  126. break;
  127. default:
  128. break;
  129. };
  130. UINT16 typeCount = VertexElement::getTypeCount(elem.getType());
  131. GLenum glType = GLHardwareBufferManager::getGLType(elem.getType());
  132. GLsizei vertexSize = static_cast<GLsizei>(vertexBuffer->getVertexSize());
  133. glVertexAttribPointer(attribLocation, typeCount, glType, normalized,
  134. vertexSize, bufferData);
  135. glEnableVertexAttribArray(attribLocation);
  136. }
  137. wantedVAO.mAttachedBuffers = (GLVertexBuffer**)bs_alloc<GLVertexBuffer*>(numUsedBuffers);
  138. for (UINT32 i = 0; i < numUsedBuffers; i++)
  139. {
  140. wantedVAO.mAttachedBuffers[i] = usedBuffers[i];
  141. wantedVAO.mAttachedBuffers[i]->registerVAO(wantedVAO);
  142. }
  143. stackDeallocLast(usedBuffers);
  144. stackDeallocLast(streamToSeqIdx);
  145. auto iter = mVAObjects.insert(wantedVAO);
  146. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexArrayObject);
  147. return *iter.first;
  148. }
  149. void GLVertexArrayObjectManager::notifyBufferDestroyed(const GLVertexArrayObject& vao)
  150. {
  151. mVAObjects.erase(vao);
  152. for (UINT32 i = 0; i < vao.mNumBuffers; i++)
  153. {
  154. vao.mAttachedBuffers[i]->unregisterVAO(vao);
  155. }
  156. glDeleteVertexArrays(1, &vao.mHandle);
  157. bs_free(vao.mAttachedBuffers);
  158. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexArrayObject);
  159. }
  160. }