Instance

2019-05-31  本文已影响0人  MiAo鲜声

Instance的意义

我们使用Vulkan的第一步和OpenGL一样,都需要初始化函数库,OpenGL用一些函数例如glutinit之类的就可以完成,但是在Vulkan里面你需要通过创建 instance 来完成上面的事情,在创建 instance 的时候,我们可以通过设置不同参数来初始化一个VkInstance来提供一个包含我们想要的功能的库(比如说用来屏幕绘制的交换链,如果只是离线渲染不需要呈现到屏幕来,那就不需要这个功能)。


1 Instance的创建的销毁


1.1 创建Instance需要的结构体

我们需要用到VkInsatnceCreateInfo结构体,该结构体定义如下。

typedef struct VkInstanceCreateInfo {
    VkStructureType             sType; 
    const void*                 pNext;
    VkInstanceCreateFlags       flags;
    const VkApplicationInfo*    pApplicationInfo;
    uint32_t                    enabledLayerCount;
    const char* const*          ppEnabledLayerNames;
    uint32_t                    enabledExtensionCount;
    const char* const*          ppEnabledExtensionNames;
} VkInstanceCreateInfo;

参数详解:


1.2 创建Insatnce需要用到的函数

VkResult vkCreateInstance (
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance )

参数详解:


1.3 例子:简单的创建Instance

// 创建VkInstanceCreateInfo需要用到的结构体
        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_1;  // 使用的Vulkan Api版本
// 创建Instance所需要的结构体
        VkInstanceCreateInfo createInfo = {};
        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
        createInfo.pApplicationInfo = &appInfo;
        createInfo.enabledLayerCount =0;
        createInfo.enabledExtensionNames=0;
        createInfo.pNext=nullptr;
        createInfo.ppEnabledLayerNames=nullptr;
        createInfo.ppEnabledExtensionNames=nullptr;
        createInfo.flags=0;
        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
            throw std::runtime_error("failed to create instance!");
        }

1.4 告诉Instance你要使用的扩展

这里特别注意!!!你要在你引用的glfw头文件前加一个宏定义#define GLFW_INCLUDE_VULKAN因为glfw是默认支持OpenGL的

启用glfw扩展:
因为我们使用的glfw需要使用一些扩展,用下面代码获取glfw扩展

uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;

glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
//这时我们需要把有关于createInfo的extension部分改成如下所示
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;

将glfw所需要的扩展打印出来


输出glfw需要的扩展.png

更建议用下面的方式存扩展

// 因为以后会有很多扩展,这里建议用vector<const char*>存起来
vector<const char*> extensions_required;
/*
..........中间省略了将各种扩展push_back进extensions_required的过程
*/
createInfo.enabledExtensionCount = extensions_required.size();
createInfo.ppEnabledExtensionNames = extensions_required.data();

1.5 检查Vulkan是否支持扩展

但是我们并不知道使用的Vulkan版本是否支持上面的扩展,所以我们需要查询

uint32_t extensionCount = 0;
// 把第三个个参数设置为nullptr,下面函数只返回可用扩展的个数
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> extensions(extensionCount);
// 然后再用同一个函数获取extensionCount个可用扩展。
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
// 然后讲extensions里的内容输出查看
std::cout << "available extensions:" << std::endl;
for (const auto& extension : extensions) {
    std::cout << "\t" << extension.extensionName << std::endl;
}

该代码输出如下图所示,,输出会因电脑还有系统不同而变化:


可用的Vulkan扩展

2 销毁Instance所用到的函数

void vkDestroyInstance(
    VkInstance instance,
    const VkAllocationCallbacks* pAllocator);

参数详解:


这时候我们综合上面的知识,写一个Instance类,为什么要写,因为后面会有很多其他的Vulkan变量,例如VkDevice等等,他们的创建都需要相应的Vk×××CreateInfo,如果我们要挨个手动管理他们各自的创建信息还有其他一些东西太麻烦了,我们要把依附性强的东西放到一个类里面,让类来管理比较轻松一点


class Instance
{
public:
    VkInstance instance=nullptr;
    VkApplicationInfo appInfo=
               {
                    VK_STRUCTURE_TYPE_APPLICATION_INFO, // VkStructureType    sType;
                    nullptr, // const void*        pNext;
                    "Vulkan Application",// const char*        pApplicationName;
                    VK_MAKE_VERSION(1,0,0), // uint32_t           applicationVersion;
                    "No Engine", // const char*        pEngineName;
                    VK_MAKE_VERSION(1,0,0), // uint32_t           engineVersion;
                    VK_API_VERSION_1_1 // uint32_t           apiVersion;
                };
    VkInstanceCreateInfo createInfo={
                        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType             sType;
                        nullptr, // const void*                 pNext;
                        0, // VkInstanceCreateFlags       flags;
                        &appInfo, // const VkApplicationInfo*    pApplicationInfo;
                        0, // uint32_t                    enabledLayerCount;
                        nullptr,// const char* const*          ppEnabledLayerNames;
                        0,// uint32_t                    enabledExtensionCount;
                        nullptr// const char* const*          ppEnabledExtensionNames;
                };

