System.Drawing 对于我们想要做的事情来说是否太慢了?

问题描述 投票:0回答:3

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

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

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

我已经分析了该应用程序,超过 80% 的 CPU 时间都消耗在上面对 DrawImage 的调用上。我知道 GDI+ 很慢并且不使用(很少?)GPU...并且应用程序的目标平台不能保证 GPU 一开始就不会被集成。但我不知道事情会这么糟糕。

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

-编辑-

BackBuffer 代表系统启动时创建的位图。其尺寸与屏幕分辨率相匹配。在各种事件(例如鼠标悬停和单击)期间,会在其上绘制各个区域。它的创建相当简单:

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

Gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
c# gdi+ system.drawing
3个回答
4
投票

创建自己的“后台缓冲区”而不是使用内置的双缓冲支持很难获得高性能。 最重要的是缓冲区的像素格式。 在大多数现代机器上,无论我尝试过什么,32bppPArgb 格式的速度是其他格式的 10 倍。 青睐内置双缓冲支持,以获得卓越的性能。 另一个可能的损失是您尝试使剪切区域尽可能小。 当该地区变得复杂时,这可以字节。 如果让快速的鼠标移动生成小的矩形更新区域,听起来您已经很接近了。 当绘画落后时,几乎总是会落后,因为鼠标具有更高的优先级,您可以构建一个非常复杂的小矩形链。 首先通过使整个区域无效来测试这一点。 下一个方法是自己扩展该区域,始终保持单个矩形。 当 OnPaint 运行时重置它。

如果处理得当,GDI+ 可以具有非常好的性能。我建议使用诸如

RedGate's Ants

4
投票

使用 Graphics

事件中传递的
    OnDraw
  • 对象,不要创建自己的
    使用剪切区域来最小化需要重绘的区域
    在类范围内创建绘图对象,例如画笔、字体和笔(不要每次都重新创建)
  • 避免有太多源自
  • OnDraw
  • 方法的方法调用
  • 避免在绘图阶段创建过多的对象
    Try/catch 块会影响性能
  • 可以使用 GDI 代替 GDI+(参见下面的链接)
  • 此外,还有一个选项可以替代 BitBlt。请参阅此处
  • 类似的问题和解决方案

我认为您想要创建一个继承自

Form

1
投票
OnPaint

方法中进行绘图,而不是监听表单中的

Paint
事件。
    

© www.soinside.com 2019 - 2024. All rights reserved.