Dispose problems

moviestar

21-09-2007 14:59:52

Hi all,

I am using Mogre in a popup form that is part of my application. The first time the form is displayed, everything works fine. When the form is closed, I call the mRoot.Dispose() function to cleanup. However, when I display again the form, I get a crash:

Exception Type: System.AccessViolationException
Exception Message:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Exception Source: Mogre
Stack Trace:
at Mogre.TextureManager.set_DefaultNumMipmaps(UInt32 num)

After investigation, it seems that it may be related to the fact that the TextureManager singleton is static and seems to be disposed when the root object is Disposed. However, its reference is not set to null internally in the TextureManager class (c.f. _singleton member). Meaning that when a new Root object is created (on the second try) and I try to use the TextureManager object, the singleton does not get re-initialized.

So my question is how can I avoid the crash by disposing my resources correctly when my form closes. I am not able to find anywhere (using Reflector) where the _singleton of the TextureManager class is reset to null. And I do not want to keep those references in memory when my Mogre form is closed.

Thanks for your help.

Hugo

wgzeng

26-10-2007 14:22:23

i also meet the same question! you can try to use "Mogre.ResourceGroupManger.Dispose()" in Mogre_Dispose() function. i use this solution to make some Mogre_forms working, but it is no use for the Mogre_forms which use "Mogre.MeshManger.CreatePlane()"!

bleubleu

26-10-2007 17:57:57

Hi!

These kind of problem can be tricky with Mogre. The sequence of operation wehn you create/dispose your objects is critical. It is pretty hard to diagnose the problem without any code, but could verify that you are not keeping a reference to any Texture in you app ?? Like a TexturePtr somewhere ? All the *Ptr must be released (disposed and/or set to null) BEFORE disposing of root.

If it doesnt work, try posting some code, I can look at it with you.

Mat

wgzeng

29-10-2007 04:56:50

my source code(VS2005 express + WinXp):