            Instance():isCreated(false)
            {
                // get the available extension and layers
                queryAvailableExtensions();
                queryAvailableLayers();
                // enable the validation layers
                if (enableValidationLayers)
                {
                        enableLayer("VK_LAYER_LUNARG_standard_validation");
                        enableExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
                }
            }
            ~Instance()
            {
                if(auto_destroy)
                destroy();
            }
                // enable extensions fcuntion
            void enableExtension(const char * extension)
            {
                if (extensions_available.count(string(extension)))
                    extensions_required.push_back(extension);
                else
                    std::cerr << "Error: " << extension << " Required but Not Support !" << endl;
            }
                // enable layers function
            void enableLayer(std::vector<const char*> requiredlayers)
            {
                for (auto& layer : requiredlayers)
                enableLayer(layer);
            }
            void enableLayer(const char * layer)
            {
                if (layers_available.count(string(layer)))
                    layers_required.push_back(layer);
                else
                    std::cerr << "Error: " << layer << " Required but Not Support !" << endl;
            }
                // create the instance
            VkResult creat(const VkAllocationCallbacks* pAllocator = nullptr)
            {
                if (isCreated)
                    return VK_SUCCESS;
                else
                {
                    VkResult result;
                    // prepare the extension of  need;
                    createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions_required.size());
                    if (createInfo.enabledExtensionCount)
                        createInfo.ppEnabledExtensionNames = extensions_required.data();
                    // prepare the layer of need
                    createInfo.enabledLayerCount = static_cast<uint32_t>(layers_required.size());
                    if (createInfo.enabledLayerCount)
                        createInfo.ppEnabledLayerNames = layers_required.data();
                    // if fail to create Instance
                    if ((result = vkCreateInstance(&createInfo, pAllocator, &instance)) != VK_SUCCESS)
                    {
                        throw string("Error:  fail to create Vulkan Instance. \n") + string("Detail: vkCreateInstance() return ") + toString(result);
                    }
                    // succeed to create Instance
                    else
                    {
                        isCreated = true;
                        std::cout << "Info: succeed to create Vulkan Instance.\n";
                    }
                    return result;
                }
            }
                // destroy the instance
            void destroy(const VkAllocationCallbacks* pAllocator = nullptr)
            {
                if (isCreated)
                {
                    vkDestroyInstance(instance, pAllocator);
                    isCreated = false;
                }
            }

        private:
            bool isCreated = false;
            std::vector<const char*> extensions_required;
            std::vector<const char*> layers_required;
            std::map<std::string, VkExtensionProperties> extensions_available;
            std::map<std::string, VkLayerProperties> layers_available;
            bool auto_destroy = true;

            // get the available extensions
        inline void queryAvailableExtensions()
        {
            uint32_t extensionCount = 0;
            VkResult result;
            result = vkEnumerateInstanceExtensionProperties(NULL,&extensionCount, nullptr);
            if (result != VK_SUCCESS)
            {
                std::cerr << "Fatal: fail to query Vulkan available Extension ! " << endl
                    << "vkEnumerateInstanceExtensionProperties() return " << toString(result);
                return;
            }
            if (extensionCount > 0)
            {
                std::vector<VkExtensionProperties> extensions(extensionCount);
                vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensions.data());
                for (auto& extension : extensions)
                    extensions_available.insert(make_pair(extension.extensionName, extension));
            }
            else
                cout << "Info: No Vulkan Extension Available ! " << endl;
        }
            // get the available layers
        inline void queryAvailableLayers()
        {
            VkResult result;
            uint32_t layerCount = 0;
            result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
            if (result != VK_SUCCESS)
            {
                std::cerr << "Error: fail to query Vulkan available Layers" << endl
                    << "vkEnumerateInstanceLayerProperties() return " << toString(result) << endl;
                return;
            }
            if (layerCount > 0)
            {
                std::vector<VkLayerProperties> availableLayers(layerCount);
                vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
                for (auto& layer : availableLayers)
                    layers_available.insert(make_pair(layer.layerName, layer));
            }
            else
                cout << "Info: No Vulkan Layer Available ! " << endl;
        }
   
};
上一篇下一篇

猜你喜欢

热点阅读