我注意到,在MFC应用程序中,我正在开发一个拖动滚动条以平滑向下滚动文档的框架,当一个包含一段文本的块显示在屏幕上时,帧率会下降到不连续的水平,但是当它不在屏幕上时,会变得光滑平滑。 调查性能,我发现单一的CDC::DrawText
调用的文本段负责。 这是在一个优化的发布版本。
我使用QueryPerformanceCounter
来获得DrawText调用的高分辨率度量,如下所示:
QueryPerformanceCounter(...); pDC->DrawText(some_cstring, some_crect, DT_WORDBREAK); QueryPerformanceCounter(...);
该文本是unicode,lorem-ipsum样式填充符,长度为865个字符,并在给定矩形和字体(Segoe UI, lfHeight
= -12,标准正文文本大小)的情况下封装了7位和1位的行。 从我的测量结果来看,这个电话平均需要7.5毫秒,21毫秒的单峰。 (注意跟上一个60Hz的显示器,你会得到大约16ms来渲染每个更新。)
我尝试了一些改进来提高性能:
DT_WORDBREAK
提高了大约1ms的性能(快了大约7倍),但是由于只有一行文本正在屏幕上显示,并且有超过7行的文字中断,这似乎暗示了瓶颈在其他地方。 SetBkMode(TRANSPARENT)
)。 所以我尝试了一个不透明的模式,用一个坚实的背景填充。 没提升。 lfQuality
从NONANTIALIASED_QUALITY
更改为NONANTIALIASED_QUALITY
。 它看起来像边缘和边缘的废物,没有任何改善。 这是运行在Windows 7 64位笔记本电脑与英特尔酷睿2双核P8400 @ 2.26 GHz和4 GB内存 – 我不认为这是一个缓慢的系统。
每次绘制时我都会调用DrawText(),这显然会影响性能,这是一个很慢的function,尤其是如果几个文本块可以同时显示的话。 这足以让体验感觉呆滞。 不过,Firefox可以使用更多的文本在ClearType中渲染一个像这样的页面,而且看起来很好。 我究竟做错了什么? 我该如何解决实际的DrawText调用的糟糕performance?
在每次刷新时绘制文本都是浪费的。 使用双缓冲 ,也就是说,绘制一个离屏位图,只是将其投影到屏幕上。 然后,对于滚动,只需要复制大部分位图或根据需要横向,然后只绘制无效区域(在将结果传送到屏幕之前)。
如果结果太慢,请将绘制的文本保存在离屏位图中,然后用blit而不是绘制。
干杯&hth。,
根据这个德国的博文 ,这个问题与支持亚洲语言字体有关。 如果你在XP中启用这些,你会得到同样的perf命中。 在Vista / 7中,它们是默认启用的,不能关闭它们。
编辑:也许,使用不同的字体可能会有所帮助..(一个不包含亚洲字符)。
用户无法在7毫秒内读取7行的文本,因此通话本身速度不够快。
显示器的60 Hz刷新率完全不相关。 您不需要为每个帧重新渲染相同的文本。 视频卡将高兴地再次发送相同的像素到屏幕上。
所以,我想你有另一个问题。 你是否想知道滚动文字? 请问你真的有问题,而不是假设DrawText是罪魁祸首。
为了打破单词分隔的文字,DrawText需要反复尝试获得一个文本块的宽度,看看它是否合适,然后把余下的部分放在一边。 每次通话都需要这样做。 如果你的文本不变,这是一个不必要的开销。 作为解决方法,您可以自行测量文本并插入临时换行符,并删除DT_WORDBREAK标志。
你考虑过Direct2D / DirectWrite吗?
无论如何,它应该更好地工作,如果你只是一次绘制文本到自己的内存直流和blit,直到你想要在每一次迭代绘制任何直流。