检测交换链支持

并不是所有的显卡设备都具有可以直接将图像呈现到屏幕的能力。比如,被设计用于服务器的显卡是没有任何显示输出设备的。此外,由于图像呈现非常依赖窗口系统,以及和窗口系统有关的窗口表面,这些并非Vulkan核心的一部分。使用交换链,我们必须保证VK_KHR_swapchain设备扩展被启用。

为了确保VK_KHR_swapchain设备扩展被设备支持,我们需要扩展VK_KHR_swapchain函数检测该扩展是否被支持。之前,我们已经介绍了列出VkPhysicalDevice对象支持的扩展列表的方法,现在只需要在这个列表中检测是否存在VK_KHR_swapchain扩展即可。Vulkan的头文件提供了一个叫做VK_KHR_SWAPCHAIN_EXTENSION_NAME的宏,它等价于VK_KHR_swapchain。我们使用这个宏来做检测,而不直接使用VK_KHR_swapchain,可以保证代码具有更好的兼容性。

首先,我们定义所需的的设备扩展列表,这类似于我们之前定义的要启用的校验层列表。

const std::vector<const char*> deviceExtensions = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME
};

接着,添加一个叫做checkDeviceExtensionSupport的函数,然后在isDeviceSuitable函数中调用它:

bool isDeviceSuitable(VkPhysicalDevice device) {
    QueueFamilyIndices indices = findQueueFamilies(device);

    bool extensionsSupported = checkDeviceExtensionSupport(device);

    return indices.isComplete() && extensionsSupported;
}

bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
    return true;
}

修改checkDeviceExtensionSupport函数的函数体枚举设备扩展列表,检测所需的扩展是否存在:

bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
    uint32_t extensionCount;
    vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);

    std::vector<VkExtensionProperties> availableExtensions(extensionCount);
    vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());

    std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());

    for (const auto& extension : availableExtensions) {
        requiredExtensions.erase(extension.extensionName);
    }

    return requiredExtensions.empty();
}

在这里,我们将所需的扩展保存在一个集合中,然后枚举所有可用的扩展,将集合中的扩展剔除,最后,如果这个集合中的元素为0,说明我们所需的扩展全部都被满足。实际上,如果设备支持呈现队列,那么它就一定支持交换链。但我们最好还是显式地进行交换链扩展的检测,然后显式地启用交换链扩展。

启用交换链扩展,只需要对逻辑设备的创建过程做很小地修改:

createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();