我有一个非常接近完成的SharpDX项目。它使用Kinect进行交互。因此,我的项目将WPF用于Kinect区域和KinectUserViewer对象。到目前为止,SharpDX已经为一切工作做得很好,然而,当它到达使用direct3D的程序的某个部分时,它开始闪烁。这显然与D3Dimage(由MainWindow.xaml中的SharpDXElement使用)可能从根本上被打破并且不适合WPF中的有效D3D渲染这一事实相关联。 [1]。有没有办法保持我的WPF元素,而不是使用direct3D闪烁?
答案 0 :(得分:5)
闪烁可能表示GPU在D3DImage尝试将其复制到其前缓冲区之前未完成渲染帧。这很容易在WPF中发生,因为WPF没有使用呈现给交换链的标准机制来呈现帧。相反,大多数代码使用如下内容:
// rendering code
Device.Flush(); // or equivalent, depending on Direct3D version used
D3DImage.Lock();
D3DImage.AddDirtyRect(...);
D3DImage.Unlock();
至少是SharpDXElement.InvalidateRender
后面的模式 - 我没有看到该文件中的Device.Flush()
,但我怀疑它是在调用代码中。
问题是Device.Flush()
不同步。它适用于轻型GPU负载 - GPU在锁定/解锁代码完成之前完成 - 但是对于较重的负载,它通常没有完成渲染,导致至少某些帧的空白帧。这显示为闪烁。
开源的好处是你可以修改代码。要验证此问题并提供简单(如果是hackish)解决方案,请尝试给GPU多一点时间:
D3DImage.Lock();
Thread.Sleep(2); // 2ms
D3DImage.AddDirtyRect(...);
D3DImage.Unlock();
如果这减少或消除了您的闪烁,这是您的问题。至少对于Direct3D 10或11,更彻底的解决方案是use query events as described in this question。
使用Windows窗体的问题是最终导致WPF空域问题(WPF项目无法在子窗口上方绘制)。 Airspace issues can be fixed,但这项工作比编辑SharpDXElement要复杂得多。
答案 1 :(得分:2)
问题不在于锁定机制。通常使用Present
绘制来呈现图像。 Present
将等待所有绘图准备就绪。使用D3DImage,您没有使用Present()
方法。您可以锁定,添加DirtyRect并解锁D3DImage
,而不是呈现。
渲染完成异步,因此当您解锁时,绘制操作可能没有准备好。这会导致闪烁效应。有时您会看到一半画出的物品。一个糟糕的解决方案(我已经测试过)在解锁之前添加了一个小延迟。它有点帮助,但它不是一个简洁的解决方案。太可怕了!
<强>解决方案:强>
我继续其他的事情;我正在使用MSAA (抗锯齿)进行评估,我遇到的第一个问题是;无法在dx11 / dx9共享纹理上完成MSAA,因此我决定渲染到新纹理(dx11)并创建dx9共享纹理的副本。我把头撞在桌子上,因为现在它已经消除了反义词并且轻弹了!!
看起来thr复制动作等待所有绘图准备好(当然)现在它有助于完成绘图。
所以,创建一个纹理副本:
DXDevice11.Device.ImmediateContext.ResolveSubresource(
_dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat);
(_dx11BackpageTexture
是共享纹理,_dx11RenderTexture
是MSAA dx11纹理)将等待渲染准备就绪并创建副本。
这就是我摆脱闪烁的方式......
答案 2 :(得分:1)
我有同样的问题,DeviceCreationFlags.SingleThreaded
帮了我。