System.Drawing对我们想做的事情来说太慢了吗?

时间:2010-11-10 19:28:02

标签: c# gdi+ system.drawing

我目前正在开发win表单应用程序的用户界面。主窗口是无边框形式,其表面区域几乎完全在Form.Paint事件中呈现。创建一个后台缓冲区并按常规绘制:

private void form_Paint(object sender, PaintEventArgs e) {
  e.Graphics.DrawImage(BackBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}

后缓冲区的某些区域在各种条件下重绘;鼠标悬停效应很常见。仔细重绘的类只会使适用的区域无效。尽管如此,只需在表格上滑动鼠标就足以将高端CPU驱动到> 50%的使用时间为几秒钟。

我已经分析了应用程序,并且在上面调用DrawImage时,超过80%的CPU时间被烧毁。我知道GDI +很慢并且没有(很少?)使用GPU ...而应用程序的目标平台并不能保证GPU不会首先集成。但我不知道这是不是很糟糕。

我是否应该面对这样一个事实:GDI +对于我们希望做的事情来说还不够快,或者仍然有机会改进代码?

-edit -

BackBuffer表示在系统启动期间创建的位图。它的大小与屏幕分辨率相匹配。在诸如鼠标悬停和点击之类的各种事件期间,在其上绘制了各种区域。它的创建非常简单:

this.BufferBmp = new Bitmap(screenWidth, screenHeight);
this.Gfx = Graphics.FromImage(BufferBmp);

Gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;

3 个答案:

答案 0 :(得分:3)

如果你对待它,GDI +可以非常好地表现。我建议使用类似RedGate's Ants的内容来分析绘图代码,但是您可以通过其他几个经验法则来提高性能:

  • 使用在OnDraw事件中传递的Graphics对象,不要创建自己的
  • 使用剪裁区域最小化需要重绘的区域
  • 在类范围内创建绘图对象,如画笔,字体和笔(不要每次都重新创建)
  • 避免使用源自OnDraw方法的太多方法调用
  • 在绘图阶段避免过多的对象创建
  • Try / catch块会影响性能
  • 可以使用GDI而不是GDI +(参见下面的链接)

此外,还可以选择使用BitBlt。请点击此处查看similar question and solution

答案 1 :(得分:3)

创建自己的“后台缓冲区”而不是使用内置的双缓冲支持很难获得高效率。重要的是伟大的交易是缓冲区的像素格式。在大多数现代机器上,无论如何,我尝试的任何一种机器,32bppPArgb格式都是十倍的速度。支持内置的双缓冲支持,以实现卓越的性能。

另一种可能的损失是您尝试保持裁剪区域尽可能小。当区域变得复杂时,这可以字节。如果你让快速鼠标移动产生小的矩形更新区域,听起来就像你那么接近。当绘画落后时,它几乎总是会因为鼠标获得更高的优先级,你可以建立一个非常复杂的小矩形链。首先通过使整个区域无效来测试它。接下来的方法是自己扩展区域,始终保持一个矩形。在OnPaint运行时重置。

答案 2 :(得分:1)

我认为你想要创建一个继承自Form的新类,然后在OnPaint方法中进行绘制,而不是从表单中监听Paint事件。 / p>