Vulkan 开发(二):Vulkan 实例

开篇,Vulkan 概述 一文对比了 Vulkan 和 OpenGL 的特点,重点介绍了 Vulkan 的优势体现在哪里,本文将接着介绍 Vulkan 的一些重要概念。

实例(Instance)

Vulkan 实例 是 Vulkan API中的一个基本概念,它是连接 Vulkan 库和应用程序之间的桥梁,用于初始化Vulkan 库。 创建 Vulkan 实例涉及到向驱动程序提供应用程序的一些细节,如应用程序信息和引擎信息等。

在Vulkan中,实例(VkInstance)是存储所有每个应用状态的对象,应用程序必须在执行任何其他 Vulkan 操作之前创建一个 Vulkan 实例。

这个类似于 OpenGL 的上下文概念,一个实例代表一整 Vulkan 环境(或上下文)。不同的 Vulkan环境能够获取到不同的 Vulkan 功能特性。

创建 VkInstance

Vulkan 编程中 ,创建一个 Vulkan 组件有一个固定的规则,首先需要设置一个创建组件信息的结构体 VkxxxCreateInfo,然后调用创建组件的 API VkCreatexxx 。

VkInstanceCreateInfo

arduino 复制代码
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 是该结构体的类型枚举值, 必须 是 VkStructureType::VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO 。
  • pNext 要么是 nullptr 要么指向其他结构体来扩展该结构体。
  • flags 是 VkInstanceCreateFlagBits 所表示的位域值,用于设置 VkInstance 的行为。
  • pApplicationInfo 要么是 nullptr, 要么指向应用信息结构体,用于应用细节设置。
  • enabledLayerCount 激活的 layer 数量。
  • ppEnabledLayerNames 指向数量为 enabledLayerCount 的 layer 字符串数组,用于设置要激活的 layer。
  • enabledExtensionCount 激活 instance 扩展的数量。
  • ppEnabledExtensionNames 指向数量为 enabledExtensionCount 的扩展字符串数组,用于设置要激活的 instance 扩展。

重点讲下 VkApplicationInfo、Layer 和 Extension

VkApplicationInfo

ini 复制代码
  VkApplicationInfo appInfo = {
      .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
      .pNext = nullptr,
      .pApplicationName = "my_vulkan_app",
      .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
      .pEngineName = "vulkan_tutorial",
      .engineVersion = VK_MAKE_VERSION(1, 0, 0),
      .apiVersion = VK_MAKE_VERSION(1, 0, 0),
  };
  • sType 是该结构体的类型枚举值, 必须 是 VkStructureType::VK_STRUCTURE_TYPE_APPLICATION_INFO 。
  • pNext 要么是 NULL 要么指向其他结构体来扩展该结构体。
  • pApplicationName 要么是 NULL 要么指向一个以空字符为结尾的 UTF-8 字符串,用于表示用户自定义应用名称。
  • applicationVersion 一个无符号整型,用于用户自定义应用版本。
  • pEngineName 要么是 nullptr 要么指向一个以空字符为结尾的 UTF-8 字符串,用于表示用户自定义引擎名称。
  • engineVersion 一个无符号整型,用于用户自定义引擎版本。
  • apiVersion 是应用打算使用的 Vulkan 的最高 核心 版本,并且忽略 apiVersion 的 patch 版本

其中 pApplicationName 、 applicationVersion 、 pEngineName 和 engineVersion 这几个值随便设置,甚至可以不设置,赋为空都可以,这些参数不影响实例的创建。

而 apiVersion 参数是最为重要的核心参数 ,当创建实例时,该参数用于指定此实例环境中 Vulkan 的 核心 版本 。

如果你 Vulkan 版本设置错了,可能没法使用一些特性。

Vulkan API 的最新版本是 1.3,目前 Vulkan 有 4 个版本:

  • Vulkan 1.0 主要提供光栅化图形和并行计算的功能。对应 VK_API_VERSION_1_0 。
  • Vulkan 1.1 主要为 Vulkan 1.0 不完善的地方进行补全。对应 VK_API_VERSION_1_1 。
  • Vulkan 1.2 主要提供硬件光追的功能。对应 VK_API_VERSION_1_2 。
  • Vulkan 1.3 主要提供动态光栅化图形的功能。对应 VK_API_VERSION_1_3 。

