0

I'm trying to get around XNA 3.1's automatic clearing of the depth buffer when switching render targets by copying the IDirect3DSurface9 from the depth buffer before the render targets are switched, then restore the depth buffer at a later point.

In the code, the getDepthBuffer method is a pointer to the IDirect3DDevice9 GetDepthStencilBuffer function. The pointer to that method seems to be correct, but when I try to get the IDirect3DSurface9 pointer it returns an exception (0x8876086C - D3DERR_INVALIDCALL). The surfacePtr pointer ends up pointing to 0x00000000.

Any idea on why it is not working? And any ideas on how to fix it?

Heres the code:

    public static unsafe Texture2D GetDepthStencilBuffer(GraphicsDevice g)
    {
        if (g.DepthStencilBuffer.Format != DepthFormat.Depth24Stencil8)
        {
            return null;
        }

        Texture2D t2d = new Texture2D(g, g.DepthStencilBuffer.Width, g.DepthStencilBuffer.Height, 1, TextureUsage.None, SurfaceFormat.Color);
        FieldInfo f = typeof(GraphicsDevice).GetField("pComPtr", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
        object o = f.GetValue(g);
        void* devicePtr = Pointer.Unbox(f.GetValue(g));
        void* getDepthPtr = AccessVTable(devicePtr, 160);
        void* surfacePtr;

        var getDepthBuffer = (GetDepthStencilBufferDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(getDepthPtr), typeof(GetDepthStencilBufferDelegate));
        var rv = getDepthBuffer(&surfacePtr);

        SetData(t2d, 0, surfacePtr, g.DepthStencilBuffer.Width, g.DepthStencilBuffer.Height, (uint)(g.DepthStencilBuffer.Width / 4), D3DFORMAT.D24S8);
        Marshal.Release(new IntPtr(devicePtr));
        Marshal.Release(new IntPtr(getDepthPtr));
        Marshal.Release(new IntPtr(surfacePtr));
        return t2d;
    }
  • Answer in this post http://stackoverflow.com/questions/2497641/slimdx-device-reset-crashes-with-a-d3derr-invalidcall-invalid-call-200553051 can be helpful – Petr Abdulin Dec 01 '11 at 05:02

1 Answers1

1

XNA3.1 will not clear your depth-stencil buffer upon changing render targets, it will however resolve it (so that it's unusable for depth tests) if you are not careful with your render target changes.

For example:

SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(null)
SetRenderTarget(someOtherRenderTarget)

Will cause the depth-stencil buffer to be resolved, but the following will not:

SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(someOtherRenderTarget)

I'm unsure why this happens with XNA3.1 (and earlier versions), but ever since figuring that out I've been able to keep the same depth-stencil buffer alive through many render target changes, even Clear operations as long as the clear specified ClearOptions.Target only.

Udo Held
  • 12,314
  • 11
  • 67
  • 93
default ex
  • 11
  • 1