【问题标题】:Poor performance with DrawText on Win7 x64在 Win7 x64 上使用 DrawText 时性能不佳
【发布时间】:2011-05-15 21:53:21
【问题描述】:

我注意到在我正在开发的一个 MFC 应用程序中,当拖动滚动条以平滑地向下滚动文档时,当屏幕上显示一个包含大约一段文本的块时,帧速率会下降到断断续续的水平,但当它是丝滑的时候屏幕外。调查性能,我发现单个CDC::DrawText调用了负责文本的段落。这是一个优化的发布版本。

我使用QueryPerformanceCounter 获得了只是 DrawText 调用的高分辨率测量值,如下所示:

QueryPerformanceCounter(...);
pDC->DrawText(some_cstring, some_crect, DT_WORDBREAK);
QueryPerformanceCounter(...);

文本是 unicode,lorem-ipsum 样式填充符,865 个字符长,并在给定矩形和字体(Segoe UI,lfHeight = -12,标准正文文本大小)的情况下环绕 7 位行.根据我的测量,该调用单独平均需要 7.5 毫秒,奇数峰值为 21 毫秒。 (请注意,要跟上 60Hz 的显示器,每次更新需要大约 16 毫秒的时间来渲染。)

我尝试进行一些更改以提高性能:

  • 删除DT_WORDBREAK 可将性能提高到大约 1 毫秒(大约快 7 倍),但考虑到只有一行文本出现在屏幕上,并且有超过 7 行断字,这似乎表明我的瓶颈在别处。
  • 我在透明模式下绘制文本 (SetBkMode(TRANSPARENT))。所以我尝试了使用纯色背景填充的不透明模式。没有改善。
  • 我认为 ClearType 渲染可能是罪魁祸首。我将字体lfQualityCLEARTYPE_QUALITY 更改为NONANTIALIASED_QUALITY。它看起来像废话,边缘很锋利,没有任何改进。
  • 根据评论建议,我使用的是 CMemDC,但我摆脱了它并直接绘图。它像疯了一样闪烁,没有任何改善。

这是在配备 Intel Core 2 Duo P8400 @ 2.26 GHz 和 4 GB RAM 的 Windows 7 64 位笔记本电脑上运行的 - 我认为它不算是慢速系统。

我每次绘制时都会调用 DrawText(),这显然会影响性能如此缓慢的函数,尤其是当其中几个文本块同时可见时。这足以让体验变得迟缓。然而,Firefox 可以在 ClearType 中呈现这样的页面,其中包含更多文本,并且似乎处理得很好。我究竟做错了什么?如何解决实际 DrawText 调用的性能不佳问题?

【问题讨论】:

  • 如果更改硬件加速会发生什么?
  • 认为在 Win7 上使用老式 GDI(我认为是 MFC 内部使用)的方式根本不好。我的建议是转向 GDI+ 方式。 (msdn.microsoft.com/en-us/library/ms535991(v=VS.85).aspx)。您可以尝试告诉我们结果。
  • @Keynslug 我严重怀疑 GDI+ 会更好,因为它完全用软件实现,并且一次又一次地表明,它慢得要命。我的建议是更多地研究 Direct2D。那可能会更好。
  • 你为什么要每帧都渲染字符串?内存 DC 建议意味着将文本一次渲染到内存 DC,然后每帧一次 blit。

标签: c++ windows performance mfc


【解决方案1】:

每次刷新都绘制文本是浪费。使用双缓冲,即在屏幕外绘制位图,然后将其blit 到屏幕上。然后,对于滚动,只需根据需要向上或向下或横向复制大部分位图,然后仅绘制无效区域(在将结果blitting 到屏幕之前)。

如果结果太慢,请将绘制的文本也保留在屏幕外位图中,并使用 blit 而不是绘制。

干杯,

【讨论】:

    【解决方案2】:

    根据this german blogpost,问题与对亚洲语言字体的支持有关。如果您在 XP 中启用它们,您将获得相同的性能命中。在 Vista/7 中,它们是默认启用的,您不能将它们关闭。

    编辑:也许,使用不同的字体可能会有所帮助..(不包含亚洲字符的字体)。

    【讨论】:

    • 博客文章似乎是指使用 DT_CALCRECT 标志,它实际上并没有呈现任何文本 - 我说的是呈现。仅供参考,当我使用 DT_CALCRECT 时,它似乎快了大约 7 倍 - 因此,正如预期的那样,渲染比计算范围慢得多。另外,如果我能保持最好的国际支持,我会更愿意!
    • @AshelysBrain:是的,情况不同。但是您可以轻松测试根本原因是否相同。如果您在 XP 机器上启用这两个复选框,并运行您的测试代码,它对性能有何影响?
    【解决方案3】:

    用户无法在 7 毫秒内阅读 7 行文本,因此调用本身已经足够快了。

    显示器的 60 Hz 刷新率完全无关紧要。您不需要为每一帧重新渲染相同的文本。视频卡会很高兴地再次将相同的像素发送到屏幕。

    所以,我认为您还有另一个问题。您是否想知道滚动文本?请询问您真正遇到的问题,而不是假设 DrawText 是罪魁祸首。

    【讨论】:

    • 啊,对。我有一种感觉,你有一个 XY 问题。所以,是的,DrawText 实际上已经足够快了。但是你不应该仅仅因为它现在需要在屏幕上低几个像素就重新渲染文本。在不同的偏移量处重新使用(未修改的!)CMemDC,并为新可见的部分添加额外的 CMemDC 应该可以解决问题。这条评论有点小,无法涵盖所有​​细节。
    【解决方案4】:

    为了在分词时分断文本,DrawText 需要反复尝试获取文本块的宽度,看是否适合,然后将剩余部分重新做一遍。它需要在每次通话时执行此操作。如果您的文本不变,这是不必要的开销。作为一种解决方法,您可以自己测量文本并插入临时换行符并删除 DT_WORDBREAK 标志。

    【讨论】:

      【解决方案5】:

      你考虑过 Direct2D/DirectWrite 吗?

      无论如何,如果您只将文本绘制一次到它自己的 mem dc 并将其传送到您希望在每次迭代中绘制的任何 dc 上,它应该会更好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-13
        • 1970-01-01
        • 2013-01-07
        • 2013-04-11
        • 2012-08-15
        • 2012-02-11
        • 1970-01-01
        相关资源
        最近更新 更多