每个 Vulkan 新版本的发布不单单提供基本功能,还会提供一系列扩展功能,并且会将之前版本中的一些扩展功能提升囊括至核心版本中。

Layer

Vulkan 的 Layer(层)是一种重要的机制,允许开发者在 Vulkan API 的核心功能上插入额外的功能和工具。

image.png

Layer 主要的特点是模块化,可以根据需要加载和卸载,开发者可以选择在应用程序初始化时启用哪些层。
常用作正确性验证检查。 比如你添加了验证层 VK_LAYER_KHRONOS_validation ,如果在执行阶段发生了使用错误, Layer 会输出错误信息,帮助开发者定位错误。

目前 Vulkan 支持的 层 如下:

  • VK_LAYER_KHRON OS_validation Vulkan API 验证和错误检查。
  • VK_LAYER_LUNARG_gfxreconstruct 使用 GFXReconstruct 捕获应用的 Vulkan 指令。
  • VK_LAYER_LUNARG_api_dump 输出调用的 API 和传入的参数。
  • VK_LAYER_KHRONOS_profiles 帮助测试硬件的性能,而不需要物理接触每个设备。该 层 将会覆盖从 GPU 查询到的数据。
  • VK_LAYER_LUNARG_monitor 在应用界面的标题处显示帧率。
  • VK_LAYER_LUNARG_screenshot 将显示的画面帧输出到一个图片文件中。
  • VK_LAYER_KHRONOS_synchronization2 使用系统实现的 VK_KHR_synchronization2 扩展,而不是驱动实现的。
  • VK_LAYER_KHRONOS_shader_object 使用系统实现的 VK_EXT_shader_object 扩展,而不是驱动实现的。

可以通过 vkEnumerateInstanceLayerProperties函数获取系统中 Vulkan 支持的 Layer :

ini 复制代码
uint32_t layer_property_count = 0;
vkEnumerateInstanceLayerProperties(&layer_property_count, nullptr);

std::vector<VkLayerProperties> layer_properties(layer_property_count);
vkEnumerateInstanceLayerProperties(&layer_property_count, layer_properties.data());

思考:vkEnumerateInstanceLayerProperties 这个函数为什么调用了 2 次?

其中 VkLayerProperties 定义如下:

arduino 复制代码
// 由 VK_VERSION_1_0 提供
typedef struct VkLayerProperties {
    char        layerName[VK_MAX_EXTENSION_NAME_SIZE];
    uint32_t    specVersion;
    uint32_t    implementationVersion;
    char        description[VK_MAX_DESCRIPTION_SIZE];
} VkLayerProperties;

Extension

Vulkan Extensions(扩展)是对 Vulkan API 的功能扩展,它们允许硬件制造商、平台开发者和第三方提供额外的功能和特性,这些功能和特性不包含在核心 Vulkan 规范中。

在 Vulkan 中有两类扩展:

  • Instance 扩展 与使用哪一个 GPU 设备无关,与 Vulkan 环境有关。 VkInstanceCreateInfo 中的 enabledExtensionCount 和 ppEnabledExtensionNames 就是用于配置此类 Instance 扩展 。
  • Device 扩展 与使用哪一个 GPU 设备有关。不同厂家的 GPU 设备会支持不同的设备扩展。这将会在之后的章节展开。

VkInstance 支持的实例扩展可以通过 vkEnumerateInstanceExtensionProperties 函数获取:

arduino 复制代码
// 由 VK_VERSION_1_0 提供
VkResult vkEnumerateInstanceExtensionProperties(
    const char*                                 pLayerName,
    uint32_t*                                   pPropertyCount,
    VkExtensionProperties*                      pProperties);

要想获取全部的扩展,该函数的调用与 vkEnumerateInstanceLayerProperties(...) 类似,调用两遍,第一遍 pProperties 为 nullptr ,第二遍为有效值即可:

arduino 复制代码
uint32_t extension_property_count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extension_property_count, nullptr);

