A potential bug in the XNA Framework ?

On two separate occasions my XNA application has crashed because of an AccessViolationException thrown from Microsoft.Xna.Framework.dll!Microsoft.Xna.Framework.Graphics.Texture2D.GetSurfaceLeve(int level = 0). The exception is being thrown when I try to change the render target. Both times the error has been thrown it was after about 5 minutes of running the application without any problems (and on the same line). The second time I kept moving the mouse around and was using the computer to make sure it wasn't an issue being caused by my screen saver. I am not making any native calls into anything except QueryPerformanceTimer() and QueryPerformanceFrequency() which are being imported in a separate class using PInvoke.

Render Targets:
m_positionMap - r32g32b32a32f
m_normalMap - r32g32b32a32f
m_colorMap - r32g32b32a32f
m_depthMap - r32f

System Specs:
HP/Compaq nx9600
ATI Radeon x600 mobility 128mb with the latest Omega drivers
3.2ghz intel pentium 4
1.5gb ddr2 RAM
Windows XP pro SP2

I have a screen shot of my screen at the time of the exception: Screen Shot
I replicated the bug a third time. Same thing after ~5 mins: Screen Shot



Answer this question

A potential bug in the XNA Framework ?

  • IamHuM

    Sorry for taking so long to reply.

    Leaf - the using() keyword is exactly what I am doing. Also the original back buffer is being restored before the using() block falls out of scope.

    protected override void Draw()
    {
    //other stuff...

    // TODO: Add your drawing code here
    using(Surface backBuffer = graphics.GraphicsDevice.GetBackBuffer(0, 0))
    {

    Ralf - thanks for your input however I am not so sure the problem has to do with the device being reset. I currently am not handling device resets and when they occur (either forced or because of my screen saver) I get a DeviceLostException thrown from graphics.GraphicsDevice.Present(). Unfortunately I have not been able to try your suggestion and check the IsDisposed property because I have been unable to replicate the bug today (with 0 code changes). Secondly when the exception was thrown it was during m_normalMap being set to render target 1 - after render target 0 had been set to m_positionMap. Surely if m_normalMap was disposed due to a loss of the device or some such thing then m_positionMap would've had the same problem Also I had made sure to keep the window active the entire duration specifically to make sure it wasn't a problem being caused by a lost device. I am a bit stumped at the moment and unless I can get it to start replicating the bug again I am out of ideas. Maybe it had something to do with one of the applications I had running in the background Thanks for the suggestions and performance tips.


  • Andy Goodwin

    Ralf,

    yes of course that would be better, thanks for the hint.

    I also was surprised by the problem, since as you have mentioned Xna is internally managing all managed references to DirectX resources. I think I may have mentioned the problem in another thread but basically it can be seen with that snippet I posted above. If the Dispose is not done and a reset happens then Xna will fail to fire the DeviceReset event, but will fire the DeviceResetting event. I should probably put a bug in but had originally assumed it was my own fault.

    Cheers,
    Leaf.


  • MCP_SS

    How do I *cause* a device reset to occur with XNA I want to make sure that I'm writing my code such that if one occurs, my VertexBuffers and IndexBuffers are reloaded properly. In Managed DirectX 1.1, one would occur as soon as you resize the window but this doesn't seem to be the case with XNA. I've tried resizing, minimizing, maximizing, nothing seems to cause the reset to occur.

  • Cyber Sinh

    If I hook the DeviceReset and DeviceResetting events, then I can see them being fired when I minimise and then restore; both events get fired on restore. I see the same when I change the window size. I tested using this very simple Game class:

    partial class Game1 : Microsoft.Xna.Framework.Game
    {
    public Game1()
    {
    InitializeComponent();
    }

    protected override void OnStarting()
    {
    graphics.DeviceReset += new EventHandler(graphics_DeviceReset);
    graphics.DeviceResetting += new EventHandler(graphics_DeviceResetting);
    base.OnStarting();
    }

    void graphics_DeviceResetting(object sender, EventArgs e)
    {
    System.Diagnostics.Trace.WriteLine("Device Resetting");
    }

    void graphics_DeviceReset(object sender, EventArgs e)
    {
    System.Diagnostics.Trace.WriteLine("Device Reset");
    }

    protected override void Update()
    {
    float elapsed = (float)ElapsedTime.TotalSeconds;

    UpdateComponents();
    }

    protected override void Draw()
    {
    if (!graphics.EnsureDevice())
    return;

    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    graphics.GraphicsDevice.BeginScene();

    DrawComponents();

    graphics.GraphicsDevice.EndScene();
    graphics.GraphicsDevice.Present();
    }
    }

    Cheers,
    Leaf.


  • Binary

    You should try to use the Direct3D debug runtime and a debug monitor. Maybe this could tell you what going wrong,



  • PLeopard

    The most aggressive test you can do is to lock the system (Windows Key + L) and then go back again. Depending on the system you use you will see different screens after you locked the system.

    If your app still renders everything right you should not fear other resets.

    If you want to debug your reset methods you can simply call Reset on the device.



  • Fluxtah

    Just guessing but I saw something vaguely similar. Since you're setting render targets, are you saving and restoring the backbuffer render target And if so are you releasing it afterwards

    Something like this:

    using (Surface oldRT = device.GetRenderTarget(0))
    {
    device.SetRenderTarget(0, newRT);

    // draw to texture

    device.SetRenderTarget(0, oldRT);

    // draw to back buffer

    }

    I had to do something like that to ensure that device resets worked, which is a different situation from yourself but they might be related.

    Cheers,
    Leaf.


  • kameneye

    Leaf. wrote:
    If I hook the DeviceReset and DeviceResetting events, then I can see them being fired when I minimise and then restore; both events get fired on restore. I see the same when I change the window size. I tested using this very simple Game class:

    This is strange, maybe someone can explain what's going on: I was hooking up my DeviceReset event handler in my Game component's constructor rather than OnStarting(). Hooking it up in this way, I could minimize/maximize the window just fine without DeviceReset being called and my VertexBuffers obviously still had data because it was still rendering properly. When I would switch users like Ralf suggested, it would call my DeviceReset and properly reset(I put a breakpoint on the function call to be sure). If I put them in OnStarting() they are always called on minimized and maximize like Leaf's example. What are the ramifications of this I'd really like some more documentation on where the proper places to do these things are.

  • becklighter

    Device reset is a good point here.

    Keith, could you please try to open the quick watch for the texture that caused the exception and look for the “IsDisposed” property In the case it is true you have lost the texture. This is a hint that your device-reset methods are not correct.

    Leaf, I am surprised that you need to do this. Anyway if you are willing to take a performance hint from an old DirectX programmer you should handle this a little bit different.

    - Add a Surface field (backbuffer) to your class and store the back buffer there (GetBackBuffer)

    - Instead of using GetRenderTarget every time you can then set the backbuffer direct.

    - During DeviceReseting you should Dispose the Backbuffer

    - DeviceReset should be used to get it again.

    The reason for this is that you should reduce the number of calls to Get* methods inside your render methods to the absolute limit.



  • A potential bug in the XNA Framework ?