【发布时间】: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_renderingSurface 和m_outputSurface 是两个渲染目标(SharpDX.Direct3D9.Surface),m_d3dDevice 是DeviceEx 对象。
这很好用,即没有撕裂,但是几秒钟后我得到一个 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 好的,我添加了该方法的代码,并在问题末尾添加了一些精度。