c# - 调用 SetBackBuffer 时出现 D3DImage OutOfMemoryException

标签 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 是一个指向我们当前未渲染到的 D3D 渲染目标的 IntPtr,而 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()。

谢谢。

最佳答案

每次您将其后台缓冲区指针设置为不同的内容时,D3DImage 似乎都会创建一个新的 Direct3D 纹理。这最终被清理了,但是像我所做的那样将它设置为每秒 30 次并没有留下足够的时间,而且无论如何都是一个很大的性能 killer 。我采用的方法是创建多个 D3DImage,每个都有自己的表面,将它们全部放在彼此之上并切换它们的 Visibility 属性,以便一次只显示一个。这似乎工作得很好并且不会泄漏任何内存。

关于c# - 调用 SetBackBuffer 时出现 D3DImage OutOfMemoryException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14612259/

相关文章:

c# - LINQ to Entities 无法识别该方法(在相关实体上)

WPF - 从 ItemsControl 的 ItemTemplate 中绑定(bind)到项目索引?

wpf - Windows 10 中的正宗 Windows 7 主题?

c# - 使用字体时 WPF TextBlock 内存泄漏

directx - 可以用 XNA 和 C# 制作真正的游戏吗?

opengl - 着色器 - 镜面闪光 - 闪闪发光的效果

c# - 如何正确获取android.net.Uri 的文件大小?

c# - 按元素划分子列表中的列表

c# - PredicateBuilder 可重用 DateTime 谓词 setter

c# - 快速多窗口渲染