I load a material from the ResourceCache, then I Clone() it and modify a shader parameter in it.
I keep references to both instances in my class and use them on my models depending on some state.
I can use the original material (loaded from the ResourceCache), but the cloned instance I can only use one time.
When I try to set it on my model a second time my app crashes completely (giving me a stack trace).
What can the problem be? Isn't Clone() supposed to work?
I'm using version 1.1.120.
Posts
@EsaKylli.5920 can you please provide a small repro code snippet\project?
This is part of my code (in a subclass to Component):
CreateMaterials() is called when the Application starts. The material is set on my StaticModel via SetMaterial().
If I comment out the initialization of "boxMaterialSelected", and instead use the commented out line at the end (loading from ResourceCache) it works.
@EsaKylli.5920
I modified StaticScene sample with this code:
and it works fine for me (Windows). Can you please create a small repro project?
Your above code works fine for me too (on Mac).
I have isolated the problem now to this specific use-case (modified StaticScene).
If you left-click once, and then another time you should get a crash.
The funny thing here is that if you don't use a cloned material (but two different ones loaded from the ResourceCache) it works.
I have no clue what's going on....
@EsaKylli.5920
The problem is:
when you replace cloned material with the original one via this code:
selectedNodeModel.SetMaterial(originalMaterial);
the inner Urho3D will delete cloned material as nobody uses it anymore (for example, if the scene would have some long-live StaticModel with this cloned material - the bug wouldn't happen).
Initial
SetMaterial(clonedMaterial)
incremented inner RefsCount to 1 from 0 and the following operationselectedNodeModel.SetMaterial(originalMaterial);
did
ReleasRef
over clonedMaterial and since RefCount became 0 - it triggered "delete".So as a workaround you can do:
clonedMaterial = originalMaterial.Clone("Clonned");
clonedMaterial.AddRef(); //surrogate reference in order to keep it alive
That makes sense. I guess it's a consequence when mixing managed (C#) and unmanaged (C++) code?
(When working with Urho3D in C++ I remember I had to encapsulate the material reference in my class in a SharedPtr.)
Do I have to add ReleseRef() to it also? When should I do that? Not when exiting the game, isn't it deallocated anyway in that case?
@EsaKylli.5920
It's a temporary workaround, will be fixed in the next version. As for now, yes, you'll have to call ReleaseRef once you don't need "clonedMaterial" anymore (otherwise it will leak).
So what you are saying is that the reference counting will work automatically between managed and unmanaged code (in a coming version)?
Do I have to call ReleaseRef() even when exiting the game?