wpfmultithreadingflickersharpdxd3dimage

D3DImage and SharpDX flickering on slow hardware


I am using the SharpDX.WPF project for the WPF abilities, it seems like an easy to understand low-overhead library, compared to the Toolkit that comes with SharpDX (which has the same issue!)

First: I fixed the SharpDX.WPF project for the latest SharpDX using the following: https://stackoverflow.com/a/19791534/442833

Then I made the following hacky adjustment to DXElement.cs, a solution that was also done here:

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();
    }

Then I render 8000 cubes in a cube pattern...

Yielding...

gets printed to the console quite often, but the flickering is still there. I am assuming that WPF is nice enough to show the image using a different thread before the rendering is done, not sure though... This same issue also happens when I use the Toolkit variant of WPF support with SharpDX.

Images to demonstate the issue:

Note: It randomly switches between these old images, randomly. I am also using really old hardware which makes the flickering much more appearant (GeForce Quadro FX 1700)

A made a repo which contains the exact same source-code as I am using to get this issue: https://github.com/ManIkWeet/FlickeringIssue/


Solution

  • I think you are not locking properly. As far as I understand the MSDN documentation you are supposed to lock during the entire rendering not just at the end of it:

    While the D3DImage is locked, your application can also render to the Direct3D surface assigned to the back buffer.

    The information you find on the net about D3DImage/SharpDX is somewhat confusing because the SharpDX guys don't really like the way D3DImage is implemented (can't blame them), so there are statements about this being a "bug" on Microsofts side when its actually just improper usage of the API.

    Yes, locking during rendering has performance issues, but it is probably not possible to fix them without porting WPF to DirectX11 and implementing something like a SwapChainPanel which is available in UWP apps. (WPF itself still runs on DirectX9)

    If the locking is a performance issue for you, one idea I had (but never tested) is that you could render to an offscreen surface and reduce the lock duration to copying that surface over to the D3DImage. No idea if that would help performance wise but its something to try.