BsMeshHeap.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #include "BsMeshHeap.h"
  2. #include "BsCoreThread.h"
  3. #include "BsTransientMesh.h"
  4. #include "BsHardwareBufferManager.h"
  5. #include "BsVertexDataDesc.h"
  6. #include "BsVertexData.h"
  7. #include "BsMeshData.h"
  8. #include "BsMath.h"
  9. #include "BsEventQuery.h"
  10. namespace BansheeEngine
  11. {
  12. const float MeshHeap::GrowPercent = 1.5f;
  13. MeshHeap::MeshHeap(UINT32 numVertices, UINT32 numIndices,
  14. const VertexDataDescPtr& vertexDesc, IndexBuffer::IndexType indexType)
  15. :mNumVertices(numVertices), mNumIndices(numIndices), mNextFreeId(0),
  16. mIndexType(indexType), mVertexDesc(vertexDesc), mCPUIndexData(nullptr),
  17. mNextQueryId(0)
  18. {
  19. for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
  20. {
  21. mCPUVertexData.push_back(nullptr);
  22. }
  23. }
  24. MeshHeap::~MeshHeap()
  25. {
  26. }
  27. MeshHeapPtr MeshHeap::create(UINT32 numVertices, UINT32 numIndices,
  28. const VertexDataDescPtr& vertexDesc, IndexBuffer::IndexType indexType)
  29. {
  30. MeshHeap* meshHeap = new (bs_alloc<MeshHeap>()) MeshHeap(numVertices, numIndices, vertexDesc, indexType);
  31. MeshHeapPtr meshHeapPtr = bs_core_ptr<MeshHeap, GenAlloc>(meshHeap);
  32. meshHeapPtr->_setThisPtr(meshHeapPtr);
  33. meshHeapPtr->initialize();
  34. return meshHeapPtr;
  35. }
  36. void MeshHeap::initialize_internal()
  37. {
  38. THROW_IF_NOT_CORE_THREAD;
  39. growVertexBuffer(mNumVertices);
  40. growIndexBuffer(mNumIndices);
  41. }
  42. void MeshHeap::destroy_internal()
  43. {
  44. THROW_IF_NOT_CORE_THREAD;
  45. for(auto& cpuVertBuffer : mCPUVertexData)
  46. bs_free(cpuVertBuffer);
  47. if(mCPUIndexData != nullptr)
  48. bs_free(mCPUIndexData);
  49. CoreObject::destroy_internal();
  50. }
  51. TransientMeshPtr MeshHeap::alloc(const MeshDataPtr& meshData, DrawOperationType drawOp)
  52. {
  53. UINT32 meshIdx = mNextFreeId++;
  54. MeshHeapPtr thisPtr = std::static_pointer_cast<MeshHeap>(getThisPtr());
  55. TransientMesh* transientMesh = new (bs_alloc<TransientMesh>()) TransientMesh(thisPtr, meshIdx, meshData->getNumVertices(), meshData->getNumIndices(), drawOp);
  56. TransientMeshPtr transientMeshPtr = bs_core_ptr<TransientMesh, GenAlloc>(transientMesh);
  57. transientMeshPtr->_setThisPtr(transientMeshPtr);
  58. transientMeshPtr->initialize();
  59. mMeshes[meshIdx] = transientMeshPtr;
  60. queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::allocInternal, this, transientMeshPtr, meshData));
  61. return transientMeshPtr;
  62. }
  63. void MeshHeap::dealloc(const TransientMeshPtr& mesh)
  64. {
  65. auto iterFind = mMeshes.find(mesh->mId);
  66. if(iterFind == mMeshes.end())
  67. return;
  68. mesh->markAsDestroyed();
  69. mMeshes.erase(iterFind);
  70. queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::deallocInternal, this, mesh));
  71. }
  72. void MeshHeap::allocInternal(TransientMeshPtr mesh, const MeshDataPtr& meshData)
  73. {
  74. // Find free vertex chunk and grow if needed
  75. UINT32 smallestVertFit = 0;
  76. UINT32 smallestVertFitIdx = 0;
  77. while(smallestVertFit == 0)
  78. {
  79. UINT32 curIdx = 0;
  80. for(auto& chunkIdx : mFreeVertChunks)
  81. {
  82. ChunkData& chunk = mVertChunks[chunkIdx];
  83. if(chunk.size >= meshData->getNumVertices() && (chunk.size < smallestVertFit || smallestVertFit == 0))
  84. {
  85. smallestVertFit = chunk.size;
  86. smallestVertFitIdx = curIdx;
  87. }
  88. curIdx++;
  89. }
  90. if(smallestVertFit > 0)
  91. break;
  92. UINT32 newNumVertices = mNumVertices;
  93. while(newNumVertices < (mNumVertices + meshData->getNumVertices()))
  94. {
  95. newNumVertices = Math::roundToInt(newNumVertices * GrowPercent);
  96. }
  97. growVertexBuffer(newNumVertices);
  98. }
  99. // Find free index chunk and grow if needed
  100. UINT32 smallestIdxFit = 0;
  101. UINT32 smallestIdxFitIdx = 0;
  102. while(smallestIdxFit == 0)
  103. {
  104. UINT32 curIdx = 0;
  105. for(auto& chunkIdx : mFreeIdxChunks)
  106. {
  107. ChunkData& chunk = mIdxChunks[chunkIdx];
  108. if(chunk.size >= meshData->getNumIndices() && (chunk.size < smallestIdxFit || smallestIdxFit == 0))
  109. {
  110. smallestIdxFit = chunk.size;
  111. smallestIdxFitIdx = curIdx;
  112. }
  113. curIdx++;
  114. }
  115. if(smallestIdxFit > 0)
  116. break;
  117. UINT32 newNumIndices = mNumIndices;
  118. while(newNumIndices < (mNumIndices + meshData->getNumIndices()))
  119. {
  120. newNumIndices = Math::roundToInt(newNumIndices * GrowPercent);
  121. }
  122. growIndexBuffer(newNumIndices);
  123. }
  124. UINT32 freeVertChunkIdx = 0;
  125. UINT32 freeIdxChunkIdx = 0;
  126. auto freeVertIter = mFreeVertChunks.begin();
  127. freeVertChunkIdx = (*freeVertIter);
  128. for(UINT32 i = 0; i < smallestVertFitIdx; i++)
  129. {
  130. freeVertIter++;
  131. freeVertChunkIdx = (*freeVertIter);
  132. }
  133. mFreeVertChunks.erase(freeVertIter);
  134. auto freeIdxIter = mFreeIdxChunks.begin();
  135. freeIdxChunkIdx = (*freeIdxIter);
  136. for(UINT32 i = 0; i < smallestIdxFitIdx; i++)
  137. {
  138. freeIdxIter++;
  139. freeIdxChunkIdx = (*freeIdxIter);
  140. }
  141. mFreeIdxChunks.erase(freeIdxIter);
  142. ChunkData& vertChunk = mVertChunks[freeVertChunkIdx];
  143. ChunkData& idxChunk = mIdxChunks[freeIdxChunkIdx];
  144. UINT32 vertChunkStart = vertChunk.start;
  145. UINT32 idxChunkStart = idxChunk.start;
  146. UINT32 remainingNumVerts = vertChunk.size - meshData->getNumVertices();
  147. UINT32 remainingNumIdx = idxChunk.size - meshData->getNumIndices();
  148. vertChunk.size = meshData->getNumVertices();
  149. idxChunk.size = meshData->getNumIndices();
  150. if(remainingNumVerts > 0)
  151. {
  152. if(!mEmptyVertChunks.empty())
  153. {
  154. UINT32 emptyChunkIdx = mEmptyVertChunks.top();
  155. ChunkData& emptyChunk = mVertChunks[emptyChunkIdx];
  156. mEmptyVertChunks.pop();
  157. emptyChunk.start = vertChunkStart + meshData->getNumVertices();
  158. emptyChunk.size = remainingNumVerts;
  159. }
  160. else
  161. {
  162. ChunkData newChunk;
  163. newChunk.size = remainingNumVerts;
  164. newChunk.start = vertChunkStart + meshData->getNumVertices();
  165. mVertChunks.push_back(newChunk);
  166. mFreeVertChunks.push_back((UINT32)(mVertChunks.size() - 1));
  167. }
  168. }
  169. if(remainingNumIdx > 0)
  170. {
  171. if(!mEmptyIdxChunks.empty())
  172. {
  173. UINT32 emptyChunkIdx = mEmptyIdxChunks.top();
  174. ChunkData& emptyChunk = mIdxChunks[emptyChunkIdx];
  175. mEmptyIdxChunks.pop();
  176. emptyChunk.start = idxChunkStart + meshData->getNumIndices();
  177. emptyChunk.size = remainingNumIdx;
  178. }
  179. else
  180. {
  181. ChunkData newChunk;
  182. newChunk.size = remainingNumIdx;
  183. newChunk.start = idxChunkStart + meshData->getNumIndices();
  184. mIdxChunks.push_back(newChunk);
  185. mFreeIdxChunks.push_back((UINT32)(mIdxChunks.size() - 1));
  186. }
  187. }
  188. AllocatedData newAllocData;
  189. newAllocData.vertChunkIdx = freeVertChunkIdx;
  190. newAllocData.idxChunkIdx = freeIdxChunkIdx;
  191. newAllocData.useFlags = UseFlags::GPUFree;
  192. newAllocData.eventQueryIdx = createEventQuery();
  193. newAllocData.mesh = mesh;
  194. mMeshAllocData[mesh->getMeshHeapId()] = newAllocData;
  195. // Actually copy data
  196. for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
  197. {
  198. if(!mVertexDesc->hasStream(i))
  199. continue;
  200. if(!meshData->getVertexDesc()->hasStream(i))
  201. continue;
  202. // Ensure vertex sizes match
  203. UINT32 vertSize = mVertexData->vertexDeclaration->getVertexSize(i);
  204. UINT32 otherVertSize = meshData->getVertexDesc()->getVertexStride(i);
  205. if(otherVertSize != vertSize)
  206. {
  207. BS_EXCEPT(InvalidParametersException, "Provided vertex size for stream " + toString(i) + " doesn't match meshes vertex size. Needed: " +
  208. toString(vertSize) + ". Got: " + toString(otherVertSize));
  209. }
  210. VertexBufferPtr vertexBuffer = mVertexData->getBuffer(i);
  211. UINT8* vertDest = mCPUVertexData[i] + vertChunkStart * vertSize;
  212. memcpy(vertDest, meshData->getStreamData(i), meshData->getNumVertices() * vertSize);
  213. if(vertexBuffer->vertexColorReqRGBFlip())
  214. {
  215. UINT32 vertexStride = mVertexDesc->getVertexStride(i);
  216. for(INT32 semanticIdx = 0; semanticIdx < VertexBuffer::MAX_SEMANTIC_IDX; semanticIdx++)
  217. {
  218. if(!mVertexDesc->hasElement(VES_COLOR, semanticIdx, i))
  219. continue;
  220. UINT8* colorData = vertDest + mVertexDesc->getElementOffsetFromStream(VES_COLOR, semanticIdx, i);
  221. for(UINT32 j = 0; j < mVertexData->vertexCount; j++)
  222. {
  223. UINT32* curColor = (UINT32*)colorData;
  224. (*curColor) = ((*curColor) & 0xFF00FF00) | ((*curColor >> 16) & 0x000000FF) | ((*curColor << 16) & 0x00FF0000);
  225. colorData += vertexStride;
  226. }
  227. }
  228. }
  229. vertexBuffer->writeData(vertChunkStart * vertSize, meshData->getNumVertices() * vertSize, vertDest, BufferWriteType::NoOverwrite);
  230. }
  231. UINT32 idxSize = mIndexBuffer->getIndexSize();
  232. // Ensure index sizes match
  233. if(meshData->getIndexElementSize() != idxSize)
  234. {
  235. BS_EXCEPT(InvalidParametersException, "Provided index size doesn't match meshes index size. Needed: " +
  236. toString(idxSize) + ". Got: " + toString(meshData->getIndexElementSize()));
  237. }
  238. UINT8* idxDest = mCPUIndexData + idxChunkStart * idxSize;
  239. memcpy(idxDest, meshData->getIndexData(), meshData->getNumIndices() * idxSize);
  240. mIndexBuffer->writeData(idxChunkStart * idxSize, meshData->getNumIndices() * idxSize, idxDest, BufferWriteType::NoOverwrite);
  241. }
  242. void MeshHeap::deallocInternal(TransientMeshPtr mesh)
  243. {
  244. auto findIter = mMeshAllocData.find(mesh->getMeshHeapId());
  245. assert(findIter != mMeshAllocData.end());
  246. AllocatedData& allocData = findIter->second;
  247. if(allocData.useFlags == UseFlags::GPUFree)
  248. {
  249. allocData.useFlags = UseFlags::Free;
  250. freeEventQuery(allocData.eventQueryIdx);
  251. mFreeVertChunks.push_back(allocData.vertChunkIdx);
  252. mFreeIdxChunks.push_back(allocData.idxChunkIdx);
  253. mergeWithNearbyChunks(allocData.vertChunkIdx, allocData.idxChunkIdx);
  254. mMeshAllocData.erase(findIter);
  255. }
  256. else if(allocData.useFlags == UseFlags::Used)
  257. allocData.useFlags = UseFlags::CPUFree;
  258. }
  259. void MeshHeap::growVertexBuffer(UINT32 numVertices)
  260. {
  261. mNumVertices = numVertices;
  262. mVertexData = std::shared_ptr<VertexData>(bs_new<VertexData, PoolAlloc>());
  263. mVertexData->vertexCount = mNumVertices;
  264. mVertexData->vertexDeclaration = mVertexDesc->createDeclaration();
  265. // Create buffers and copy data
  266. for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
  267. {
  268. if(!mVertexDesc->hasStream(i))
  269. continue;
  270. UINT32 vertSize = mVertexData->vertexDeclaration->getVertexSize(i);
  271. VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
  272. vertSize, mVertexData->vertexCount, GBU_DYNAMIC);
  273. mVertexData->setBuffer(i, vertexBuffer);
  274. // Copy all data to the new buffer
  275. UINT8* oldBuffer = mCPUVertexData[i];
  276. UINT8* buffer = (UINT8*)bs_alloc(vertSize * numVertices);
  277. UINT32 destOffset = 0;
  278. if(oldBuffer != nullptr)
  279. {
  280. for(auto& allocData : mMeshAllocData)
  281. {
  282. ChunkData& oldChunk = mVertChunks[allocData.second.vertChunkIdx];
  283. UINT8* oldData = oldBuffer + oldChunk.start * vertSize;
  284. memcpy(buffer + destOffset * vertSize, oldData, oldChunk.size * vertSize);
  285. destOffset += oldChunk.size;
  286. }
  287. bs_free(oldBuffer);
  288. }
  289. if(destOffset > 0)
  290. vertexBuffer->writeData(0, destOffset * vertSize, buffer, BufferWriteType::NoOverwrite);
  291. mCPUVertexData[i] = buffer;
  292. }
  293. // Reorder chunks
  294. UINT32 destOffset = 0;
  295. Vector<ChunkData> newVertChunks;
  296. List<UINT32> freeVertChunks;
  297. for(auto& allocData : mMeshAllocData)
  298. {
  299. ChunkData& oldChunk = mVertChunks[allocData.second.vertChunkIdx];
  300. ChunkData newChunk;
  301. newChunk.start = destOffset;
  302. newChunk.size = oldChunk.size;
  303. allocData.second.vertChunkIdx = (UINT32)newVertChunks.size();
  304. newVertChunks.push_back(newChunk);
  305. destOffset += oldChunk.size;
  306. }
  307. // Add free chunk
  308. if(destOffset != mNumVertices)
  309. {
  310. ChunkData newChunk;
  311. newChunk.start = destOffset;
  312. newChunk.size = mNumVertices - destOffset;
  313. newVertChunks.push_back(newChunk);
  314. freeVertChunks.push_back((UINT32)(newVertChunks.size() - 1));
  315. }
  316. mVertChunks = newVertChunks;
  317. mFreeVertChunks = freeVertChunks;
  318. while(!mEmptyVertChunks.empty())
  319. mEmptyVertChunks.pop();
  320. }
  321. void MeshHeap::growIndexBuffer(UINT32 numIndices)
  322. {
  323. mNumIndices = numIndices;
  324. mIndexBuffer = HardwareBufferManager::instance().createIndexBuffer(mIndexType, mNumIndices, GBU_DYNAMIC);
  325. // Copy all data to the new buffer
  326. UINT32 idxSize = mIndexBuffer->getIndexSize();
  327. UINT8* oldBuffer = mCPUIndexData;
  328. UINT8* buffer = (UINT8*)bs_alloc(idxSize * numIndices);
  329. UINT32 destOffset = 0;
  330. if(oldBuffer != nullptr)
  331. {
  332. for(auto& allocData : mMeshAllocData)
  333. {
  334. ChunkData& oldChunk = mIdxChunks[allocData.second.idxChunkIdx];
  335. UINT8* oldData = oldBuffer + oldChunk.start * idxSize;
  336. memcpy(buffer + destOffset * idxSize, oldData, oldChunk.size * idxSize);
  337. destOffset += oldChunk.size;
  338. }
  339. bs_free(oldBuffer);
  340. }
  341. if(destOffset > 0)
  342. mIndexBuffer->writeData(0, destOffset * idxSize, buffer, BufferWriteType::NoOverwrite);
  343. mCPUIndexData = buffer;
  344. // Reorder chunks
  345. destOffset = 0;
  346. Vector<ChunkData> newIdxChunks;
  347. List<UINT32> freeIdxChunks;
  348. for(auto& allocData : mMeshAllocData)
  349. {
  350. ChunkData& oldChunk = mIdxChunks[allocData.second.idxChunkIdx];
  351. ChunkData newChunk;
  352. newChunk.start = destOffset;
  353. newChunk.size = oldChunk.size;
  354. allocData.second.idxChunkIdx = (UINT32)newIdxChunks.size();
  355. newIdxChunks.push_back(newChunk);
  356. destOffset += oldChunk.size;
  357. }
  358. // Add free chunk
  359. if(destOffset != mNumIndices)
  360. {
  361. ChunkData newChunk;
  362. newChunk.start = destOffset;
  363. newChunk.size = mNumIndices - destOffset;
  364. newIdxChunks.push_back(newChunk);
  365. freeIdxChunks.push_back((UINT32)(newIdxChunks.size() - 1));
  366. }
  367. mIdxChunks = newIdxChunks;
  368. mFreeIdxChunks = freeIdxChunks;
  369. while(!mEmptyIdxChunks.empty())
  370. mEmptyIdxChunks.pop();
  371. }
  372. UINT32 MeshHeap::createEventQuery()
  373. {
  374. UINT32 idx = 0;
  375. if(mFreeEventQueries.size() > 0)
  376. {
  377. idx = mFreeEventQueries.top();
  378. mFreeEventQueries.pop();
  379. }
  380. else
  381. {
  382. QueryData newQuery;
  383. newQuery.query = EventQuery::create();
  384. newQuery.queryId = 0;
  385. mEventQueries.push_back(newQuery);
  386. idx = (UINT32)(mEventQueries.size() - 1);
  387. }
  388. return idx;
  389. }
  390. void MeshHeap::freeEventQuery(UINT32 idx)
  391. {
  392. mEventQueries[idx].query->onTriggered.clear();
  393. mEventQueries[idx].queryId = 0;
  394. mFreeEventQueries.push(idx);
  395. }
  396. std::shared_ptr<VertexData> MeshHeap::_getVertexData() const
  397. {
  398. return mVertexData;
  399. }
  400. IndexBufferPtr MeshHeap::_getIndexBuffer() const
  401. {
  402. return mIndexBuffer;
  403. }
  404. UINT32 MeshHeap::getVertexOffset(UINT32 meshId) const
  405. {
  406. auto findIter = mMeshAllocData.find(meshId);
  407. assert(findIter != mMeshAllocData.end());
  408. UINT32 chunkIdx = findIter->second.vertChunkIdx;
  409. return mVertChunks[chunkIdx].start;
  410. }
  411. UINT32 MeshHeap::getIndexOffset(UINT32 meshId) const
  412. {
  413. auto findIter = mMeshAllocData.find(meshId);
  414. assert(findIter != mMeshAllocData.end());
  415. UINT32 chunkIdx = findIter->second.idxChunkIdx;
  416. return mIdxChunks[chunkIdx].start;
  417. }
  418. void MeshHeap::notifyUsedOnGPU(UINT32 meshId)
  419. {
  420. auto findIter = mMeshAllocData.find(meshId);
  421. assert(findIter != mMeshAllocData.end());
  422. AllocatedData& allocData = findIter->second;
  423. assert(allocData.useFlags != UseFlags::Free);
  424. if(allocData.useFlags == UseFlags::GPUFree)
  425. allocData.useFlags = UseFlags::Used;
  426. QueryData& queryData = mEventQueries[allocData.eventQueryIdx];
  427. queryData.queryId = mNextQueryId++;
  428. queryData.query->onTriggered.clear();
  429. queryData.query->onTriggered.connect(std::bind(&MeshHeap::queryTriggered, this, meshId, queryData.queryId));
  430. queryData.query->begin();
  431. }
  432. void MeshHeap::queryTriggered(UINT32 meshId, UINT32 queryId)
  433. {
  434. auto findIter = mMeshAllocData.find(meshId);
  435. assert(findIter != mMeshAllocData.end());
  436. AllocatedData& allocData = findIter->second;
  437. // If query ids don't match then it means there either a more recent query or
  438. // the buffer was discarded and we are not interested in query result
  439. QueryData& queryData = mEventQueries[allocData.eventQueryIdx];
  440. if(queryId == queryData.queryId)
  441. {
  442. assert(allocData.useFlags != UseFlags::Free && allocData.useFlags != UseFlags::GPUFree);
  443. if(allocData.useFlags == UseFlags::CPUFree)
  444. {
  445. allocData.useFlags = UseFlags::Free;
  446. freeEventQuery(allocData.eventQueryIdx);
  447. mFreeVertChunks.push_back(allocData.vertChunkIdx);
  448. mFreeIdxChunks.push_back(allocData.idxChunkIdx);
  449. mergeWithNearbyChunks(allocData.vertChunkIdx, allocData.idxChunkIdx);
  450. mMeshAllocData.erase(findIter);
  451. }
  452. else
  453. allocData.useFlags = UseFlags::GPUFree;
  454. }
  455. }
  456. void MeshHeap::mergeWithNearbyChunks(UINT32 chunkVertIdx, UINT32 chunkIdxIdx)
  457. {
  458. // Merge vertex chunks
  459. ChunkData& vertChunk = mVertChunks[chunkVertIdx];
  460. for(auto& freeChunkIdx : mFreeVertChunks)
  461. {
  462. if(chunkVertIdx == freeChunkIdx)
  463. continue;
  464. ChunkData& curChunk = mVertChunks[freeChunkIdx];
  465. if(curChunk.size == 0) // Already merged
  466. continue;
  467. bool merged = false;
  468. if(curChunk.start == (vertChunk.start + vertChunk.size))
  469. {
  470. vertChunk.size += curChunk.size;
  471. merged = true;
  472. }
  473. else if((curChunk.start + curChunk.size) == vertChunk.start)
  474. {
  475. vertChunk.start = curChunk.start;
  476. vertChunk.size += curChunk.size;
  477. merged = true;
  478. }
  479. if(merged)
  480. {
  481. // We can't remove the chunk since that would break the indexing scheme, so
  482. // mark it as empty and set size to 0. It will be reused when needed.
  483. curChunk.start = 0;
  484. curChunk.size = 0;
  485. mEmptyVertChunks.push(freeChunkIdx);
  486. }
  487. }
  488. // Merge index chunks
  489. ChunkData& idxChunk = mIdxChunks[chunkIdxIdx];
  490. for(auto& freeChunkIdx : mFreeIdxChunks)
  491. {
  492. if(chunkIdxIdx == freeChunkIdx)
  493. continue;
  494. ChunkData& curChunk = mIdxChunks[freeChunkIdx];
  495. if(curChunk.size == 0) // Already merged
  496. continue;
  497. bool merged = false;
  498. if(curChunk.start == (idxChunk.start + idxChunk.size))
  499. {
  500. idxChunk.size += curChunk.size;
  501. merged = true;
  502. }
  503. else if((curChunk.start + curChunk.size) == idxChunk.start)
  504. {
  505. idxChunk.start = curChunk.start;
  506. idxChunk.size += curChunk.size;
  507. merged = true;
  508. }
  509. if(merged)
  510. {
  511. // We can't remove the chunk since that would break the indexing scheme, so
  512. // mark it as empty and set size to 0. It will be reused when needed.
  513. curChunk.start = 0;
  514. curChunk.size = 0;
  515. mEmptyIdxChunks.push(freeChunkIdx);
  516. }
  517. }
  518. }
  519. }