Vlukan基础教程-03.校验层
作者:Sun zi chao     发布时间:2022-03-20 10:58:00    阅读次数:101
本系列文章介绍Vlukan编程。Vlukan是一个跨平台的2D和3D绘图应用程序接口(API),是OpenGL的“继任者”。学习本教程的同学需要有GLFW以及C++的编程经验。有OpenGL或DirectX经验更好。

Vulkan校验层常被用来做下面的工作:

  • 1.检测参数值是否合法
  • 2.追踪对象的创建和清除操作,发现资源泄漏问题
  • 3.追踪调用来自的线程,检测是否线程安全。
  • 4.将API调用和调用的参数写入日志
  • 5.追踪API调用进行分析和回放

这是官方文档给出的解释。很抽像吧。简单说,Vulkan把系统某一部份功能打包成一个层,这个层的实现需要到若干个Vulkan扩展。我们可以检测系统支持扩展来确定Vlukan某部份功能可以使用,也可以通过校验层来检查。相比较而言,检验层更加方便,它的流程如下:

  • 1.枚举系统支持的所有校验层。
  • 2.从第1步枚举出来的校验层中寻找是否有我们要的校验层。如果有下一步,没有退出程序。
  • 3.再遍历检查所需校验层所用到扩展是否可用。
  • 4.第3步的检查过程会返回到一个回调函数,方便我们检查是确失那一部份内容。

本节的例子有点长,它主要实现两个步骤。

  • 1.枚举系统所支持的校验层
  • 2.检查系统是否支持VK_LAYER_KHRONOS_validation校验层

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <string.h>
#include <iostream>
#include <vector>

const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;

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

//是否启用校验层
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif


VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
    auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
    if (func != nullptr) {
        return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
    } else {
        return VK_ERROR_EXTENSION_NOT_PRESENT;
    }
}

void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {
    auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
    if (func != nullptr) {
        func(instance, debugMessenger, pAllocator);
    }
}

class HelloTriangleApplication {
public:
    void run() {
        initWindow();
        initVulkan();
        mainLoop();
        cleanup();
    }

private:
    GLFWwindow* window;

    VkInstance instance;
    VkDebugUtilsMessengerEXT debugMessenger;

    void initWindow() {
        glfwInit();

        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

        window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan_01", nullptr, nullptr);
    }

    void initVulkan() {
        createInstance();
        setupDebugMessenger();
    }

    void mainLoop() {
        while (!glfwWindowShouldClose(window)) {
            glfwPollEvents();
        }
    }

    void cleanup() {

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

        vkDestroyInstance(instance, nullptr);

        glfwDestroyWindow(window);

        glfwTerminate();
    }

    void createInstance() {
        //检查校验层是否有效
        if (enableValidationLayers && !checkValidationLayerSupport()) {
            throw std::runtime_error("validation layers requested, but not available!");
        }

        //定义程序信息
        VkApplicationInfo appInfo{};
        appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
        appInfo.pApplicationName = "Hello Triangle";
        appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.pEngineName = "No Engine";
        appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.apiVersion = VK_API_VERSION_1_0;

        VkInstanceCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
        createInfo.pApplicationInfo = &appInfo;

        //获取所需Vulkan的扩展
        auto extensions = getRequiredExtensions();

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

        createInfo.enabledLayerCount = 0;

        //校验层
        VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
        createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
        createInfo.ppEnabledLayerNames = validationLayers.data();
        populateDebugMessengerCreateInfo(debugCreateInfo);
        createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;

        //创建Vulkan实例
        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
            throw std::runtime_error("failed to create instance!");
        }
    }

    //返回GFLW所需扩展和启用校验层所需扩展
    std::vector<const char*> getRequiredExtensions() {
        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions;
        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);

        if (enableValidationLayers) {
            extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
        }

        return extensions;
    }

    void showExtensions(){
        uint32_t extensionCount = 0;
        vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);

        std::vector<VkExtensionProperties> extensions(extensionCount);

        vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());

        std::cout << "\n系统支持Vulkan扩展:\n";

        for (const auto& extension : extensions) {
            std::cout << '\t' << extension.extensionName << '\n';
        }
    }

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

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

        std::cout<<"本系统支持校验层数:"<<layerCount<<"\n";
        int i=1;

        for (const auto& layerProperties : availableLayers) {
            std::cout<<"-------Validtion Layer "<<i++<<"---------\n";
            std::cout<<"名称:"<<layerProperties.layerName<<"\n";
            std::cout<<"描述:"<<layerProperties.description<<"\n\n";
        }

        bool layerFound;

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

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

                    uint32_t propertyCount;

                    vkEnumerateInstanceExtensionProperties(layerProperties.layerName,&propertyCount,NULL);
                    std::vector<VkExtensionProperties> propertiesList;
                    propertiesList.resize(propertyCount);

                    vkEnumerateInstanceExtensionProperties(layerProperties.layerName,&propertyCount,propertiesList.data());

                    std::cout<<"所需扩展:\n";

                    for(auto ep:propertiesList){
                        if(enableValidationLayers==true){
                            std::cout<<"\t"<<ep.extensionName<<"\n";
                        }
                    }
                    break;
                }
            }

            if (!layerFound) {
                return false;
            }
        }
        return true;
    }
    
    //设置调试相关参数及回调函数
    void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
        createInfo = {};
        createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
        createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
        createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
        //设置调试信息回调函数debugCallback
        createInfo.pfnUserCallback = debugCallback;
    }

    static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {

        std::string msg="Validation Layer ";

        switch(messageSeverity){
            case 1:
                msg+="诊断信息:";
                break;
            case 2:
                msg+="资源创建:";
                break;
            case 3:
                msg+="警告信息:";
                break;
            case 4:
                msg+="错误信息:";
                break;

        }

        std::cerr << msg << pCallbackData->pMessage <<"\t"<<"\n\n";

        return VK_FALSE;
    }

    void setupDebugMessenger() {
        if (!enableValidationLayers) return;

        VkDebugUtilsMessengerCreateInfoEXT createInfo;
        populateDebugMessengerCreateInfo(createInfo);

        if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
            throw std::runtime_error("failed to set up debug messenger!");
        }
    }
};

int main() {
    HelloTriangleApplication app;

    try {
        app.run();
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}


检举系统支持的校验层


校验层的调试信息

最后,只要不出现validation layers requested, but not available!信息,程序就是正确的,系统就是可以跑Vulkan程序。


桂ICP备11003301号-1 公安备案号:45040302000027 Copyright @ 2021- 2022 By Sun zi chao

阅读统计: 1.93W 文章数量: 76 运行天数: 416天 返回cmnsoft