为什么GUI代码的计算成本如此之高?

时间:2009-02-02 07:57:39

标签: user-interface language-agnostic

所有Stackoverflowers,

我想知道为什么GUI代码负责吸走很多很多cpu周期。原则上,图形渲染远没有Doom复杂(尽管大多数企业GUI会引入大量的橱窗装饰)。事件处理层看起来也是一个沉重的代价,但是,一个编写良好的实现似乎应该在具有大量内存/缓存的现代处理器上有效地在上下文之间切换。

如果有人在他们的大型GUI应用程序或常见API本身上运行了一个分析器,我对瓶颈所在的位置感兴趣。

可能的解释(我想象)可能是:

  1. 硬件和应用程序界面之间的高级抽象
  2. 很多级别的间接到正确的代码来执行
  3. 低优先级(与其他流程相比)
  4. 行为不当的应用程序充斥着API
  5. 过多的物体定位?
  6. 在API中完成糟糕的设计选择(不仅仅是问题,还有设计理念)
  7. 有些GUI框架比其他框架要好得多,所以我希望听到不同的观点。例如,Unix / X11系统与Windows有很大不同,甚至比WinForms还要多。

    编辑:现在是社区维基 - 去吧。我还有一件事要补充 - 我是学校里的算法人员,如果GUI代码中的算法效率低下,他们会感兴趣。然后,它可能只是实现开销。

5 个答案:

答案 0 :(得分:9)

我一般不知道,但我想在你的列表中添加另一个项目 - 字体渲染和计算。查找字体中的矢量字形并将其转换为具有抗锯齿功能的位图表示并非易事。通常需要完成两次 - 首先计算文本的宽度/高度以进行定位,然后实际在正确的坐标处绘制文本。

此外,今天的大多数绘图代码依赖于剪切机制来仅更新GUI的一部分。因此,如果只需要重绘一个部分,代码实际上会在幕后重绘整个窗口,然后只需要实际更新所需的部分。

<强>加了:

在评论中我发现了这个:

  

我对此也很感兴趣。不能仅使用cpu渲染gui,因为如果你的gfx-card没有合适的驱动程序,桌面图形会让难以置信慢。如果你有gfx驱动程序,那么desktop-gfx有点快,但从来没有像directx / opengl应用程序那么快。

这是我理解的交易:今天的每张显卡都支持绘图的通用界面。我不确定它是否被称为“VESA”,“SVGA”,或者它们是否只是过去的旧名称。无论如何,这个界面涉及通过中断做所有事情。对于每个像素,都有一个中断调用。或类似的东西。然而,正确的VGA驱动程序能够利用DMA和其他增强功能,使整个过程不会占用大量CPU资源。

已添加2:啊,对于OpenGL / DirectX - 这是今天显卡的另一个功能。它们针对独占模式下的3D操作进行了优化。这就是速度的原因。普通的GUI只使用基本的2D绘图程序。因此,每次想要更新时,它都会发送整个屏幕的内容。然而,3D应用程序会将一堆纹理和三角形定义发送到VRAM(视频RAM),然后重复使用它们进行绘制。他们只是说“把纹理设置#25的三角形设置#38并绘制它们”。所有这些东西都缓存在VRAM中,所以这又快了。

我不确定,但我怀疑现代的3D加速GUI(Vista Aero,Linux上的compiz等)也可能会利用这一点。他们可以预先向VGA发送公共位图,然后直接从VRAM重复使用它们。但是,任何应用程序绘制的表面仍然需要每次都直接发送以进行更新。

已添加3:更多想法。 :)适用于Windows,Linux等的现代GUI是面向窗口小部件(面向Windows的扬声器控制)。这个问题是每个小部件都有自己的绘图代码和相关的绘图表面(或多或少)。当窗口需要重新绘制时,它会调用其所有子窗口小部件的绘图代码,这些子窗口小部件又调用其子窗口小部件的绘图代码等。每个窗口小部件重绘其整个表面,即使其中一些被遮挡通过其他小部件。利用上述剪辑技术,立即丢弃这些绘制信息中的一些以减少闪烁和其他伪像。但仍然有很多手动绘图代码,包括位图blitting,拉伸,倾斜,绘制线条,文本,填充等等。所有这些都转化为一系列putpixel调用,通过剪切滤镜/掩码和其他过滤东西。啊,是的,阿尔法混合今天也变得流行,效果更好,这意味着更多的工作。所以......是的,你可以说这是因为大量的抽象和间接。但是......你真的可以做得更好吗?我不这么认为。只有3D技术可能有所帮助,因为它们利用GPU进行alpha计算和裁剪。

