BsMeshHeap.cpp 19 KB

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