BsGLVertexArrayObjectManager.cpp 6.2 KB

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