BsMeshHeap.cpp 20 KB

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