GpuParticles.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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/Renderer/GpuParticles.h>
  6. #include <AnKi/Renderer/GBuffer.h>
  7. #include <AnKi/Resource/ParticleEmitterResource2.h>
  8. #include <AnKi/Scene/Components/ParticleEmitter2Component.h>
  9. namespace anki {
  10. Error GpuParticles::init()
  11. {
  12. ParticleSimulationScratch scratchTemplate = {};
  13. scratchTemplate.m_aabbMin = IVec3(kMaxI32);
  14. scratchTemplate.m_aabbMax = IVec3(kMinI32);
  15. m_scratchBuffers.resize(kMaxEmittersToSimulate);
  16. CommandBufferInitInfo cmdbInit("Init particles");
  17. CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
  18. U32 count = 0;
  19. for(auto& buff : m_scratchBuffers)
  20. {
  21. BufferInitInfo buffInit(generateTempPassName("GPU particles scratch #%u", count++));
  22. buffInit.m_size = sizeof(ParticleSimulationScratch);
  23. buffInit.m_usage = BufferUsageBit::kSrvCompute | BufferUsageBit::kCopyDestination;
  24. buff = GrManager::getSingleton().newBuffer(buffInit);
  25. WeakArray<ParticleSimulationScratch> out;
  26. const BufferView src = RebarTransientMemoryPool::getSingleton().allocateCopyBuffer<ParticleSimulationScratch>(1, out);
  27. out[0] = scratchTemplate;
  28. cmdb->copyBufferToBuffer(src, BufferView(buff.get()));
  29. }
  30. cmdb->endRecording();
  31. FencePtr fence;
  32. GrManager::getSingleton().submit(cmdb.get(), {}, &fence);
  33. fence->clientWait(kMaxSecond);
  34. return Error::kNone;
  35. }
  36. void GpuParticles::populateRenderGraph(RenderingContext& ctx)
  37. {
  38. SceneBlockArray<ParticleEmitter2Component>& emitters = SceneGraph::getSingleton().getComponentArrays().getParticleEmitter2s();
  39. if(emitters.getSize() == 0) [[unlikely]]
  40. {
  41. return;
  42. }
  43. // Create the renderpass
  44. RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
  45. NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass("GPU particle sim");
  46. pass.newTextureDependency(getGBuffer().getDepthRt(), TextureUsageBit::kSrvCompute);
  47. pass.newTextureDependency(getGBuffer().getColorRt(2), TextureUsageBit::kSrvCompute);
  48. pass.newBufferDependency(getRenderer().getGpuSceneBufferHandle(), BufferUsageBit::kUavCompute);
  49. pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
  50. CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
  51. SceneBlockArray<ParticleEmitter2Component>& emitters = SceneGraph::getSingleton().getComponentArrays().getParticleEmitter2s();
  52. // Handle the readbacks
  53. for(ParticleEmitter2Component& emitter : emitters)
  54. {
  55. if(!emitter.isValid())
  56. {
  57. continue;
  58. }
  59. auto it = m_readbacks.find(emitter.getUuid());
  60. if(it != m_readbacks.getEnd())
  61. {
  62. // Emitter found, access the readback
  63. it->m_lastFrameSeen = getRenderer().getFrameCount();
  64. ParticleSimulationCpuFeedback feedback;
  65. PtrSize dataOut = 0;
  66. getRenderer().getReadbackManager().readMostRecentData(it->m_readback, &feedback, sizeof(feedback), dataOut);
  67. if(dataOut && feedback.m_aabbMin < feedback.m_aabbMax)
  68. {
  69. ANKI_ASSERT(feedback.m_uuid == emitter.getUuid());
  70. emitter.updateBoundingVolume(feedback.m_aabbMin, feedback.m_aabbMax);
  71. }
  72. }
  73. else
  74. {
  75. // Emitter not found, create new entry
  76. ReadbackData& data = *m_readbacks.emplace(emitter.getUuid());
  77. data.m_lastFrameSeen = getRenderer().getFrameCount();
  78. }
  79. }
  80. // Remove old emitters
  81. while(true)
  82. {
  83. Bool foundAnOldOne = false;
  84. for(auto it = m_readbacks.getBegin(); it != m_readbacks.getEnd(); ++it)
  85. {
  86. const U32 deleteAfterNFrames = 10;
  87. if(it->m_lastFrameSeen + deleteAfterNFrames < getRenderer().getFrameCount())
  88. {
  89. m_readbacks.erase(it);
  90. foundAnOldOne = true;
  91. }
  92. }
  93. if(!foundAnOldOne)
  94. {
  95. break;
  96. }
  97. }
  98. // Compute work
  99. U32 count = 0;
  100. for(ParticleEmitter2Component& emitter : emitters)
  101. {
  102. if(!emitter.isValid())
  103. {
  104. continue;
  105. }
  106. cmdb.pushDebugMarker(generateTempPassName("Emitter %u", emitter.getUuid()), Vec3(1.0f, 1.0f, 0.0f));
  107. const ParticleEmitterResource2& rsrc = emitter.getParticleEmitterResource();
  108. const ParticleEmitterResourceCommonProperties& commonProps = rsrc.getCommonProperties();
  109. auto it = m_readbacks.find(emitter.getUuid());
  110. ANKI_ASSERT(it != m_readbacks.getEnd());
  111. const BufferView readbackBuffer =
  112. getRenderer().getReadbackManager().allocateStructuredBuffer<ParticleSimulationCpuFeedback>(it->m_readback, 1);
  113. cmdb.bindShaderProgram(&rsrc.getShaderProgram());
  114. ParticleSimulationConstants consts;
  115. consts.m_viewProjMat = ctx.m_matrices.m_viewProjection;
  116. consts.m_invertedViewProjMat = ctx.m_matrices.m_invertedViewProjection;
  117. consts.m_unprojectionParams = ctx.m_matrices.m_unprojectionParameters;
  118. consts.m_randomNumber = getRandom() % kMaxU32;
  119. consts.m_dt = emitter.getDt();
  120. consts.m_gpuSceneParticleEmitterIndex = emitter.getGpuSceneParticleEmitter2Index();
  121. *allocateAndBindConstants<ParticleSimulationConstants>(cmdb, ANKI_PARTICLE_SIM_CONSTANTS, 0) = consts;
  122. rgraphCtx.bindSrv(ANKI_PARTICLE_SIM_DEPTH_BUFFER, 0, getGBuffer().getDepthRt());
  123. rgraphCtx.bindSrv(ANKI_PARTICLE_SIM_NORMAL_BUFFER, 0, getGBuffer().getColorRt(2));
  124. cmdb.bindSrv(ANKI_PARTICLE_SIM_GPU_SCENE_TRANSFORMS, 0, GpuSceneArrays::Transform::getSingleton().getBufferView());
  125. cmdb.bindUav(ANKI_PARTICLE_SIM_GPU_SCENE, 0, GpuSceneBuffer::getSingleton().getBufferView());
  126. cmdb.bindUav(ANKI_PARTICLE_SIM_GPU_SCENE_PARTICLE_EMITTERS, 0, GpuSceneArrays::ParticleEmitter2::getSingleton().getBufferView());
  127. cmdb.bindUav(ANKI_PARTICLE_SIM_SCRATCH, 0, BufferView(m_scratchBuffers[count++].get()));
  128. cmdb.bindUav(ANKI_PARTICLE_SIM_CPU_FEEDBACK, 0, readbackBuffer);
  129. const U32 numthreads = GrManager::getSingleton().getDeviceCapabilities().m_maxWaveSize;
  130. cmdb.dispatchCompute((commonProps.m_particleCount + numthreads - 1) / numthreads, 1, 1);
  131. cmdb.popDebugMarker();
  132. }
  133. });
  134. }
  135. } // end namespace anki