Double buffer for Silverlight game - silverlight

I start learning Silverlight and would like to create some simple game.
I am using CompositionTarget.Rendering event for my animation
But animation is not smooth, I developed games before and I used double buffer to avoid such problems, but I can't find if it possible with Silverlight.
Does anybody know how to create smooth animation with CompositionTarget.Rendering event.
Thanks,
.NET Developer.

Are you assuming that the Rendering event fires at a constant rate? It's not guaranteed to. On my machine it usually fires 60 times per second, but sometimes it's a bit faster and sometimes noticeably slower. It seems to skip a frame on occasion, which could cause your animation not to be smooth.
However, the event gives you the information to determine exactly how long it's been since the last frame (though you have to know how to get it), and you can code your animation to take this into account. Move farther if it's been a longer amount of time since the last frame, etc.
You need to take the EventArgs that's passed to your event handler, cast it to RenderingEventArgs, and then read its RenderingTime property. Calculate the delta in RenderingTime since your last event; that tells you how long it's been since your last frame was shown, and you can use that to pace your animations.
CompositionTarget.Rendering += CompositionTarget_Rendering;
...
private static TimeSpan? _lastRenderTime;
private void CompositionTarget_Rendering(object sender, EventArgs e) {
var args = (RenderingEventArgs) e;
var elapsed = _lastRenderTime.HasValue ?
args.RenderingTime - _lastRenderTime.Value :
TimeSpan.Empty;
_lastRenderTime = args.RenderingTime;
// "elapsed" tells you how long since the last frame.
// Now you can update your animation accordingly. For example,
var left = Canvas.GetLeft(_myControl);
left += elapsed.TotalSeconds * 100;
Canvas.SetLeft(_myControl, left);
}
I've heard that, at least in WPF, RenderTime doesn't tell you the current time, but rather what time it will be when the frame is shown on the screen. I haven't seen that substantiated from official sources, and even if it's true, I don't know if it's true for Silverlight as well. But whatever the case, it will give you the best possible information for writing your animation.

How much processing do you perform in Rendering event? As one option you can render part of your scene into WriteableBitmap and only use rendering event to swap bitmaps.

Related

Jerky animation when scrolling image in WPF using SharpDX

