Vulkan:创建Vulkan实例

大家好,接下来将为大家介绍Vulkan:创建Vulkan实例。

Vulkan打交道,通常的步骤是创建一个intance去初始化Vulkan library。这个instance是您的应用程序与Vulkan库之间的连接桥梁,通常创建过程中,需要向驱动程序提供一些应用层的信息。

1、创建实例基本介绍

Vulkan API使用vkInstance对象来存储所有每个应用的状态。应用程序在执行任何其他Vulkan操作之前必须创建一个Vulkan实例,基本的Vulkan架构看起来是这样的:

上面的图显示了一个Vulkan应用程序链接到一个被称为加载器(Loader)的Vulkan库。创建实例会初始化这个装载器Loader。加载器还会加载并初始化低层级的图形驱动程序Driver,通常由GPU硬件的供应商提供。

请注意在图表中提到的layers,它们也是被loader加载的。layers通常被用来执行validation验证操作。validation是驱动的错误校验。在Vulkan中,驱动程序比OpenGL等其他的API更加的轻量化,这正是因为驱动将validation功能交给layers代理的结果。同时layers也并不是必须的,而且在每一次创建实例的时候,layers可以被选择性的加载。

2、相关API介绍

vkCreateInstance

vkCreateInstance函数的原型为:

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

参数说明:

VkResult - 函数的返回状态。
VkInstanceCreateInfo - 创建一个实例所需要的额外的信息,这是一个相当重要的结构体。
VkAllocationCallbacks - 用户可以设定自定义的内存分配函数,不指定的话,Vulkan会使用默认的NULL。
VkInstance - 如果instance实例能够被顺利的创建,这个就是实例的句柄。

VkInstanceCreateInfo 结构体

Vulkan创建对象的时候,总会有一个VkObjectCreateInfo参数。创建instance对象时,对应VkInstanceCreateInfo参数。

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

sType - 指明这个结构体的类型。既然这是一个VkInstanceCreateInfo 结构体,你需要将其设置为VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO。其目的如下:

  • driver层,validation layer层或者其他的该结构体的消费者,能够通过该字段做一些校验。
  • 结构体可以通过void*指针来传递给使用这个结构体的对象,然后还是能够识别出这个指针该有的类型。

由于sType总是结构体的第一个字段,该结构体的消费者总是能够轻易的确定它的类型,然后决定来如何处理它。

pNext - 用于传递扩展指定的消息,该字段通常被设置为NULL

flags - 当前没有flags被定义,将其设置为0。

pApplicationInfo - 应用相关的结构体信息。

enabledLayerCount 和 ppEnabledLayerNames - 本节接下来内容会讲。

enabledExtensionCount 和 ppEnabledExtensionNames - 本节内容暂时不涉及。

VkApplicationInfo 结构体

这个结构体提供了应用的一些由Vulkan实现的基本的信息。

typedef struct VkApplicationInfo {
    VkStructureType    sType;
    const void*        pNext;
    const char*        pApplicationName;
    uint32_t           applicationVersion;
    const char*        pEngineName;
    uint32_t           engineVersion;
    uint32_t           apiVersion;
} VkApplicationInfo;

sType 和 pNext - 同 vkInstanceCreateInfo 结构体一样

pApplicationNameapplicationVersionpEngineNameengineVersion - 这些是非必要填写的字段。如果需要的话,这些是应用程序可以提供的自由字段。 一些 tools, loaders, layers, 或者 drivers 的实现可能会用这些字段进行debugging或者出报告。driver甚至可以使用这些字段来更改自身的行为,这取决于当前的应用程序。

apiVersion - vulkan API的版本。

3、一个简单的示例程序

// 01_instance_creation.cpp
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <iostream>
#include <stdexcept>
#include <cstdlib>

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

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

private:
    GLFWwindow* window;

    VkInstance instance;

    void initWindow() {
        glfwInit();

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

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

    void initVulkan() {
        createInstance();
    }

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

    void cleanup() {
        vkDestroyInstance(instance, nullptr);

        glfwDestroyWindow(window);

        glfwTerminate();
    }

    void createInstance() {
        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;

        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions;
        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

        createInfo.enabledExtensionCount = glfwExtensionCount;
        createInfo.ppEnabledExtensionNames = glfwExtensions;

        createInfo.enabledLayerCount = 0;

        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
            throw std::runtime_error("failed to create instance!");
        }
    }
};

int main() {
    HelloTriangleApplication app;

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

    return EXIT_SUCCESS;
}
C++

代码详细介绍如下:

a:声明一个VKInstance对象,添加一个createInstance函数,并在initVulkan函数中调用。

private:
VkInstance instance;

void initVulkan() {
    createInstance();
}

b:接下来创建VkApplicationInfo这个数据结构对象:

VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pNext = nullptr;
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;

c:创建VkInstanceCreateInfo结构体对象如下:

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

unsigned int glfwExtensionCount = 0;
const char** glfwExtensions;

glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.enabledLayerCount = 0;

d:创建vulkan实例对象:

VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);

e:检查instance是否已经成功创建,我们不需要保存结果,仅仅使用 VK_SUCCESS 值来检测即可:

if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
    throw std::runtime_error("failed to create instance!");
}

f:扩展的详细信息,我们首先需要知道有多少个扩展存在。可以通过将后一个参数置空来获取扩展数量:

uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);

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

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

std::cout << "available extensions:" << std::endl;

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

g:正确销毁VkInstance:

void cleanup() {
    vkDestroyInstance(instance, nullptr);

    glfwDestroyWindow(window);

    glfwTerminate();
}
发布了47 篇原创文章 · 获赞 57 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u010281924/article/details/105357066