3

我正在使用 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()。

谢谢。

4

2 回答 2

0

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

于 2013-02-01T01:54:17.183 回答
0

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

于 2013-10-14T20:19:52.963 回答