2

How is the approach to plot complex drawings with Direct2D (Sharpdx)?

Actually I am using a WindowsRenderTarget, connecting it with a Direct2D1.Factory and drawing to a RenderControl.

        Factory2D = new SharpDX.Direct2D1.Factory(FactoryType.MultiThreaded);
        FactoryWrite = new SharpDX.DirectWrite.Factory();
        var properties = new HwndRenderTargetProperties();
        properties.Hwnd = this.Handle;
        properties.PixelSize = new Size2(this.ClientSize.Width, this.ClientSize.Height);
        properties.PresentOptions = PresentOptions.RetainContents;

        RenderTarget2D = new WindowRenderTarget(Factory2D, new RenderTargetProperties(new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)), properties);
        RenderTarget2D.AntialiasMode = AntialiasMode.PerPrimitive;

The drawing is done in the Paint Event of the form:

RenderTarget2D.BeginDraw();
RenderTarget2D.Clear(Color4.Black);
drawProgress(); // Doing Paintings like DrawLine, Multiple PathGeometrys, DrawEllipse and DrawText
RenderTarget2d.EndDraw();

In the MouseMove/MouseWheel event the drawing will be recalculated (for scaling or calculation of the elements that will be displayed). This process need about 8-10ms. The next step is actually

this.Refresh(); 

Here, I guess, is the problem, this progress needs up to 140ms.

So the scaling/moving of the plot has about 7fps.

Also the program occupies more and more memory when refreshing the Control

////Edit

Painting of lines:

    private void drawLines(Pen pen, PointF[] drawElements)
    {
        SolidColorBrush tempBrush = new SolidColorBrush(RenderTarget2D, SharpDX.Color.FromRgba(pen.Color.ToArgb()));

        int countDrawing = (drawElements.Length / 2) + drawElements.Length % 2;

        for (int i = 0; i < countDrawing; i++)
        {
            drawLine(new Vector2(drawElements[i].X, drawElements[i].Y), new Vector2(drawElements[i + 1].X, drawElements[i + 1].Y), brushWhite);
        }
    }

Painting geometrys:

RenderTarget2D.DrawGeometry(graphicPathToPathGeometry(p), penToSolidColorBrush(pen));

    private PathGeometry graphicPathToPathGeometry(GraphicsPath path)
    {
        geometry = new PathGeometry(Factory2D);
        sink = geometry.Open();
        if (path.PointCount > 0)
        {
            sink.BeginFigure(new Vector2(path.PathPoints[path.PointCount - 1].X, path.PathPoints[path.PointCount - 1].Y), FigureBegin.Hollow);
            sink.AddLines(pointFToVector2(path.PathPoints));
            sink.EndFigure(new FigureEnd());
            sink.Close();
        }
        return geometry;
    }

In mouse move the drawing will be recalculated by just building differences between Cursor.Position.X/Y old and Cursor.Position.X/Y new. So the the lines will be recalculated really often :)

Brian Rasmussen
  • 114,645
  • 34
  • 221
  • 317
zaimen
  • 157
  • 1
  • 12
  • As I understand, you are calling `this.Refresh()` at the end of MouseMove/MouseWheel, right ? How you are measuring the performance exactly ? When you are initializing the resources from your first snippet ? Is your second snippet the whole content of the Paint event ? Are you creating any resources in the `drawProgress()` ? – Peter Kostov Feb 17 '15 at 08:27
  • I measure it with a Stopwatch that will be reseted in the refresh event. Actually I started using a renderloop and do the paint stuff there. I guess the problem is the drawing process. I actually repaint the complete painting everytime, even when the screen is blank. I think my approach is wrong. Another thing is the memory usage. The program gets bigger and bigger. I never dispose anything but also don't know how to do this. The rendertarget is blocked by the renderloop – zaimen Feb 17 '15 at 10:13
  • Without seeing your drawing process (ie - `drawProgress()`), we will only guess. – Peter Kostov Feb 17 '15 at 10:46
  • The draw progress has tons of calculations :) About 500 Drawlines, 300 PathGeometrys (no complex ones, but here are is the biggest performance lack), 100 Ellipses. But this is not the problem. The problem is that I repaint the stuff every single frame. I use'd the MiniRect example as base. There is also no reset of the RenderTarget to get the memory clear. I think I'm using the wrong basics, I never use a SwapChain or Backbuffer. I never set a Viewport or something like this. When the my program runs 30 seconds, it reaches 1,6gigs ram :/ – zaimen Feb 17 '15 at 10:55
  • I could make only a guess... Probably, you are creating resources in your `drawProgress()`. You should not. A core principle is that you have to create your resources at once and then just reuse them in your drawing routine(s). What do you mean with "resetting the RenderTarget" ? Also, do you have a discrete video adapter or you are using a cpu-integrated one ? – Peter Kostov Feb 17 '15 at 12:13

2 Answers2

1

The main bottleneck is your graphicPathToPathGeometry() function. You are creating and "filling" a PathGeometry in a render loop. As I mentioned above, a core principle is that you have to create your resources at once and then just reuse them in your drawing routine(s).

About your memory leak... your code samples don't provide enough information, but most probably you are not freeing the resources that you are creating (ie PathGeometry, SolidColorBrush and the ones we don't see).

The simplest advise is - use your render loop only for rendering/drawing and reuse resources instead of recreating them.

Improving the performance of Direct2D apps

Peter Kostov
  • 941
  • 1
  • 6
  • 15
  • You are absolutly right. For me, as a beginner, it was not that clear to calculate something inside the renderloop – zaimen Feb 20 '15 at 07:40
0

One part of the problem is:

SolidColorBrush tempBrush = new SolidColorBrush(RenderTarget2D, SharpDX.Color.FromRgba(pen.Color.ToArgb()));

Creating objects of any kind inside the renderloop creates a big memory lack in the application. Drawing existing values is the way to go.

I guess the performance issue will also be based on this problem.

zaimen
  • 157
  • 1
  • 12