首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >D3DImage和SharpDX在慢速硬件上的闪烁

D3DImage和SharpDX在慢速硬件上的闪烁
EN

Stack Overflow用户
提问于 2014-12-08 12:33:23
回答 3查看 2.8K关注 0票数 4

我将SharpDX.WPF项目用于WPF功能,与SharpDX附带的工具包相比,它似乎是一个易于理解的低开销库(它有相同的问题!)

首先:我使用以下方法修复了最新SharpDX.WPF的SharpDX项目:https://stackoverflow.com/a/19791534/442833

然后,我对DXElement.cs进行了如下的恶意调整,这是一个也是这里的解决方案。

代码语言:javascript
复制
private Query queryForCompletion;
    public void Render()
    {
        if (Renderer == null || IsInDesignMode)
            return;

        var test = Renderer as D3D11;
        if (queryForCompletion == null)
        {

            queryForCompletion = new Query(test.Device,
                new QueryDescription {Type = QueryType.Event, Flags = QueryFlags.None});
        }

        Renderer.Render(GetDrawEventArgs());

        Surface.Lock();
        test.Device.ImmediateContext.End(queryForCompletion);
        // wait until drawing completes
        Bool completed;
        var counter = 0;
        while (!(test.Device.ImmediateContext.GetData(queryForCompletion, out completed)
                 && completed))
        {
            Console.WriteLine("Yielding..." + ++counter);
            Thread.Yield();
        }
        //Surface.Invalidate();
        Surface.AddDirtyRect(new Int32Rect(0, 0, Surface.PixelWidth, Surface.PixelHeight));
        Surface.Unlock();
    }

然后我用立方体模式渲染了8000个立方体.

屈服..。

经常被打印到控制台,但是闪烁仍然存在。我假设WPF足够好,可以在呈现之前使用不同的线程显示图像,但不确定.当我在SharpDX中使用WPF支持的Toolkit变体时,也会出现同样的问题。

妖魔化问题的图像:

  • 坏的
  • 更好
  • 差不多了
  • 意欲

注意:它随机地在这些旧图像之间切换,随机。我还使用了非常老的硬件,这使得闪烁的外观更加美观(GeForce Quadro FX 1700)

A制作了一个回购程序,其中包含与我用于获取此问题的完全相同的源代码:https://github.com/ManIkWeet/FlickeringIssue/

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-09-18 09:34:53

我觉得你锁得不好。就我所理解的MSDN文档而言,您应该在整个呈现过程中锁定它,而不仅仅是在它的末尾:

当D3DImage被锁定时,应用程序还可以将其呈现到分配给back缓冲区的Direct3D表面。

您在网络上找到的关于D3DImage/SharpDX的信息有点令人困惑,因为SharpDX人员并不真正喜欢D3DImage的实现方式(不能怪他们),所以在微软方面,当它实际上不正确地使用API时,有人说它是一个"bug“。

是的,呈现期间的锁定存在性能问题,但如果不将WPF移植到DirectX11并实现类似于UWP应用程序中的SwapChainPanel,则很可能无法修复它们。(WPF本身仍然运行在DirectX9上)

如果锁定对您来说是一个性能问题,我有一个想法(但从未测试过)是,您可以将锁呈现到屏幕外表面,并将锁定时间缩短到将该表面复制到D3DImage。不知道这是否有助于性能的明智,但这是值得一试的。

票数 1
EN

Stack Overflow用户

发布于 2016-09-19 20:39:53

D3DImage锁定有关,请注意,D3DImage.TryLock API具有相当非常规的语义,而大多数开发人员并不期望这样做:

,小心! 即使在https://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.unlock(v=vs.110).aspx表示失败(即返回false)的情况下,也必须调用https://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.trylock(v=vs.110).aspx

虽然可能更多的是令人震惊的设计选择而不是bug本身,但误解此行为会导致D3DImage死锁和挂起,因此可能是人们试图使D3DImage正常工作而遭受的挫折的主要原因。

下面的代码是一个正确的WPF D3D呈现,在我的应用程序中没有闪烁:

代码语言:javascript
复制
void WPF_D3D_render(IntPtr pSurface)
{
    if (TryLock(new Duration(default(TimeSpan))))
    {
        SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
        AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight));
    }
    Unlock();    //  <--- !
}

是的,这个不直观的代码实际上是正确的;D3DImage.TryLock(0) 每次返回失败时都会泄漏一个内部D3D缓冲区锁。您不必相信我的话,以下是来自PresentationCore.dll v4.0.30319的CLR代码:

代码语言:javascript
复制
private bool LockImpl(Duration timeout)
{
    bool flag = false;

    if (_lockCount == uint.MaxValue)
        throw new InvalidOperationException();

    if (_lockCount == 0)
    {
        if (timeout == Duration.Forever)
            flag = _canWriteEvent.WaitOne();
        else
            flag = _canWriteEvent.WaitOne(timeout.TimeSpan, false);

        UnsubscribeFromCommittingBatch();
    }
    _lockCount++;
    return flag;
}

注意,无论函数返回成功还是失败,内部_lockCount字段都是递增的。如果要避免某些死锁,必须自己调用Unlock(),如上面的第一个代码示例所示。如果不这样做,那么调试也是很麻烦的,因为组件在下一个呈现传递之前不会(可能)死锁,而此时相关的证据早就消失了。

MSDN似乎没有提到异常行为,但公平地说,如果调用成功,文档也不会指出您必须调用Unlock()

票数 5
EN

Stack Overflow用户

发布于 2016-11-11 14:12:44

问题不在于锁定机制。通常,您使用Present绘制图像。Present将等待直到所有绘图准备就绪。对于D3DImage,您没有使用Present()方法。而不是呈现,而是锁定、添加DirtyRect和解锁D3DImage

呈现是异步的,所以当您解锁时,绘制操作可能还没有准备好。这导致了闪烁效应。有时你会看到一半画出来的东西。一个糟糕的解决方案(我已经测试过)是在解锁之前添加一个小延迟。这有点帮助,但不是一个好的解决办法。太糟糕了!

解决方案:

我继续做其他的事情;我正在用MSAA (抗别名)进行补偿,我面临的第一个问题是: MSAA不能在dx9 11/dx9 9共享纹理上完成,所以我决定呈现到一个新的纹理(dx11),并创建一个dx9共享纹理的副本。我把头撞在桌子上,因为现在它是反别名的,而且是自由的!!在添加脏rect之前,不要忘记调用Flush()

因此,创建纹理的副本:DXDevice11.Device.ImmediateContext.ResolveSubresource(_dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat); (___dx11BackpageTexture是共享纹理)将等待呈现就绪,并创建副本。

,这就是我如何摆脱闪烁的.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27358128

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档