Need an alternative to SharpDXElement. WPF Flicker Workaround

I have a SharpDX project that is very close to completion. He uses Kinect for interaction. Because of this, my project uses WPF for both the Kinect area and the KinectUserViewer object. SharpDX did a great job for everything, however, when it gets into a certain part of a program that uses direct3D heavily, it starts to flicker. This, apparently, is due to the fact that D3Dimage (used by SharpDXElement in MainWindow.xaml) can be "fundamentally broken and unsuitable for efficient rendering of D3D in WPF" [1] . Is there a way to save my WPF elements and not flicker using direct3D?

+5
source share
3 answers

A flicker probably indicates that the GPU has not finished displaying the frame before D3DImage attempts to copy it to the front buffer. This can easily happen in WPF because WPF does not use the standard swap chaining engine to render the frame. Instead, most codes use something like the following:

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

This is at least a pattern followed by SharpDXElement.InvalidateRender - I don't see Device.Flush() in this file, but I suspect it is in the calling code.

The problem is that Device.Flush() not synchronous. It works great for light loads of the GPU - the GPU ends before the lock / unlock code is completed, but for heavier loads it often does not finish rendering, which leads to an empty frame, at least for some frames. It looks like a flicker.

The good thing about open source is that you can change the code. To test this problem and provide an easy (if hacky) solution, try giving the GPU a little more time:

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

If this 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 are getting problems with WPF airspace (lack of the ability for WPF elements to draw above the child window). Airspace issues can be fixed , but the job is a bit more complicated than editing SharpDXElement.

+5
source

The problem is not with the locking mechanism. Usually you use Present for drawing to represent the image. Present will wait until all the drawings are ready. With D3DImage you are not using the Present() method. Instead of presenting, you lock, add a DirtyRect, and unlock D3DImage .

Rendering is done asynchrone, so when you unlock, the drawing actions may not be ready. This causes a flicker effect. Sometimes you see elements half elongated. A bad solution (I tested) adds a little delay before unlocking. It helped a little, but it was not an easy solution. It was terrible!

Decision:

I continued something else; I experimented with MSAA (anti-aliasing), and the first problem I encountered; MSAA cannot be performed on the dx11 / dx9 general texture, so I decided to display a new texture (dx11) and create a copy for the general dx9 texture. I slammed my head on the table, because now it was smooth and unemotional!

It looks like the thr copy action is waiting until the whole drawing is ready (of course), now it will help complete the drawing.

So, create a copy of the texture:

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

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

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

+2
source

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

+1
source

Source: https://habr.com/ru/post/1210875/


All Articles