MeshResource.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/MeshResource.h>
  6. #include <AnKi/Resource/ResourceManager.h>
  7. #include <AnKi/Resource/MeshBinaryLoader.h>
  8. #include <AnKi/Resource/AsyncLoader.h>
  9. #include <AnKi/Resource/AccelerationStructureScratchAllocator.h>
  10. #include <AnKi/Util/Functions.h>
  11. #include <AnKi/Util/Filesystem.h>
  12. #include <AnKi/Core/App.h>
  13. #include <AnKi/Physics/PhysicsWorld.h>
  14. namespace anki {
  15. class MeshResource::LoadContext
  16. {
  17. public:
  18. MeshResourcePtr m_mesh;
  19. MeshBinaryLoader m_loader;
  20. LoadContext(MeshResource* mesh)
  21. : m_mesh(mesh)
  22. , m_loader(&ResourceMemoryPool::getSingleton())
  23. {
  24. }
  25. };
  26. /// Mesh upload async task.
  27. class MeshResource::LoadTask : public AsyncLoaderTask
  28. {
  29. public:
  30. MeshResource::LoadContext m_ctx;
  31. LoadTask(MeshResource* mesh)
  32. : m_ctx(mesh)
  33. {
  34. }
  35. Error operator()([[maybe_unused]] AsyncLoaderTaskContext& ctx) final
  36. {
  37. return m_ctx.m_mesh->loadAsync(m_ctx.m_loader);
  38. }
  39. static BaseMemoryPool& getMemoryPool()
  40. {
  41. return ResourceMemoryPool::getSingleton();
  42. }
  43. };
  44. MeshResource::~MeshResource()
  45. {
  46. for(Lod& lod : m_lods)
  47. {
  48. UnifiedGeometryBuffer::getSingleton().deferredFree(lod.m_indexBufferAllocationToken);
  49. for(VertexStreamId stream : EnumIterable(VertexStreamId::kMeshRelatedFirst, VertexStreamId::kMeshRelatedCount))
  50. {
  51. UnifiedGeometryBuffer::getSingleton().deferredFree(lod.m_vertexBuffersAllocationToken[stream]);
  52. }
  53. }
  54. }
  55. Error MeshResource::load(const ResourceFilename& filename, Bool async)
  56. {
  57. UniquePtr<LoadTask> task;
  58. LoadContext* ctx;
  59. LoadContext localCtx(this);
  60. String basename;
  61. getFilepathFilename(filename, basename);
  62. const Bool rayTracingEnabled = GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled;
  63. if(async)
  64. {
  65. task.reset(AsyncLoader::getSingleton().newTask<LoadTask>(this));
  66. ctx = &task->m_ctx;
  67. }
  68. else
  69. {
  70. task.reset(nullptr);
  71. ctx = &localCtx;
  72. }
  73. // Open file
  74. MeshBinaryLoader& loader = ctx->m_loader;
  75. ANKI_CHECK(loader.load(filename));
  76. const MeshBinaryHeader& header = loader.getHeader();
  77. // Misc
  78. m_indexType = header.m_indexType;
  79. m_aabb.setMin(header.m_boundingVolume.m_aabbMin);
  80. m_aabb.setMax(header.m_boundingVolume.m_aabbMax);
  81. m_positionsScale = header.m_vertexAttributes[VertexStreamId::kPosition].m_scale[0];
  82. m_positionsTranslation = Vec3(&header.m_vertexAttributes[VertexStreamId::kPosition].m_translation[0]);
  83. m_isConvex = !!(loader.getHeader().m_flags & MeshBinaryFlag::kConvex);
  84. // Submeshes
  85. m_subMeshes.resize(header.m_subMeshCount);
  86. for(U32 i = 0; i < m_subMeshes.getSize(); ++i)
  87. {
  88. for(U32 lod = 0; lod < header.m_lodCount; ++lod)
  89. {
  90. m_subMeshes[i].m_firstIndices[lod] = loader.getSubMeshes()[i].m_lods[lod].m_firstIndex;
  91. m_subMeshes[i].m_indexCounts[lod] = loader.getSubMeshes()[i].m_lods[lod].m_indexCount;
  92. m_subMeshes[i].m_firstMeshlet[lod] = loader.getSubMeshes()[i].m_lods[lod].m_firstMeshlet;
  93. m_subMeshes[i].m_meshletCounts[lod] = loader.getSubMeshes()[i].m_lods[lod].m_meshletCount;
  94. }
  95. m_subMeshes[i].m_aabb.setMin(loader.getSubMeshes()[i].m_boundingVolume.m_aabbMin);
  96. m_subMeshes[i].m_aabb.setMax(loader.getSubMeshes()[i].m_boundingVolume.m_aabbMax);
  97. }
  98. // LODs
  99. m_lods.resize(header.m_lodCount);
  100. for(I32 l = I32(header.m_lodCount - 1); l >= 0; --l)
  101. {
  102. Lod& lod = m_lods[l];
  103. // Index stuff
  104. lod.m_indexCount = header.m_indexCounts[l];
  105. ANKI_ASSERT((lod.m_indexCount % 3) == 0 && "Expecting triangles");
  106. const PtrSize indexBufferSize = PtrSize(lod.m_indexCount) * getIndexSize(m_indexType);
  107. lod.m_indexBufferAllocationToken = UnifiedGeometryBuffer::getSingleton().allocate(indexBufferSize, getIndexSize(m_indexType));
  108. // Vertex stuff
  109. lod.m_vertexCount = header.m_vertexCounts[l];
  110. for(VertexStreamId stream : EnumIterable(VertexStreamId::kMeshRelatedFirst, VertexStreamId::kMeshRelatedCount))
  111. {
  112. if(header.m_vertexAttributes[stream].m_format == Format::kNone)
  113. {
  114. continue;
  115. }
  116. m_presentVertStreams |= VertexStreamMask(1 << stream);
  117. lod.m_vertexBuffersAllocationToken[stream] =
  118. UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[stream], lod.m_vertexCount);
  119. }
  120. // Meshlet
  121. if(GrManager::getSingleton().getDeviceCapabilities().m_meshShaders || g_cvarCoreMeshletRendering)
  122. {
  123. const PtrSize meshletIndicesSize = header.m_meshletPrimitiveCounts[l] * sizeof(U8Vec4);
  124. lod.m_meshletIndices = UnifiedGeometryBuffer::getSingleton().allocate(meshletIndicesSize, sizeof(U8Vec4));
  125. const PtrSize meshletBoundingVolumesSize = header.m_meshletCounts[l] * sizeof(MeshletBoundingVolume);
  126. lod.m_meshletBoundingVolumes = UnifiedGeometryBuffer::getSingleton().allocate(meshletBoundingVolumesSize, sizeof(MeshletBoundingVolume));
  127. const PtrSize meshletGeomDescriptorsSize = header.m_meshletCounts[l] * sizeof(MeshletGeometryDescriptor);
  128. lod.m_meshletGeometryDescriptors =
  129. UnifiedGeometryBuffer::getSingleton().allocate(meshletGeomDescriptorsSize, sizeof(MeshletGeometryDescriptor));
  130. lod.m_meshletCount = header.m_meshletCounts[l];
  131. }
  132. }
  133. // BLAS
  134. if(rayTracingEnabled)
  135. {
  136. for(U32 submeshIdx = 0; submeshIdx < m_subMeshes.getSize(); ++submeshIdx)
  137. {
  138. SubMesh& subMesh = m_subMeshes[submeshIdx];
  139. for(U32 lodIdx = 0; lodIdx < header.m_lodCount; ++lodIdx)
  140. {
  141. Lod& lod = m_lods[lodIdx];
  142. AccelerationStructureInitInfo inf(ResourceString().sprintf("%s_%s", "BLAS", basename.cstr()));
  143. inf.m_type = AccelerationStructureType::kBottomLevel;
  144. inf.m_bottomLevel.m_indexBuffer = BufferView(lod.m_indexBufferAllocationToken)
  145. .incrementOffset(getIndexSize(m_indexType) * subMesh.m_firstIndices[lodIdx])
  146. .setRange(getIndexSize(m_indexType) * subMesh.m_indexCounts[lodIdx]);
  147. inf.m_bottomLevel.m_indexCount = subMesh.m_indexCounts[lodIdx];
  148. inf.m_bottomLevel.m_indexType = m_indexType;
  149. inf.m_bottomLevel.m_positionBuffer = lod.m_vertexBuffersAllocationToken[VertexStreamId::kPosition];
  150. inf.m_bottomLevel.m_positionStride = getFormatInfo(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition]).m_texelSize;
  151. inf.m_bottomLevel.m_positionsFormat = kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition];
  152. inf.m_bottomLevel.m_positionCount = lod.m_vertexCount;
  153. const PtrSize requiredMemory = GrManager::getSingleton().getAccelerationStructureMemoryRequirement(inf);
  154. subMesh.m_blasAllocationTokens[lodIdx] = UnifiedGeometryBuffer::getSingleton().allocate(requiredMemory, 1);
  155. inf.m_accelerationStructureBuffer = subMesh.m_blasAllocationTokens[lodIdx];
  156. subMesh.m_blas[lodIdx] = GrManager::getSingleton().newAccelerationStructure(inf);
  157. }
  158. }
  159. }
  160. // Submit the loading task
  161. if(async)
  162. {
  163. LoadTask* pTask;
  164. task.moveAndReset(pTask);
  165. AsyncLoader::getSingleton().submitTask(pTask, AsyncLoaderPriority::kMedium);
  166. }
  167. else
  168. {
  169. ANKI_CHECK(loadAsync(loader));
  170. }
  171. return Error::kNone;
  172. }
  173. Error MeshResource::loadAsync(MeshBinaryLoader& loader) const
  174. {
  175. GrManager& gr = GrManager::getSingleton();
  176. TransferGpuAllocator& transferAlloc = TransferGpuAllocator::getSingleton();
  177. Array<TransferGpuAllocatorHandle, kMaxLodCount*(U32(VertexStreamId::kMeshRelatedCount) + 1 + 3)> handles;
  178. U32 handleCount = 0;
  179. Buffer* unifiedGeometryBuffer = &UnifiedGeometryBuffer::getSingleton().getBuffer();
  180. const BufferUsageBit unifiedGeometryBufferNonTransferUsage = unifiedGeometryBuffer->getBufferUsage() ^ BufferUsageBit::kCopyDestination;
  181. CommandBufferInitInfo cmdbinit;
  182. cmdbinit.m_flags = CommandBufferFlag::kSmallBatch | CommandBufferFlag::kGeneralWork;
  183. CommandBufferPtr cmdb = gr.newCommandBuffer(cmdbinit);
  184. // Set transfer to transfer barrier because of the clear that happened while sync loading
  185. const BufferBarrierInfo barrier = {UnifiedGeometryBuffer::getSingleton().getBufferView(), unifiedGeometryBufferNonTransferUsage,
  186. BufferUsageBit::kCopyDestination};
  187. cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
  188. // Upload index and vertex buffers
  189. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  190. {
  191. const Lod& lod = m_lods[lodIdx];
  192. // Upload index buffer
  193. {
  194. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  195. ANKI_CHECK(transferAlloc.allocate(lod.m_indexBufferAllocationToken.getAllocatedSize(), handle));
  196. void* data = handle.getMappedMemory();
  197. ANKI_ASSERT(data);
  198. ANKI_CHECK(loader.storeIndexBuffer(lodIdx, data, handle.getRange()));
  199. cmdb->copyBufferToBuffer(handle, lod.m_indexBufferAllocationToken);
  200. }
  201. // Upload vert buffers
  202. for(VertexStreamId stream : EnumIterable(VertexStreamId::kMeshRelatedFirst, VertexStreamId::kMeshRelatedCount))
  203. {
  204. if(!(m_presentVertStreams & VertexStreamMask(1 << stream)))
  205. {
  206. continue;
  207. }
  208. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  209. ANKI_CHECK(transferAlloc.allocate(lod.m_vertexBuffersAllocationToken[stream].getAllocatedSize(), handle));
  210. U8* data = static_cast<U8*>(handle.getMappedMemory());
  211. ANKI_ASSERT(data);
  212. // Load to staging
  213. ANKI_CHECK(loader.storeVertexBuffer(lodIdx, U32(stream), data, handle.getRange()));
  214. // Copy
  215. cmdb->copyBufferToBuffer(handle, lod.m_vertexBuffersAllocationToken[stream]);
  216. }
  217. if(lod.m_meshletBoundingVolumes.isValid())
  218. {
  219. // Indices
  220. TransferGpuAllocatorHandle& handle = handles[handleCount++];
  221. const PtrSize primitivesSize = lod.m_meshletIndices.getAllocatedSize();
  222. ANKI_CHECK(transferAlloc.allocate(primitivesSize, handle));
  223. ANKI_CHECK(loader.storeMeshletIndicesBuffer(lodIdx, handle.getMappedMemory(), primitivesSize));
  224. cmdb->copyBufferToBuffer(handle, lod.m_meshletIndices);
  225. // Meshlets
  226. ResourceDynamicArray<MeshBinaryMeshlet> binaryMeshlets;
  227. binaryMeshlets.resize(loader.getHeader().m_meshletCounts[lodIdx]);
  228. ANKI_CHECK(loader.storeMeshletBuffer(lodIdx, WeakArray(binaryMeshlets)));
  229. TransferGpuAllocatorHandle& handle2 = handles[handleCount++];
  230. ANKI_CHECK(transferAlloc.allocate(lod.m_meshletBoundingVolumes.getAllocatedSize(), handle2));
  231. WeakArray<MeshletBoundingVolume> outMeshletBoundingVolumes(static_cast<MeshletBoundingVolume*>(handle2.getMappedMemory()),
  232. loader.getHeader().m_meshletCounts[lodIdx]);
  233. TransferGpuAllocatorHandle& handle3 = handles[handleCount++];
  234. ANKI_CHECK(transferAlloc.allocate(lod.m_meshletGeometryDescriptors.getAllocatedSize(), handle3));
  235. WeakArray<MeshletGeometryDescriptor> outMeshletGeomDescriptors(static_cast<MeshletGeometryDescriptor*>(handle3.getMappedMemory()),
  236. loader.getHeader().m_meshletCounts[lodIdx]);
  237. for(U32 i = 0; i < binaryMeshlets.getSize(); ++i)
  238. {
  239. const MeshBinaryMeshlet& inMeshlet = binaryMeshlets[i];
  240. MeshletGeometryDescriptor& outMeshletGeom = outMeshletGeomDescriptors[i];
  241. MeshletBoundingVolume& outMeshletBoundingVolume = outMeshletBoundingVolumes[i];
  242. outMeshletBoundingVolume = {};
  243. outMeshletGeom = {};
  244. for(VertexStreamId stream : EnumIterable(VertexStreamId::kMeshRelatedFirst, VertexStreamId::kMeshRelatedCount))
  245. {
  246. if(!(m_presentVertStreams & VertexStreamMask(1u << stream)))
  247. {
  248. continue;
  249. }
  250. outMeshletGeom.m_vertexOffsets[U32(stream)] =
  251. lod.m_vertexBuffersAllocationToken[stream].getOffset() / getFormatInfo(kMeshRelatedVertexStreamFormats[stream]).m_texelSize
  252. + inMeshlet.m_firstVertex;
  253. }
  254. outMeshletGeom.m_firstPrimitive =
  255. lod.m_meshletIndices.getOffset() / getFormatInfo(kMeshletPrimitiveFormat).m_texelSize + inMeshlet.m_firstPrimitive;
  256. outMeshletGeom.m_primitiveCount = inMeshlet.m_primitiveCount;
  257. outMeshletGeom.m_vertexCount = inMeshlet.m_vertexCount;
  258. outMeshletGeom.m_positionTranslation = m_positionsTranslation;
  259. outMeshletGeom.m_positionScale = m_positionsScale;
  260. outMeshletBoundingVolume.m_aabbMin = inMeshlet.m_boundingVolume.m_aabbMin;
  261. outMeshletBoundingVolume.m_aabbMax = inMeshlet.m_boundingVolume.m_aabbMax;
  262. outMeshletBoundingVolume.m_coneDirection_R8G8B8_Snorm_cosHalfAngle_R8_Snorm =
  263. Vec4(inMeshlet.m_coneDirection, cos(inMeshlet.m_coneAngle / 2.0f)).packSnorm4x8();
  264. outMeshletBoundingVolume.m_coneApex = inMeshlet.m_coneApex;
  265. outMeshletBoundingVolume.m_sphereRadius =
  266. ((outMeshletBoundingVolume.m_aabbMin + outMeshletBoundingVolume.m_aabbMax) / 2.0f - outMeshletBoundingVolume.m_aabbMax).length();
  267. outMeshletBoundingVolume.m_primitiveCount = inMeshlet.m_primitiveCount;
  268. }
  269. cmdb->copyBufferToBuffer(handle2, lod.m_meshletBoundingVolumes);
  270. cmdb->copyBufferToBuffer(handle3, lod.m_meshletGeometryDescriptors);
  271. }
  272. }
  273. if(gr.getDeviceCapabilities().m_rayTracingEnabled)
  274. {
  275. // Build BLASes
  276. for(U32 submeshIdx = 0; submeshIdx < m_subMeshes.getSize(); ++submeshIdx)
  277. {
  278. const SubMesh& submesh = m_subMeshes[submeshIdx];
  279. // Set the barriers
  280. BufferBarrierInfo bufferBarrier;
  281. bufferBarrier.m_bufferView = UnifiedGeometryBuffer::getSingleton().getBufferView();
  282. bufferBarrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  283. bufferBarrier.m_nextUsage = unifiedGeometryBufferNonTransferUsage;
  284. Array<AccelerationStructureBarrierInfo, kMaxLodCount> asBarriers;
  285. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  286. {
  287. asBarriers[lodIdx].m_as = submesh.m_blas[lodIdx].get();
  288. asBarriers[lodIdx].m_previousUsage = AccelerationStructureUsageBit::kNone;
  289. asBarriers[lodIdx].m_nextUsage = AccelerationStructureUsageBit::kBuild;
  290. }
  291. cmdb->setPipelineBarrier({}, {&bufferBarrier, 1}, {&asBarriers[0], m_lods.getSize()});
  292. // Build BLASes
  293. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  294. {
  295. Bool addBarrier;
  296. const BufferView scratchBuff =
  297. AccelerationStructureScratchAllocator::getSingleton().allocate(submesh.m_blas[lodIdx]->getBuildScratchBufferSize(), addBarrier);
  298. if(addBarrier)
  299. {
  300. BufferBarrierInfo barr;
  301. barr.m_bufferView = scratchBuff;
  302. barr.m_previousUsage = BufferUsageBit::kAccelerationStructureBuildScratch;
  303. barr.m_nextUsage = BufferUsageBit::kAccelerationStructureBuildScratch;
  304. cmdb->setPipelineBarrier({}, {&barr, 1}, {});
  305. }
  306. cmdb->buildAccelerationStructure(submesh.m_blas[lodIdx].get(), scratchBuff);
  307. }
  308. // Barriers again
  309. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  310. {
  311. asBarriers[lodIdx].m_as = submesh.m_blas[lodIdx].get();
  312. asBarriers[lodIdx].m_previousUsage = AccelerationStructureUsageBit::kBuild;
  313. asBarriers[lodIdx].m_nextUsage = AccelerationStructureUsageBit::kAllRead;
  314. }
  315. cmdb->setPipelineBarrier({}, {}, {&asBarriers[0], m_lods.getSize()});
  316. }
  317. }
  318. else
  319. {
  320. // Only set a barrier
  321. BufferBarrierInfo bufferBarrier;
  322. bufferBarrier.m_bufferView = UnifiedGeometryBuffer::getSingleton().getBufferView();
  323. bufferBarrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  324. bufferBarrier.m_nextUsage = unifiedGeometryBufferNonTransferUsage;
  325. cmdb->setPipelineBarrier({}, {&bufferBarrier, 1}, {});
  326. }
  327. // Finalize
  328. FencePtr fence;
  329. cmdb->endRecording();
  330. GrManager::getSingleton().submit(cmdb.get(), {}, &fence);
  331. for(U32 i = 0; i < handleCount; ++i)
  332. {
  333. transferAlloc.release(handles[i], fence);
  334. }
  335. m_loadedLodCount.store(m_lods.getSize());
  336. return Error::kNone;
  337. }
  338. Error MeshResource::getOrCreateCollisionShape(Bool wantStatic, U32 lod, PhysicsCollisionShapePtr& out) const
  339. {
  340. lod = min<U32>(lod, getLodCount() - 1);
  341. Bool isConvex = m_isConvex;
  342. if(!isConvex && !wantStatic)
  343. {
  344. ANKI_RESOURCE_LOGW("Requesting a non-static non-convex collision shape is not supported. Will create a convex hull instead");
  345. isConvex = true;
  346. }
  347. const Lod& l = m_lods[lod];
  348. LockGuard lock(l.m_collisionShapeMtx);
  349. if(!l.m_collisionShapes[isConvex])
  350. {
  351. MeshBinaryLoader loader(&ResourceMemoryPool::getSingleton());
  352. ANKI_CHECK(loader.load(getFilename()));
  353. ResourceDynamicArray<Vec3> positions;
  354. ResourceDynamicArray<U32> indices;
  355. ANKI_CHECK(loader.storeIndicesAndPosition(lod, indices, positions));
  356. if(isConvex)
  357. {
  358. l.m_collisionShapes[isConvex] = PhysicsWorld::getSingleton().newConvexHullShape(positions);
  359. }
  360. else
  361. {
  362. l.m_collisionShapes[isConvex] = PhysicsWorld::getSingleton().newStaticMeshShape(positions, indices);
  363. }
  364. }
  365. out = l.m_collisionShapes[isConvex];
  366. return Error::kNone;
  367. }
  368. } // end namespace anki