std::vector<VkExtensionProperties> extension_properties(extension_property_count);
vkEnumerateInstanceExtensionProperties(nullptr, &extension_property_count, extension_properties.data());

其中 VkExtensionProperties 定义如下:

arduino 复制代码
// 由 VK_VERSION_1_0 提供
typedef struct VkExtensionProperties {
    char        extensionName[VK_MAX_EXTENSION_NAME_SIZE];//扩展名称
    uint32_t    specVersion;//版本
} VkExtensionProperties;

有一些实例扩展我们需要重点关注一下

  • VK_KHR_surface 代表窗口通用平面扩展。
  • VK_{vender}_{platform}_surface 代表各个平台各自的窗口平面(各自平台适配到通用平面)。

比如

  • VK_KHR_win32_surface 为 Windows 平台,供应商为 Khronos 。
  • VK_OHOS_surface 为 OpenHarmony 平台,供应商为 华为 。
  • VK_KHR_android_surface 为 Android 平台,供应商为 Khronos 。
  • VK_KHR_[wayland/xcb/xlib]_surface 为 Linux 平台(其中 [wayland/xcb/xlib] 表示三者其一),供应商为 Khronos 。

创建 Instance 示例:

ini 复制代码
VkInstance instance = nullptr;

std::vector<const char*> instance_extensions;
instance_extensions.push_back("VK_KHR_surface");
instance_extensions.push_back("VK_KHR_android_surface");//Android
//如果是 WIndow 平台使用 VK_KHR_win32_surface

std::vector<const char *> instance_layers;
instance_layers.push_back("VK_LAYER_KHRONOS_validation");//添加验证层

VkApplicationInfo appInfo = {
      .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
      .pNext = nullptr,
      .pApplicationName = "my_vulkan_app",
      .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
      .pEngineName = "example",
      .engineVersion = VK_MAKE_VERSION(1, 0, 0),
      .apiVersion = VK_MAKE_VERSION(1, 0, 0),
  };

VkInstanceCreateInfo instanceCreateInfo{
      .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
      .pNext = nullptr,
      .pApplicationInfo = &appInfo,
      .enabledLayerCount = 
          static_cast<uint32_t>(instance_layers.size()),
      .ppEnabledLayerNames = instance_layers.data(),
      .enabledExtensionCount =
          static_cast<uint32_t>(instance_extensions.size()),
      .ppEnabledExtensionNames = instance_extensions.data(),
  };

VkResult result = vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
if (result != VK_SUCCESS)
{
   //VkInstance 创建失败
}

// 开启 Vulkan 编程 ...

vkDestroyInstance(instance, nullptr);//通过 vkDestroyInstance 函数销毁 instance

技术交流

技术交流/职场困惑解答,可以添加我的微信:Byte-Flow

-- END --

相关推荐
壕壕5 天前
Re: 0x03. 从零开始的光线追踪实现-多球体着色
macos·计算机图形学
web像素之境11 天前
实时光线追踪加速硬件结构(详细版)
游戏·gpu·计算机图形学
唯道行21 天前
计算机图形学·9 几何学
人工智能·线性代数·计算机视觉·矩阵·几何学·计算机图形学
唯道行24 天前
计算机图形学·6 OpenGL编程3 谢尔宾斯基垫与三维编程
人工智能·算法·计算机视觉·计算机图形学·三维·谢尔宾斯基垫
charlie1145141911 个月前
2D 计算机图形学基础速建——2
笔记·学习·线性代数·教程·计算机图形学
charlie1145141911 个月前
2D 计算机图形学基础速建——1
笔记·学习·教程·计算机图形学·基础
ObjectX前端实验室2 个月前
【图形编辑器架构】节点树与渲染树的双向绑定原理
前端·计算机图形学·图形学
ObjectX前端实验室2 个月前
【图形编辑器架构】渲染层篇 — 从 React 到 Canvas 的声明式渲染实现
前端·计算机图形学·图形学
ObjectX前端实验室2 个月前
【图形编辑器架构】节点树篇 — 从零构建你的编辑器数据中枢
前端·计算机图形学·图形学
壕壕2 个月前
Re: 0x02. 从零开始的光线追踪实现-射线跟球的相交
macos·计算机图形学