MaterialPtr Problem

WarehouseJim

01-12-2010 13:42:32

Background: I'm using Mogre 1.7.1.0 .NET 4 and Direct3D9 render system. I'm also using Miyagi.

Every frame I update a number of textures that work with InstancedGeometry (and I do similarly with some StaticGeometry). To do this, I get a ResourcePtr from the MaterialsManager and then do:

MaterialPtr myMaterialPtr = myResourcePtr;

99% of the time this works fine, but every so often (sometimes after hours of running) it crashes saying it can't cast the ResourcePtr as a MaterialPtr. Does anyone know why this might happen? Is it a bug?
I'm trying to catch the exception and if it occurs, I'll remove the material and texture (referenced by name) from the materialsManager:

MaterialManager.Singleton.Remove(myMaterialName);
TextureManager.Singleton.Remove(myTextureName);

then re-create again, but it's a slow process to see if this works given the bug is fairly rare, so any advice is appreciated.

To get around this problem previously, I tried keeping references to the TexturePtr and MaterialPtr, but when I resize the screen I found out that you needed to dispose of the pointers or it would crash - I found out that when you resize, the D3D9RenderSystem sets all the texture buffers to null on the card, and somehow keeping the TexturePtr must have been interrupting it. So I got past one bug, but it still crashed occasionally and it's went totally crazy on another computer with all the textures being screwed up. Can anyone advise me what the general policy should be with pointers and how should you deal with them e.g. disposing etc.

thanks,

WarehouseJim

smiley80

01-12-2010 14:51:45

You have to make sure you dispose any instance of a ResourcePtr or a type that is derived from Resource (MaterialPtr, TexturePtr, FontPtr, etc).
Implicit conversion from ResourcePtr creates a new object, so you also have to do:

using (ResourcePtr rp = [GetResourcePtr])
{
using (MaterialPtr mp = rp)
{
}
}

WarehouseJim

01-12-2010 16:44:21

I didn't know that at all. thanks.

Is this kind of stuff documented anywhere / how should I have known it?

Also, I assume I should be disposing non-pointer objects from Mogre e.g. if you do

Technique myTechnique = myMaterialPtr.GetTechnique(0)

you should explicitly dispose myTechnique?

Beauty

02-12-2010 00:56:12

Yes, this is a nice way by C#.
The advantage is, that the "used" variable will be disposed automatically after leaving the { } block.
using ( ... )
{ ... }


When you create a material by code you need a MaterialPtr.
After creation the material is managed by the MaterialManager and you don't need the pointer.
In my application I always call Dispose() for the MaterialPtr immediately after usage. So I'm shure to avoig trouble.

If you need to modify the code later, just create a new pointer (to the material) by usage of
MaterialPtr myMaterial = MaterialManager.Singleton.GetByName(...)
So you need only to keep the material name in memory for access in the future.



additional note
Be shure, that you:

* Use unique material names.
(An option is to attach a unique String which you can create by Guid.NewGuid().ToString() )

* Be shure that the material exists befor you call GetByName(...).
If you are not shure, check it before.
For example write it like this:

String materialName = ... // as you want

MaterialPtr myMaterial;
if (MaterialManager.Singleton.ResourceExists(materialName))
myMaterial = MaterialManager.Singleton.Create(materialName);
else
myMaterial = MaterialManager.Singleton.GetByName(materialName);

// ... create/modify material here

myMaterial.Dispose();


Also have a look to the links of this wiki page:
http://www.ogre3d.org/tikiwiki/-material
Maybe there are also more links on the linked page.

Good luck for Mogre application :wink:

WarehouseJim

02-12-2010 11:19:09

Just to check, where previously I was doing

using(TexturePtr texturePtr = TextureManager.Singleton.CreateManual(....))
{
renderTexture = texture.GetBuffer().GetRenderTarget();
}

I should now be doing

using(TexturePtr texturePtr = TextureManager.Singleton.CreateManual(....))
{
using(HardwarePixelBufferSharedPtr buffer = texture.GetBuffer() )
{
renderTexture =buffer.GetRenderTarget();
}
}

smiley80

02-12-2010 16:22:42

To be on the safe side you should also dispose the rendertexture:
using(TexturePtr tex = TextureManager.Singleton.CreateManual(....))
{
using (HardwarePixelBufferSharedPtr buf = tex.GetBuffer())
{
using (RenderTexture renderTexture = buf.GetRenderTarget())
{
}
}
}

But generally it only seems to be necessary for *Ptr types.

And you have to be careful with methods that return a ResourcePtr like TextureManager.Singleton.GetByName:
using (ResourcePtr rp = TextureManager.Singleton.GetByName(...))
{
using (TexturePtr tex = rp)
{
}
}

tafkag

07-12-2010 15:13:03

Thanks smiley80 for your very informative postings.

Beauty

07-12-2010 18:58:21

And to be shure you should check if the texture exists before you call GetByName(...).
You can check like this:
TextureManager.Singleton.ResourceExists(...)

If needed, you could do similar checks for materials, ManualObjects, Overlays, etc.