背景
众所周知,Vulkan是个跨平台的图形渲染API,为了友好地支持跨平台,Vulkan自然也抽象出了很多接口层去对接各个操作系统,抹平系统间的差异,Swap Chains即为WSI。
其本质上是一种图像队列,此队列会按顺序依次将队列中的若干图形显示在屏幕上。我们的应用程序需要获得这个队列中的图像,并在此图像中执行绘制操作,绘制完毕以后,将它重新放置到原来的队列中,类似Android的Graphic Buffer Queue。
swap chain 的常规作用是保障图形显示与幕刷新率同步。
Swap Chain Support
Vulkan支持的平台众多,也不是所有的平台都具备将(渲染出来的)图像直接显示在屏幕上的功能,有些以计算为目的应用是不需要把绘制的结果呈现给用户。所以显示相关的API并不是Vulkan核心API的一部分,而是通过扩展(extensions)的方式提供。
因此在查询到当前运行环境对 swap chain 的支持情况之后,你需要明确启用 VK_KHR_swapchain 所代表的设备扩展功能。注意,Vulkan头文件中提供了宏定义 VK_KHR_SWAPCHAIN_EXTENSION_NAME ,它定义了 VK_KHR_swapchain(一种swap chain的实现)。使用这个宏定义的优势在于,编译或(编辑)过程中编译器可以直接检查出拼写错误(如果直接使用字符串 "VK_KHR_swapchain" 则无法让编译器去检查拼写错误)。
Enabling device extensions
启动一个swap chain对象首先要启用 VK_KHR_swapchain 扩展。需要在设备创建过程中开启:
Querying details of swap chain support
前面我们检测了当前设备是否支持swap chain,但由于设备对Vulkan支持的碎片化导致了我们还需要更多的检查才能保证正常的绘制显示。有三种基础属性,我们需要检查:
- 基本的对象能力(swap chain 中图像数量的最大最小值,图像宽或高的最大最小值)
-
表面格式(像素数据格式,色彩空间)
-
显示模式
每个属性都有各自的特点,今天重点分析下显示模式这一方面,其他的后续有机会再详说。
显示模式
显示模式是 swap chain 功能中最核心的特性,也是设计swap chain的初衷,因为它直接关系到图像如何送显。
在OpenGL中当完成对缓冲区的渲染后,需要使用前缓冲区切换图像,可以将渲染好的图像显示在计算机屏幕上。我们只能决定是否在空白间隔显示图像(在启用了垂直同步的情况下)。
在Vulkan中我们不会受限于只能渲染一幅图像(存储在后备缓冲区中的),而且也不会受限于只能在两种显示模式(启用或禁用垂直同步)中进行选择。我们可以在多种显示模式中进行选择,但我们需要在创建交换链的过程中设定该显示模式。
在Vulcan中获取所需场景的显示模式流程如下:
- 调用vkEnumeratePhysicalDevices()函数获取物理句柄
-
获取已创建的显示曲面,将该显示曲面的句柄存储在一个VkSurfaceKHR类型的变量中
-
创建一个VkPresentModeKHR类型的变量,将其命名为desired_present_mode。将想要使用的显示模式存储在这个变量中,用于存储显示模式
-
创建一个uint32_t类型的变量,用于存储设备支持的显示模式。
-
调用vkGetPhysicalDeviceSurfacePresentModesKHR,如果成功则获得该设备支持的显示模式数量
-
创建std::vector<VkPresentModeKHR>,再调vkGetPhysicalDeviceSurfacePresentModesKHR,若返回VK_SUCCESS表示集合里包含了设备支持的显示模式类型
-
匹配需要的显示模式,未匹配则可选用FIFO显示模式,因其是必备选项。
IMMEDIATE
应用提交的图像(数据) 立即被转移到屏幕,因该模式下无缓冲队列,也不会等待Vsync的触发,所以可能会产生显示屏幕中的画面撕裂现象。
FIFO
每个Vulkan API的实现都必须支持FIFO模式。在使用这种模式的情况下,当显示图像时,该图像会被添加到FIFO队列,该队列的长度等于交换链中图像的总数减一。通过使用这种队列,图像能够以与空白时间同步的方式(垂直同步)在计算机屏幕上显示,其被显示的次序永远会与其被添加到队列中的次序相同,刷新显示的时刻叫做"垂直空白"。这种显示模式中不会出现画面撕裂,因为启用了垂直同步功能。这种模式与OpenGL中将交换间隔设置为1的缓冲区交换模式类似。
FIFO Relax
在FIFO上做了修改,当图像的显示时长超过一个vsync周期时,下一个图像不会再等待下一次vsync的到来,而是立刻显示。如果显示速度足够快,就不会出现画面撕裂,但如果我们编写的应用程序的绘图速度低于显示器的刷新频率,就会出现画面撕裂。该行为与OpenGL中EXT_swap_control_tear扩展设置的行为类似。
MAILBOX
可以将其视为三缓冲区显示模式。这种显示模式会使用一个队列,但该队列仅会含有一个元素。该队列中的图像会通过与空白间隔同步的方式在屏幕上显示(在启用了垂直同步的情况下)。但是当应用程序显示图像时,新图像会替换队列中的图像。因此,显示引擎总是会显示最后一个、最新的可用图像,而这种显示模式不会出现画面撕裂。
总结
本文主要分析了Vulkan绘制显示部分的基础架构--swap chain的设计、兼容性,并分析了其中重要的属性-显示模式的各种特性,至于其他的特性后续有机会再分析。我们可以看到Vulkan在显示部分也有更丰富的场景支持和更自由的选择权供应用选择。