在Win7 x64上使用DrawText表现不佳

时间:2010-11-25 20:54:06

标签: c++ windows performance mfc

我注意到在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毫秒。 (注意为了跟上60Hz的监视器,你需要大约16ms来渲染每次更新。)

我尝试进行一些更改以改善效果:

  • 删除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调用的糟糕表现?

5 个答案:

答案 0 :(得分:7)

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

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

干杯&第h。,

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

为了打破单词分隔符上的文本,DrawText需要反复尝试获取文本块的宽度以查看它是否合适,然后取余数并完成。它需要在每次通话时都这样做。如果您的文本不变,这是一个不必要的开销。作为解决方法,您可以自己测量文本并插入临时换行符并删除DT_WORDBREAK标志。

答案 4 :(得分:0)

你考虑过Direct2D / DirectWrite吗?

无论如何,如果您只是将文本绘制到自己的内存中,并且将每次迭代绘制到任何想要的DC上,那么它应该会更好。