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?
-
Can you please show some related code? It would help tremendously to see where you are when answering a question like this. – rfornal Jan 12 '15 at 01:27
-
It has over 15000 lines of code. It is hard to find relevant code. It uses the toolkit.game class for the draw and update loop. I use primarily spritebatch but parts of it use both xna and direct3D, including the part in question. Is there a part in particular you think would help? – Asor Jan 12 '15 at 02:11
-
Say, I took a look at your link and when I looked at the context of your quote, they also mentioned a limited workaround using a Windows Form. If I understood the workaround, that would essentially host a Windows Form in the D3DImage replacement area - and I think *only* that area would not be able to use XAML elements. Would that work for you? Or am I missing something about the nature of the workaround? – J Trana Jan 12 '15 at 05:20
-
As I interpreted it, this made it so I couldn't have the KinectUserViewer display on top of the sharpDX content. I may be wrong. – Asor Jan 12 '15 at 06:50
-
Yes, I played around with a sample and I found that WPF objects can not be placed on top of the form. The KinectUserViewer is a small-ish window on the top and center of the screen. It has the time and weather to the left and right of it via sharpDX. I guess if there is a way I can show the userview in sharpDX I could use that fix, but I'm not sure how to go about that. – Asor Jan 12 '15 at 19:53
-
You can host WPF inside the WinForm, which would make your structure like this: WPF hosts Winform hosts WPF, ugly but probably works. – ManIkWeet Jan 23 '15 at 09:33
4 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.

- 1
- 1

- 2,126
- 14
- 23
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....

- 21,446
- 3
- 42
- 57
-
BRILLIANT. Going to try this. Been plagued by DX11/DX9 flickering for years and have tried so many different hacks/workarounds ... – Dr. Andrew Burnett-Thompson Jan 01 '17 at 11:25
Finally I solve this problem: 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();
}