I am trying to smoothly scroll some images across a window using DirectX11 via SharpDX in a WPF application.
A bit of background:
The images are signal returns, varying by time, that have been loaded from a file and loaded into D3D as a texture array, and the image itself is rendered as a series of textured quads (a series of adjoining rectangles in a very long horizontal line).
The viewport is set up so that the left and right edges represent time offsets, and the signal is displayed for the time period that falls between these times.
The DirectX implementation is very simple; the quad vertices are generated once, and a very small per-frame buffer contains a simple 2D world-view transform that updates scale and translation according to the current visible range/zoom etc.
As far as I can tell, the D3D implementation is not part of the problem I am having - it really is a very simple set up, and seems to be rendering extremely quickly (as it should), and although I do have some fancier stuff (streaming of textures from disk as required), I have disabled all of these and am running with very simple (small) textures whilst I try and resolve the issue I am having..
The problem:
Scrolling of the image is not smooth when the visible time range is animated. The image "jitters" much of the time, and frankly looks awful (when it is not jittering, it looks great).
The setup:
DirectX is rendered to a D3DImage, with a bit of work going on behind the scenes to make DX11 work - this code is taken from https://sharpdxwpf.codeplex.com/
There are multiple D3DImages (up to a total of 4), arranged in a grid (I have been testing with two, both of which contain signals for the same time period and are animated together).
These D3DImages are drawn by a DrawingVisual (which is hosted by a custom FrameworkElement) where they are used as the source of an ImageBrush. The frameworkelement object triggers a render as required, and the drawing visual handles the D3D render call and draws a rectangle to fill the control using the D3DImage brush.
The time range value is animated using a WPF DoubleAnimation. The visuals that are currently displayed are bound to this value via INotifyPropertyChanged and trigger a render (via InvalidateVisual) on each change.
DrawingVisual render code, triggered by change of "Position" value (start of visible time range):
// update scene per-frame buffer first, with world-view transform
using (DrawingContext dc = RenderOpen()
{
_scene.Renderer.Render(_draw_args);
_image.Invalidate();
dc.DrawRectangle(_brush, null, new Rect(viewer.RenderSize));
}
What I have tried:
I have tried a number of things (and searched a lot) to try and determine whether the issue is due to jittery render request timing, or if the issue is further into the render process.
Hooking into CompositionTarget.Rendering
Firstly driving the update of the position value via CompositionTarget.Rendering, and leaving the rest of the process as-is (i.e. elements react to the change of this value):
(needless to say, this is very much "test" code):
Stopwatch rsw;
long last_time = 0;
void play()
{
rsw = new Stopwatch();
last_time = 0;
rsw.Start();
CompositionTarget.Rendering += rendering;
}
void rendering(object sender, EventArgs e)
{
double update_distance = rsw.ElapsedMilliseconds - last_time;
Position += 10 * update_distance;
last_time = rsw.ElapsedMilliseconds;
}
Results - worse than the simple double animation.
Using a DispatcherTimer. Similar to above, using a timer in conjunction with a stopwatch to judge the elapsed time a little better. Worse results again, with the interesting side note that CPU usage dropped from about 7% (half a core) to 0.7%.
The original attempt, along with variants 1 & 2, all try to update a single value that then triggers the render of interested parties. Out of interest, I logged the time differences between render requests as they reached the Drawing visual - although the DisptacherTimer actually gave the most consistent results there (both WPF animation and CompositionTarget dropped the odd frame), the DisptacherTimer also gave the most jittery animation.
Updating the image, but not invalidating the visual. Updating the source of an ImageBrush updates the displayed image, without having to re-render the DrawingVisual. This method produced very jittery results.
CompositionTarget.Rendering in the framework element itself. This produced the best results of the lot, but still not perfect. Jitter would happen, then dissipate, only to return again. In this approach, the framework element that holds the DV hooks up to CompositionTarget.Rendering, and the visual queries the current position, which is being animated independently. I could almost live with this approach.
Attempting the wait until the D3D scene is rendered, before invalidating the image (no discernible improvement):
_scene.Renderer.Render(_draw_args);
_scene.Renderer.Device.ImmediateContext.End(q);
while (!(_scene.Renderer.Device.ImmediateContext.IsDataAvailable(q)))
Thread.Yield();
_image.Invalidate();
Observations:
I really don't think this is a performance issue as such. My dev machine has a good graphics card, 8 i7 cores etc, and this is a simple rendering operation.
This really seems like some sort of synchronisation issue between D3D and the WPF rendering, but I have no idea how to begin looking into this.
If I have two images animating in parallel, the jitter is much more pronounced on the first of the two (usually).
If I actively resize the window whilst animating, animation is perfectly smooth (despite the fact that a lot of extra work is being done, as the D3D context is being resized constantly).
EDIT
I've taken things back as far as possible to try and isolate the problem, and the issue seems to be fundamental to the way in which D3DImage is updated & rendered by WPF.
I have modified the WPFHost example in the SharpDX Samples solution so that the simple trigangle that is displayed is animated across the screen. This example is hosted in a DX10ImageSource that is rendered by a DPFCanvas on CompositionTarget.Rendering.
This example couldn't be more simple, and is about as "close to the metal" as you can get whilst rendering a D3DImage in WPF. A single triangle, translated across the screen by a value calculated from the time difference between renders. The stutter remains, coming and going, as if some sort of synchronisation issue. It baffles me, but essentially makes SharpDX unusable within WPF for any sort of smooth animations, which is extremely disappointing.
If anyone is interested in reproducing this problem, the SharpDX samples are available here: https://github.com/sharpdx/SharpDX-Samples
I made the following simple changes to the WPFHost example:
void IScene.Render()
{
...
EffectMatrixVariable wv = this.SimpleEffect.GetVariableBySemantic("WorldView").AsMatrix();
wv.SetMatrix(this.WorldViewMatrix);
...
}
void IScene.Update(TimeSpan sceneTime)
{
float x = (float)sceneTime.Milliseconds * 0.001f - 0.5f;
WorldViewMatrix = Matrix.Translation(x, 0, 0);
}
and in shader Simple.fx:
float4x4 WorldViewTransform : WorldView;
PS_IN VS( VS_IN input )
{
PS_IN output = (PS_IN)0;
output.pos = mul(input.pos, WorldViewTransform);
output.col = input.col * Overlay;
return output;
}
D3DImage is fundamentally broken.
If you don't need to overlay XAML elements on top of D3D or you do not need to resize too frequently the D3D surface, prefer to host a HWND/WinForm into your WPF apps and render to it directly using regular rendering loop. If you want a bit more details about the reasons, you can check this issue.

How to smooth WPF animation?

I am struggling in smoothing WPF animation
Actually my animation code is as follows:
private void AnimateX ( FrameworkElement element, double XMoveStart, double XMoveEnd, int secondX)
{
SineEase eEase = new SineEase();
eEase.EasingMode = EasingMode.EaseInOut;
Storyboard sb = new Storyboard();
DoubleAnimation daX = new DoubleAnimation(XMoveStart, XMoveEnd, new Duration(new TimeSpan(0, 0, 0, secondX, 0)));
daX.EasingFunction = eEase;
Storyboard.SetTargetProperty(daX, new PropertyPath("(Canvas.Left)"));
sb.Children.Add(daX);
element.BeginStoryboard(sb);
}
The above code is a method to move an object horizontally with sine ease. When only one object is moving, it is OK. However, whenever two or more objects move together (call AnimateX method on another object when the previous animation has not yet completed), the animation starts to become jittery. By jittery I mean, the objects are kind of shaking during the course of animation.
I faced the same problem many times. I found out that depending on the objects you add to your canvas, WPF will often have to regenerate representations of these objects on every frame (which I believe might be your case, depending on the type of UI elements you are manipulating). You can solve the jitter issue by telling WPF to cache a representation of your canvas in a bitmap. This is done very simply as follows, in your Xaml definition of the canvas:
<Canvas ...Your canvas properties...>
<Canvas.CacheMode>
<BitmapCache />
</Canvas.CacheMode>
...Your objects...
</Canvas>`
This reduces the load on your WPF application, as it simply stores the representation of your objects as a bitmap image, and as a consequence your application does not have to redraw them on every frame. This solution only works if your animation is applied externally to the canvas, and that there is no on-going local animations applying to the individual objects drawn in your canvas. You'll want to create separates canvases with their own caching if other animations in your code move the two objects with respect to each other.
Note that some UI elements will not be eased by this strategy. However, I've seen this strategy work efficiently for many elements, including TextBoxes and the likes, as well as geometric shapes. In any case, it's always worth the try.
Secondly, if caching local representations does not suffice, then you might want to have a look at the performance of your code and see if any process could be responsible for blocking the UI momentarily. There is no uniform solution regarding this aspect and it depends on what else is putting strain on your application UI. Cleaning the code and using asynchronous processes where relevant could help.
Finally, if, after all these checks the overall demand on your application remains too high, you can somewhat remove some strain on the application by reducing its general frame rate, the default being 60. You can try 30 or 40 and see if this improves the jittering by including the following code in your initialization:
Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline), new FrameworkPropertyMetadata { DefaultValue = 40 });
Just a guess, but what happens if you directly animate the property, withoud using a Storyboard?
private void AnimateX(FrameworkElement element, double xMoveStart, double xMoveEnd, double durationSeconds)
{
DoubleAnimation animation = new DoubleAnimation
{
From = xMoveStart,
To = xMoveEnd,
Duration = TimeSpan.FromSeconds(durationSeconds),
EasingFunction = new SineEase { EasingMode = EasingMode.EaseInOut }
};
element.BeginAnimation(Canvas.LeftProperty, animation);
}

How to update a graph on a panel at 25 FPS in C++/CLI / Windows Forms?

My Application is recieving data from external hardware and plots it onto a panel (can be actually any other child of "Control"). The painting currently happens in a "OnPaint" callback. A List is used to store the recently recieved data to allow to redraw the whole graph in OnPaint to get the proportions right if e.g. the window gets resized.
The graph itself is drawn with the e->Graphics element using lines between two data points.
This is working fine, but when I have new data coming in every 50 ms (= repaint the whole graph), the graph soon begins to flicker. The flickering gets stronger the more data needs to be plotted (when the right side of the control is reached, the data cache gets cleared, so there is a finite max number of data points in the graph).
The main part of my code:
void Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)
{
Size^ s = m_Control->Size;
Bitmap^ bmp = gcnew Bitmap(s->Width, s->Height);
Graphics^ g = Graphics::FromImage(bmp);
for each(double y in m_Data)
{
/* ...calculations etc... */
g->DrawLine(Pens::Blue, recentX, recentY, currentX, currentY);
}
e->Graphics->DrawImageUnscaled(bmp, 0, 0);
}
Any suggestion how I can optimize the painting to get rid of the flickering? Thanks in advance!
The flickering comes from WinForms erasing the background before calling your Paint handler.
You need to write your own custom control inheriting from Panel, and override OnPaintBackground to do nothing (especially, do not call the base class version).
Speaking independengly from your platform or language, this is kind of problems solved mostly using a method called governing the frame rate.
You will call your paint method, then estimate how much time spent on painting. Now you know how much time spent during a step and how long your refreshment intervals are - in your case it's 40 ms -. You can sleep the thread for (intervals - timespent) milliseconds.
By the way, it is my first answer and I know I am terrible at explaining stuff.

wpf progress bar slows 10x times serial port communications... how could be possible that?

I know that this could look a dumb question, but here's my problem.
I have a worker dialog that "hides" a backgroundworker, so in a worker thread I do my job, I report the progress in a standard way and then I show the results in my WPF program.
The dialog contains a simply animated gif and a standard wpf progress bar, and when a progress is notified I set Value property. All lokks as usual and works well for any kind of job, like web service calls, db queries, background elaboration and so on.
For my job we use also many "couplers", card readers that reads data from smart card, that are managed with native C code that access to serial port (so, I don't use .NET SerialPort object).
I have some nunit tests and I read a sample card in 10 seconds, but using my actual program, under the backgroundworker and showing my worker dialog, I need 1.30 minutes to do the SAME job.
I struggled into problem for days until I decide to remove the worker dialog, and without dialog I obtain the same performances of the tests!
So I investigated, and It's not the dialog, not the animated gif, but the wpf progress bar!
Simply the fact that a progress bar is shown (so, no animation, no Value set called, nothing of nothing) slows serialport communicatitons.
Looks incredible? I've tested this behavior and it's exactly what happens.
What you describe sounds completely normal. Updating a progress bar's value once is a relatively trivial task, but if your code is performing a large number of operations, then updating the progress bar each time can end up taking much more total time than just the operations would themselves.
If your code performs, say, 10,000 operations, try setting your progress bar's maximimum value to 10, and only update the bar every 1,000 operations.
Another possibility is to set the bar's value using BeginInvoke instead of Invoke (if this is how you're doing it in the first place). Invoke blocks until the invoked method is completed, which means each operation in your loop has to wait for the progress bar to be updated before continuing.
I always use the following code for updating progress bars (has to be run in the UI thread)
private int UpdateCount = 0;
public void UpdateProgress(int value)
{
// We are updating every tenth time.
if (((UpdateCount % 10) == 0)) {
ProgressBar1.Value = value;
}
UpdateCount += 1;
}

Longish delay between two consecutive KeyDown events

I'm kind of writing a little game engine -- purely to understand how these work from the inside. I currently don't want to mess with OpenGL or DirectX, so I stick to drawing on a control with GDI+ and all that WinForms stuff.
Obviously, I need to handle input. More specifically, keyboard events. This, however, poses a problem:
protected override void OnKeyDown(KeyEventArgs e)
{
Trace.WriteLine(string.Format("KD {0:hh:MM:ss.fff} {1}",
DateTime.Now, e.KeyCode));
}
This code (even with the shortest repeat delay set in the Keyboard applet in the Control Panel) yeilds the following:
KD 10:02:18.318 Right
KD 10:02:18.570 Right
KD 10:02:18.598 Right
KD 10:02:18.639 Right
KD 10:02:18.667 Right
KD 10:02:18.701 Right
As you can see, there's a 0.25 sec. delay between first two events. This results in sluggish movements of objects on screen, obviously: it first moves slightly to the right, then pauses for a noticeable moment, and then continues on.
How do I resolve that issue? Can this be done in pure WinForms or should I go DirectInput (or whatever is the kosher way nowadays?) route?
Using Windows messages isn't the best way to go for input interaction.
I know nothing about WinForms, but I assume on key events use messages.
I've used DirectInput (v7) many years ago, and it was really fast.
Perhaps GetKeyboardState or GetAsyncKeyState in a game loop are good alternatives.

Resources