代码之家  ›  专栏  ›  技术社区  ›  AshleysBrain

Win7 x64上的DrawText性能不佳

  •  8
  • AshleysBrain  · 技术社区  · 14 年前

    我注意到在我开发的MFC应用程序中,当拖动滚动条以平滑地向下滚动文档时,当屏幕上有一个包含大约一段文本的块时,帧速率会下降到不稳定的水平,而当它在屏幕外时,则会变得平滑。在调查表演时,我发现 CDC::DrawText 要求对该段文字负责。这是一个优化的发布版本。

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

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

    文本是unicode,lorem ipsum样式的填充,865个字符长,在给定矩形和字体的7位和1位行上换行(Segoe UI, lfHeight =-12,标准正文文本大小)。从我的测量来看 单独地 平均需要7.5毫秒,奇数峰值为21毫秒(注意,要跟上60赫兹的监视器,每次更新大约需要16毫秒)

    我试着做一些改变来提高性能:

    • 移除 DT_WORDBREAK 将性能提高到大约1毫秒(大约快7倍),但考虑到只有一行文本进入屏幕,并且只有7行多的文本出现断字,这似乎表明瓶颈在其他地方。
    • 我在透明模式下绘制文本( SetBkMode(TRANSPARENT) ). 所以我尝试了不透明模式和一个坚实的背景填充。没有进步。
    • 我认为ClearType渲染可能是罪魁祸首。我改了字体 lfQuality CLEARTYPE_QUALITY NONANTIALIASED_QUALITY . 它看起来像是有锋利边缘的垃圾,没有任何改进。
    • 根据一个评论建议,我使用的是CMemDC,但我摆脱了它,并做了直接绘图。它像疯了一样忽闪忽闪,没有进步。

    这是在一台Windows7 64位笔记本电脑上运行的,带有英特尔酷睿2双核P8400@2.26GHz和4GB内存——我不认为这算是一个慢系统。

    每次绘制时我都会调用DrawText(),这显然会影响函数的性能,特别是在同时可以看到其中几个文本块的情况下。这足以让你的体验变得迟钝。然而,Firefox可以在ClearType中呈现这样一个页面,它有更多的文本,并且看起来处理得很好。我做错什么了?我怎样才能避免实际的DrawText调用的糟糕性能?

    5 回复  |  直到 14 年前
        1
  •  7
  •   Cheers and hth. - Alf    14 年前

    每次刷新时绘制文本都是浪费。使用 双缓冲 ,也就是说,绘制一个屏幕外的位图,然后将其快速显示到屏幕上。然后,对于滚动,只需在必要时向上或向下或侧向复制大部分位图,然后只绘制无效区域(在将结果块化到屏幕之前)。

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

    干杯。,

        2
  •  2
  •   user180326user180326    14 年前

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

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

        3
  •  2
  •   MSalters    14 年前

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

    显示器的60赫兹刷新率完全不相关。不需要为每个帧重新呈现相同的文本。显卡会很高兴再次将相同的像素发送到屏幕上。

    所以,我觉得你还有一个问题。你想知道滚动文本吗?请问一下你真正遇到的问题,而不是假设DrawText是罪魁祸首。

        4
  •  1
  •   Mark Ransom    14 年前

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

        5
  •  0
  •   Rune Aamodt    14 年前

    你考虑过Direct2D/DirectWrite吗?

    不管怎样,如果你只将文本绘制一次到它自己的mem-dc,然后将其blit到每次迭代时你希望它绘制的任何dc上,它应该会工作得更好。