diff --git a/Assets/Shaders/ParticleUpdate_CS.glsl b/Assets/Shaders/ParticleUpdate_CS.glsl index 33da0d5e..722833ad 100644 --- a/Assets/Shaders/ParticleUpdate_CS.glsl +++ b/Assets/Shaders/ParticleUpdate_CS.glsl @@ -118,6 +118,9 @@ void main() if (particle.life > 0.0f) { + // update position from velocity + // particle.position += particle.velocity * genericDataBuffer.data.dt; + // particle.life -= genericDataBuffer.data.dt; if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f) { diff --git a/Assets/Shaders/Particle_VS.glsl b/Assets/Shaders/Particle_VS.glsl index e6f73eb2..2645fe87 100644 --- a/Assets/Shaders/Particle_VS.glsl +++ b/Assets/Shaders/Particle_VS.glsl @@ -78,8 +78,11 @@ void main() vec2 particleScaleData = particle.scaleAndDecay.xz; // x and y mat4 localModel = mat4 (1.0f); - localModel[0][0] = particleScaleData.x; - localModel[1][1] = particleScaleData.y; + localModel[0][0] = 1.0f; + localModel[1][1] = 1.0f; + + // localModel[0][0] = particleScaleData.x; + // localModel[1][1] = particleScaleData.y; mat4 rotate = mat4(1.0f); rotate[0][0] = cos(angle); @@ -89,6 +92,6 @@ void main() // localModel = rotate * localModel; localModel[3] = vec4 (particle.position.xyz, 1.0f); - gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); - // gl_Position = vec4(vertexPos, 1.0f); + // gl_Position = cameraData.vpMat * localModel * vec4(vertexPos, 1.0f); + gl_Position = vec4(vertexPos, 1.0f); } \ No newline at end of file diff --git a/Assets/Shaders/Particle_VS.shshaderb b/Assets/Shaders/Particle_VS.shshaderb index 7afc0202..c863fca2 100644 Binary files a/Assets/Shaders/Particle_VS.shshaderb and b/Assets/Shaders/Particle_VS.shshaderb differ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp index d07ad2f4..2c51e5eb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/GlobalData/SHGraphicsPredefinedData.cpp @@ -251,7 +251,7 @@ namespace SHADE // particle draw call binding SHVkDescriptorSetLayout::Binding particleDrawDataBinding { - .Type = vk::DescriptorType::eStorageBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame) + .Type = vk::DescriptorType::eStorageBufferDynamic, // SSBO, dynamic (1 set for each frame) .Stage = vk::ShaderStageFlagBits::eCompute, .BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, .DescriptorCount = 1, diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 57b373dd..1cbd359c 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -707,9 +707,11 @@ namespace SHADE #endif } + renderGraph->Begin(frameIndex); auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex); + particleSubSystem->ResetInstanceCounts(cmdBuffer, frameIndex); particleSubSystem->Run(cmdBuffer, frameIndex); renderGraph->Execute(frameIndex, descPool, MESH_DATA); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp index 8e1ce707..7e1e9455 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.cpp @@ -14,6 +14,8 @@ #include "Graphics/Pipeline/SHVkPipeline.h" #include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/SHVkUtil.h" +#include "Graphics/Synchronization/SHVkFence.h" + namespace SHADE { @@ -68,7 +70,7 @@ namespace SHADE } // buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered. - comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); + comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT); } @@ -151,12 +153,6 @@ namespace SHADE { auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING); - uint32_t instanceCountOffset = sizeof (vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount); - uint32_t ZERO = 0; - - // reset instance count to 0 - comp.drawCallData->WriteToMemory (&ZERO, sizeof(uint32_t), 0, instanceCountOffset); - // bind the descriptor sets required for emitting particles cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]); @@ -170,7 +166,7 @@ namespace SHADE //cmdBuffer->DrawArrays(4, 1, 0, 0); } - void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept + void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, std::vector& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept { // pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it. vk::BufferMemoryBarrier particleDataBarrier @@ -219,18 +215,17 @@ namespace SHADE // make new barrier on stack... vk::BufferMemoryBarrier drawDataBarrier { - .srcAccessMask = vk::AccessFlagBits::eShaderWrite, - .dstAccessMask = vk::AccessFlagBits::eShaderRead, + .srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryWrite, + .dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead, .buffer = emitter.drawCallData->GetVkBuffer(), .offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA], .size = static_cast(sizeof(vk::DrawIndirectCommand)) }; // ...copy assign barriers on heap - postUpdateBarriers[EMITTER_INDEX * 3] = particleDataBarrierPost; - postUpdateBarriers[(EMITTER_INDEX * 3) + 1] = indicesDataBarrier; - postUpdateBarriers[(EMITTER_INDEX * 3) + 2] = drawDataBarrier; - + postUpdateBarriers[EMITTER_INDEX * 2] = particleDataBarrierPost; + postUpdateBarriers[(EMITTER_INDEX * 2) + 1] = indicesDataBarrier; + preDrawBarriers[EMITTER_INDEX] = drawDataBarrier; } void SHParticleSubSystem::Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept @@ -310,7 +305,7 @@ namespace SHADE SHComponentManager::CreateComponentSparseSet(); } - void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex) noexcept + void SHParticleSubSystem::Run(Handle cmdBuffer, uint32_t frameIndex, Handle waitFence) noexcept { float dt = static_cast(SHFrameRateController::GetRawDeltaTime()); @@ -332,7 +327,11 @@ namespace SHADE // After we invoke the updates for the emitters, we need to make sure all particles and indices data are done updating // before we issue them for rendering. std::vector postUpdateBarriers{}; - postUpdateBarriers.resize(emitters.size() * 3); + postUpdateBarriers.resize(emitters.size() * 2); + + std::vector preDrawBarriers{}; + preDrawBarriers.resize(emitters.size()); + // If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in // the update compute. HOWEVER since a NUM_FRAME_BUFFERS frames would have passed by then, we will not insert 1 here. @@ -350,6 +349,10 @@ namespace SHADE SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex); uint32_t i = 0; + + if (waitFence) + waitFence->Wait(true); + for (auto& emitter : emitters) { if (!emitter.initialized) @@ -382,7 +385,7 @@ namespace SHADE } // prepare barriers - PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex); + PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, preDrawBarriers, emitter, i, frameIndex); // Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so). emitter.toEmit = false; @@ -398,6 +401,7 @@ namespace SHADE /* EMITTING PARTICLES DONE, BEGIN UPDATES.... */ /*-----------------------------------------------------------------------*/ + // bind the pipeline for updating cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline); @@ -411,9 +415,53 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // issue the barrier to wait for output particles to be done updating and indices data to finish being modified. cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, postUpdateBarriers, {}); + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eDrawIndirect, {}, {}, preDrawBarriers, {}); } + void SHParticleSubSystem::ResetInstanceCounts(Handle cmdBuffer, uint32_t frameIndex) noexcept + { + auto& emitters = SHComponentManager::GetDense(); + std::vector preResetBarriers{}; + preResetBarriers.resize(emitters.size()); + + uint32_t i = 0; + for (auto& emitter : emitters) + { + if (emitter.initialized) + { + // pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it. + vk::BufferMemoryBarrier drawDataHostWriteBarrier + { + .srcAccessMask = vk::AccessFlagBits::eIndirectCommandRead | vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, + .dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eHostWrite, + .buffer = emitter.drawCallData->GetVkBuffer(), + .offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_DRAW_DATA], + .size = static_cast(sizeof(vk::DrawIndirectCommand)) + }; + + preResetBarriers[i] = drawDataHostWriteBarrier; + } + ++i; + } + + cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eHost, {}, {}, preResetBarriers, {}); + + + for (auto& emitter : emitters) + { + if (emitter.initialized) + { + //uint32_t instanceCountOffset = 20; + uint32_t instanceCountOffset = sizeof(vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount); + uint32_t ZERO = 0; + + // reset instance count to 0 + emitter.drawCallData->WriteToMemory(&ZERO, sizeof(uint32_t), 0, instanceCountOffset); + } + } + } + void SHParticleSubSystem::Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept { auto& emitters = SHComponentManager::GetDense(); @@ -432,6 +480,7 @@ namespace SHADE } } + void SHParticleSubSystem::Exit(void) noexcept { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h index 73404e3d..bb8f570d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Particles/SHParticleSubSystem.h @@ -20,6 +20,7 @@ namespace SHADE class SHVkShaderModule; class SHRenderer; class SHParticleEmitterComponent; + class SHVkFence; @@ -81,12 +82,13 @@ namespace SHADE void UpdateCompoennt(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; void RenderComponent(Handle cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept; - void PreparePrePostUpdateBarriers (std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept; + void PreparePrePostUpdateBarriers (std::vector& preUpdateBarriers, std::vector& postUpdateBarriers, std::vector& preDrawBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept; public: void Init(Handle device, Handle inDescPool, Handle compatibleRenderpass, Handle subpass, Handle VS, Handle FS, Handle emitCS, Handle defaultUpdateCS) noexcept; - void Run(Handle cmdBuffer, uint32_t frameIndex) noexcept; + void Run(Handle cmdBuffer, uint32_t frameIndex, Handle waitFence = {}) noexcept; + void ResetInstanceCounts (Handle cmdBuffer, uint32_t frameIndex) noexcept; void Render(Handle cmdBuffer, Handle renderer, uint32_t frameIndex) noexcept; void Exit(void) noexcept; diff --git a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h index 7c48a5f6..9e552a85 100644 --- a/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h +++ b/SHADE_Engine/src/Graphics/Synchronization/SHVkFence.h @@ -30,7 +30,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - bool Wait (bool waitAll, uint64_t timer) noexcept; + bool Wait (bool waitAll, uint64_t timer = std::numeric_limits::max()) noexcept; void Reset (void) noexcept; /*-----------------------------------------------------------------------*/