Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need SharpDXElement alternative. Workaround to sharpDX WPF flickering

I have a SharpDX project that is very near completion. It uses a Kinect for interaction. Because of this my project uses WPF both for the Kinect region and the KinectUserViewer object. SharpDX has worked great for everything so far, however, when it gets to a certain part of the program that uses direct3D heavily, it begins to flicker. This is apparently connected to the fact that D3Dimage (utilized by the SharpDXElement in MainWindow.xaml) may be "fundamentally broken and unsuitable for efficient D3D rendering in WPF" [1]. Is there a way to keep my WPF elements and not get flickering with direct3D?

like image 903
Asor Avatar asked Jan 12 '15 01:01

Asor


3 Answers

Flickering likely indicates that the GPU is not finished rendering the frame before you D3DImage tries to copy it to its front buffer. This can easily happen in WPF because WPF doesn't use the standard mechanism of presenting to a swap chain to render a frame. Instead, most code uses something like the following:

// rendering code
Device.Flush(); // or equivalent, depending on Direct3D version used
D3DImage.Lock();
D3DImage.AddDirtyRect(...);
D3DImage.Unlock();

That's at least the pattern followed by SharpDXElement.InvalidateRender - I don't see the Device.Flush() in that file but I suspect that it is in the calling code.

The problem is that Device.Flush() is not synchronous. It works fine for light GPU loads - the GPU finishes before the Lock/Unlock code has finished - but for heavier loads it often hasn't finished rendering, resulting in a blank frame at least for some frames. This appears as flicker.

The nice thing about open source is that you can modify the code. To verify this problem and provide an easy (if hackish) solution, try giving the GPU a bit more time:

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

If that reduces or eliminates your flicker, this is your problem. A more thorough solution, at least for Direct3D 10 or 11, is to use query events as described in this question.

The problem with using Windows Forms is that you end up with WPF airspace issues (the lack of ability for WPF items to draw above the child window). Airspace issues can be fixed, but the work is quite a bit more complex than editing the SharpDXElement.

like image 70
NextInLine Avatar answered Nov 20 '22 19:11

NextInLine


The problem is not the Locking mechanism. Normally you use Present to draw to present the image. Present will wait until all drawing is ready. With D3DImage you are not using the Present() method. Instead of Presenting, you lock, adding a DirtyRect and unlock the D3DImage.

The rendering is done asynchrone so when you are unlocking, the draw actions might not be ready. This is causing the flicker effect. Sometimes you see items half drawn. A poor solution (i've tested with) is adding a small delay before unlocking. It helped a little, but it wasn't a neat solution. It was terrible!

Solution:

I continued with something else; I was expirimenting with MSAA (antialiasing) and the first problem I faced was; MSAA cannot be done on the dx11/dx9 shared texture, so i decided to render to a new texture (dx11) and create a copy to the dx9 shared texture. I slammed my head on the table, because now it was anti-aliased AND flicking-free!!

Looks like thr copy action waits until all drawing is ready (of course) now it helps completing the drawing.

So, creating a copy of the texture:

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

(_dx11BackpageTexture is the shared texture and _dx11RenderTexture is the MSAA dx11 texture) will wait until the rendering is ready and will create a copy.

This is how I got rid of the flickering....

like image 2
Jeroen van Langen Avatar answered Nov 20 '22 18:11

Jeroen van Langen


I had the same problem, DeviceCreationFlags.SingleThreaded helped me.

like image 1
Mariusz K Avatar answered Nov 20 '22 17:11

Mariusz K