Instance

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;

参数详解:

  • sType指定该结构体的类型,这里必须是VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
  • pNext是为了以后扩展用的,这里我们设置为nullptr
  • flags暂时不用管,我们设置为0
  • pApplicationInfo指定了存着程序信息的VkApplicationInfo结构体
  • enabledLayerCount用来告诉Instance需要的Layer的个数
  • ppEnabledLayerNames用来告诉Instance需要的Layer名字,是个字符串数组,创建时会根据上面提供的参数从该指针读取相应个数
  • enabledExtensionCount和Layer一样,不过是扩展的个数
  • ppEnabledExtensionNames和Layer,用来提供扩展的名字

1.2 创建Insatnce需要用到的函数

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

参数详解:

  • pCreateInfo Instance创建时所需要的CreateInfo,也就是VkInstanceCreateInfo结构体
  • pAllocator 自定义内存分配回调,设置为nullptr就好
  • pInstance 被创建的Instance变量

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所需要的扩展打印出来


Instance_第1张图片
输出glfw需要的扩展.png

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

// 因为以后会有很多扩展,这里建议用vector存起来
vector 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 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;
}

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


Instance_第2张图片
可用的Vulkan扩展

2 销毁Instance所用到的函数

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

参数详解:

  • instance之前创建成功的Instance
  • pAllocator自定义分配回调函数,和创建一样设置为nullptr

这时候我们综合上面的知识,写一个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 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(extensions_required.size());
                    if (createInfo.enabledExtensionCount)
                        createInfo.ppEnabledExtensionNames = extensions_required.data();
                    // prepare the layer of need
                    createInfo.enabledLayerCount = static_cast(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 extensions_required;
            std::vector layers_required;
            std::map extensions_available;
            std::map 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 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 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;
        }
   
};

你可能感兴趣的:(Instance)