Skip to content

门泊吴船亦已谋

Vulkan 画三角形 第二章 创建 Vulkan 实例

开始一切之前,我们先引入 Vulkan 的头文件

#include <vulkan/vulkan.h>

注意这行代码要写在包含 GLFW 之前,因为 GLFW 可以通过条件编译来为 Vulkan 提供一些支持

创建实例

然后要做的事情就是创建 Vulkan 实例。实例可以把你的应用程序跟 Vulkan 类库连接起来,创建实例需要指定一些信息

首先添加一个成员变量用来保存和处理实例

VkInstance instance;

然后添加一个成员函数 createInstance 用于创建实例,并在 initVulkan 中调用它

void initVulkan() {
    createInstance();
}

接下来我们开始填充这个成员函数

首先我们需要填充一个结构体用于存储我们应用程序的相关信息。这并不是必须的,但是驱动可以通过我们提供的信息对我们的应用进行优化。比如说我们的应用如果使用了一个知名的图形引擎,那么驱动就可以针对这个引擎的特定行为进行优化

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;
}

对于这个结构体,我们在 sType 中明确地指定了它的类型,并且 Vulkan 中大部分的其他结构体也都是一样

接下来我们需要填充另一个结构体,这个结构体存储着创建实例所需要的信息,并作会在创建实例时直接把这个结构体作为参数传递过去。需要注意的是,Vulkan 中的大部分方法调用也都是直接传递一个结构体,而不是拆开为一个一个的参数

我们在 createInstance 方法的末端添加以下代码

// 实例创建信息
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;

这两行代码的作用显而易见,然后我们来指定扩展。Vulkan 是一个跨平台的 API,这就意味着你需要一些扩展来跟窗体系统交互。而 GLFW 提供了方便的内建函数来获取所需要的扩展,于是我们只需要把它们存入结构体中就行了

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!");

贴一下 createInstance 的完整代码,但其实就是把上面的代码片段按顺序拼接到 createInstance 函数里,为了方便,后面的文章就不贴完整代码了

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!");
}

销毁实例

另外,需要在 cleanup 函数中销毁实例

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

    glfwDestroyWindow(window);
    glfwTerminate();
}

最后我们可以调试看看有没有写错