GDI +表现技巧

时间:2009-11-06 21:02:40

标签: .net performance gdi system.drawing

有没有人知道讨论GDI +性能的任何可靠的(有希望的,广泛的)书籍/网站(超出明显的范围)?

例如,我最近遇到了this excellent experiment。我最近也注意到Graphics.FillPath()Graphics.DrawPath()更快。我很想知道我缺少的其他重要信息。

好感, 大卫

2 个答案:

答案 0 :(得分:19)

嗯。如果您需要绘制路径的轮廓,那么知道FillPath比DrawPath更快是没有收获的!

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

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

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

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

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

答案 1 :(得分:10)

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