-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify the clone modifier and spawners, and fix races. #387
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! I really like the way things are moving, this is going in the same direction as my upcoming hierarchy change so although this will heavily conflict due to touching the same code (I'll handle it) conceptually the changes align, moving the cloning as an init of sort.
On the code itself, mostly OK overall, but there's a number of small points I either don't understand or could be clarified. I don't think there's any major error though. If you can do one more pass on it that'd be great.
Thanks a lot!
src/spawn.rs
Outdated
} | ||
} | ||
|
||
/// Holds the runtime state for the initializer of each particle group on a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not "each", isn't it? It's "a single" particle group, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the rework, I like the API changes! I tried out this PR, and I've noticed some differences that I think are notable:
- Since trail lifetimes are
CpuValue
s, their lifetimes can't be configured via properties. Not a big issue, to be clear, I'll just make separate effect assets when I need a different lifetime. - My effects spawn a single particle in group 0, but now I need at least a group 0 capacity of 2 for the particles to show up at all
- Now many attributes (including
POSITION
andHDR_COLOR
, but excludingAGE
) must be initialized ininit
instead of just being set inupdate
I've also still noticed lag and artifacts like in #376, see the end of this video:
2024-10-23.13-47-01.mp4
I didn't read through these changes, just left comments on some things I noticed
899f1ab
to
656ee1b
Compare
Comments addressed. |
656ee1b
to
8a9a8de
Compare
Great PR! |
This large patch essentially makes particle trails and ribbons part of the spawner, which is processed during the init phase, rather than modifiers that execute during the update phase. Along the way, this made it easier to fix race conditions in spawning of trails, because spawning only happens in the init phase while despawning only happens in the update phase. This addresses djeedai#376, as well as underflow bugs that could occur in certain circumstances. In detail, this commit makes the following changes: * Every group now has an *initializer*. An initializer can either be a *spawner* or a *cloner*. This allows spawners to spawn into any group, not just the first one. * The `EffectSpawner` component is now `EffectInitializers`, a component which contains the initializers for every group. Existing code that uses `EffectSpawner` can migrate by picking the first `EffectInitializer` from that component. * The `CloneModifier` has been removed. Instead, use a `Cloner`, which manages the `age` and `lifetime` attributes automatically to avoid artifacts. The easiest way to create a cloner is to call `with_trails` or `with_ribbons` on your `EffectAsset`. * The `RibbonModifier` has been removed. Instead, at most one of the groups may be delegated the ribbon group. The easiest way to delegate a ribbon group is to call `EffectAsset::with_ribbons`. (It may seem like a loss of functionality to only support one ribbon group, but it actually isn't, because there was only one `prev` and `next` attribute pair and so multiple ribbons never actually worked before.) * The `capacity` parameter in `EffectAsset::new` is no longer a vector of capacities. Instead, you supply the capacity of each group as you create it. I figured this was cleaner. * Init modifiers can now be specific to a particle group, and they execute for cloned particles as well. There's no need to use update modifiers to set values on cloned particles. * Age and lifetime can no longer be set manually for cloned particles. (They can still be set as usual for spawned particles.) This enforces LIFO ordering for ribbons, which is necessary to avoid races. * Underflow of particle counts that could occur in certain scenarios involving multiple groups is fixed. The racy hack that "put back" particles that would otherwise underflow the alive count is no longer needed. * Particle linked lists no longer race with one another (djeedai#376). Closes djeedai#376.
8a9a8de
to
1ebaff0
Compare
Fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks all good to me, but I'd like for @Seldom-SE to confirm that the lags are gone before merging, because that was the entire point of this change (or part of it at least).
Also @pcwalton can you please consider avoiding force-push in the future, especially on large PRs like this? In general with git this doesn't work well with PRs, but here the GitHub UI is rather bad, and I can only see the difference between your previous and current version at the file level (whether the file was modified or not, as a boolean state), not at the line level (what actually changed). So each time I have to review 3000 lines again to figure out what changed in render/mod.rs
for example 😢 At least with incremental commits I can look at just the newer commits. I'll squash on merge anyway (unless there's a strong reason to keep history, but that's very rare). Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like for @Seldom-SE to confirm that the lags are gone before merging
This PR fixes some long random freezes we were running into, but doesn't fix the constant low FPS at about 750 particles. I'm getting FPS lows in the same ballpark (1-4.5) in a given situation in our game. Whatever's causing that lag is likely out of scope for this PR, and I'm not seeing the ribbon artifacts anymore, so I think this is good to merge.
Thanks!
* `ribbon` was a bit buggy because we could spawn and clone the newly-spawned particle on the first frame. I changed the shader to use `max_update` instead. * `spawn_on_command`, `activate`, and `force_field` were broken because we were copying `Spawner`s. I fixed that and removed `#[derive(Copy)]` so it doesn't happen again.
Fixed. See the commit message for more details as to what was going wrong. |
Ok, I fixed the problem by reverting to |
This large patch essentially makes particle trails and ribbons part of the spawner, which is processed during the init phase, rather than modifiers that execute during the update phase. Along the way, this made it easier to fix race conditions in spawning of trails, because spawning only happens in the init phase while despawning only happens in the update phase. This addresses #376, as well as underflow bugs that could occur in certain circumstances.
In detail, this commit makes the following changes:
Every group now has an initializer. An initializer can either be a spawner or a cloner. This allows spawners to spawn into any group, not just the first one.
The
EffectSpawner
component is nowEffectInitializers
, a component which contains the initializers for every group. Existing code that usesEffectSpawner
can migrate by picking the firstEffectInitializer
from that component.The
CloneModifier
has been removed. Instead, use aCloner
, which manages theage
andlifetime
attributes automatically to avoid artifacts. The easiest way to create a cloner is to callwith_trails
orwith_ribbons
on yourEffectAsset
.The
RibbonModifier
has been removed. Instead, at most one of the groups may be delegated the ribbon group. The easiest way to delegate a ribbon group is to callEffectAsset::with_ribbons
. (It may seem like a loss of functionality to only support one ribbon group, but it actually isn't, because there was only oneprev
andnext
attribute pair and so multiple ribbons never actually worked before.)The
capacity
parameter inEffectAsset::new
is no longer a vector of capacities. Instead, you supply the capacity of each group as you create it. I figured this was cleaner.Init modifiers can now be specific to a particle group, and they execute for cloned particles as well. There's no need to use update modifiers to set values on cloned particles.
Age and lifetime can no longer be set manually for cloned particles. (They can still be set as usual for spawned particles.) This enforces LIFO ordering for ribbons, which is necessary to avoid races.
Underflow of particle counts that could occur in certain scenarios involving multiple groups is fixed. The racy hack that "put back" particles that would otherwise underflow the alive count is no longer needed.
Particle linked lists no longer race with one another (Artifacts in
firework
example #376).Closes #376.