public class My3DUnit : UserControl
{
private System.ComponentModel.Container components = null;
private bool _IsFirst;
public Mogre.SceneManager sceneMgr;
public Mogre.Root root;
protected Mogre.Camera camera;
protected Mogre.Viewport viewport;
protected Mogre.RenderWindow window;
protected Point position;
protected IntPtr hWnd;

public My3DUnit()
{
InitializeComponent();
this.Disposed += new EventHandler(Mogre_Disposed);

hWnd = this.Handle;
position = new Point(0, 0);
_IsFirst = true;

}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

void Mogre_Disposed(object sender, EventArgs e)
{
if (root != null)
{
root.Dispose();
root = null;
}

}

private void InitializeComponent()
{
this.SuspendLayout();

this.Name = "My3DUnit";
this.ResumeLayout(false);
}

protected override void OnPaint(PaintEventArgs e)
{
if (_IsFirst)
{
InitMogre();
_IsFirst = false;
root.RenderOneFrame();
}
else
{
root.RenderOneFrame();
}

base.OnPaint (e);
}

protected void InitMogre()
{

root = new Mogre.Root();

Mogre.ConfigFile cf = new Mogre.ConfigFile();
cf.Load("resources.cfg", "\t:=", true);

Mogre.ConfigFile.SectionIterator seci = cf.GetSectionIterator();

String secName, typeName, archName;

while (seci.MoveNext())
{
secName = seci.CurrentKey;
Mogre.ConfigFile.SettingsMultiMap settings = seci.Current;
foreach (System.Collections.Generic.KeyValuePair<string, string> pair in settings)
{
typeName = pair.Key;
archName = pair.Value;
Mogre.ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
}
}

bool foundit = false;
foreach (Mogre.RenderSystem rs in root.GetAvailableRenderers())
{
root.RenderSystem = rs;
String rname = root.RenderSystem.Name;
if (rname == "Direct3D9 Rendering Subsystem")
{
foundit = true;
break;
}
}

if (!foundit)
return; //we didn't find it... Raise exception?

root.RenderSystem.SetConfigOption("Full Screen", "No");
root.RenderSystem.SetConfigOption("Video Mode", "1024 x 768 @ 32-bit colour");
root.Initialise(false);

Mogre.NameValuePairList misc = new Mogre.NameValuePairList();
misc["externalWindowHandle"] = hWnd.ToString();
window = root.CreateRenderWindow("Simple Mogre Form Window" , 0, 0, false, misc);
Mogre.ResourceGroupManager.Singleton.InitialiseAllResourceGroups();

CreateScene();

}

protected void CreateScene()
{
sceneMgr = root.CreateSceneManager(Mogre.SceneType.ST_GENERIC, "SceneMgr");
sceneMgr.AmbientLight = new Mogre.ColourValue(0.25f, 0.25f, 0.25f);
sceneMgr.ShadowTechnique = Mogre.ShadowTechnique.SHADOWTYPE_STENCIL_ADDITIVE;

camera = sceneMgr.CreateCamera("SimpleCamera");
camera.SetPosition(-300f, 200f, 400f);
camera.LookAt(Mogre.Vector3.ZERO);
camera.NearClipDistance = 5;

viewport = window.AddViewport(camera);
viewport.BackgroundColour = new Mogre.ColourValue(0.0f, 0.0f, 0.0f, 1.0f);
camera.AspectRatio = viewport.ActualWidth / viewport.ActualHeight;

sceneMgr.SetSkyDome(true, "Examples/SpaceSkyPlane", 10, 3);

Mogre.Entity ent = sceneMgr.CreateEntity("Robot", "robot.mesh");
ent.CastShadows = true;
Mogre.SceneNode node = sceneMgr.RootSceneNode.CreateChildSceneNode("RobotNode");
node.AttachObject(ent);

Mogre.Light light = sceneMgr.CreateLight("RobotLight");
light.Type = Mogre.Light.LightTypes.LT_POINT;
light.DiffuseColour = new Mogre.ColourValue(1, 1, 1);
light.SetPosition(-10, 100, 10);
node.AttachObject(light);

//create plane
Mogre.Plane plane = new Mogre.Plane(Mogre.Vector3.UNIT_Y, 0);
Mogre.MeshManager.Singleton.CreatePlane("GroundMesh", Mogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Mogre.Vector3.UNIT_Z);
ent = sceneMgr.CreateEntity("Ground", "GroundMesh");
node = sceneMgr.RootSceneNode.CreateChildSceneNode("GroundNode");
node.AttachObject(ent);
ent.SetMaterialName("Examples/Rockwall");
ent.CastShadows = true;

}

}

bleubleu

30-10-2007 00:16:49

Hi there!


I tried your code and guess what ? No problems here. Eveything runs smoothly both in debug and release mode. The log file show no problem during the ogre shutdown. Humm.

I dont know what to say, maybe a version thing.

Mat

wgzeng

30-10-2007 15:29:54

please build form1, form1 contains button1, click button1 execute "new form2",my3dunit embed in form2. run program , show form1, click button1 to show form2. close form2, then click button1, you can find some problems.

bleubleu

31-10-2007 00:07:41

Hi,

Thanks for the deltails, I managed to reproduce the problem. There are a few problems with the code as-is.

First, because of the way Mogre handles singletons, you are not allowed to create/delete and recreate the Root object. So simply create it once at the beginning of the program and then later access it with Root.Singleton.

[STAThread]
static void Main()
{
Root root = new Root();

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());

root.Dispose();
root = null;
}


Also, because you will no longer destroy and re-create the root object, you need to cleanup the scene manager and render window when disposing of your control.

void Mogre_Disposed(object sender, EventArgs e)
{
viewport.Dispose();
viewport = null;

camera.Dispose();
camera = null;

sceneMgr.ClearScene();

Root.Singleton.DestroySceneManager(sceneMgr);
Root.Singleton.RenderSystem.DestroyRenderWindow(window.Name);

sceneMgr = null;
window = null;
}


Also, The GroundPlane you create for the floor, you must only create the mesh once, because you will get a name conflict in the MeshManager the second time around. So check to make sure it doesnt already exists.

if (!MeshManager.Singleton.ResourceExists("GroundMesh"))
{
Mogre.MeshManager.Singleton.CreatePlane("GroundMesh", Mogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, true, 1, 5, 5, Mogre.Vector3.UNIT_Z);
}


