使用校验层

在本章节,我们将使用LunarG的Vulkan SDK提供的校验层。和使用扩展一样,使用校验层需要指定校验层的名称。LunarG的Vulkan SDK允许我们通过VK_LAYER_KHRONOS_validation来隐式地开启所有可用的校验层。

首先,让我们添加两个变量到程序中来控制是否启用指定的校验层。这里,我们通过条件编译来设定是否启用校验层。代码中的NDEBUG宏是C++标准的一部分,表示是否处于非调试模式下:

const int WIDTH = 800;
const int HEIGHT = 600;

const std::vector<const char*> validationLayers = {
    "VK_LAYER_KHRONOS_validation"
};

#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif

接着,我们添加了一个叫做checkValidationLayerSupport的函数来请求所有可用的校验层。首先,我们调用vkEnumerateInstanceLayerProperties函数获取了所有可用的校验层列表。这一函数的用法和前面我们在创建Vulkan实例章节中使用的vkEnumerateInstanceExtensionProperties函数相同。

bool checkValidationLayerSupport() {
    uint32_t layerCount;
    vkEnumerateInstanceLayerProperties(&layerCount, nullptr);

    std::vector<VkLayerProperties> availableLayers(layerCount);
    vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());

    return false;
}

接着,检查是否所有validationLayers列表中的校验层都可以在availableLayers列表中找到:

for (const char* layerName : validationLayers) {
    bool layerFound = false;

    for (const auto& layerProperties : availableLayers) {
        if (strcmp(layerName, layerProperties.layerName) == 0) {
            layerFound = true;
            break;
        }
    }

    if (!layerFound) {
        return false;
    }
}
return true;

现在,我们在createInstance函数中调用它:

void createInstance() {
    if (enableValidationLayers && !checkValidationLayerSupport()) {
        throw std::runtime_error("validation layers requested, but not available!");
    }

        ...
}

现在,在调试模式下编译运行程序,确保没有错误出现。如果程序运行时出现错误,请确保正确安装了Vulkan SDK。如果程序报告缺少可用的校验层,可以查阅LunarG的Vulkan SDK的官方文档寻找解决方法。

最后,修改我们之前的填写的VkInstanceCreateInfo结构体信息,在校验层启用时使用校验层:

if (enableValidationLayers) {
    createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
    createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
    createInfo.enabledLayerCount = 0;
}

如果校验层检查成功,vkCreateInstance函数调用就不会返回VK_ERROR_LAYER_NOT_PRESENT这一错误代码,但为了保险起见,读者应该运行程序来确保没有问题出现。