2D绘图性能(GDI + vs SlimDX)

时间:2012-04-23 18:56:21

标签: c# wpf gdi+ slimdx

我是一个团队的一员,该团队创建了一个工具,用于查看C#/ WPF中非常大且互连的图形并与之交互。查看图形并与图形交互是通过一个自定义控件完成的,该控件接受一组DrawingVisual并在画布上显示它们。图中的节点可能具有使用我们的编辑器创建的自定义形状。当前控件运行良好,并且与我们的程序相当,但在考虑更大的图形(20,000多个节点和大量连接)时,存在对性能的合理担忧。

经过一些研究后,似乎有两种方法:

  • 将图形绘制到WriteableBitmap或InteropBitmap的GDI +路径。
  • SlimDX或DirectX变体(托管在D3DImage中)


鉴于这两种极为不同的方法,哪种方法最适合考虑:

  • 即使在查看整个图表时,与图表的交互也必须快速。
  • 更新视觉效果应该很快(颜色或尺寸更改)
  • 命中测试必须快速(点和矩形)。
  • 必须及时完成开发。

您会使用哪种方法?为什么?

编辑:
看起来similar question被问到但没有回答。

3 个答案:

答案 0 :(得分:7)

我为我的cartographic application使用GDI。虽然GDI +比DirectX慢,但我发现有很多东西和技巧可以用来加快速度。在绘制数据之前,大量的CPU用于准备数据,因此GDI不应该是那里唯一的瓶颈。

需要注意的事项(这些也足以应用于其他图形引擎):

  1. 首先:衡量。使用分析器查看代码中的真正瓶颈。
  2. 重用GDI原语。这很重要。如果您必须绘制100,000个看起来相同或相似的图形对象,请使用相同的PenBrush等。创建这些原语非常昂贵。
  3. 缓存渲染数据 - 例如:如果您不需要,请不要重新计算gfx元素位置。
  4. 平移/缩放时,使用较低的GDI +质量绘制场景(并且无需昂贵的GDI操作)。有许多Graphics对象设置会降低质量。用户停止平移后,以高质量绘制场景。
  5. 许多提高性能的小事。我已经开发了这个应用程序2 - 3年(或者它已经4个嗯?)现在我仍然想方设法改进:)。这就是分析很重要的原因 - 代码更改会影响性能,因此您需要分析新代码。
  6. 另一件事:我没有使用过SlimDX,但我确实尝试过Direct2D(我指的是Microsoft.WindowsAPICodePack.DirectX.Direct2D1)。在我的情况下,性能比GDI +快得多,但我在渲染位图时遇到了一些问题,而且没有时间找到合适的解决方案。

答案 1 :(得分:3)

我最近将一些绘图代码移植到DirectX,并对结果非常满意。我们主要使用bit-bashing渲染位图,并且看到渲染时间可以在几分钟内测量,减少到大约1-2秒。

这不能直接与你的使用进行比较,因为我们已经使用SlimDX从C ++中的bit-bashing转变为C#中的Direct3D,但我想你会看到性能优势,即使它们不是我们正在看到的程度。

我建议你看一下使用Direct2D和SlimDX。您将需要使用DirectX 10.1,因为Direct2D由于某种原因与DirectX 11不兼容。如果您在WPF中使用了绘图API,那么您已经熟悉Direct2D,因为据我所知,它的API基于WPF绘图API。 Direct2D的主要问题是缺少文档,事实上它只适用于Vista。

我没有尝试使用DirectX 10 / WPF互操作,但我相信它是可能的(http://stackoverflow.com/questions/1252780/d3dimage-using-dx10)

编辑:我想我会从绘制简单多边形的代码中给出一个比较。首先是WPF版本:

        StreamGeometry geometry = new StreamGeometry();

        using (StreamGeometryContext ctx = geometry.Open())
        {
            foreach (Polygon polygon in mask.Polygons)
            {
                bool first = true;

                foreach (Vector2 p in polygon.Points)
                {
                    Point point = new Point(p.X, p.Y);

                    if (first)
                    {
                        ctx.BeginFigure(point, true, true);
                        first = false;
                    }
                    else
                    {
                        ctx.LineTo(point, false, false);
                    }
                }
            }
        }

现在是Direct2D版本:

        Texture2D maskTexture = helper.CreateRenderTexture(width, height);

        RenderTargetProperties props = new RenderTargetProperties
        {
            HorizontalDpi = 96,
            PixelFormat = new PixelFormat(SlimDX.DXGI.Format.Unknown, AlphaMode.Premultiplied),
            Type = RenderTargetType.Default,
            Usage = RenderTargetUsage.None,
            VerticalDpi = 96,
        };

        using (SlimDX.Direct2D.Factory factory = new SlimDX.Direct2D.Factory())
        using (SlimDX.DXGI.Surface surface = maskTexture.AsSurface())
        using (RenderTarget target = RenderTarget.FromDXGI(factory, surface, props))
        using (SlimDX.Direct2D.Brush brush = new SolidColorBrush(target, new SlimDX.Color4(System.Drawing.Color.Red)))
        using (PathGeometry geometry = new PathGeometry(factory))
        using (SimplifiedGeometrySink sink = geometry.Open())
        {
            foreach (Polygon polygon in mask.Polygons)
            {
                PointF[] points = new PointF[polygon.Points.Count()];
                int i = 0;

                foreach (Vector2 p in polygon.Points)
                {
                    points[i++] = new PointF(p.X * width, p.Y * height);
                }

                sink.BeginFigure(points[0], FigureBegin.Filled);
                sink.AddLines(points);
                sink.EndFigure(FigureEnd.Closed);
            }

            sink.Close();
            target.BeginDraw();
            target.FillGeometry(geometry, brush);
            target.EndDraw();
        }

正如您所看到的,Direct2D版本的工作量略多(并且依赖于我编写的一些辅助函数),但实际上它非常相似。

答案 2 :(得分:1)

让我尝试列出每种方法的优点和缺点 - 这可能会让您对使用哪种方法有所了解。

GDI专业人士

  • 使用
  • 轻松绘制矢量形状
  • 无需包含额外的库

GDI缺点

  • 比DX慢
  • 需要限制“花式”绘画(渐变等)或者它可能会减慢速度
  • 如果图表需要互动 - 可能不是一个很好的选择

SlimDX专业人士

  • 可以比GDI更快地进行一些精美的绘画
  • 如果绘图是互动的 - 这种方法会更好
  • 自绘制基元后,您可以控制每个缩放级别的质量

SlimDX缺点

  • 绘制简单形状并不容易 - 您需要编写自己的抽象或使用可帮助您绘制形状的库
  • 使用GDI并不是那么简单,尤其是在
  • 之前没有使用它的情况下

也许更多我忘了放在这里,但也许这些会对初学者有用吗?

-A。