I have a control that uses D3DImage to host a SharpDX DirectX9 surface and allows use to pan, zoom, and interact with world objects and the result is really awesome. Performance is actually an amazing consistent 60fps EXCEPT when the window is minimized and brought back up or the user locks and then unlocks the screen. When the window regains focus the fps drop to about 25-30fps. I can "fix" the issue by unloading and loading the control back into its container and then BOOM, 60fps.
I call the main render function using a DispatcherTimer set at 10ms. Before, I was using the CompositionTarget.Rendering event but performance wasn't as good as using the DispatcherTimer. I fairly certain that I'm handling lost resources correctly. Any ideas about these missing frames per second?
EDIT: I am having this same exact problem. Unfortunately, doing an automatic device reset doesn't fix the issue but if I have a button that executes the same reset method then my fps goes back to normal.
Locking / Unlocking the screen causes a device lost. But you probably know that.
Anyway I use D3DImage in WPF as well. My performance problems ended when I called
D3DImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero)
on each device lost. I used to have responsiveness issues after a device lost until I realized WPF was still holding a reference to a texture. Of course you should later re-set the backbuffer when you have an updated texture.
Although it is unclear what exactly is going wrong behind the scenes, it is clear that D3DImage keeps a refcount to your texture, which can prohibit a successful recovery in the case of a device lost. In my case, we simply had no updates.
Sorry for the anectodal answer... But until a real D3DImage expert enters the room, it's better than nothing.
P.S. I am using SlimDX but I don't think it matters... For all that I know SharpDX is a fork of SlimDX.
There's an overload to SetBackBuffer that takes an additional Boolean flag:
D3DImage.SetBackBuffer(D3DResourceType, IntPtr, Boolean)
When you call the SetBackBuffer(D3DResourceType, IntPtr) overload, or call the SetBackBuffer(D3DResourceType, IntPtr, Boolean) overload with the enableSoftwareFallback parameter set to false, the [WPF] rendering system releases its reference to the back buffer when the front buffer becomes unavailable and nothing is displayed.
I'm no expert either, but I would guess that this is what's happening; Because you didn't set that flag to 'true', WPF is calling Release() on what happens to be the last COM ref count for your D3D surface as soon as it exits the lock. This would seem to require that you be maintaining an additional ref count of your own.
For one thing, I've noticed that, even after getting your "used" surface "back" from a WPF lock/unlock round-trip, you need to still not release it until your next surface takes its place (i.e. in a successful call to d3dimg.SetBackBuffer). Otherwise, you'll get flickering when the WPF window is dragged around the screen. Given that that's the only reliable method I've discovered for detecting when WPF is truly done with your buffer, it does seem pointless for WPF to be concerned with AddRef'ing or Release'ing it.
What's generally confusing with D3DImage is that the IDirect3DDevice9 that's running WPF is not really associated with the IDirect3DDevice9 that generated the surface you're putting forth as a back buffer... for WPF. The whole Lock/Unlock business is presumably for WPF's benefit, and has nothing to do with your own (possibly lockable?) IDirect3DSurface9 rendertarget's survival.
Beware!If using D3DImage.TryLock, beware of its, um... shall we say, unconventional semantics: You must call Unlock even in the case where TryLock returns false. For more information, see https://stackoverflow.com/a/39581727/147511.
Related
I readed some articles about RenderLoop inside C# using SharpDX but all has the same problem.
Using this loops it's fine for rendering at V-Sync rate except when some events happens.
For example dragging the window or right clicking mouse over window bar(opening menu) will stop the Loop. There is a way to avoid this? I want(even not refreshing the control) a stable 60 FPS loop.
I am rendering on a Control(Panel) and i need this.
The OP has surely resolved this issue by now, but since there are no answers after 3 months, here is mine:
Don't use SharpDx VSync when running in a window -- it's not meant for that, and will certainly cause contention & deadlocks. VSync is only helpful when you own the entire screen.
Just present your swapChain and let the window manager show it when it can, and you'll get the highest frame rate you can feed.
This same thing bit me a while back, and although I didn't find the answer anywhere in the documentation, it's obvious when you think about it: it would be impossible for windows to manage the desktop if each window tried to coordinate with VSync independently.
bool vSync = false; // vSync should not be used in windowed modes -- may cause UI deadlocks when resizing form windows
swapChain.Present(vSync ? 1 : 0, PresentFlags.None, new PresentParameters()); // requires v11.1
Hello: I am trying to create an app which will display a moving sphere. App will vary speed and direction. I've tried Adobe Flash but cannot get it smooth. Smoothness is essential in this case. So I am trying C#.
Initially, I can see that this can be implemented by:
1) Creating a PictureBox of a sphere, and using a Timer, change its coordinates. or
2) Using the this.paint function to draw a filled circle, and somehow, with a timer, erasing and redrawing it.
Can someone recommend the best path to take? I'll have a main menu where the user will chose speed/direction/how many etc... and then simply show the "game window" with the moving spheres. Any guidance would be much appreciated.
This is to be displayed on a PC only.
Thanks
-Ed
I just answered a similar question here.
NOTE: Depending on your needs, it is possible to achieve smooth animations under winforms (under certain conditions) though you are responsible for everything. wpf provides an animation framework but wpf is perhaps a milestone harder.
It probably does not matter should you pursue winforms first or WPF. You arguably could learn the basics under winforms then move over to wpf. wpf may require you to learn quite a bit before you can do anything.
Summary
Essentially what this does is to create an offscreen bitmap that we will draw into first. It is the same size as the UserControl. The control's OnPaint calls DrawOffscreen passing in the Graphics that is attached to the offscreen bitmap. Here we loop around just rendering the tiles/sky that are visible and ignoring others so as to improve performance.
Once it's all done we zap the entire offscreen bitmap to the display in one operation. This serves to eliminate:
Flicker
Tearing effects (typically associated with lateral movement)
There is a Timer that is scheduled to update the positions of all the tiles based on the time since the last update. This allows for a more realistic movement and avoids speed-ups and slow-downs under load. Tiles are moved in the OnUpdate method.
If you note in the code for Timer1OnTick I call Invalidate(Bounds); after animating everything. This does not cause an immediate paint rather Windows will queue a paint operation to be done at a later time. Consecutive pending operations will be fused into one. This means that we can be animating positions more frequently than painting during heavy load. Animation mechanic is independent of paint. That's a good thing, you don't want to be waiting for paints to occur. xna does a similar thing
Please refer to my full SO answer complete with sample code
Here are a few hints to get you going:
First you will need to come to a decision about which platform to target: WPF or Winforms.
Then you should know what to move across what; a nice Bitmap or just a circle across an empty background or a Bitmap or a Form with controls on it.
In Winforms both your approaches will work, esp. if you set a circular region see here for an example of that. (The part in the fun comment!)
And yes, a Timer is the way to animate the sphere. Btw, a Panel or even a Label can display an Bitmap just as well as a PictureBox.
For smooth movements make sure to set the Form.Doublebuffered=true, if you move across a Form. If you move across any other control (except a PictureBox or a Label) you will need to subclass it to get access to the DoubleBuffered property!
It is often also a good idea to keep the Location of a moving item in a variable as a PointF and use floats for its speed because this way you can fine grain the speed and Location changes and also the Timer Intervals!
There are quite some topics available about GDI drawing and flickering issues, but I haven´t been able to find any regarding drawing in an other process.
The issue
Basically I´m trying to draw to a Hwnd using Graphics.FromHwnd. This works perfectly, but there is a lot of flickering involved. The application I´m trying to draw on is a game (not made by me) and has quite a high refresh rate, unlike forms.
Attempts
I´ve tried doing the drawing both using a GDI.Rectangle function that used the HDC to draw and using Graphics.DrawRectangle to draw to the Hwnd. I don't notice a difference in performance but 'Graphics' seems a bit easier in use since it doesn't need gdi32.dll to draw shapes, unlike GDI.
I've also tried doublebuffering but yet again I do not notice any difference.
To me it seems that the doublebuffering is not working because of the fact that I'm trying to draw in such a high refresh rate window.
Question
Is it possible to get the window's refresh rate and use that for a timer to update the graphic?
is it possible to make graphics 'stick' until updated so they don't automatically disappear?
If anyone knows how to do this, or knows other solutions to get rid of the flickering I would appreciate the help!
Thanks in advance.
After doing some research I've come to the conclusion that using a transparent window will suit my case best. Here's how I came to that conclusion:
I've used an application to read window events to check if there was any continuous event stream that could be the window invalidation, but there wasn't.
I did find out a way that should make it possible to actually read when the game invalidates the window, but it's kind of a hack: It's possible to replace the game's d3d9.dll file with your own, calling all the original functions, but catching the events. I don't have any details on how or even if it works since having to distribute a dll to end-users is not an option for me, not to mention that this is in fact hacking.
I have a bot that plays a flash game automatically. I have loaded the flash object through an extended WebView a friend coded for me and I use native imports to send click messages to the handle. Everything works good for about 30 minutes. After that the bot, GUI and whole mechanism starts getting slower and slower, lagging more and more, eventually ending up clicking totally different coordinates. I suspect there's a memory leak or performance issue in my source code. How can I find that out or fix it?
I've created a WPF application using C# that renders about 50 3D elements and animates the camera in order to move around the scene.
While it all works, I've noticed as the camera moves, ugly video tearing occurs.
I'm well aware of the standard cause of tearing, ie the application is updating frames at a different rate from the monitor/adapter vertical sync.
I've also read that the default screen update rate in WPF is 60 frames per second and that on XP WPF updates without regard to the montior v-sync.
For certain scenes the tearing is less noticeable, but often it is distracting enough to be a real problem.
I'm really hoping there is a resolution, after all Windows Forms has had double buffering for years. Moving to WPF is actally a backward step for many types of application if there is no resolution.
So, on Windows XP, how can I configure WPF to remove tearing?
I'm looking for more helpful answers then "move to Vista". This is simply out of the question for many of the future users of this application.
No answers yet, surely with the number of WPF developers out there someone else has seen this problem?
In the meantime I've investigated/read some more and have come across the Timeline.DesiredFrameRate property.
With my display running at 50hz vertical refresh I tried setting this to 50 FPS in the hope this would brings things in sync. Unfortunately this had no effect on the tearing.
However, I did have to apply it to a single specific animation I created (in code) using BeginAnimation(). I'm not sure how this would affect a "global" framerate at all.
Instead, I would have expected to need to do this at a more global level, say on the viewport, however I couldn't find DesiredFramerate property on the viewport object.
Another area to look at could be the RenderCapability.Tier but I haven't had the time to look in detail yet.
[Update]
No solution but a useful tip. To set the DesiredFramerate globally (ie for all animations in the viewport) you can override the PropertyMetadata for the
Timeline.DesiredFrameRateProperty dependency property:
// Set the global desired framerate to 50 frames per second
Startup += delegate(object sender, StartupEventArgs e)
{
Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline),
new PropertyMetadata(50));
};
It's best to place this in the constructor of the standard WPF Application class.
Unfortunately this didn't solve my problem because even setting it to FPS, it must not be synced accurately enough with monitor v-sync.
It is handy to know about though, particularly if you have slow moving animations and want to save CPU usage by setting the FPS much lower then the default 60fps.
[Update]
Setting the DesireFrameRate to some very high value such as 100+ seems to reduce but not remove the flicker. One big drawback however is that the CPU (on my 4 yo PC) goes to 35%.