BsMeshHeap.cpp 18 KB

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