Smooth WPF animations on Remote Desktop to VM

So I’m attempting to make a docking library very similar to the ones used in VSCode and Atom, however I’ve run into some issues. Basically, for the start, I need to make a box starting from width 0 to increase to the end of the screen. I’m able to achieve this:

Rectangle rectangle = new Rectangle(); myCanvas.Children.Add(rectangle); rectangle.Width = 0; rectangle.Height = ActualHeight; rectangle.Fill = new SolidColorBrush(Color.FromArgb(80, 120, 120, 120)); Storyboard sb = new Storyboard(); DoubleAnimation da = new DoubleAnimation(rectangle.Width, ActualWidth, new Duration(TimeSpan.FromMilliseconds(1000)));  Storyboard.SetTargetProperty(da, new PropertyPath("(Rectangle.Width)")); sb.Children.Add(da);  rectangle.BeginStoryboard(sb); 

The animation is quite smooth on my dev-machine, but when remote-desktoping into a VM, the animation is VERY choppy. However, VSCodes and Atoms animations are still pretty decent. Is there any way to make this work better? Thanks.

EDIT: Is there a way to make a smooth animation for Winforms aswell?

EDIT 2: So I have this Winforms GDI code sample here:

private void FastTimer_Tick(object sender, EventArgs e) {     var x = 1;     if (solidBrush == IntPtr.Zero)     {         solidBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.FromArgb(120, 120, 120)));         hDC = CreateGraphics().GetHdc();     }      index += x;      int w = x;     int h = Height;      //create memory device context     var memdc = CreateCompatibleDC(hDC);      //create bitmap     var hbitmap = CreateCompatibleBitmap(hDC, index, h);      ////select bitmap in to memory device context     var holdbmp = SelectObject(memdc, hbitmap);       RECT rect = new RECT(new Rectangle(0, 0, w, h));     FillRect(memdc, ref rect, solidBrush);          AlphaBlend(hDC, index - x, 0, w, h, memdc, 0, 0, w, h, new BLENDFUNCTION(0, 0, 128, 0));     SelectObject(memdc, holdbmp);     DeleteObject(hbitmap);     DeleteDC(memdc); } 

With the fast timer core being this (Interval is 1000 in testing):

double frequency = Stopwatch.Frequency; long prevTicks = 0; while (true) {     if (!_enabled)     {         return;     }     double interval = frequency / Interval;     long ticks = Stopwatch.GetTimestamp();     if (ticks >= prevTicks + interval)     {         prevTicks = ticks;         Tick?.Invoke(this, EventArgs.Empty);     } } 

However, the animations are still choppy on Remote Desktop. (I know RD cannot use hardware acceleration, but I thought GDI was hardware-accelerated on compatible machines, but I do not see any GPU usage on my dev-machine) With regards to thatguys answer, how do I make this faster?

Add Comment
1 Answer(s)

These issues are common with WPF and are caused by bitmap remoting, see this Microsoft blog.

Starting with the release of NET 3.5 SP1 (including NET 4), WPF renders the application content using a software rasterizer on the server and then remotes the content as bitmaps in all cases.

This is crucial for animations, due to lots of redrawing. Animations often affect a large area at once, imagine a color gradient. Therefore, large parts of the application need to be invalidated and redrawn. Furthermore, there is a the lack of support for occlusion in WPF that might aggravate the issue, too.

Bitmaps are highly compressed by the underlying RDC stack and only regions that changed are being updated. Also note that WPF does not currently have efficient occlusion support, so for instance animations that are completely hidden behind other opaque WPF elements will still force invalidation and RDP update.

The reason that you might not encouter this issue for eaxmple in native Win32 or MFC applications is that they use GDI or GDI+ for drawing their user interface controls.

When apps use GDI (such as many Win32 and Winforms apps do), only the GDI primitives are remoted. In many cases this can be more efficient than remoting WPF apps since WPF apps remotes bitmaps which typically result in more content being sent over the wire than a similar GDI-based app. The additional data may result in slower performance depending on network bandwidth and the size and frequency of updates.

Atom and VS Code are built on Electron which is based on chromium, not WPF, that is why there are large differences on remote desktop.

In the linked blog you can find hints on how to improve the remote performance in general. Apart from considering to disable animations in remote desktop scenarios because there are no guarantees on factors like bandwidth or latency for your clients, the essential parts for improving animations are:

  • Adapt the DesiredFrameRate to reduce the animation frame rate, which in turn reduces traffic
  • Turn animations off in occluded areas of the application, since they cause redrawing, too
  • Reduce traffic by removing animations from default WPF control templates for ProgressBar, Button, ComboBox and others, as well as all of your own non-essential animations
  • Improve RDP compression efficiency by simplifying other areas of the application, like replacing color gradients with solid colors
  • Avoid anything that is slow to render in software like bitmap effects or 3D views
  • Use a WPF performance profiling tool like Perforator to identify the critical areas that are invalidated frequently to optimize them
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.