That's as far as I had time to get. Now the application will still crash the second time, but i am not sure why. It has nothing to do with Mogre, it an Ogre thing. When you delete the last window, the Render System seems to be released and then when you try to relaunch it it seems to fail... :?

I am not sure what kind of application you are developping, but a workaroung would be to simple hide your windows. If you are building a game, you usually need 1 window. I you are aiming for something like an editor, you can create 2-3 windows and then simply delete them at the very end.

Mat

wgzeng

31-10-2007 04:51:37

Hi,


Thanks a lot for your help! I will try it again.

wgzeng

12-11-2007 14:30:53

I rewrote my codes under your suggestion. When I 'close' forms, I hide them in fact. Everything is great, but when I use MDI child form ... Form crashes when I show form again! If I don't use MDI childform, everything is OK.
namespace MogreTest
{
public partial class Form2 : Form
{
public Root root;
public Form1 frm;

public Form2()
{
InitializeComponent();

this.Disposed += new EventHandler(Form2_Disposed);

InitMogre();
}

void Form2_Disposed(object sender, EventArgs e)
{
if (root != null)
{
root.Dispose();
root = null;
}
}

public void InitMogre()
{

root = new Root();

ConfigFile cf = new ConfigFile();
cf.Load("resources.cfg", "\t:=", true);

ConfigFile.SectionIterator seci = cf.GetSectionIterator();

String secName, typeName, archName;

while (seci.MoveNext())
{
secName = seci.CurrentKey;
ConfigFile.SettingsMultiMap settings = seci.Current;
foreach (KeyValuePair<string, string> pair in settings)
{
typeName = pair.Key;
archName = pair.Value;
ResourceGroupManager.Singleton.AddResourceLocation(archName, typeName, secName);
}
}

bool foundit = false;
foreach (RenderSystem rs in root.GetAvailableRenderers())
{
root.RenderSystem = rs;
String rname = root.RenderSystem.Name;
if (rname == "Direct3D9 Rendering Subsystem")
{
foundit = true;
break;
}
}

if (!foundit)
return; //we didn't find it... Raise exception?

root.RenderSystem.SetConfigOption("Full Screen", "No");
root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour");

root.Initialise(false);

}

private void newForm1ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (frm == null)
{
frm = new Form1();
frm.MdiParent = this;
frm.Show();
}
else
{
frm.Show();
}
}
}

public partial class Form1 : Form
{
public Root root;
protected static int WinCount = 0;
protected bool _isInit;
public SceneManager sceneMgr1;

protected Camera camera1;
protected Viewport viewport1;
protected RenderWindow window1;

protected Point position;
protected IntPtr hWnd;

public Form1()
{
InitializeComponent();

InitMogre();
}

protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
base.OnClosing(e);
}

public void InitMogre()
{
root = Root.Singleton;

NameValuePairList misc1 = new NameValuePairList();
misc1["externalWindowHandle"] = this.Handle.ToString();
WinCount ++;
window1 = root.CreateRenderWindow("Simple Mogre Form Window" + WinCount.ToString(), 0, 0, false, misc1);

ResourceGroupManager.Singleton.InitialiseAllResourceGroups();

sceneMgr1 = root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr" + WinCount.ToString());
sceneMgr1.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);

camera1 = sceneMgr1.CreateCamera("SimpleCamera" + WinCount.ToString());
camera1.Position = new Vector3(0f, 0f, 100f);

camera1.LookAt(new Vector3(0f, 0f, -300f));
camera1.NearClipDistance = 5;

viewport1 = window1.AddViewport(camera1);
viewport1.BackgroundColour = new ColourValue(0.0f, 0.0f, 0.0f, 1.0f);

Entity ent = sceneMgr1.CreateEntity("ogre"+WinCount.ToString(), "ogrehead.mesh");
SceneNode node = sceneMgr1.RootSceneNode.CreateChildSceneNode("ogreNode"+WinCount.ToString());
node.AttachObject(ent);
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
root.RenderOneFrame();
}

}
}


Zeng