答案 1 :(得分:5)

让我们首先说编写库比编写独立代码要困难得多。要求您的抽象可以在尽可能多的上下文中重用,包括您尚未使用的上下文,这使得该任务即使对于有经验的程序员也具有挑战性。

在库中,编写GUI工具包库是一个着名的难题。这是因为使用GUI库的程序范围很广,需求量非常大。 Mr Why和Martin DeMollo discussed the requirements placed of GUI libraries不久前。

编写GUI小部件本身很困难,因为计算机用户对界面行为的细节非常敏感。非原生小部件永远不会感觉对不对,不是吗?为了使非原生小部件正确 - 为了使任何小部件正确 - 事实上 - 你需要花费大量时间来调整行为的细节。

因此,由于用于创建高度可重用组件的抽象机制所带来的效率低下,GUI很慢,这增加了优化代码所用的时间短暂,因此花费了大量时间才能使行为正常。< / p>

答案 2 :(得分:2)

嗯,这是非常多的。

最简单但可能很明显的答案是这些GUI应用程序背后的程序员是非常糟糕的程序员。您可以编写代码来完成最奇怪的事情并且会更快但很少有人关心如何做到这一点,或者他们认为这是一个昂贵的非盈利时间浪费的努力。

为GPU设置直接卸载计算并不一定能解决任何问题。 GPU就像CPU一样,除了它不那么通用,而且更像数据并行处理器。它可以非常好地进行图形计算。无论你有什么图形API /操作系统和驱动程序组合都没那么重要......好吧,以Vista为例,他们改变了桌面组合引擎。这个引擎只是更好地堆肥,而且由于GUI应用程序的重要瓶颈是重绘,这是一个简洁的优化策略。这种虚拟化计算需求的想法,每次只更新最小的变化。

Win32在需要重绘时向窗口发送WM_PAINT消息,这可能是因为窗口相互遮挡的结果。然而,它取决于窗口本身,以确定实际改变了什么。不仅如此,没有任何改变,或者所做的改变是微不足道的,所以它可能只是在你最顶级的表面上进行了预测。

这种图形处理今天不一定存在。我会说,人们已经避免编写真正高效且虚拟化的渲染解决方案,因为收益/成本比率相当低/高(差)。

Windows Presentation Foundation(WPF)所做的事情,我认为它远远优于大多数其他GUI API,它将布局更新和渲染更新分成两个单独的过程。虽然WPF是托管代码,但渲染引擎却不是。渲染的结果是托管的WPF渲染引擎构建了一个命令队列(这是DirectX和OpenGL所做的),然后将其传递给本机渲染引擎。这里更优雅的是,WPF将尝试保留任何不会改变视觉状态的计算。如果可能的话,你可以避免昂贵的渲染调用,而不需要渲染(虚拟化)。

与告诉Win32窗口重绘自身的WM_PAINT相比,WPF应用程序会检查该窗口的哪些部分需要重新绘制,并且只重绘最小的更改。

现在WPF不是至高无上的,它是微软的坚定努力,但它不是圣杯......运行管道的代码仍然可以改进,任何托管应用程序的内存占用量仍然超过我想要的。但我希望这是你正在寻找的那种答案。

WPF能够异步做一些相当不错的事情,如果你想做一个真正响应的低延迟/低CPU的用户界面,这是一个很大的问题。异步操作不仅仅是在不同的线程上卸载工作。

总结一下,缓慢而昂贵的图形用户界面意味着过多的重新涂漆和重新涂漆的种类非常昂贵,即整个表面区域。

答案 3 :(得分:0)

我在某种程度上取决于语言。您可能已经注意到Java和RealBasic应用程序比它们基于C语言(C ++,C#,Objective-C)的应用程序慢一点。

然而,GUI应用程序比命令行应用程序复杂得多。终端窗口只需要绘制一个不支持按钮的简单窗口。

还有多个循环用于额外的输入和功能。

答案 4 :(得分:0)

我认为你可以在“窗口系统设计中找到一些有趣的想法:如果我在2002年再做一次”,由James Gosling(Java家伙,也因他在X11前窗口工作而闻名)系统)。在线提供here[pdf]

这篇文章侧重于积极的一面(如何让它变得快速),而不是消极的一面(是什么让它变慢),但它仍然是一个很好的阅读主题。