2
0

BsGLVertexArrayObjectManager.cpp 5.5 KB

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