【问题标题】:D3DImage OutOfMemoryException when calling SetBackBuffer调用 SetBackBuffer 时出现 D3DImage OutOfMemoryException
【发布时间】:2013-01-30 19:39:04
【问题描述】:

我正在使用 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 个不同的 D3DImage 并交替它们的可见性以避免不得不一直调用它们的 SetBackBuffer()。

谢谢。

【问题讨论】:

  • 我对 DirectX 的经验很少,但我相信您尝试遵循的解决方案是正确的(因为据我所知,这与 DirectDraw 的固有工作方式相似)。也许您的 SwapSurfaces 方法有问题。您能否将其定义添加到问题中?
  • @TheodorosChatzigiannakis 好的,我添加了该方法的代码,并在问题末尾添加了一些精度。

标签: c# wpf directx direct3d


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-18
      • 2012-10-05
      • 2020-02-10
      • 1970-01-01
      • 1970-01-01
      • 2012-08-09
      • 1970-01-01
      相关资源
      最近更新 更多