Sprite / Particle generator design pattern

Hi

I’m trying to create a kind of rudimentary particle generator.

I’m using a SpreadBuilder to handle the creation, and each instance removes itself from the list when its life is over.

So far I have it running using stride as renderer pipeline, the only problem I see is that the RefCnt increases on each instance creation.

If I use a stable count of instances the RefCnt doesn’t increase.

Which programing pattern should I use to avoid this behavior?

I’m considering Factory Pattern, but don’t see an easy way to include an Update state where the instances get computed.

Thank you.

More information about Factory Pattern.

Can you post a mini patch showing the problem ?

Also what is the RefCnt you’re mentioning ?

Hi @lecloneur Press F2 on the render screen to see the RefCnt,

As I understand high RefCnt can create memory leak due the garbage collector optimization mechanism.

I’ve updated your Factory Pattern patch, now the slices get automatically removed after a certain time, and the RefCnt doesn’t increase.

FactoryPatternAutoRegister_Update.vl (162.2 KB)

Clean up and Random Lifetime

FactoryPatternAutoRegister_Update_2.vl (163.6 KB)

Here a more advanced version, where the Argument “MeshProperties” is a record.

In this case some parameters are animated along the lifetime of the instance.

There is a limitation while animating any of the properties present in “EntityComponent”.

As soon as the material or radius are animated the RefCnt increases

FactoryPatternAutoRegister_Update_3.vl (179.8 KB)

I’m wondering if there is a proper way to achieve what I have in mind, and also thinking that probably my original approach is right and the RefCnt issue is just a limitation in the Stride render pipeline.

It’s not like that, basically your ref count increase as soon as your “instance” is holding some resources, basically if you have a model component it’s bound to gpu somewhere… You can see it here

It’s a little bit hard to explain, but easily speaking, if you change the radius of sphere like that, it’s not going to “modify” existing mesh, it would create new one, instead you should use transformation or custom material maybe..

I think i’ve seen on stride’s discord few days ago that they are tent to fix exactly how to handle resource if user not disposing it,

If changing how you handle sphere radius is not going to help then, the only approaches are digging deeper in stride pipeline…

Honestly i think if ref count increases when you animate mesh like that is more of vvvv bug, that should be checked e.g. empty patch with sphere and lfo and check the ref count

Thank you @antokhio that makes me feel less stupid.

FactoryPatternAutoRegister_Update_4.vl (225.1 KB)

The RefCnt related to the material is strange, no idea about it but I did some refactoring to decoupled everything.
The repository is passed to the manager which pass the items to the render.

I think the repo in the example I made is not very relevant because there is only one manager. If multiple manager then I guess they all could add different object to one repository.

Here is another version with Repo directly to render

FactoryPatternAutoRegister_Update_5.vl (227.0 KB)

1 Like

Cool stuff,

thank you so much

I’ve done a correction in the manager,

Animation wasn’t unregistered

FactoryPatternAutoRegister_Update_6.vl (228.1 KB)

And a question regarding performance, does it make sense to read the Items list on 3 ForEach loops?

So far, there is the LifeCycle computation

Animation computation

and finally the render stage

I would say that everything could be done in the Render stage ForEach loop, doesn’t it?

@lecloneur Thank you so much for investing some time on this,

I think your version is much easier to understand, providing a couple of interesting methods and it’s much closer to a “clean Design Pattern”, but also creates a bit of overload computing the same list 3 times.

Correct me if i’m wrong but in my understanding, the Manager shouldn’t deal with the Update/Runtime stage, just the list items handle.

Update/Runtime stage is where the animation and rendering happens, the only issue I see on my approach is the need of Reverse Sequence to avoid calling an element that was already removed from the list.

Also in this particular case the Update/Runtime stage deletes slices from the list, and it can be consider an extension of the manager.

Here my version.

FactoryPatternAutoRegister_Update_7.vl (198.6 KB)

Use the node TryDispose (Instance) on the particles you remove from your list. In case the specific particle (or IRenderable in your case) contains a process node which needs cleanup (like nodes dealing with graphics resources), it will internally implement IDisposable automatically and cleanup all process nodes accordingly. This in turn will take care of releasing any native resources allocated by those nodes and the ref count of the D3D11 device should go down.

Sometimes you might also do something specific on Dispose yourself, in that case implement the interface explicitly, add the Dispose method and assign stuff to it accordingly.

In other words: as long as you use process nodes inside of process nodes, the lifetime of each is well defined, when the parent patch gets disposed, it also disposes all its child nodes. But once you break out of that cycle through dynamic instantiation you need to take care of that dynamic boundary you created and dispose those dynamically created instances.

Still no clear where & when should I use the TryDispose (Instance)

When I remove the instance from the list?

And more in detail, Do I connect the specific slice to TryDispose (Instance)node?

Do I need also to implement IDisposable and call Dispose method on the Entities I create?

What should I assing in this specific case?

I see there is also a TryDispose (Sequence) node, would it be useful when clearing the whole list?

Thank you @Elias

Try right before you remove from the list, the dispose call is synchronous so should work e.g.:

Or like that:

It looks i’m missing something, the RefCnt is still increasing even with TryDispose added as @antokhio suggested

FactoryPatternAutoRegister_Update_8.vl (200.9 KB)

I’ll try to have a more in depth look tomorrow. The RefCnt can sometimes be a bit tricky to read, also due to Stride engine caching certain things. But if it doesn’t go down at all even though we are sure the instances get disposed properly when we remove them could hint to a bug. Will get back to you.

1 Like

After a bit of profiling it looks to me the ref count goes up because Stride internally caches internal render states per material. So the question would be for you - can you build your system in a way that you re-use materials?

Usage of TryDispose looks correct in your latest sketch. However your Clear operation does not dispose the instances. You should either call it on each of them before clearing or use that TryDispose (Sequence) overload.