Direct3D补充篇:表面缓冲区技术实现动画的流畅显示

本篇讲的是我们开始一些工程之前所需要掌握了解的东西。只要是补充篇基本都不涉及代码,只是对某些重要属性的分析和基础的普及。我会从多个方面去引入,刚入门的同学也能看明白。

表面缓冲区是Direct3D中比较重要的一部分,在代码学习之前很有必要先了解一下。
1、2部分是为了入门的同学准备的,如果已经理解了为什么要设置表面缓冲区,也可以跳过直接看3、4部分


一、屏幕刷新率和FPS

这两个词汇对于游戏爱好者来说不会陌生,FPS是Frames Per Second的缩写,意味着在运行一个游戏的时候每秒显示的帧数,假设游戏运行在50帧/秒的情况下,那么显示器每秒会呈现给我们50幅图像,被人眼捕获后,得到物体“运动”的感觉,当帧率提高到80帧/秒时,每秒呈现的画面数增多,游戏看起来运行的也更加流畅。在屏幕分辨率以及游戏场景的处理复杂度不变的情况下,FPS的值越高那么我们认为该显卡的处理性能越高,也就是我们常说的,电脑的“配置”很高(当然“配置”也不仅仅是通过显卡来衡量的)
这是比较简单的情况,我们设想显卡就是一个“画师”,越娴熟的“画师”绘制同一幅画的时间就越短,那么每秒绘制的“画”当然也越多。
既然每秒绘制的“画”的数量越多越好,我们就尽量提高它,提高到什么程度呢?100?1000?或者10000?

显然这并不现实,在提高到某个数量后,问题就出现了。

这时我们需要引入另一个词汇,屏幕刷新率,这是一项衡量显示器性能的指标,它的单位也是帧/秒,不过这是显示器每秒能绘制的图像的数量,它受制于显示器与电脑通信的带宽和显示器自身的性能。现在假设显卡在一秒内处理了100幅图像,然后准备按次序把它们交给显示器去显示,但是可惜的是显示器的质量并没有那么好,它一秒只能刷新80幅图像,于是问题就出现了,在显卡0.01秒递交一幅图像的这段时间间隔内,显示器还没来得及完成一幅图像的刷新。换言之,显卡递交下一幅图像时,显示器还在显示上一张图像。

整个过程如下图所示:

Direct3D补充篇:表面缓冲区技术实现动画的流畅显示_第1张图片
我们发现,最后的图像是上一张图像和当前图像的合并,这种画面上半部分是前一帧,下半部分是当前帧的现象,叫做撕裂(tearing)
撕裂的现象在一般情况下不会发生,因为当画面更新不快的时候,前后帧的图其实差不多,只有在第一人称射击等画面高速变换的大型游戏中,画面才会容易产生撕裂


一些画面撕裂的例子:

Direct3D补充篇:表面缓冲区技术实现动画的流畅显示_第2张图片

Direct3D补充篇:表面缓冲区技术实现动画的流畅显示_第3张图片


二、垂直同步

对于画面撕裂,一般会采用垂直同步的方法去避免,当显示器光针从屏幕左上角移动到右下角(即绘制完了一幅图像),光针又会再从右下回扫至左上,对整幅图像做校准以确保画面没有产生撕裂,回扫完毕后,发送信号给电脑,提示“我已经处理完了,现在可以给我下一张图”,这样我们就可以得到一张完整的图。
不过在微软的官方文档中 https://msdn.microsoft.com/en-us/library/windows/desktop/bb206356(v=vs.85).aspx已经说明,垂直同步很慢,因为在光针回扫至左上这段时间内,屏幕不会再接受一张新的图像,这就意味着这段时间内,显卡都不用再产生一幅新图像了,就算产生了屏幕也不会接收。(相当于在做无用功)
可是对于显卡来说,它承担着各种游戏复杂环境的处理任务,所以即使光针回扫这段时间也是很宝贵的,我们要让显卡一直保持工作。

这有点像操作系统中的生产者消费者问题,解决方法也是类似:增加缓冲池。


三、Direct3D中的表面缓冲区

D3D中表面缓冲区(surface)是像素的矩阵,它的高和宽分别是屏幕的宽高像素值,这比较好理解,相当于为一张图开辟了一块存储空间。
而整个缓冲池是由多个表面缓冲区来构成的,在D3D中这样的缓冲池称作交换链(Swap Chain)。
我们把屏幕读取画面信息的那个缓冲区称作前缓冲区(front buffer),它里面存储屏幕将要读取的下一个表面,交换链的其他区域作为后缓冲区(back buffer)。
显卡处理完一幅图像后,直接将该表面存储到后缓冲区中,然后接着生成下一个表面,而不用再等待屏幕去做垂直同步。这种技术同时也让显卡的运行更自由不用再考虑屏幕刷新率。
交换链可以不止一个,在窗口模式下,可以运行多个D3D程序,这种情况下也会有多个交换链。但是全屏模式下,则只能有一个交换链。

PS:表面缓冲区存储的是表面而不是最终的图像,因为还有一个深度缓冲区(关于深度缓冲区以后做介绍),所以称之为“表面”而不是“图像”。


四、不同的交换方法

在屏幕垂直同步期间,D3D设备会更新前缓冲区的内容,让后缓冲区中的表面能移动到前缓冲区中供显示器调用。
在D3D中有多种移动方法可使用:

1.D3DSWAPEFFECT_COPY

这种方法是在回扫时把后缓冲区的数据复制到前缓冲区,确保后缓冲区的数据没有任何变化。一般来说此时交换链只有一个后缓冲区。

2.D3DSWAPEFFECT_FLIP

因为显卡的前缓冲区只是一个指针,所以我们可以直接交换前缓冲区和后缓冲区的指针来达到更新前缓冲区的目的。
当有多个缓冲区时,D3D采用队列的方式,循环改动指针(如下图)
Direct3D补充篇:表面缓冲区技术实现动画的流畅显示_第4张图片


3.D3DSWAPEFFECT_DISCARD

在微软官方的文档中的解释是,在全屏的情况下使用D3DSWAPEFFECT_COPY模式,或者在窗口下,使用D3DSWAPEFFECT_FLIP模式会使得运行效率大大降低,所以使用D3DSWAPEFFECT_DISCARD来让其自动选择最优的模式,但是为什么会发生这种情况则没有给出解释,我的理解是,多个窗口更难做多个队列的指针交换,而比较容易copy,但是只有一个交换链的时候,队列则会更加有效。


参考文献:

关于垂直同步的一些细节,实际上游戏中的“开启垂直同步”选项是指将屏幕刷新一帧的信号送入显卡3D图形处理部分,从而让显卡在生成3D图形时受垂直同步信号的制约。开启垂直同步,在显卡性能极好的条件下,FPS实际上是受到屏幕刷新率制约的,但是画面会更加流畅。而在显卡性能非常低,达不到屏幕刷新率的情况下,打开垂直同步反而会增加显卡的负担。

http://www.dnpz.net/diannaozhishi/1565.html


微软Direct3D官方文档

https://msdn.microsoft.com/en-us/library/windows/desktop/bb206356(v=vs.85).aspx


关于变换效果的解释

http://www.cnblogs.com/lc-cnblong/p/3365031.html


你可能感兴趣的:(Direct3D)