当前位置:C++技术网 > 精选软件 > 绘图技术的闪烁原因探究6:绘图技术探究补充进阶分析

绘图技术的闪烁原因探究6:绘图技术探究补充进阶分析

更新时间:2016-05-05 13:30:39浏览次数:1+次

    我在《绘图技术的闪烁原因探究》系列文章(在C++技术网的搜索框中输入标题即可搜索到)中,分析了绘图的基本原理,可以说是入门级的分析。但是鉴于完整细致的分析,让初学者更好的入门,所以以多篇形式展开。平心而论,这系列文章并没有很深入,但是对于初学者确实有一定的引导的。当然,也是抛准引玉,毕竟我不是专门从事绘图方面的开发(游戏开发或UI开发),所以研究的不深。不过研究多少也都分享出来了。相信对于初学者学习绘图技术有一定的作用的。不过要进一步学习,还需要学习大量的资料,我这系列文章只是帮你打开一扇门而已。
    文章推送到微信公众号cpp_coder后,有一个朋友仔细阅读了,并给出了详细的专业的回答,看的出来朋友功底之深厚,我也细细拜读了,特此原文引用发布出来,供大家进一步学习了解绘图技术。当然,技术无止境,以下的内容也不是绘图技术的全部,也是作为进一步的引导,给读者一个继续学习的方向。

朋友【tearshark】补充的原文:

    闪烁的原因关键在于 垂直同步 (点击左边链接查看垂直同步概念)。无论是crt显示器还是液晶显示器,绘制一次图像都不是0秒完成的,大都需要16毫秒,这也是大部分显示器刷新率是60的原因。如果在显示器刷新过程中,程序更改了显示内容,导致的结果就是图像撕裂。如果程序在多帧绘制时间内才完成绘制,因为图像被反复覆盖,表现出来就是闪烁。

    解决这个问题的根本在于,必须在两次绘制的非常短小的时间间隔内,完成绘制。显然这个时间是不够正常绘制的。怎么办呢?
    方案就是采用双缓存,程序绘制的内存与显示器显示的内存不是同一个。程序绘制完成后,在垂直同步时间内,即显示器绘制两帧的间隙内,完成图像数据的传送。这个传送通过硬件支持,做成了两块内存的指针交换,而不是内存拷贝,可以说是瞬间完成了。程序的绘制也可以跨越多帧时间了,绘制完成了,而显示器还在绘制的话,通常程序就只能等待显示器绘制完成,即垂直同步时间到来,然后再提交绘制内容。这样一来,程序绘制无论多慢,都不会闪烁了。

    为什么说通常程序只能等待垂直同步呢?没用更好的办法吗?
    为了消除等待垂直同步的时间,程序可以再开辟第三块内存立马进行绘制,绘制到垂直同步时间到来的时候,将之前已经绘制完成的内容,即第二块内存提交给显示器,然后继续绘制第三块。第三块绘制完成后,立刻拿第一块内存进行绘制,在下一个垂直同步时间内,提交第三块的内容。这就是三缓冲的来由。可以极大的降低程序等待垂直同步浪费的时间。

    依次类推,那可不可以做四缓冲五缓冲呢?是不是缓冲越多越好呢?
    即便在现在内存白菜价的今天,缓冲也不是越多越好。
    首先,三缓冲已经能很好的消除程序等待垂直同步浪费的时间了,再多提升的效率很小,无意义。
    其次,缓冲越多,则绘制完成时间与真正显示的时间,间隔也越久。用通俗的话说,就是延迟时间越长。这对于激烈的fps,act类游戏来说是致命的。这也是职业玩家会使用高刷新率的显示器的原因,或者干脆关闭垂直同步,以图像撕裂的代价换取更低的延迟。其实还有另外的原因,导致需要三缓冲。猜猜是什么?
    其实现在的3D游戏,其渲染流水线非常深,深到一定程度,以至于一次绘制,从完整提交数据到最后渲染出来,可能跨越了一帧的时间。而提交数据花费的时间却小于一帧的时间。那这个时候也需要三缓冲甚至四缓冲,来消除程序等待显卡完成整个流水线的时间。这时就不是程序等待显示器垂直同步时间了。
    回头把这系列文章看了看,现象说了不少,代码也写了不少,就是没有说到关键点上。无论你绘制多块,多少个缓冲,只要提交数据不是在垂直同步的时间间隔内完成,都会有画面撕裂甚至闪烁。

    非常感谢tearshark的补充,收益匪浅。我相信,其他读者也会因此收益。如果要深入了解绘图技术,有一段路要走,我们这系列的文章,只是提供绘图技术的基本的应用,更多技术细节,希望有更多人来分享。