2

I'm writing a CAD-like application which needs to display maybe tens of thousands of lines when stuff is zoomed out.

At the moment I use C++ and Direct2D, which works quite smoothly: I can draw 100000 lines in something like 16 milliseconds. So I know my (average) machine can handle that.

I'm trying to move to WPF but I'm finding the performance disappointing. With the code below the redraw takes nearly one second (when I resize the window for example).

Profiling says the bottleneck is somewhere in [wpfgfx_v0400.dll], but I can't see exactly which functions.

So my questions: What am I doing wrong? How can I improve the performance of the code below?

public partial class MainWindow : Window
{
    public MainWindow ()
    {
        InitializeComponent ();

        var gg = new GeometryGroup ();

        Random random = new Random ();
        for (int i = 0; i < 1000; i++)
        {
            Point p0 = new Point (random.Next (1000), random.Next (1000));
            Point p1 = new Point (random.Next (1000), random.Next (1000));
            var lineGeometry = new LineGeometry (p0, p1);

            gg.Children.Add (lineGeometry);
        }

        var stroke = new SolidColorBrush (Colors.Red);

        gg.Freeze ();
        stroke.Freeze ();

        this.Content = new Path () { Data = gg, Stroke = stroke };
    }
}
adigostin
  • 633
  • 7
  • 20
  • *"How can I improve the performance of the code below?"* do not use WPF – MichaC Nov 19 '13 at 14:07
  • Did you check [this post](http://stackoverflow.com/q/16107877/21727)? – mbeckish Nov 19 '13 at 14:11
  • I'm considering doing that, but I thought maybe I'm doing something very wrong in my test, cause I can't imagine Microsoft writing a framework which can't handle the drawing of 1000 lines. – adigostin Nov 19 '13 at 14:11
  • mbeckish, if I do my drawing in OnRender(), that drawing gets covered by any Background I set. (And I need to set a Background or else I'm not getting mouse events, among other problems.) Not that it makes much difference anyway. I had tried doing the drawing there too. I just happened to post the code that does the drawing using Geometries. – adigostin Nov 19 '13 at 14:18
  • I don't think the slowness is from the line drawing. I think its because you are calling the Random.Next method a 1000 times. Random.Next is slow. Instead, try pre-filling a 1000 element array with random numbers, then generate your points from the array in the loop. – Icemanind Nov 19 '13 at 14:43
  • 1
    icemanind, note that i'm already "pre-filling". The code I posted belongs to a constructor, which only ever gets called once. – adigostin Nov 19 '13 at 14:46
  • I tried your code, but in the `OnRender()` method of a custom `FrameworkElement` and it works ok. Response time is immediate with 1000 lines. I'll try with 200,000. – Federico Berasategui Nov 19 '13 at 16:02
  • 1
    Nope, I tried 200,000 and the Window is completely unusable... – Federico Berasategui Nov 19 '13 at 16:13

1 Answers1

2

Drawing things in WPF is slower than you'd expect! A line with 1000 points shouldn't be a problem in general, but I wouldn't hope to draw anywhere near 100000 points using WPF geometry primitives - instead you'll eventually have to drop down to either rasterizing yourself or using some raw DirectX embedded in your WPF application.

Specifically the case of a single line of 1000 points should be well within the bounds of reason, some thoughts:

  • With random data, if the line goes back and forth to cover a lot of area, this can lead to some very ugly performance. This is not simply a case of creating a large area to redraw - going back and forth seems to cause some bad situation with WPF geometries

  • If you're drawing a single line, try using a PolyLine or PolyLineSegment in your Path

  • If you do actually want a number of disconnected lines, rather than a GeometryGroup full of LineGeometry, use a Path with many PathFigures.

For the general case as other answers have pointed out, you can look into OnRender or DrawingVisual type approaches, depending what you're doing the performance may or may not be better. I think you'll still struggle with the amount of elements you're suggesting, unless you can do some kind of virtualization.

Nicholas W
  • 2,231
  • 1
  • 14
  • 15