MeshResource.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Copyright (C) 2009-2022, 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/Core/GpuMemoryPools.h>
  10. #include <AnKi/Util/Functions.h>
  11. #include <AnKi/Util/Filesystem.h>
  12. namespace anki {
  13. class MeshResource::LoadContext
  14. {
  15. public:
  16. MeshResourcePtr m_mesh;
  17. MeshBinaryLoader m_loader;
  18. LoadContext(const MeshResourcePtr& mesh, GenericMemoryPoolAllocator<U8> alloc)
  19. : m_mesh(mesh)
  20. , m_loader(&mesh->getManager(), alloc)
  21. {
  22. }
  23. };
  24. /// Mesh upload async task.
  25. class MeshResource::LoadTask : public AsyncLoaderTask
  26. {
  27. public:
  28. MeshResource::LoadContext m_ctx;
  29. LoadTask(const MeshResourcePtr& mesh)
  30. : m_ctx(mesh, mesh->getManager().getAsyncLoader().getAllocator())
  31. {
  32. }
  33. Error operator()([[maybe_unused]] AsyncLoaderTaskContext& ctx) final
  34. {
  35. return m_ctx.m_mesh->loadAsync(m_ctx.m_loader);
  36. }
  37. GenericMemoryPoolAllocator<U8> getAllocator() const
  38. {
  39. return m_ctx.m_mesh->getManager().getAsyncLoader().getAllocator();
  40. }
  41. };
  42. MeshResource::MeshResource(ResourceManager* manager)
  43. : ResourceObject(manager)
  44. {
  45. memset(&m_meshGpuDescriptor, 0, sizeof(m_meshGpuDescriptor));
  46. }
  47. MeshResource::~MeshResource()
  48. {
  49. m_subMeshes.destroy(getAllocator());
  50. m_vertexBufferInfos.destroy(getAllocator());
  51. if(m_vertexBuffersOffset != MAX_PTR_SIZE)
  52. {
  53. getManager().getVertexGpuMemory().free(m_vertexBuffersSize, m_vertexBuffersOffset);
  54. }
  55. if(m_indexBufferOffset != MAX_PTR_SIZE)
  56. {
  57. const PtrSize indexBufferSize = PtrSize(m_indexCount) * ((m_indexType == IndexType::U32) ? 4 : 2);
  58. getManager().getVertexGpuMemory().free(indexBufferSize, m_indexBufferOffset);
  59. }
  60. }
  61. Bool MeshResource::isCompatible(const MeshResource& other) const
  62. {
  63. return hasBoneWeights() == other.hasBoneWeights() && getSubMeshCount() == other.getSubMeshCount();
  64. }
  65. Error MeshResource::load(const ResourceFilename& filename, Bool async)
  66. {
  67. UniquePtr<LoadTask> task;
  68. LoadContext* ctx;
  69. LoadContext localCtx(MeshResourcePtr(this), getTempAllocator());
  70. StringAuto basename(getTempAllocator());
  71. getFilepathFilename(filename, basename);
  72. const Bool rayTracingEnabled = getManager().getGrManager().getDeviceCapabilities().m_rayTracingEnabled;
  73. if(async)
  74. {
  75. task.reset(getManager().getAsyncLoader().newTask<LoadTask>(MeshResourcePtr(this)));
  76. ctx = &task->m_ctx;
  77. }
  78. else
  79. {
  80. task.reset(nullptr);
  81. ctx = &localCtx;
  82. }
  83. // Open file
  84. MeshBinaryLoader& loader = ctx->m_loader;
  85. ANKI_CHECK(loader.load(filename));
  86. const MeshBinaryHeader& header = loader.getHeader();
  87. //
  88. // Submeshes
  89. //
  90. m_subMeshes.create(getAllocator(), header.m_subMeshCount);
  91. for(U32 i = 0; i < m_subMeshes.getSize(); ++i)
  92. {
  93. m_subMeshes[i].m_firstIndex = loader.getSubMeshes()[i].m_firstIndex;
  94. m_subMeshes[i].m_indexCount = loader.getSubMeshes()[i].m_indexCount;
  95. m_subMeshes[i].m_aabb.setMin(loader.getSubMeshes()[i].m_aabbMin);
  96. m_subMeshes[i].m_aabb.setMax(loader.getSubMeshes()[i].m_aabbMax);
  97. }
  98. //
  99. // Index stuff
  100. //
  101. m_indexCount = header.m_totalIndexCount;
  102. ANKI_ASSERT((m_indexCount % 3) == 0 && "Expecting triangles");
  103. m_indexType = header.m_indexType;
  104. const PtrSize indexBufferSize = PtrSize(m_indexCount) * ((m_indexType == IndexType::U32) ? 4 : 2);
  105. ANKI_CHECK(getManager().getVertexGpuMemory().allocate(indexBufferSize, m_indexBufferOffset));
  106. //
  107. // Vertex stuff
  108. //
  109. m_vertexCount = header.m_totalVertexCount;
  110. m_vertexBufferInfos.create(getAllocator(), header.m_vertexBufferCount);
  111. m_vertexBuffersSize = 0;
  112. for(U32 i = 0; i < header.m_vertexBufferCount; ++i)
  113. {
  114. alignRoundUp(MESH_BINARY_BUFFER_ALIGNMENT, m_vertexBuffersSize);
  115. m_vertexBufferInfos[i].m_offset = m_vertexBuffersSize;
  116. m_vertexBufferInfos[i].m_stride = header.m_vertexBuffers[i].m_vertexStride;
  117. m_vertexBuffersSize += m_vertexCount * m_vertexBufferInfos[i].m_stride;
  118. }
  119. ANKI_CHECK(getManager().getVertexGpuMemory().allocate(m_vertexBuffersSize, m_vertexBuffersOffset));
  120. // Readjust the individual offset now that we have a global offset
  121. for(U32 i = 0; i < header.m_vertexBufferCount; ++i)
  122. {
  123. m_vertexBufferInfos[i].m_offset += m_vertexBuffersOffset;
  124. }
  125. for(VertexAttributeId attrib = VertexAttributeId::kFirst; attrib < VertexAttributeId::kCount; ++attrib)
  126. {
  127. AttribInfo& out = m_attributes[attrib];
  128. const MeshBinaryVertexAttribute& in = header.m_vertexAttributes[attrib];
  129. if(!!in.m_format)
  130. {
  131. out.m_format = in.m_format;
  132. out.m_relativeOffset = in.m_relativeOffset;
  133. out.m_buffIdx = U8(in.m_bufferBinding);
  134. ANKI_ASSERT(in.m_scale == 1.0f && "Not supported ATM");
  135. }
  136. }
  137. // Other
  138. m_aabb.setMin(header.m_aabbMin);
  139. m_aabb.setMax(header.m_aabbMax);
  140. m_vertexBuffer = getManager().getVertexGpuMemory().getVertexBuffer();
  141. //
  142. // Clear the buffers
  143. //
  144. if(async)
  145. {
  146. CommandBufferInitInfo cmdbinit;
  147. cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::GENERAL_WORK;
  148. CommandBufferPtr cmdb = getManager().getGrManager().newCommandBuffer(cmdbinit);
  149. cmdb->fillBuffer(m_vertexBuffer, m_vertexBuffersOffset, m_vertexBuffersSize, 0);
  150. cmdb->fillBuffer(m_vertexBuffer, m_indexBufferOffset, indexBufferSize, 0);
  151. const BufferBarrierInfo barrier = {m_vertexBuffer.get(), BufferUsageBit::TRANSFER_DESTINATION,
  152. BufferUsageBit::VERTEX, 0, MAX_PTR_SIZE};
  153. cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
  154. cmdb->flush();
  155. }
  156. //
  157. // Create the BLAS
  158. //
  159. if(rayTracingEnabled)
  160. {
  161. AccelerationStructureInitInfo inf(StringAuto(getTempAllocator()).sprintf("%s_%s", "Blas", basename.cstr()));
  162. inf.m_type = AccelerationStructureType::BOTTOM_LEVEL;
  163. inf.m_bottomLevel.m_indexBuffer = m_vertexBuffer;
  164. inf.m_bottomLevel.m_indexBufferOffset = m_indexBufferOffset;
  165. inf.m_bottomLevel.m_indexCount = m_indexCount;
  166. inf.m_bottomLevel.m_indexType = m_indexType;
  167. U32 bufferIdx;
  168. Format format;
  169. U32 relativeOffset;
  170. getVertexAttributeInfo(VertexAttributeId::POSITION, bufferIdx, format, relativeOffset);
  171. BufferPtr buffer;
  172. PtrSize offset;
  173. PtrSize stride;
  174. getVertexBufferInfo(bufferIdx, buffer, offset, stride);
  175. inf.m_bottomLevel.m_positionBuffer = buffer;
  176. inf.m_bottomLevel.m_positionBufferOffset = offset;
  177. inf.m_bottomLevel.m_positionStride = U32(stride);
  178. inf.m_bottomLevel.m_positionsFormat = format;
  179. inf.m_bottomLevel.m_positionCount = m_vertexCount;
  180. m_blas = getManager().getGrManager().newAccelerationStructure(inf);
  181. }
  182. // Fill the GPU descriptor
  183. if(rayTracingEnabled)
  184. {
  185. m_meshGpuDescriptor.m_indexBufferPtr = m_vertexBuffer->getGpuAddress() + m_indexBufferOffset;
  186. U32 bufferIdx;
  187. Format format;
  188. U32 relativeOffset;
  189. getVertexAttributeInfo(VertexAttributeId::POSITION, bufferIdx, format, relativeOffset);
  190. BufferPtr buffer;
  191. PtrSize offset;
  192. PtrSize stride;
  193. getVertexBufferInfo(bufferIdx, buffer, offset, stride);
  194. m_meshGpuDescriptor.m_vertexBufferPtrs[VertexAttributeBufferId::POSITION] = buffer->getGpuAddress() + offset;
  195. getVertexAttributeInfo(VertexAttributeId::NORMAL, bufferIdx, format, relativeOffset);
  196. getVertexBufferInfo(bufferIdx, buffer, offset, stride);
  197. m_meshGpuDescriptor.m_vertexBufferPtrs[VertexAttributeBufferId::NORMAL_TANGENT_UV0] =
  198. buffer->getGpuAddress() + offset;
  199. if(hasBoneWeights())
  200. {
  201. getVertexAttributeInfo(VertexAttributeId::BONE_WEIGHTS, bufferIdx, format, relativeOffset);
  202. getVertexBufferInfo(bufferIdx, buffer, offset, stride);
  203. m_meshGpuDescriptor.m_vertexBufferPtrs[VertexAttributeBufferId::BONE] = buffer->getGpuAddress() + offset;
  204. }
  205. m_meshGpuDescriptor.m_indexCount = m_indexCount;
  206. m_meshGpuDescriptor.m_vertexCount = m_vertexCount;
  207. m_meshGpuDescriptor.m_aabbMin = header.m_aabbMin;
  208. m_meshGpuDescriptor.m_aabbMax = header.m_aabbMax;
  209. }
  210. // Submit the loading task
  211. if(async)
  212. {
  213. getManager().getAsyncLoader().submitTask(task.get());
  214. LoadTask* pTask;
  215. task.moveAndReset(pTask);
  216. }
  217. else
  218. {
  219. ANKI_CHECK(loadAsync(loader));
  220. }
  221. return Error::NONE;
  222. }
  223. Error MeshResource::loadAsync(MeshBinaryLoader& loader) const
  224. {
  225. GrManager& gr = getManager().getGrManager();
  226. TransferGpuAllocator& transferAlloc = getManager().getTransferGpuAllocator();
  227. Array<TransferGpuAllocatorHandle, 2> handles;
  228. CommandBufferInitInfo cmdbinit;
  229. cmdbinit.m_flags = CommandBufferFlag::SMALL_BATCH | CommandBufferFlag::GENERAL_WORK;
  230. CommandBufferPtr cmdb = gr.newCommandBuffer(cmdbinit);
  231. // Set barriers
  232. const BufferBarrierInfo barrier = {m_vertexBuffer.get(), BufferUsageBit::VERTEX,
  233. BufferUsageBit::TRANSFER_DESTINATION, 0, MAX_PTR_SIZE};
  234. cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
  235. // Write index buffer
  236. {
  237. const PtrSize indexBufferSize = PtrSize(m_indexCount) * ((m_indexType == IndexType::U32) ? 4 : 2);
  238. ANKI_CHECK(transferAlloc.allocate(indexBufferSize, handles[1]));
  239. void* data = handles[1].getMappedMemory();
  240. ANKI_ASSERT(data);
  241. ANKI_CHECK(loader.storeIndexBuffer(data, indexBufferSize));
  242. cmdb->copyBufferToBuffer(handles[1].getBuffer(), handles[1].getOffset(), m_vertexBuffer, m_indexBufferOffset,
  243. handles[1].getRange());
  244. }
  245. // Write vert buff
  246. {
  247. ANKI_CHECK(transferAlloc.allocate(m_vertexBuffersSize, handles[0]));
  248. U8* data = static_cast<U8*>(handles[0].getMappedMemory());
  249. ANKI_ASSERT(data);
  250. // Load to staging
  251. PtrSize offset = 0;
  252. for(U32 i = 0; i < m_vertexBufferInfos.getSize(); ++i)
  253. {
  254. alignRoundUp(MESH_BINARY_BUFFER_ALIGNMENT, offset);
  255. ANKI_CHECK(
  256. loader.storeVertexBuffer(i, data + offset, PtrSize(m_vertexBufferInfos[i].m_stride) * m_vertexCount));
  257. offset += PtrSize(m_vertexBufferInfos[i].m_stride) * m_vertexCount;
  258. }
  259. ANKI_ASSERT(offset == m_vertexBuffersSize);
  260. // Copy
  261. cmdb->copyBufferToBuffer(handles[0].getBuffer(), handles[0].getOffset(), m_vertexBuffer, m_vertexBuffersOffset,
  262. handles[0].getRange());
  263. }
  264. // Build the BLAS
  265. if(gr.getDeviceCapabilities().m_rayTracingEnabled)
  266. {
  267. const BufferBarrierInfo buffBarrier = {m_vertexBuffer.get(), BufferUsageBit::TRANSFER_DESTINATION,
  268. BufferUsageBit::ACCELERATION_STRUCTURE_BUILD | BufferUsageBit::VERTEX
  269. | BufferUsageBit::INDEX,
  270. 0, MAX_PTR_SIZE};
  271. const AccelerationStructureBarrierInfo asBarrier = {m_blas.get(), AccelerationStructureUsageBit::NONE,
  272. AccelerationStructureUsageBit::BUILD};
  273. cmdb->setPipelineBarrier({}, {&buffBarrier, 1}, {&asBarrier, 1});
  274. cmdb->buildAccelerationStructure(m_blas);
  275. const AccelerationStructureBarrierInfo asBarrier2 = {m_blas.get(), AccelerationStructureUsageBit::BUILD,
  276. AccelerationStructureUsageBit::ALL_READ};
  277. cmdb->setPipelineBarrier({}, {}, {&asBarrier2, 1});
  278. }
  279. else
  280. {
  281. const BufferBarrierInfo buffBarrier = {m_vertexBuffer.get(), BufferUsageBit::TRANSFER_DESTINATION,
  282. BufferUsageBit::VERTEX | BufferUsageBit::INDEX, 0, MAX_PTR_SIZE};
  283. cmdb->setPipelineBarrier({}, {&buffBarrier, 1}, {});
  284. }
  285. // Finalize
  286. FencePtr fence;
  287. cmdb->flush({}, &fence);
  288. transferAlloc.release(handles[0], fence);
  289. transferAlloc.release(handles[1], fence);
  290. return Error::NONE;
  291. }
  292. } // end namespace anki