ParticleEmitter2Component.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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/Scene/Components/ParticleEmitter2Component.h>
  6. #include <AnKi/Scene/Components/MeshComponent.h>
  7. #include <AnKi/Scene/Components/MoveComponent.h>
  8. #include <AnKi/Resource/ParticleEmitterResource2.h>
  9. #include <AnKi/Resource/ResourceManager.h>
  10. #include <AnKi/Resource/MeshResource.h>
  11. #include <AnKi/GpuMemory/RebarTransientMemoryPool.h>
  12. namespace anki {
  13. // Contains some shared geometry data and it's a singleton because we don't want to be wasting time and memory for every emitter
  14. class ParticleEmitter2Component::ParticleEmitterQuadGeometry : public MakeSingletonLazyInit<ParticleEmitterQuadGeometry>
  15. {
  16. public:
  17. UnifiedGeometryBufferAllocation m_quadPositions;
  18. UnifiedGeometryBufferAllocation m_quadUvs;
  19. UnifiedGeometryBufferAllocation m_quadIndices;
  20. GpuSceneArrays::MeshLod::Allocation m_gpuSceneMeshLods;
  21. U32 m_userCount = 0;
  22. Bool m_uploadedToGpuScene = false;
  23. SpinLock m_mtx;
  24. void init()
  25. {
  26. initGeom();
  27. initGpuScene();
  28. }
  29. void initGeom()
  30. {
  31. // Allocate and populate a quad
  32. const U32 vertCount = 4;
  33. const U32 indexCount = 6;
  34. m_quadPositions = UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition], vertCount);
  35. m_quadUvs = UnifiedGeometryBuffer::getSingleton().allocateFormat(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv], vertCount);
  36. m_quadIndices = UnifiedGeometryBuffer::getSingleton().allocateFormat(Format::kR16_Uint, indexCount);
  37. static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition] == Format::kR16G16B16A16_Unorm);
  38. WeakArray<U16Vec4> transientPositions;
  39. const BufferView positionsAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(vertCount, transientPositions);
  40. transientPositions[0] = U16Vec4(0, 0, 0, 0);
  41. transientPositions[1] = U16Vec4(kMaxU16, 0, 0, 0);
  42. transientPositions[2] = U16Vec4(kMaxU16, kMaxU16, 0, 0);
  43. transientPositions[3] = U16Vec4(0, kMaxU16, 0, 0);
  44. static_assert(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv] == Format::kR32G32_Sfloat);
  45. WeakArray<Vec2> transientUvs;
  46. const BufferView uvsAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(vertCount, transientUvs);
  47. transientUvs[0] = Vec2(0.0f);
  48. transientUvs[1] = Vec2(1.0f, 0.0f);
  49. transientUvs[2] = Vec2(1.0f, 1.0f);
  50. transientUvs[3] = Vec2(0.0f, 1.0f);
  51. WeakArray<U16> transientIndices;
  52. const BufferView indicesAlloc = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer(indexCount, transientIndices);
  53. transientIndices[0] = 0;
  54. transientIndices[1] = 1;
  55. transientIndices[2] = 3;
  56. transientIndices[3] = 1;
  57. transientIndices[4] = 2;
  58. transientIndices[5] = 3;
  59. CommandBufferInitInfo cmdbInit("Particle quad upload");
  60. cmdbInit.m_flags |= CommandBufferFlag::kSmallBatch;
  61. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
  62. Buffer* dstBuff = &UnifiedGeometryBuffer::getSingleton().getBuffer();
  63. cmdb->copyBufferToBuffer(positionsAlloc, m_quadPositions);
  64. cmdb->copyBufferToBuffer(uvsAlloc, m_quadUvs);
  65. cmdb->copyBufferToBuffer(indicesAlloc, m_quadIndices);
  66. BufferBarrierInfo barrier;
  67. barrier.m_bufferView = BufferView(dstBuff);
  68. barrier.m_previousUsage = BufferUsageBit::kCopyDestination;
  69. barrier.m_nextUsage = dstBuff->getBufferUsage();
  70. cmdb->setPipelineBarrier({}, {&barrier, 1}, {});
  71. cmdb->endRecording();
  72. GrManager::getSingleton().submit(cmdb.get());
  73. }
  74. void initGpuScene()
  75. {
  76. m_gpuSceneMeshLods.allocate();
  77. }
  78. void deinit()
  79. {
  80. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadPositions);
  81. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadUvs);
  82. UnifiedGeometryBuffer::getSingleton().deferredFree(m_quadIndices);
  83. m_gpuSceneMeshLods.free();
  84. }
  85. void addUser()
  86. {
  87. LockGuard lock(m_mtx);
  88. if(m_userCount == 0)
  89. {
  90. init();
  91. }
  92. ++m_userCount;
  93. }
  94. void removeUser()
  95. {
  96. LockGuard lock(m_mtx);
  97. ANKI_ASSERT(m_userCount > 0);
  98. if(m_userCount == 1)
  99. {
  100. deinit();
  101. }
  102. --m_userCount;
  103. }
  104. // Do that outside of init() because we can only upload to the GPU scene at specific places in the frame
  105. void tryUploadToGpuScene()
  106. {
  107. LockGuard lock(m_mtx);
  108. if(!m_uploadedToGpuScene)
  109. {
  110. m_uploadedToGpuScene = true;
  111. GpuSceneMeshLod meshLod = {};
  112. meshLod.m_vertexOffsets[U32(VertexStreamId::kPosition)] =
  113. m_quadPositions.getOffset() / getFormatInfo(kMeshRelatedVertexStreamFormats[VertexStreamId::kPosition]).m_texelSize;
  114. meshLod.m_vertexOffsets[U32(VertexStreamId::kUv)] =
  115. m_quadUvs.getOffset() / getFormatInfo(kMeshRelatedVertexStreamFormats[VertexStreamId::kUv]).m_texelSize;
  116. meshLod.m_indexCount = 6;
  117. meshLod.m_firstIndex = m_quadIndices.getOffset() / sizeof(U16);
  118. meshLod.m_positionScale = 1.0f;
  119. meshLod.m_positionTranslation = Vec3(-0.5f, -0.5f, 0.0f);
  120. Array<GpuSceneMeshLod, kMaxLodCount> meshLods;
  121. meshLods.fill(meshLod);
  122. m_gpuSceneMeshLods.uploadToGpuScene(meshLods);
  123. }
  124. }
  125. };
  126. ParticleEmitter2Component::ParticleEmitter2Component(SceneNode* node)
  127. : SceneComponent(node, kClassType)
  128. {
  129. ParticleEmitterQuadGeometry::getSingleton().addUser();
  130. }
  131. ParticleEmitter2Component::~ParticleEmitter2Component()
  132. {
  133. ParticleEmitterQuadGeometry::getSingleton().removeUser();
  134. }
  135. ParticleEmitter2Component& ParticleEmitter2Component::setParticleEmitterFilename(CString fname)
  136. {
  137. ParticleEmitterResource2Ptr newRsrc;
  138. const Error err = ResourceManager::getSingleton().loadResource(fname, newRsrc);
  139. if(err)
  140. {
  141. ANKI_SCENE_LOGE("Failed to load resource: %s", fname.cstr());
  142. }
  143. else
  144. {
  145. m_resource = std::move(newRsrc);
  146. m_anyDirty = true;
  147. }
  148. return *this;
  149. }
  150. CString ParticleEmitter2Component::getParticleEmitterFilename() const
  151. {
  152. if(m_resource)
  153. {
  154. return m_resource->getFilename();
  155. }
  156. else
  157. {
  158. return "*Error*";
  159. }
  160. }
  161. void ParticleEmitter2Component::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added)
  162. {
  163. ANKI_ASSERT(other);
  164. if(other->getType() == SceneComponentType::kMesh)
  165. {
  166. bookkeepComponent(m_meshComponent, other, added);
  167. m_anyDirty = true;
  168. }
  169. }
  170. Bool ParticleEmitter2Component::isValid() const
  171. {
  172. Bool valid = !!m_resource;
  173. if(m_geomType == ParticleGeometryType::kMeshComponent)
  174. {
  175. valid = valid && m_meshComponent->isValid();
  176. }
  177. return valid;
  178. }
  179. void ParticleEmitter2Component::update(SceneComponentUpdateInfo& info, Bool& updated)
  180. {
  181. m_gpuSceneReallocationsThisFrame = false;
  182. m_dt = F32(info.m_dt);
  183. if(!isValid()) [[unlikely]]
  184. {
  185. for(auto& s : m_gpuScene.m_particleStreams)
  186. {
  187. GpuSceneBuffer::getSingleton().deferredFree(s);
  188. }
  189. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_aliveParticleIndices);
  190. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_anKiParticleEmitterProperties);
  191. m_gpuScene.m_gpuSceneParticleEmitter.free();
  192. m_gpuSceneReallocationsThisFrame = true;
  193. return;
  194. }
  195. ParticleEmitterQuadGeometry::getSingleton().tryUploadToGpuScene();
  196. if(info.m_checkForResourceUpdates) [[unlikely]]
  197. {
  198. if(m_resource->isObsolete()) [[unlikely]]
  199. {
  200. ANKI_SCENE_LOGV("Particle emitter resource is obsolete. Will reload it");
  201. BaseString<MemoryPoolPtrWrapper<StackMemoryPool>> fname(info.m_framePool);
  202. fname = m_resource->getFilename();
  203. ParticleEmitterResource2Ptr oldVersion = m_resource;
  204. m_resource.reset(nullptr);
  205. if(ResourceManager::getSingleton().loadResource(fname, m_resource))
  206. {
  207. ANKI_SCENE_LOGE("Can't update the particle resource. Ignoring the load");
  208. m_resource = oldVersion;
  209. }
  210. else
  211. {
  212. m_anyDirty = true;
  213. ANKI_ASSERT(!m_resource->isObsolete());
  214. }
  215. }
  216. }
  217. if(!m_anyDirty) [[likely]]
  218. {
  219. return;
  220. }
  221. // From now on it's dirty, do all updates
  222. m_gpuSceneReallocationsThisFrame = true; // Difficult to properly track so set it to true and don't bother
  223. m_anyDirty = false;
  224. updated = true;
  225. const ParticleEmitterResourceCommonProperties& commonProps = m_resource->getCommonProperties();
  226. // Streams
  227. for(ParticleProperty prop : EnumIterable<ParticleProperty>())
  228. {
  229. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_particleStreams[prop]);
  230. m_gpuScene.m_particleStreams[prop] =
  231. GpuSceneBuffer::getSingleton().allocate(commonProps.m_particleCount * kParticlePropertySize[prop], alignof(U32));
  232. }
  233. // Alive particles index buffer
  234. {
  235. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_aliveParticleIndices);
  236. m_gpuScene.m_aliveParticleIndices = GpuSceneBuffer::getSingleton().allocate(commonProps.m_particleCount * sizeof(U32), alignof(U32));
  237. }
  238. // AnKiParticleEmitterProperties
  239. {
  240. GpuSceneBuffer::getSingleton().deferredFree(m_gpuScene.m_anKiParticleEmitterProperties);
  241. ConstWeakArray<U8> prefilled = m_resource->getPrefilledAnKiParticleEmitterProperties();
  242. m_gpuScene.m_anKiParticleEmitterProperties = GpuSceneBuffer::getSingleton().allocate(prefilled.getSizeInBytes(), alignof(U32));
  243. GpuSceneMicroPatcher::getSingleton().newCopy(m_gpuScene.m_anKiParticleEmitterProperties, prefilled.getSizeInBytes(), prefilled.getBegin());
  244. }
  245. // GpuSceneParticleEmitter2
  246. {
  247. if(!m_gpuScene.m_gpuSceneParticleEmitter)
  248. {
  249. m_gpuScene.m_gpuSceneParticleEmitter.allocate();
  250. }
  251. GpuSceneParticleEmitter2 emitter;
  252. zeroMemory(emitter);
  253. for(ParticleProperty prop : EnumIterable<ParticleProperty>())
  254. {
  255. emitter.m_particleStateSteamOffsets[U32(prop)] = m_gpuScene.m_particleStreams[prop].getOffset();
  256. }
  257. emitter.m_aliveParticleIndicesOffset = m_gpuScene.m_aliveParticleIndices.getOffset();
  258. emitter.m_particleCount = commonProps.m_particleCount;
  259. emitter.m_emissionPeriod = commonProps.m_emissionPeriod;
  260. emitter.m_particlesPerEmission = commonProps.m_particlesPerEmission;
  261. emitter.m_particleEmitterPropertiesOffset = m_gpuScene.m_anKiParticleEmitterProperties.getOffset();
  262. if(m_geomType == ParticleGeometryType::kMeshComponent)
  263. {
  264. const MeshResource& meshr = m_meshComponent->getMeshResource();
  265. emitter.m_particleAabbMin = meshr.getBoundingShape().getMin().xyz;
  266. emitter.m_particleAabbMax = meshr.getBoundingShape().getMax().xyz;
  267. }
  268. else
  269. {
  270. emitter.m_particleAabbMin = Vec3(-0.5f);
  271. emitter.m_particleAabbMax = Vec3(+0.5f);
  272. }
  273. emitter.m_reinitializeOnNextUpdate = 1;
  274. emitter.m_worldTransformsIndex = info.m_node->getFirstComponentOfType<MoveComponent>().getGpuSceneTransformsIndex();
  275. emitter.m_uuid = getUuid();
  276. m_gpuScene.m_gpuSceneParticleEmitter.uploadToGpuScene(emitter);
  277. }
  278. }
  279. U32 ParticleEmitter2Component::getGpuSceneMeshLodIndex(U32 submeshIdx) const
  280. {
  281. ANKI_ASSERT(isValid());
  282. if(m_geomType == ParticleGeometryType::kQuad)
  283. {
  284. return ParticleEmitterQuadGeometry::getSingleton().m_gpuSceneMeshLods.getIndex() * kMaxLodCount;
  285. }
  286. else
  287. {
  288. return m_meshComponent->getGpuSceneMeshLodsIndex(submeshIdx);
  289. }
  290. }
  291. Error ParticleEmitter2Component::serialize(SceneSerializer& serializer)
  292. {
  293. ANKI_SERIALIZE(m_resource, 1);
  294. return Error::kNone;
  295. }
  296. } // end namespace anki