4

有谁知道讨论 GDI+ 性能(除了显而易见的)的任何可靠(并且希望是广泛的)书籍/网站吗?

例如,我最近遇到了这个出色的实验。我最近还注意到这Graphics.FillPath()Graphics.DrawPath(). 我很想知道我还缺少哪些其他重要信息。

善意,大卫

4

2 回答 2

21

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

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

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

一旦你完成了所有这些事情,你就可以开始寻找关于优化渲染的书籍。当然,如果它仍然太慢。运行分析器以找出渲染的哪些部分最慢。

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

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

于 2009-12-25T21:13:13.060 回答
11

这可能不是您要寻找的答案,但请考虑完全不使用 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+ 的一个原因是它不太可能被硬件加速)。

于 2009-12-26T04:37:15.563 回答