Open AtlaStar opened 1 week ago
Since I forgot to link it when I submitted the bug, this is a branch fixing a slew of GPU particles bugs which includes the mentioned solution, a potential fix #97904, and the changes in PR #97871 which I opened the other day. https://github.com/AtlaStar/godot/tree/Continued-GPU-particles-fixes
Tested versions
Godot v4.4.dev (db66bd35a) Godot v4.3.stable.mono
System information
Godot v4.4.dev (76a135926) - Windows 10.0.19045 - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated AMD Radeon RX 6650 XT (Advanced Micro Devices, Inc.; 31.0.24033.1003) - AMD Ryzen 7 3800X 8-Core Processor (16 threads)
Issue description
If a parent GPU particle node's FPS is significantly greater than its sub emitter, it will not emit particles. Doing a deep dive into the matter I believe has exposed the main culprit;
vkCmdCopyBuffer
calls will write to the sub-emitter buffer while a read on the next frame is required to reset and activate particles in the child.As you can see here, the source/dest buffer is written to as 2 particles were set to be emitted by
emit_subparticle
within the compute shader. In addition you can tell that at this step in the frame, anothervkCmdCopyBuffer
is queued working over the same buffers as in EID 56 and 57...and as you can see on the next copy to buffer, the value is resetThe compute shader being dispatched at this point are
particles.glsl
shaders of the parent, as the child runs its particles compute and copy particles compute before the parent dispatches for additional context. This is important because the child shader runs at the beginning of the compute step in the frame, and relies on the buffer not having a 0 value in order to reset particles. As demonstrated above, the "flushing" of particles is done on the first part of the compute pass with the amount to reset set on the previous frame.It is also possible that accumulation of fractional delta values when using non-integer lifetimes can allow particles to sometimes be emitted, as the write to the buffer saying new particles were created can happen at the end, it just isn't likely while using integer lifetime values for the parent...although using fractional lifetime values and changing the lifetime to an integer amount can retain enough fractional accumulation that the emission trigger will occur at the end of the compute stage, making it appear as if the bug sometimes is present and sometimes not.
As far as a fix goes, my thought is that in particles storage that you'd need to read the particle count value from the emission buffer and only write to that buffer if the particles count is less than 0, although I am not sure if that is just a band-aid solution. As such I think a fix may warrant a discussion (although I have tested locally that it does indeed work for the test case).
Steps to reproduce
Create a GPU particles parent node set its FPS to 60 Create a GPU particles child node Set as the child retain its FPS of 30.
See how no particles are generated
Minimal reproduction project (MRP)
particlebugreport.zip