需要SharpDXElement替代品。解决方法sharpDX WPF闪烁

时间:2015-01-12 01:16:09

标签: c# wpf xaml sharpdx d3dimage

我有一个非常接近完成的SharpDX项目。它使用Kinect进行交互。因此,我的项目将WPF用于Kinect区域和KinectUserViewer对象。到目前为止,SharpDX已经为一切工作做得很好,然而,当它到达使用direct3D的程序的某个部分时,它开始闪烁。这显然与D3Dimage(由MainWindow.xaml中的SharpDXElement使用)可能从根本上被打破并且不适合WPF中的有效D3D渲染这一事实相关联。 [1]。有没有办法保持我的WPF元素,而不是使用direct3D闪烁?

3 个答案:

答案 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帮了我。