BsMeshHeap.cpp 19 KB

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