我使用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_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(... )中调用Lock()和Unlock()。IntPtr.Zero),但这也没有解决问题。
在这一点上,我想知道D3DImage中是否存在错误,或者我是否应该完全使用不同的方法。我可以用D3D交换链替换我的两个渲染目标吗?这样我就不用一直用不同的指针调用SetBackBuffer了吗?我是Direct3D的新手。
编辑:我使用.NET反射器查看了D3DImage.SetBackBuffer()的代码,它每次都会创建一个InteropBitmap。它不会为IntPtr.Zero做任何特别的事情。因为我每秒调用这个函数很多次,所以可能资源没有时间被释放。在这一点上,我正在考虑使用两种不同的D3DImages,并交替使用它们的可见性,以避免必须一直调用它们的SetBackBuffer()。
谢谢。
发布于 2013-02-01 09:54:17
每次您将其后台缓冲区指针设置为不同的值时,D3DImage似乎都会创建一个新的Direct3D纹理。这最终会被清理,但像我这样每秒设置30次并不会让它有足够的时间,而且无论如何都是一个很大的性能杀手。我采用的方法是创建几个D3DImages,每个都有自己的表面,将它们放在彼此的顶部,并切换它们的可见性属性,以便一次只显示一个。这似乎工作得很好,并且不会泄漏任何内存。
发布于 2013-10-15 04:19:53
我使用D3DImage以快速的帧频显示图像,也遇到了同样的问题。我发现,如果将后台缓冲区指针设置为不同的指针,D3DImage确实会创建一个新的纹理。但是,如果您只更改后台缓冲区指针的内容(而不是指针的地址),则不会创建新的纹理。
https://stackoverflow.com/questions/14612259
复制相似问题