BsMeshHeap.cpp 20 KB

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