D3DImage OutOfMemoryException when calling SetBackBuffer

I am using D3DImage to display images captured with Direct3D. Direct3D rendering should be done on its own thread, while the GUI thread takes the surface when it wants and puts it on the screen using D3DImage.

At first I tried to do it with a single D3D render target, however even with in-place locks I had a serious break, i.e. the render thread was rewriting the surface when WPF was copying it on its front buffer. Seems like WPF is very unpredictable when it copies data (i.e. not to D3DImage.Unlock () or even to the next D3DImage.Lock () as the documentation suggests).

So now what I do is that I have two render targets, and every time WPF renders a frame, it asks for the render thread to swap its targets. So I always render to target WPF that is not being used.

This means that on every graphical refresh of the window, I do something like

m_d3dImage.Lock();
m_d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, m_d3dRenderer.OutputSurface);
m_d3dImage.Unlock();
m_d3dRenderer.SwapSurfaces();

      

where OutputSurface is an IntPtr that points to a D3D render target that we are not currently processing, and SwapSurfaces simply swaps two surface pointers and calls IDirect3DDevice9 :: SetRenderTarget with the one we will use to display the next one.

EDIT: as requested, here is the SwapSurfaces () code:

var temp = m_renderingSurface;
m_renderingSurface = m_outputSurface;
m_outputSurface = temp;
m_d3dDevice.SetRenderTarget(0, m_renderingSurface);

      

Where m_renderingSurface

and m_outputSurface

are two render targets ( SharpDX.Direct3D9.Surface

), and m_d3dDevice

is an object DeviceEx

.

This works nicely, i.e. no breaks, however after a few seconds I get an OutOfMemoryException and Direct3D has the following debug output:

Direct3D9: (ERROR) :Invalid iBackBuffer parameter passed to GetBackBuffer
Direct3D9: (ERROR) :Error during initialization of texture. CreateTexture failed.
Direct3D9: (ERROR) :Failure trying to create a texture
Direct3D9: (ERROR) :Error during initialization of texture. CreateTexture failed.
Direct3D9: (ERROR) :Failure trying to create a texture
MIL FAILURE: Unexpected HRESULT 0x8876017c in caller: CInteropDeviceBitmap::Present D3D failure
Direct3D9: (WARN) :Alloc of size 1577660 FAILED!
Direct3D9: (ERROR) :Out of memory allocating memory for surfaces.
Direct3D9: (ERROR) :Failure trying to create offscreen plain surface

      

I found a related thread here where the suggested solution was to call D3DImage.SetBackBuffer () and pass IntPtr.Zero, however I added that just before the existing call and that didn't solve the problem. I also tried calling Lock () and Unlock () around SetBackBuffer (... IntPtr.Zero) and that also didn't solve the problem.

At this point I am wondering if there is a bug in the D3DImage or if I should take a different approach at all. Can I replace my 2 renderers with a D3D exchange chain instead, would allow me to stop constantly calling with SetBackBuffer with a different pointer? I am new to Direct3D.

EDIT: I went through the D3DImage.SetBackBuffer () code using .NET Reflector and creating an InteropBitmap every time. It doesn't do anything special for IntPtr.Zero. Since I am calling this many times per second, the resources may not have time to free up. At this point I am thinking of using two different D3DImages and alternating their visibility so as not to call them SetBackBuffer () all the time.

Thank.

+3


source to share


2 answers


It looks like D3DImage creates a new Direct3D texture every time you set the buffer pointer to something else. This eventually clears up, but setting 30 times a second like what I'm doing doesn't leave it enough time and is a big killer anyway. The approach I took was to create multiple D3DImages, each with its own surface, stack them on top of each other and toggle their Visibility property so that only one is shown. This seems to work pretty well and is not a memory leak.



0


source


I am using D3DImage to display images at fast frame rate and was facing this issue. I found out that D3DImage creates a new texture if you point the backbuffer pointer to another pointer. But if you only change the contents of the buffer pointer (and not the pointer address), it won't create a new texture.



0


source







All Articles