Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my Direct2D drawing performance so terrible?

Tags:

.net

direct2d

I'm developing a Dotnet 4.0 application on Win7 that needs to perform mapping. As a mapping application it outputs crap loads of high resolution antialiased polygons. It currently supports two types of rendering output, GDI+ and Direct2D.

I'm concerned because the GDI+ output is around a factor of 3 faster than the Direct2D.

Both renderers are using AA. I know I can turn it off in Direct2D which improves the throughput somewhat (down to about a factor of 2 worse than GDI+). But that isn't a solution, since I can turn AA off in GDI+ too and get even better performance there. For the purpose of this benchmark my rendering code is trivial. I'm hoping I've made some ghastly mistake that someone can point out to me that will remedy the situation.

_renderTarget.BeginDraw();

// Paint background.
RectF rf = new RectF(0.0f, 0.0f, renderTargetSize.Width, renderTargetSize.Height);
_renderTarget.FillRectangle(rf, _backgroundBrush);

// Draw polygons
foreach (GisTypes.Polygon polygon in _polygons)
{
    using (PathGeometry path = _factory.CreatePathGeometry())
    {
        using (GeometrySink sink = path.Open())
        {
            sink.SetFillMode(Microsoft.WindowsAPICodePack.DirectX.Direct2D1
                .FillMode.Alternate);

            Point2F[] points = Array.ConvertAll(polygon.Points,
                x => new Point2F((float)x.X, (float)x.Y));

            sink.BeginFigure(points[0], FigureBegin.Filled);

            for (int i = 1; i < points.Length; ++i)
            {
                sink.AddLine(points[i]);
            }

            sink.EndFigure(FigureEnd.Closed);
            sink.Close();
        }

        using (TransformedGeometry transformedPath = _factory.CreateTransformedGeometry(
            path, WorldToPage))
        {
            _renderTarget.FillGeometry(transformedPath, _fillBrush);
            _renderTarget.DrawGeometry(transformedPath, _borderBrush, 1.0f);
        }
    }
}

_renderTarget.EndDraw();

In this sample code I'm using one path and one figure per polygon. The reason is because it more closely mirrors the GDI+ implemention and in the actual application rather than the sample code it simplifies rendering of the selected polyons. I know I could use a single path and multiple figures, and I have tried it that way, it is marginally faster but not by enough to have a bearing on the general issue.

I'm also using a TransformedGeometry rather than setting the transform on the RenderTarget. The reason for that is because although I want the geometry transformed I do not want the outline transformed because the scaling factor would cause it to disappear entirely.

In the particular sample data I'm using there are only a couple of hundred polygons, but each polygon can have several thousand points, so I don't think the allocation of multiple PathGeometry and TransformedGeometry during the rendering is the issue, (since there aren't many of them, and I've already tried it using just one PathGeometry and TransformedGeometry and the difference was marginal).

I wondered whether I shouldn't be rendering to an offscreen RenderTarget and blitting the result to the onscreen RenderTarget, but I've read the MSDN article on improving Direct2D performance and it made no mention of this as an optimization.

Anyone got any ideas?

like image 224
Neutrino Avatar asked Nov 28 '12 10:11

Neutrino


1 Answers

I believe that your drawing routine is creating resources too often, which is really time consuming. Geometries and Sinks being device-independent resources, you should create and retain them as long as they are not modified. Those modifications usually occur when you... change what should be drawn, of course, and when you move/resize the window or pan/zoom the content. Your drawing routine would then only draw already existing resources and should be faster.

Hope this helps.

like image 149
Papaya Avatar answered Nov 17 '22 13:11

Papaya