2
0

BsMeshHeap.cpp 19 KB

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