High color 使用16位表示颜色时,红绿蓝三个通道,每个至少可以分到5位,表示32个级别的值。剩余1位,通常会用来加在绿色通道中,因为人眼对绿色是最敏感的,对亮度的贡献度最高。High color 相对 true color 和 deep color 有很大的速度优势,因为每像素2字节对于计算机是非常友好的,访问速度会非常快。但是现在 high color 已经非常少见,因为如果每通道只有32或64个级别,那么相邻的颜色级别很容易被区分。这个问题也叫做 banding 或 posterization。由于 Mach banding 的心理效应,人类的视觉系统会放大这种差异。通过将相邻的颜色级别进行混合,进行抖动,可以降低这种效应的影响。即使是在24位的显示器上,banding 还是会被注意到,往 framebuffer 中添加噪声可以掩盖这个问题。
长方形从左从左往右,从白色到黑色,共32个级别,形成了 banding。
True color 使用24位表示RGB颜色,每个通道一个字节。在PC系统上,有时候顺序会被翻转成BGR。在计算机内部,true color常常会存储成每像素32位,因为计算机的内存系统通常对4字节的元素访问进行优化。当 true color 使用24位进行保存时,也叫做 packed pixel format。有些时候我们会为RGB通道添加一个A通道,表示 alpha 值,形成RGBA。对于实时渲染来说,通常用24位来表示颜色是足够的。虽然也能看到颜色的 banding,但是相对16位颜色来说要好的多。
Deep color每个通道使用10/12/16位,共30/36/48位表示RGB颜色。如果加上 alpha 通道,就变成 40/48/64 位。HDMI 3.1 支持30/36/48这三种模式,DisplayPort每通道最多可以支持16位。
Color buffer 通常会使用上面我们提到的方式进行压缩和缓存,除此之外,将 color buffer 中的颜色和即待写入的颜色进行混合的过程 blending,将在后面讲到。Blending 通过 raster operation/ROP 单元实现,每个 ROP 通常会连接到一个内存分区上。
四、视频输出控制器/Video Display Controller
每个GPU,都有视频输出控制器/Video Display Controller/VDC,或者叫做 display engine 或 display interface,负责将 color buffer 显示到显示器上。GPU 上有这样的硬件单元,来提供不同的接口,比如说 high-definition multimedia interface (HDMI)、DisplayPort、digital visual interface(DVI) 和 video graphics array (VGA)。即将进行显示的 color buffer 可能是位于可供 CPU 访问的内存中,也可能是位于 GPU 的显存中。每个接口都会使用相应的标准协议传输 color buffer,时间信息,甚至音频信息。VDC 也可能进行一些图形缩放、降噪和多图形源组合等功能。
显示器的图像刷新频率通常在 60Hz~144Hz之间,叫做垂直刷新率/vertical refresh rate。当屏幕刷新率低于 72Hz 时,人眼就能感受到闪烁。
近些年来,显示器技术在刷新率、每通道位数、色域和同步方面都有进步。显示器刷新率一般都是60Hz,现在120Hz的屏幕也越来越常见,甚至最高能达到600Hz。对于高刷新率,一张图形通常会显示多次,有些时候会插入一些纯黑色的帧,来最小化帧间移动时导致的模糊。相对于每通道8位的表示,现代的HDR显示器每通道可以使用10位或者更多。Dolby 的HDR显示器技术,会使用LED组来增强LCD显示器。这样可以是显示器获得 10倍的亮度和100倍的对比度。带有更大色域的显示器也越来越多,可以显示更多的颜色,更加生动的图像。
为了降低撕裂效果,厂商也开发出一些自适应的同步技术,像AMD的FreeSync和NVIDIA的G-sync。
五、单缓冲,双缓冲和三缓冲/Single, Double, and Triple Buffering
假设现在我们只有一个buffer,表示当前需要显示到显示器上的内容。当一帧中的三角形被绘制时,会随着显示器的刷新,逐渐一点点出现,这种效果是很奇怪的。即使我们的帧率和显示器刷新率相等,single buffer 还是会有问题。如果我们决定清除 buffer 然后绘制一个较大的三角形,因为VDC 会将正在绘制的color buffer区域输出,我们就会短暂地看到 color buffer的变化。这种现象叫做撕裂/tearing,画面显示看起来被分割成了两部分。在一些像Amiga 的古老系统中,你可以通过检测 Beam来防止画面撕裂,这样single buffering就是可行的。现在只有在一些 VR系统中才会用到这种 single bugger渲染架构,会使用 beam 方式来尽可能降低延迟。
目前最常用的消除撕裂的方式是使用 double buffering。一个渲染完成的图像在 front buffer 中显示,同时不可见的的 back buffer 在被绘制。当back buffer 中的图像被传输到显示器后,图形驱动会 swap front buffer 和 back buffer,来避免撕裂。Swap的过程通常都是简单地交换两个 color buffer的指针。对于 CRT 显示器,这个事件叫做 vertical retrace,整个过程叫做 vertical synchronization / Vsync / 垂直同步。虽然LCD 显示器没有 beam 的 retace,但是我们使用相同的术语来表示显示器中的交换过程。
如果渲染过程完成后,立即交换 back buffer 和 front buffer,可以最大化帧率,这样可以用来测试渲染系统的性能。但是这样其实是没有跟随 vsync 来进行更新的,同样会造成撕裂。不过因为两个buffer 都是渲染好的完整图像,撕裂效果不会像 single buffer 中那样糟糕。