MeshResource.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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_R16_Uint_vertexCount_R16_Uint = (inMeshlet.m_primitiveCount << 16u) | inMeshlet.m_vertexCount;
  257. outMeshletGeom.m_positionTranslation = m_positionsTranslation;
  258. outMeshletGeom.m_positionScale = m_positionsScale;
  259. outMeshletBoundingVolume.m_aabbMin = inMeshlet.m_boundingVolume.m_aabbMin;
  260. outMeshletBoundingVolume.m_aabbMax = inMeshlet.m_boundingVolume.m_aabbMax;
  261. outMeshletBoundingVolume.m_coneDirection_R8G8B8_Snorm_cosHalfAngle_R8_Snorm =
  262. packSnorm4x8(Vec4(inMeshlet.m_coneDirection, cos(inMeshlet.m_coneAngle / 2.0f)));
  263. outMeshletBoundingVolume.m_coneApex = inMeshlet.m_coneApex;
  264. outMeshletBoundingVolume.m_sphereRadius =
  265. ((outMeshletBoundingVolume.m_aabbMin + outMeshletBoundingVolume.m_aabbMax) / 2.0f - outMeshletBoundingVolume.m_aabbMax).length();
  266. outMeshletBoundingVolume.m_primitiveCount = inMeshlet.m_primitiveCount;
  267. }
  268. cmdb->copyBufferToBuffer(handle2, lod.m_meshletBoundingVolumes);
  269. cmdb->copyBufferToBuffer(handle3, lod.m_meshletGeometryDescriptors);
  270. }
  271. }
  272. if(gr.getDeviceCapabilities().m_rayTracingEnabled)
  273. {
  274. // Build BLASes
  275. for(U32 submeshIdx = 0; submeshIdx < m_subMeshes.getSize(); ++submeshIdx)
  276. {
  277. const SubMesh& submesh = m_subMeshes[submeshIdx];
  278. // Set the barriers
  279. BufferBarrierInfo bufferBarrier;
  280. bufferBarrier.m_bufferView = UnifiedGeometryBuffer::getSingleton().getBufferView();
  281. bufferBarrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  282. bufferBarrier.m_nextUsage = unifiedGeometryBufferNonTransferUsage;
  283. Array<AccelerationStructureBarrierInfo, kMaxLodCount> asBarriers;
  284. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  285. {
  286. asBarriers[lodIdx].m_as = submesh.m_blas[lodIdx].get();
  287. asBarriers[lodIdx].m_previousUsage = AccelerationStructureUsageBit::kNone;
  288. asBarriers[lodIdx].m_nextUsage = AccelerationStructureUsageBit::kBuild;
  289. }
  290. cmdb->setPipelineBarrier({}, {&bufferBarrier, 1}, {&asBarriers[0], m_lods.getSize()});
  291. // Build BLASes
  292. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  293. {
  294. Bool addBarrier;
  295. const BufferView scratchBuff =
  296. AccelerationStructureScratchAllocator::getSingleton().allocate(submesh.m_blas[lodIdx]->getBuildScratchBufferSize(), addBarrier);
  297. if(addBarrier)
  298. {
  299. BufferBarrierInfo barr;
  300. barr.m_bufferView = scratchBuff;
  301. barr.m_previousUsage = BufferUsageBit::kAccelerationStructureBuildScratch;
  302. barr.m_nextUsage = BufferUsageBit::kAccelerationStructureBuildScratch;
  303. cmdb->setPipelineBarrier({}, {&barr, 1}, {});
  304. }
  305. cmdb->buildAccelerationStructure(submesh.m_blas[lodIdx].get(), scratchBuff);
  306. }
  307. // Barriers again
  308. for(U32 lodIdx = 0; lodIdx < m_lods.getSize(); ++lodIdx)
  309. {
  310. asBarriers[lodIdx].m_as = submesh.m_blas[lodIdx].get();
  311. asBarriers[lodIdx].m_previousUsage = AccelerationStructureUsageBit::kBuild;
  312. asBarriers[lodIdx].m_nextUsage = AccelerationStructureUsageBit::kAllRead;
  313. }
  314. cmdb->setPipelineBarrier({}, {}, {&asBarriers[0], m_lods.getSize()});
  315. }
  316. }
  317. else
  318. {
  319. // Only set a barrier
  320. BufferBarrierInfo bufferBarrier;
  321. bufferBarrier.m_bufferView = UnifiedGeometryBuffer::getSingleton().getBufferView();
  322. bufferBarrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  323. bufferBarrier.m_nextUsage = unifiedGeometryBufferNonTransferUsage;
  324. cmdb->setPipelineBarrier({}, {&bufferBarrier, 1}, {});
  325. }
  326. // Finalize
  327. FencePtr fence;
  328. cmdb->endRecording();
  329. GrManager::getSingleton().submit(cmdb.get(), {}, &fence);
  330. for(U32 i = 0; i < handleCount; ++i)
  331. {
  332. transferAlloc.release(handles[i], fence);
  333. }
  334. m_loadedLodCount.store(m_lods.getSize());
  335. return Error::kNone;
  336. }
  337. Error MeshResource::getOrCreateCollisionShape(Bool wantStatic, U32 lod, PhysicsCollisionShapePtr& out) const
  338. {
  339. lod = min<U32>(lod, getLodCount() - 1);
  340. Bool isConvex = m_isConvex;
  341. if(!isConvex && !wantStatic)
  342. {
  343. ANKI_RESOURCE_LOGW("Requesting a non-static non-convex collision shape is not supported. Will create a convex hull instead");
  344. isConvex = true;
  345. }
  346. const Lod& l = m_lods[lod];
  347. LockGuard lock(l.m_collisionShapeMtx);
  348. if(!l.m_collisionShapes[isConvex])
  349. {
  350. MeshBinaryLoader loader(&ResourceMemoryPool::getSingleton());
  351. ANKI_CHECK(loader.load(getFilename()));
  352. ResourceDynamicArray<Vec3> positions;
  353. ResourceDynamicArray<U32> indices;
  354. ANKI_CHECK(loader.storeIndicesAndPosition(lod, indices, positions));
  355. if(isConvex)
  356. {
  357. l.m_collisionShapes[isConvex] = PhysicsWorld::getSingleton().newConvexHullShape(positions);
  358. }
  359. else
  360. {
  361. l.m_collisionShapes[isConvex] = PhysicsWorld::getSingleton().newStaticMeshShape(positions, indices);
  362. }
  363. }
  364. out = l.m_collisionShapes[isConvex];
  365. return Error::kNone;
  366. }
  367. } // end namespace anki