Jump to content
  • Advertisement
Sign in to follow this  
Raloth

MDX is acting obnoxious

This topic is 4324 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Every day I start to regret my switch to managed DirectX more and more... If anyone has experience with these problems, some advice would be greatly appreciated. 1) Mesh.Clean. Here's what the MSDN has to say about it: "A Mesh object that represents the returned cleaned mesh. If no cleaning is necessary, the returned mesh is the same as the one that was passed in." When I call Mesh.Clean, I can check the unmanaged COM pointer and verify that the mesh in and mesh out are in fact different. However, calling Dispose on the mesh I pass to Mesh.Clean also disposes the returned mesh. I have no idea why this would be if the pointers are clearly different, but it makes the function completely worthless for me. 2) Device.Reset. Something is not working like it's supposed to. I watch my program very explicitly call Dispose on all Default pool resources. The functions that do this get triggered from the Device.DeviceLost event. Curiously, Device.Present also triggers the event, which screwed with my head for a while. Objects appropriately reallocate their resources in a response to the Device.DeviceReset event. I took it down to one object and as far as I can tell, this all works like it should. However, on the second device reset event (launch, alt+tab out, alt+tab in, alt+tab out, alt+tab in), my app never fails to crash. The debug output says there are still Default resources unfreed (the ones I created and know for a fact I called Dispose on). Even if I don't call Dispose on my resources, it still crashes on the second time ([looksaround] not the first). It's as if Dispose isn't actually doing anything. I never had any of these difficulties working with native C++. Something feels lost in translation and it's making my life far more difficult than it needs to be.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Raloth
1) Mesh.Clean. Here's what the MSDN has to say about it: "A Mesh object that represents the returned cleaned mesh. If no cleaning is necessary, the returned mesh is the same as the one that was passed in." When I call Mesh.Clean, I can check the unmanaged COM pointer and verify that the mesh in and mesh out are in fact different. However, calling Dispose on the mesh I pass to Mesh.Clean also disposes the returned mesh. I have no idea why this would be if the pointers are clearly different, but it makes the function completely worthless for me.

I checked Mesh.Clean (December SDK version) with reflector, and it looks fine. How did you check the unmanaged COM pointers? Perhaps there's something wrong with the checking code.

Quote:
2) Device.Reset. Something is not working like it's supposed to. I watch my program very explicitly call Dispose on all Default pool resources. The functions that do this get triggered from the Device.DeviceLost event. Curiously, Device.Present also triggers the event, which screwed with my head for a while. Objects appropriately reallocate their resources in a response to the Device.DeviceReset event. I took it down to one object and as far as I can tell, this all works like it should. However, on the second device reset event (launch, alt+tab out, alt+tab in, alt+tab out, alt+tab in), my app never fails to crash. The debug output says there are still Default resources unfreed (the ones I created and know for a fact I called Dispose on). Even if I don't call Dispose on my resources, it still crashes on the second time ([looksaround] not the first). It's as if Dispose isn't actually doing anything.

This is similar: Managed Direct3D InvalidCallException on Second Device Reset. Perhaps you did the same mistake?

Share this post


Link to post
Share on other sites
Quote:
Original post by Muhammad Haggag
Quote:
Original post by Raloth
1) Mesh.Clean. Here's what the MSDN has to say about it: "A Mesh object that represents the returned cleaned mesh. If no cleaning is necessary, the returned mesh is the same as the one that was passed in." When I call Mesh.Clean, I can check the unmanaged COM pointer and verify that the mesh in and mesh out are in fact different. However, calling Dispose on the mesh I pass to Mesh.Clean also disposes the returned mesh. I have no idea why this would be if the pointers are clearly different, but it makes the function completely worthless for me.

I checked Mesh.Clean (December SDK version) with reflector, and it looks fine. How did you check the unmanaged COM pointers? Perhaps there's something wrong with the checking code.

Oh, I forgot to mention the real kicker. I start with a mesh...let's call it Mesh1. I use Clone on Mesh1 to make Mesh2. I call Clean on Mesh2 to make Mesh3. If I call dispose on Mesh1, Mesh3 becomes disposed as well. Something can't possibly be right there.

Quote:

Quote:
2) Device.Reset. Something is not working like it's supposed to. I watch my program very explicitly call Dispose on all Default pool resources. The functions that do this get triggered from the Device.DeviceLost event. Curiously, Device.Present also triggers the event, which screwed with my head for a while. Objects appropriately reallocate their resources in a response to the Device.DeviceReset event. I took it down to one object and as far as I can tell, this all works like it should. However, on the second device reset event (launch, alt+tab out, alt+tab in, alt+tab out, alt+tab in), my app never fails to crash. The debug output says there are still Default resources unfreed (the ones I created and know for a fact I called Dispose on). Even if I don't call Dispose on my resources, it still crashes on the second time ([looksaround] not the first). It's as if Dispose isn't actually doing anything.

This is similar: Managed Direct3D InvalidCallException on Second Device Reset. Perhaps you did the same mistake?

