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

问题描述 投票:0回答:5

我有一个 SharpDX 项目即将完成。它使用 Kinect 进行交互。因此,我的项目对 Kinect 区域和 KinectUserViewer 对象都使用 WPF。到目前为止,SharpDX 在所有方面都表现良好,但是,当它到达大量使用 direct3D 的程序的某个部分时,它开始闪烁。这显然与以下事实有关:D3Dimage(由 MainWindow.xaml 中的 SharpDXElement 使用)可能“从根本上被破坏,不适合在 WPF 中进行高效的 D3D 渲染”[1]。有没有办法让我的 WPF 元素在 direct3D 中保持不闪烁?

c# wpf xaml sharpdx d3dimage
5个回答
5
投票

闪烁可能表明在 D3DImage 尝试将帧复制到其前端缓冲区之前 GPU 尚未完成帧渲染。这在 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 在锁定/解锁代码完成之前完成),但对于较重的负载,它通常尚未完成渲染,从而导致至少某些帧出现空白帧。这看起来像是闪烁。

开源的好处是你可以修改代码。要验证这个问题并提供一个简单(如果黑客)的解决方案,请尝试给 GPU 多一点时间:

D3DImage.Lock();
Thread.Sleep(2); // 2ms
D3DImage.AddDirtyRect(...);
D3DImage.Unlock();

如果这减少或消除了闪烁,那就是你的问题了。至少对于 Direct3D 10 或 11 而言,更彻底的解决方案是使用本问题中所述的查询事件

使用 Windows 窗体的问题是您最终会遇到 WPF 空域问题(WPF 项目缺乏在子窗口上方绘制的能力)。 空域问题可以修复,但工作比编辑 SharpDXElement 复杂得多。


2
投票

问题不在于锁定机制。通常您使用

Present
来绘制来呈现图像。
Present
将等待所有绘图准备就绪。对于 D3DImage,您没有使用
Present()
方法。您无需进行演示,而是锁定、添加 DirtyRect 并解锁
D3DImage

渲染是异步完成的,因此当您解锁时,绘制操作可能尚未准备好。这导致了闪烁效应。有时您会看到半画的项目。一个糟糕的解决方案(我已经测试过)是在解锁之前添加一个小的延迟。它有一点帮助,但这不是一个巧妙的解决方案。太可怕了!

解决方案:

我继续做别的事;我正在尝试 MSAA (抗锯齿),我面临的第一个问题是; MSAA 无法在 dx11/dx9 共享纹理上完成,因此我决定渲染到新纹理 (dx11) 并创建到 dx9 共享纹理的副本。我把头撞在桌子上,因为现在它已经抗锯齿并且没有闪烁了!!

看起来复制操作要等到所有绘图准备好(当然),现在它有助于完成绘图。

因此,创建纹理的副本:

DXDevice11.Device.ImmediateContext.ResolveSubresource(
    _dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat);

_dx11BackpageTexture
是共享纹理,
_dx11RenderTexture
是MSAA dx11纹理)
将等待渲染准备就绪并创建副本。

这就是我摆脱闪烁的方法......


1
投票

我也遇到了同样的问题,

DeviceCreationFlags.SingleThreaded
帮助了我。


0
投票

最后我解决了这个问题: https://learn.microsoft.com/zh-cn/windows/win32/api/d3d11/nn-d3d11-id3d11query

public void Render()
{
    ThrowIfDisposed();
    if (RenderTarget == null)
    {
        throw new InvalidOperationException("Resize has not been called.");
    }
    D3D10.Query query = new D3D10.Query(device, new D3D10.QueryDescription()
    {
        Flags = D3D10.QueryFlags.None,
        Type = D3D10.QueryType.Event
    });
    query.Begin();
    OnRender();//do your render
    device.Flush();//d3d10 device
    query.End();
    while (!query.IsDataAvailable)
    {
        System.Threading.Thread.Yield();
    }
    query.Dispose();
    OnUpdated();
}

0
投票
 WindowRenderTarget:
 this.DoubleBuffered = false;
 SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
© www.soinside.com 2019 - 2024. All rights reserved.