BsMeshHeap.cpp 19 KB

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