No go [sad]. I haven't tried the workaround at the very bottom yet. I might just get rid of event handlers. This is an excellent example of the problems with MDX. It's an obscure behavior that isn't clearly documented anywhere (and doesn't even make sense!), and the suggested fix by Tom Miller doesn't even work. I can dispose my buffers as many times as I want without recreating them myself, but it will always crash on the second alt+tab.

Share this post


Link to post
Share on other sites
The awesomeness continues.

I went ahead and disabled the events and now device recovery works perfectly. However, I noticed a new problem in my debug output:

First-chance exception at 0x7c809e3a in Application.exe: 0xC0000005: Access violation reading location 0x015a7c50.
This is spammed several times all over the place. A simple step through showed that the first occurance is right in the app's constructor... form = new Form(); Why on earth would that throw an exception? The code at this point hasn't even touched Direct3D. It doesn't actually crash unless I tell it to in the Exceptions screen, but I'd rather not have random exceptions flying about.

Share this post


Link to post
Share on other sites
Quote:
Original post by Raloth
Oh, I forgot to mention the real kicker. I start with a mesh...let's call it Mesh1. I use Clone on Mesh1 to make Mesh2. I call Clean on Mesh2 to make Mesh3. If I call dispose on Mesh1, Mesh3 becomes disposed as well. Something can't possibly be right there.

This is really weird. Which SDK are you using? Can you post the C# reflector output for the BaseMesh.Clone and Mesh.Clean methods?

Quote:
I went ahead and disabled the events and now device recovery works perfectly. However, I noticed a new problem in my debug output:

First-chance exception at 0x7c809e3a in Application.exe: 0xC0000005: Access violation reading location 0x015a7c50.
This is spammed several times all over the place. A simple step through showed that the first occurance is right in the app's constructor... form = new Form(); Why on earth would that throw an exception? The code at this point hasn't even touched Direct3D. It doesn't actually crash unless I tell it to in the Exceptions screen, but I'd rather not have random exceptions flying about.

OK, at least there's an improvement [smile]. Can you post your Main code? Also, try to simplify until you no longer get access violations in Form(). That'd help you pin down whatever's causing this.

Share this post


Link to post
Share on other sites
I'm using .NET 2.0 with the 1.0.2911.0 SDK (October 2006).

BaseMesh.Clone:

public unsafe Mesh Clone(MeshFlags options, GraphicsStream declaration, Device device)
{
int num2;
IDirect3DDevice9* devicePtr1 = D3DX.GetUnmanagedDevice(device);
ID3DXMesh* meshPtr1 = null;
if (declaration != null)
{
num2 = (int) declaration.InternalDataPointer;
}
else
{
num2 = 0;
}
int num1 = **(((int*) this.m_lpUM))[0x30](this.m_lpUM, options, num2, devicePtr1, &meshPtr1);
if (devicePtr1 != null)
{
**(((int*) devicePtr1))[8](devicePtr1);
}
if (num1 < 0)
{
if (!DirectXException.IsExceptionIgnored)
{
Exception exception2 = Direct3DXException.GetExceptionFromResultInternal(num1);
DirectXException exception1 = exception2 as DirectXException;
if (exception1 != null)
{
exception1.ErrorCode = num1;
throw exception1;
}
throw exception2;
}
SetLastError((uint modopt(IsLongModifier)) num1);
}
if (meshPtr1 != null)
{
return new Mesh(meshPtr1, device);
}
return null;
}






Here's the Mesh.Clean I was using:

public static unsafe Mesh Clean(CleanType cleanType, Mesh mesh, GraphicsStream adjacency, GraphicsStream adjacencyOut, out string errorsAndWarnings)
{
IntPtr* ptrPtr1;
IntPtr* ptrPtr2;
if (adjacencyOut != null)
{
ptrPtr2 = &adjacencyOut.InternalData;
}
else
{
IntPtr ptr3 = new IntPtr();
ptr3 = new IntPtr(0);
ptrPtr2 = &ptr3;
}
if (adjacency != null)
{
ptrPtr1 = &adjacency.InternalData;
}
else
{
IntPtr ptr1 = new IntPtr();
ptr1 = new IntPtr(0);
ptrPtr1 = &ptr1;
}
return Mesh.Clean(cleanType, mesh, ptrPtr1[0], ptrPtr2[0], out errorsAndWarnings);
}






The actual Mesh.Clean:

