[Vulkan教程]绘制一个三角形/设置/实例(Instance)

创建实例

初始化Vulkan库时,你需要做的第一件事就是创建实例VkInstance。它是应用程序与Vulkan库之间的桥梁。创建实例时,你需要告诉驱动程序你应用程序的一些细节信息。

添加一个createInstance函数,然后在initVulkan函数中调用它。

void initVulkan() {
    createInstance();
}

创建一个成员变量保存实例:

private:
VkInstance instance;

现在,我们首先创建一个结构体VkApplicationInfo,并填入你应用程序的信息。这些数据是可选的,但它可以告诉驱动程序一些有用的信息,来优化我们的应用程序。

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

之前提到,Vulkan中的许多结构体需要你通过sType显式指定其类型。结构体一般也包含一个pNext成员,它会用来指向扩展信息,这里我们先设置为nullptr

Vulkan中一般用结构体传入参数而不是函数参数。创建Vulkan实例我们还需要另一个结构体来提供充足的的信息。这个结构体是必须的,它告诉Vulkan驱动,我们想要使用哪些全局扩展和验证层。全局扩展相对与特定设备扩展。之后的章节会讨论。

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

前两个参数很明确。后两个指定了需要的全局扩展。如概述一章所说,Vulkan是平台无关的,这意味着你需要一个针对窗口系统的扩展。GLFW有一个方便的内置函数返回需要的扩展名,我们将返回值传入结构体:

uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;

glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

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

最后两个参数制定要启用的全局验证层。我们会在下一章深入讨论验证层,现在先置空。

createInfo.enabledLayerCount = 0;

现在,我们已经指定了创建实例所需的所有参数,最后就是调用创建函数vkCreateInstance

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

如你所见,在Vulkan中创建对象的函数参数有如下模式:

  • 指向创建信息的结构体指针
  • 指向自定义分配器回调的指针(在本教程中一直为nullptr
  • 指向存储新对象句柄变量的指针

正常情况下,instance句柄就保存到我们的成员变量中了。几乎所有的Vulkan函数都会返回一个VkResultVK_SUCCESS表示成功,其它值表示一个错误码。检查返回值,我们就能知道实例是否创建成功:

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

现在可以尝试运行程序确保实例创建成功。

检查扩展支持

如果你看了vkCreateInstance的文档,你可能会发现一个叫VK_ERROR_EXTENSION_NOT_PRESENT的错误码。我们可以简单地指定我们需要的扩展,如果出现错误,我们可以结束程序。必须的扩展可以这样处理,但是对于可选的扩展,我们要用合适的方法来处理。

在创建实例之前,我们可以通过vkEnumerateInstanceExtensionProperties函数获取支持的扩展列表。它需要一个指向数量和一个指向VkExtensionProperties的指针(数组)来存储数据。它还有一个可选的验证层参数,可以通过它来过滤扩展,我们现在不需要它。

要分配一个数组保存扩展信息,我们首先需要知道扩展的数量。我们传入空数组指针即可先获取数量:

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

然后分配一个数组保存扩展信息:

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

最后,获取扩展列表:

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

每一个VkExtensionProperties都包含扩展的名称和版本。我们可以列出他们:

std::cout << "available extensions:\n";

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

你可以把这段代码加到createInstance函数中来查看扩展支持情况。你可以尝试写一段代码,来判断你需要的扩展是否都在支持列表当中。

清理

VkInstance需要在程序退出前正确销毁。你可以在cleanup函数中使用vkDestroyInstance函数销毁实例:

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

    glfwDestroyWindow(window);

    glfwTerminate();
}

vkDestroyInstance的参数很简单。前面章节介绍到,我们可以传入自定义分配器管理内存,我们会忽略它并传入nullptr。之后章节中创建的Vulkan资源,我们都应该在实例销毁前销毁。

在继续更复杂的步骤前,我们首先添加验证层来开启调试选项。

目录
上一节 绘制一个三角形/设置/基本代码
下一节 绘制一个三角形/设置/验证层

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值