【问题标题】:2D Drawing Performance (GDI+ vs SlimDX)2D 绘图性能(GDI+ 与 SlimDX)
【发布时间】:2012-04-23 18:56:20
【问题描述】:

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

经过一番研究,这两种方法似乎是:

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


鉴于这两种截然不同的方法,最好考虑哪种路线:

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

你会使用哪种方法,为什么?

编辑:
似乎有人询问了similar question,但没有得到答复。

【问题讨论】:

  • GDI+ 慢。 GDI 快速但丑陋。 D2D 更好但速度较慢。 SlimDX 是一个巨大的依赖和大的抽象学习曲线。第三个选项,使用 DX9 或(通过 DXGI 的 DX11)与 WPF D3DImage 界面握手。授予学习曲线,但更易于维护以创建 3DX 设备、上下文、缓冲区、着色器并通过 Direct3D 获取您的应用程序渲染。文档很糟糕,需要一些研究和尝试错误,但它并不像看起来那么糟糕。请参阅此处了解真实世界中的小型 18 meg demo download 包括 WPF WinForm 和 MFC,以及它的主要 WAV 和 GIS 数据。

标签: c# wpf gdi+ slimdx


【解决方案1】:

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

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

  1. 首先:测量。使用分析器查看代码中的真正瓶颈。
  2. 重用 GDI 原语。这是至关重要的。如果您必须绘制 100,000 个看起来相同或相似的图形对象,请使用相同的 PenBrush 等。创建这些图元的成本很高。
  3. 缓存渲染数据 - 例如:如果不需要,不要重新计算 gfx 元素位置。
  4. 平移/缩放时,以较低的 GDI+ 质量(且无需昂贵的 GDI 操作)绘制场景。有许多Graphics 对象设置来降低质量。用户停止平移后,以高质量绘制场景。
  5. 很多很多可以提高性能的小东西。我已经开发这个应用程序 2-3 年(或者它已经 4 年了?)现在我仍然找到改进的方法:)。这就是分析很重要的原因 - 代码更改会影响性能,因此您需要分析新代码。

另外一件事:我没有使用过 SlimDX,但我确实尝试过 Direct2D(我指的是Microsoft.WindowsAPICodePack.DirectX.Direct2D1)。就我而言,它的性能比 GDI+ 快得多,但我在渲染位图时遇到了一些问题,一直没有时间找到合适的解决方案。

【讨论】:

  • 项目负责人对走 GDI+/Bitmap 路线持谨慎态度,因为他过去的经验很慢(他可能是对的,也可能是错的)。他需要一个基于性能的解决方案,但他一直认为 DirectX 就是解决方案。您认为 GDI+ 的速度是否足以支持 30fps 并与 100k 对象交互?
  • @CBent:很难说,这在很大程度上取决于您所绘制内容的性质(显然还有硬件)。但这是我自己偶然发现的东西,我肯定会为我自己的应用程序进行实验:code.google.com/p/sharpdx。声称是最快的托管 DirectX 库 - 如果它比 WindowsAPICodePack 更快,那么它真的很快!
  • @CBent:哦,是的,当您需要快速图形时,DirectX 通常是您的选择,所以我猜您的项目负责人的想法是正确的。我选择了 GDI+ 路线,因为它是 Mono-portable - 我有用户在 Linux 和 Mac 上运行我的应用程序。
  • 感谢您的意见。我实际上已经开始尝试使用 SharpDX。不幸的是,学习曲线非常高,而且我公司没有拥有这种经验的开发人员,所以我自己学习。我们的应用程序仅针对 Windows,因此我们不必担心可移植性。
  • 迟到了。你使用什么类型的数字或浮点数?
【解决方案2】:

我最近将一些绘图代码移植到 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 版本的工作量稍大一些(并且依赖于我编写的一些辅助函数),但实际上非常相似。

【讨论】:

  • 我希望通过使用 DirectX 变体(目前正在查看 SharpDX),我们的应用程序的渲染将与您的一样多。我们正在绘制简单的线条和 2D 多边形(但它们太多以至于 WPF 开始窒息)。您在 SlimDX 研究中使用了哪些资源?
  • 恐怕这是大约一年前完成的,所以我不记得我使用的确切资源。不过,SlimDX 非常接近 Direct2D COM API,因此 C++ 中的任何示例都可以很容易地转换为 C#/SlimDX,我相信我就是这样做的。
  • 哇!我刚收到您编辑的帖子,其中包含代码。它们确实非常相似。您是否必须更改任何多边形格式以使其与 SlimDX 兼容?您的应用程序是全屏应用程序、单个 DX 表面,还是一次显示多个表面?
  • 我的应用程序实际上是一个离线渲染器,它渲染为一个 .png 文件,因此实际上没有任何内容显示在屏幕上。我使用由 SlimDX.Vector2 结构组成的多边形格式,它使用浮点数,但我想你可以只使用 WPF 多边形对象并将其中的双精度数转换为动态浮点数,如果你不介意开销。
  • (我应该补充一点,我认为将 double 转换为 float 的开销非常小)
【解决方案3】:

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

GDI 专业人士

  • 易于绘制矢量形状
  • 无需包含额外的库

GDI 缺点

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

SlimDX 专业人士

  • 可以比 GDI 更快地进行一些精美的绘图
  • 如果绘图是交互式的 - 这种方法会更好
  • 由于您绘制了图元,因此您可以控制每个缩放级别的质量

SlimDX 缺点

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

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

-A.

【讨论】:

  • 感谢您的回复!您有使用 SlimDX(wpf 集成)的经验吗?它可以渲染的东西的数量有上限吗?我正在尝试权衡 SlimDX 的学习曲线与它提供的性能优势与 GDI 路线相比。
  • 我相信 SlimDX 有一个 WPF 互操作性示例 (code.google.com/p/slimdx/source/browse/trunk/samples/Direct3D10/…)。此外,虽然 SlimDX/DirectX 可以渲染的内容本身没有上限,但请记住,性能只是显卡功率和渲染效率的函数 - 实际上 GDI 和 DX 都是如此。我建议先走 GDI 路线,如果性能不符合您的需求,请使用 SlimDX 资源。
  • 我很好奇你为什么推荐使用“GDI”的方式而不是 SlimDX。 SlimDX 的学习曲线有那么高吗?有人担心实施 GDI 方式(渲染、快速空间选择和集成)只是发现它太慢会“浪费”时间,而首先使用 GPU 加速路线将解决问题.再次感谢您的回复。
  • 我建议从 GDI 开始,因为使用 SlimDX,与在 GDI 中编写相比,您必须编写更多的低级绘图和管理代码,而且我个人不会去除非有正当理由,否则沿着这条路走下去。我建议您对最终应用中可能遇到的数字和负载进行实验,以确保。
猜你喜欢
  • 2012-08-20
  • 1970-01-01
  • 1970-01-01
  • 2018-01-07
  • 2012-07-07
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
相关资源
最近更新 更多