private static unsafe Mesh Clean(CleanType cleanType, Mesh mesh, IntPtr adjacency, IntPtr adjacencyOut, out string errorsAndWarnings)
{
ID3DXMesh* meshPtr1;
ID3DXMesh* meshPtr2 = null;
ID3DXBuffer* bufferPtr1 = null;
ID3DXBuffer** bufferPtrPtr1 = null;
if (errorsAndWarnings != null)
{
errorsAndWarnings = string.Empty;
bufferPtrPtr1 = &bufferPtr1;
}
if (mesh != null)
{
meshPtr1 = mesh.m_lpUM;
}
else
{
meshPtr1 = null;
}
int num1 = D3DXCleanMesh((int) cleanType, meshPtr1, (uint modopt(IsLongModifier) modopt(IsConstModifier)*) adjacency.ToPointer(), &meshPtr2, (uint modopt(IsLongModifier)*) adjacencyOut.ToPointer(), bufferPtrPtr1);
if (bufferPtr1 != null)
{
if (**(((int*) bufferPtr1))[0x10](bufferPtr1) > 0)
{
IntPtr ptr1 = new IntPtr();
ptr1 = new IntPtr((void*) **(((int*) bufferPtr1))[12](bufferPtr1));
errorsAndWarnings = Marshal.PtrToStringAnsi(ptr1);
}
if ((bufferPtr1 != null) && (**(((int*) bufferPtr1))[8](bufferPtr1) == 0))
{
bufferPtr1 = null;
}
}
if ((num1 < 0) && ((errorsAndWarnings == null) || (errorsAndWarnings == string.Empty)))
{
if (!DirectXException.IsExceptionIgnored)
{
Exception exception2 = Direct3DXException.GetExceptionFromResultInternal(num1);
DirectXException exception1 = exception2 as DirectXException;
if (exception1 != null)
{
exception1.ErrorCode = num1;
throw exception1;
}
throw exception2;
}
SetLastError((uint modopt(IsLongModifier)) num1);
}
if (meshPtr2 != null)
{
return new Mesh(meshPtr2, mesh.Device);
}
return null;
}






This is all a bit over my head. It took me a while to even figure out how to get this disassembly up [smile]. I'll try stripping the code down later to look at the form exceptions. Cleaning that code up was on my list of things to do...hopefully it will fix itself.

Share this post


Link to post
Share on other sites
I think the problem lies in your code, because the D3DX code looks OK. If we remove the error checking:


public unsafe Mesh Clone(MeshFlags options, GraphicsStream declaration, Device device)
{
int num2; // This will point to the vertex declaration, if available
IDirect3DDevice9* devicePtr1 = D3DX.GetUnmanagedDevice(device);
ID3DXMesh* meshPtr1 = null;
if (declaration != null)
{
num2 = (int) declaration.InternalDataPointer;
}
else
{
num2 = 0;
}
// num1 is an HRESULT
// 0x30 is the index of the Clone method in the mesh vtable
int num1 = **(((int*) this.m_lpUM))[0x30](this.m_lpUM, options, num2, devicePtr1, &meshPtr1);
if (devicePtr1 != null)
{
**(((int*) devicePtr1))[8](devicePtr1);
}

// Failure HRESULTs have the sign bit set to 1, so they are all negative
if (num1 < 0)
{
...
}

if (meshPtr1 != null)
{
// If cloning succeded, return a new mesh object with the cloned ID3DXMesh
return new Mesh(meshPtr1, device);
}
return null;
}

private static unsafe Mesh Clean(CleanType cleanType, Mesh mesh, IntPtr adjacency, IntPtr adjacencyOut, out string errorsAndWarnings)
{
ID3DXMesh* meshPtr1; // Input ID3DXMesh to be cleaned
ID3DXMesh* meshPtr2 = null; // Output ID3DXMesh
// ...

if (mesh != null)
{
meshPtr1 = mesh.m_lpUM;
}
else
{
meshPtr1 = null;
}

int num1 = D3DXCleanMesh((int) cleanType, meshPtr1, (uint modopt(IsLongModifier) modopt(IsConstModifier)*) adjacency.ToPointer(), &meshPtr2, (uint modopt(IsLongModifier)*) adjacencyOut.ToPointer(), bufferPtrPtr1);

if (bufferPtr1 != null)
{
...
}
if ((num1 < 0) && ((errorsAndWarnings == null) || (errorsAndWarnings == string.Empty)))
{
...
}

if (meshPtr2 != null)
{
// Return a new Mesh with the output pointer, meshPtr2
// If cleanup did any changes, meshPtr2 != meshPtr1, and thus a new Mesh is returned
// If cleanup didn't do any changes, meshPtr2 == meshPtr1, and thus the same mesh is returned
return new Mesh(meshPtr2, mesh.Device);
}
return null;
}



Try taking it step by step. First, simplify until you find out what's causing the crashes in the Form's constructor. When you get that out of the way, we can move into the next issue.

Also, if all fails, I'm willing to work with you on tracking down this issue through VNC if possible (i.e. you don't mind, the code isn't proprietary, etc).

Share this post


Link to post
Share on other sites
That's weird. The Clean code suddenly started working when I uncommented it out. Who knows...

The window exceptions stopped for a while, but they're back again. I have no idea what causes it. If I step through all of them I even end up in some random native .c file. I know it has something to do with Direct3D, because if I comment out my initialization for Direct3D then they don't get thrown. However, I get exceptions even before the first line pertaining to Direct3D. It doesn't actually crash the program (it just throws something up in the debug output) so I don't know if I should worry about it or not.

[edit] Ack. It also shows up with the SDK samples. It's probably no worries then.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!