C# 二维绘图性能(GDI和SlimDX)

C# 二维绘图性能(GDI和SlimDX),c#,wpf,gdi+,slimdx,C#,Wpf,Gdi+,Slimdx,我是一个团队的成员,该团队创建了一个工具,可以在C#/WPF中查看非常大且高度互连的图形并与之交互。查看图形和与图形交互是通过一个自定义控件完成的,该控件接收一组DrawingVisuals并将其显示在画布上。图形中的节点可能具有使用编辑器创建的自定义形状。当前控件工作得很好,并且与我们的程序相当耦合,但是当考虑更大的图(20000多个节点和大量连接)时,对性能存在合理的担忧 在做了一些研究之后,似乎有两种方法: 一种GDI+路由,其中图形被绘制到可写BITMAP或InteropBitmap

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

在做了一些研究之后,似乎有两种方法:

  • 一种GDI+路由,其中图形被绘制到可写BITMAP或InteropBitmap
  • SlimDX或DirectX变体(托管在D3DImage中)

鉴于这两种截然不同的方法,考虑到以下因素,哪条路线最好:

  • 即使在查看整个图形时,与图形的交互也必须快速
  • 更新视觉效果应快速(颜色或尺寸变化)
  • 命中测试必须快速(点和矩形)
  • 开发必须及时完成
你会使用哪种方法?为什么

编辑:

看起来好像有人问了一个问题,但没有回答。

让我试着列出每种方法的优缺点,这可能会让你知道该使用哪种方法

GDI专业人士

  • 易于绘制矢量形状与
  • 不需要包括额外的库
GDI Cons

  • 比DX慢
  • 需要限制“花式”绘图(渐变等),否则可能会减慢速度
  • 如果图表需要交互,可能不是一个很好的选择
SlimDX专业版

  • 可以在比GDI快的同时画一些漂亮的画
  • 如果绘图是交互式的,这种方法会更好
  • 由于绘制了基本体,因此可以在每个缩放级别控制质量
SlimDX-Cons

  • 绘制简单形状不是很容易——你需要编写自己的抽象或使用一个库来帮助你绘制形状
  • 使用GDI并不像使用GDI那么简单,尤其是在您以前没有使用过GDI的情况下
也许我忘了在这里加上更多,但也许这些可以作为开始

-A.

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

需要注意的事项(这些内容非常普遍,也适用于其他图形引擎):

  • 首先:测量。使用探查器查看代码中真正的瓶颈是什么
  • 重用GDI原语。这是至关重要的。如果必须绘制100000个外观相同或相似的图形对象,请使用相同的
    画笔
    等。创建这些基本体的成本很高
  • 缓存渲染数据-例如:如果不需要,不要重新计算gfx元素位置
  • 平移/缩放时,绘制GDI+质量较低的场景(且不需要昂贵的GDI操作)。有许多
    图形
    对象设置可降低质量。用户停止平移后,以高质量绘制场景
  • 很多很多可以提高性能的小事情。我开发这个应用已经2-3年了(或者已经4年了,嗯?),现在我仍然在寻找改进的方法:)。这就是为什么评测很重要的原因——代码更改会影响性能,因此需要评测新代码

  • 还有一件事:我没有使用SlimDX,但我尝试了Direct2D(我指的是
    Microsoft.WindowsAPICodePack.DirectX.Direct2D1
    )。在我的例子中,性能比GDI+快得多,但我在渲染位图时遇到了一些问题,从来没有时间找到合适的解决方案。

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

    <>这不能直接与你的用法相比,因为我们已经使用SLIMDX从C++中的BIT攻击到C to Direct3D,但是我想你会看到性能上的好处,即使它们不是我们所看到的数量级。 我建议您考虑一下将Direct2D与SlimDX结合使用。由于某些原因,Direct2D与DirectX 11不兼容,因此需要使用DirectX 10.1。如果您在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版本的工作量稍大一些(并且依赖于我编写的一些帮助函数),但实际上非常相似。

    感谢您的回复!您是否有使用SlimDX(wpf集成)的经验?它能呈现的东西的数量有上限吗?我试图权衡SlimDX的学习曲线和它相对于GDI路线提供的性能优势。我相信SlimDX有一个WPF互操作性示例()。此外,虽然SlimDX/DirectX渲染的内容本身没有上限,但请记住,性能只是图形卡马力和渲染效率的函数——实际上,GDI和DirectX都是如此