呈现模式

呈现模式可以说是交换链中最重要的设置。它决定了什么条件下图像才会显示到屏幕。Vulkan提供了四种可用的呈现模式:

  • VK_PRESENT_MODE_IMMEDIATE_KHR:应用程序提交的图像会被立即传输到屏幕上,可能会导致撕裂现象。

  • VK_PRESENT_MODE_FIFO_KHR:交换链变成一个先进先出的队列,每次从队列头部取出一张图像进行显示,应用程序渲染的图像提交给交换链后,会被放在队列尾部。当队列为满时,应用程序需要进行等待。这一模式非常类似现在常用的垂直同步。刷新显示的时刻也被叫做垂直回扫。

  • VK_PRESENT_MODE_FIFO_RELAXED_KHR:这一模式和上一模式的唯一区别是,如果应用程序延迟,导致交换链的队列在上一次垂直回扫时为空,那么,如果应用程序在下一次垂直回扫前提交图像,图像会立即被显示。这一模式可能会导致撕裂现象。

  • VK_PRESENT_MODE_MAILBOX_KHR:这一模式是第二种模式的另一个变种。它不会在交换链的队列满时阻塞应用程序,队列中的图像会被直接替换为应用程序新提交的图像。这一模式可以用来实现三倍缓冲,避免撕裂现象的同时减小了延迟问题。

上面四种呈现模式,只有VK_PRESENT_MODE_FIFO_KHR模式保证一定可用,所以我们还需要编写一个函数来查找最佳的可用呈现模式:

VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {
    return VK_PRESENT_MODE_FIFO_KHR;
}

作者个人认为三倍缓冲综合来说表现最佳。三倍缓冲避免了撕裂现象,同时具有较低的延迟。我们检查用于实现三倍缓冲的VK_PRESENT_MODE_MAILBOX_KHR模式是否可用,可用的话,就使用它:

VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {
    for (const auto& availablePresentMode : availablePresentModes) {
        if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
        {
            return availablePresentMode;
        }
    }
    return VK_PRESENT_MODE_FIFO_KHR;
}

不幸的是,目前而言,还有许多驱动程序对VK_PRESENT_MODE_FIFO_KHR呈现模式的支持不够好,所以,如果VK_PRESENT_MODE_MAILBOX_KHR呈现模式不可用,我们应该使用VK_PRESENT_MODE_IMMEDIATE_KHR模式:

VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {
    VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;

    for (const auto& availablePresentMode : availablePresentModes) {
        if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
        {
            return availablePresentMode;
        } else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
            bestMode = availablePresentMode;
        }
    }

    return bestMode;
}