查询交换链支持细节

只检查交换链是否可用还不够,交换链可能与我们的窗口表面不兼容。创建交换链所要进行的设置要比Vulkan实例和设备创建多得多,在进行交换链创建之前需要我们查询更多的信息。

有三种最基本的属性,需要我们检查:

  • 基础表面特性(交换链的最小/最大图像数量,最小/最大图像宽度、高度)

  • 表面格式(像素格式,颜色空间)

  • 可用的呈现模式

和findQueueFamilies函数类似,我们使用结构体来存储我们查询得到的交换链细节信息:

struct SwapChainSupportDetails {
    VkSurfaceCapabilitiesKHR capabilities;
    std::vector<VkSurfaceFormatKHR> formats;
    std::vector<VkPresentModeKHR> presentModes;
};

现在,我们添加一个叫做querySwapChainSupport的函数用于填写上面的结构体:

SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
    SwapChainSupportDetails details;

    return details;
}

在本节,我们先介绍如何查询上面的结构体所包含的信息,在下一节再对它们的具体意义进行说明。

我们先查询基础表面特性。这一属性的查询非常简单,调用下面的函数即可:

vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);

这一函数以VkPhysicalDevice对象和VkSurfaceKHR作为参数来查询表面特性。与交换链信息查询有关的函数都需要这两个参数,它们是交换链的核心组件。

下一步,我们查询表面支持的格式。这一查询结果是一个结构体列表,所以它的查询与之前设备特性查询类似,首先查询格式数量,然后分配数组空间查询具体信息:

uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);

if (formatCount != 0) {
    details.formats.resize(formatCount);
    vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}

确保向量的空间足以容纳所有格式结构体。最后,使用与调用vkGetPhysicalDeviceSurfacePresentModesKHR函数同样的方式查询支持的呈现模式:

uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);

if (presentModeCount != 0) {
    details.presentModes.resize(presentModeCount);
    vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
}

现在所有查询得到的信息已经存储在了结构体中,我可以再次扩展isDeviceSuitable函数检测交换链的能力是否满足需求。对于我们的教程而言,我们只需要交换链至少支持一种图像格式和一种支持我们的窗口表面的呈现模式即可:

bool swapChainAdequate = false;
if (extensionsSupported) {
    SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
    swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
}

我们只能在验证交换链扩展可用后查询交换链的细节信息。isDeviceSuitable函数的最后一行需要修改为:

return indices.isComplete() && extensionsSupported && swapChainAdequate;