调用SetBackBuffer时出现D3DImage OutOfMemoryException

时间:2013-01-30 19:39:05

标签: c# wpf directx direct3d

我正在使用D3DImage来显示使用Direct3D渲染的图像。 Direct3D渲染需要在自己的线程中进行,而GUI线程在需要时使用表面并使用D3DImage将其放在屏幕上。

起初我尝试使用单个D3D渲染目标来做到这一点,但是即使有锁定,我也有严重的撕裂,即渲染线程覆盖了表面,因为WPF正在它的前缓冲区上复制它。似乎WPF在复制数据时非常不可预测(即它不在D3DImage.Unlock()上,甚至在下一个D3DImage.Lock()上,正如文档所示。)

所以现在我正在做的是我有两个渲染目标,每次WPF显示一个帧时,它都会要求渲染线程交换其目标。所以我总是渲染到目标WPF没有使用。

这意味着在窗口的每个图形更新中,我都会执行类似

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

其中OutputSurface是一个IntPtr,它指向我们当前没有渲染的D3D渲染目标,SwapSurfaces只是交换两个曲面指针并调用IDirect3DDevice9 :: SetRenderTarget和我们下一步渲染的那个。

编辑:根据要求,这是SwapSurfaces()的代码:

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

其中m_renderingSurfacem_outputSurface是两个渲染目标(SharpDX.Direct3D9.Surface),而m_d3dDeviceDeviceEx对象。

这很好用,即没有撕裂,但几秒后我得到一个OutOfMemoryException,而Direct3D有以下调试输出:

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

我在这里找到了一个相关的主题,其中建议的解决方案是调用D3DImage.SetBackBuffer()并传递IntPtr.Zero,但是我在现有调用之前添加了它,但它没有解决问题。我也尝试在SetBackBuffer(... IntPtr.Zero)周围调用Lock()和Unlock(),但这也没有解决问题。

此时我想知道D3DImage中是否存在错误,或者我是否应该使用不同的方法。我是否可以用D3D交换链替换我的2个渲染目标,这是否允许我不再一直使用不同的指针调用SetBackBuffer?我是Direct3D的新手。

编辑:我使用.NET Reflector查看了D3DImage.SetBackBuffer()的代码,并且每次创建一个InteropBitmap。它对IntPtr.Zero没有任何特别的作用。由于我每秒呼叫这么多次,也许资源没有时间被释放。在这一点上,我正在考虑使用2个不同的D3DImages并交替使用它们的可见性,以避免不断调用它们的SetBackBuffer()。

感谢。

2 个答案:

答案 0 :(得分:0)

看起来D3DImage每次将其后备缓冲区指针设置为不同的东西时都会创建一个新的Direct3D纹理。这最终被清理了,但是像我一样每秒设置30次并没有留下足够的时间,而且无论如何都是一个重要的性能杀手。我采用的方法是创建几个D3DImages,每个都有自己的表面,将它们全部放在一起并切换它们的Visibility属性,这样一次只显示一个。这看起来效果很好,并且不泄漏任何记忆。

答案 1 :(得分:0)

我使用D3DImage以快​​速帧速率显示图像并遇到同样的问题。我发现如果将后备缓冲区指针设置为不同的指针,D3DImage会创建一个新的纹理。但是如果你只更改后备缓冲区指针的内容(而不是指针的地址),它将不会创建新的纹理。