【问题标题】:GDI+ performance tricks [closed]GDI+ 性能技巧 [关闭]
【发布时间】:2010-12-14 00:12:40
【问题描述】:

是否有人知道任何可靠的(并且希望是广泛的)书籍/网站讨论 GDI+ 性能(超出显而易见的范围)?

例如,我最近遇到了this excellent experiment。我最近还注意到Graphics.FillPath()Graphics.DrawPath() 快得多。我很想知道我还遗漏了哪些其他重要信息。

善意, 大卫

【问题讨论】:

    标签: .net performance gdi system.drawing


    【解决方案1】:

    嗯。如果您需要绘制路径的轮廓,知道 FillPath 比 DrawPath 快是没有好处的!

    优化 GDI+ 的最佳方法与任何其他代码完全相同:首先,不要优化它。而是:

    • 首先编写它,让它简单地工作,然后确定它是否真的太慢了​​。
    • 然后检查您的“算法”:
      • 简化您正在绘制的内容(减少您正在绘制的事物的数量),它会更快(在大多数情况下,由于减少了混乱,看起来会更好)。
      • 您是每次都绘制整个显示器,还是使用剪辑矩形来避免绘制不需要更新的图像部分?
      • 检查你是如何绘制事物的。您是否为每次重绘创建和销毁资源(例如画笔和钢笔)?将它们缓存在成员变量中。您是否多次过度绘制同一个像素? (例如,绘制背景,然后在顶部绘制位图,然后在其顶部绘制一个矩形 - 也许您可以避免其中一些重绘)。您是否使用 100 个多边形线段绘制一条曲线,而它看起来只有 10 个线段就足够了?当窗口滚动时,您是让操作系统移动现有图像,因此您只需要重新绘制新暴露的条带,还是浪费时间重新绘制整个窗口?
      • 您是在使用变换还是在代码中进行冗长的定位计算?
      • 检查所有循环并确保将尽可能多的代码移出它们 - 预先计算在循环中使用的值等。确保您的循环尽可能以对 CPU 缓存友好的方向/方式迭代您的数据.
      • 在重绘期间您的数据中是否有任何要处理的内容?也许其中一些可以预先计算或以更适合渲染的形式组织。例如不同类型的列表会更快地枚举您的数据吗?您是否正在处理 1000 个数据项以找到您需要绘制的 10 个?
      • 您能用不同的方法获得相同的外观吗?例如您可以通过交替绘制黑色和白色的 64 个方格来绘制棋盘。绘制 32 个黑色方块然后绘制 32 个白色方块可能会更快,这样可以避免矩形之间的状态变化。但您实际上可以使用白色背景清晰、4 个黑色矩形和 4 个 XOR 矩形(8 个矩形而不是 64 个 => 更快的算法)来绘制它。
    • 图像中是否有不经常更改的部分?尝试将它们缓存在屏幕外位图中,以最大程度地减少每次重绘时必须“重建”的数量。请记住,您仍然可以渲染屏幕外位图,然后在其上叠加图形基元,因此您可能会发现比您想象的更多的“静态”图像区域。
    • 您是否正在渲染位图图像?尝试将它们转换为屏幕的像素格式并将它们缓存在“原生”形式中,而不是让 GDI+ 在每次绘制它们时都对其进行转换。
    • 如果您愿意以较低质量换取更快的渲染速度,请调低质量设置

    完成所有这些操作后,您就可以开始寻找有关优化渲染的书籍了。当然,如果它仍然太慢。运行分析器以找出渲染中最慢的部分。

    在您认为可能获得收益的地方,尝试不同的渲染方式(例如,Graphics.Clear() 可能会比使用 FillRectangle() 填充背景快得多),或不同的渲染顺序(绘制首先使用一种颜色的所有东西,以防状态更改花费您时间-批处理操作对于现代显卡通常非常重要。绘制多个多边形的单个调用通常比进行多个单多边形调用要快,所以你可以累积所有将你的多边形放入延迟渲染缓冲区,然后在渲染过程结束时将它们全部提交?)

    之后,您可能不得不考虑使用 GDI 或 DirectX 来更接近硬件。

    【讨论】:

    • 嗨,杰森,感谢您的广泛回答。让我一一回答,也许它会澄清我卡住的地方:
    • “简化你正在绘制的内容”。我是,主要是。我的 GUI 实际上是一个 ZUI,所以在缩小时我已经在简化东西了。但是,我不会根据上一帧绘制它的时间来决定是否绘制它。
    • 听起来您已经解决了许多更明显的问题。你说你正在渲染很多位图,所以看看它们中的任何一个是否可以组合(绘制一个大的位图通常比绘制两个半尺寸的位图更快) - 在预处理中组合,或者只是缓存以便它们不会每次都从头开始重绘。
    • 如果您正在绘制 LOADS 对象,那么您可以考虑限制绘制的数量(例如,在某个缩放级别下降到简化的渲染方案,以便您显示较少的细节但保持可接受的性能)。另一种可能性是使用背景或延迟渲染方法(因此您在滚动和缩放时渲染非常简化的视图,然后在流程结束时以高质量重绘,因此您在需要时保留交互性,但是当您停止看看显示屏,它显示了完整的细节。
    • 另一种类似的方法是将显示分解为“图块”,因此您可以快速渲染中心(主要关注点)区域,然后随着时间的推移绘制外围图块以填充视图。这再次允许高交互性,但只要用户暂停一两秒钟,显示就会以高质量填充。
    【解决方案2】:

    这可能不是您要寻找的答案,但请考虑完全不使用 GDI+。我最近不得不重写 2D-CAM 应用程序的渲染堆栈,最重要的要求是快速获得良好的抗锯齿线(抗锯齿是促使我们重写现有 GDI 渲染器的原因)。

    以下是我在渲染 200 个项目时得到的一些结果(每个项目本身都是一些线条和填充形状的小标记)。这些是帧速率(在 Windows 7 上),所以越高越好:

    200 项: GDI=51,GDI+=20,D2D=59,WPF=33,GL=59。

    (D2D 是 Direct2D,GL 是 OpenGL)。您已经可以看到 GDI+ 落后了。 WPF 作为保留模式 API 可能存在缺陷,但 OpenGL 也是双缓冲的,并且看起来同样流畅。

    在 1000 项时,差异更加明显:

    GDI=23,GDI+=5,D2D=17,WPF=2,GL=40。

    没错,WPF 现在已经下降到 2 FPS,而 GDI+ 正在以 5 FPS 爬行。所以考虑D2D,或者干脆回到OpenGL。这就是我们现在使用的,并且在重写 3 个月后,我认为我们做出了正确的选择。编程模型本身比 D2D 看起来要干净得多。

    请注意,我们使用的 WPF 渲染是高度优化的;没有回调,没有事件,没有绑定。我们只是得到一个 DrawingContext 并使用最低级别的图元在每一帧上绘制所有内容,因此没有事件开销。

    如果您有兴趣,请告诉我,我可以将我使用的测试套件发送给您,以便您随意摆弄。

    (我可能会避开 GDI+ 的一个原因是它不太可能被硬件加速)。

    【讨论】:

    • Tarydon,恐怕这不再是一个选择。我已经在这个 GUI 上工作了 2 年多了,其中大部分时间都花在了编写 GDI+ 代码上。尽管我见过帧速率低于 10 fps 的情况,但在 95% 的情况下它相当快。最近我一直在分析代码,并发现了一些有趣的(即意想不到的)瓶颈,但我希望这项工作已经由其他人完成。不过,+1 试图帮助我。谢谢。
    • 我对 Win7 感到困惑,我认为 GDI 是这个平台上 100% 的软件。但是当我看到你的数字甚至 D2D 比 GDI 更慢时,我想知道 MSDN 标记消息之外的真相是什么。我目前仅将 GDI 用于图像加载/保存代码。
    • @Lothar 显然他没有正确使用 D2D。
    • 像板载这样的最便宜的卡在 opengl .GMA950 等上很糟糕
    猜你喜欢
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多