Link

Vulkan 初始化

与 OpenGL 不同,OpenGL 允许您几乎立即执行图形命令,Vulkan 有一个漫长的设置阶段。 为了缩短这个阶段,我们将使用库 VkBootstrap,它在所有这些样板代码方面提供了很大的帮助。

Vulkan 是一个非常显式的 API,它提供了非常“直接”的控制,您需要初始化它来执行诸如加载扩展、选择您将要使用的 GPU(或多个!)以及创建初始的 VkInstanceVkDevice 结构之类的操作,然后您将这些结构与 Vulkan 命令一起使用。

与 OpenGL 不同,Vulkan 没有全局状态,因此您需要将 VkDeviceVkInstance 与每个 API 函数调用一起发送。 在本指南中,我们将直接链接到 vulkan-1.dll 以获取函数,但这并不是唯一的方法。 您可以“手动”加载函数指针。 链接到 vulkan-1.dll 也不会加载扩展函数,您需要自己加载这些函数。 在项目代码中,提供了库 Volk,可用于加载这些扩展。 主要教程章节不会使用它,但它被提供是因为它可能是您以后想要使用的东西。

VkInstance

一切的根源是 VkInstance。 这代表 Vulkan API 上下文。 创建 VkInstance 时,您可以根据需要启用验证层,您需要的实例扩展(如 VK_KHR_surface),还可以挂钩您选择的记录器,以便在 Vulkan 驱动程序出现错误或需要记录某些内容时使用。 实例创建期间要做的主要事情是启用验证层和实例扩展。

一般来说,应用程序在其整个运行过程中只需要创建一个 VkInstance,因为它只是应用程序的全局 Vulkan 上下文。

VkPhysicalDevice

一旦我们创建了 VkInstance,我们就可以查询系统中可用的 GPU。

Vulkan 允许我们获取系统中 GPU 的列表以及它们的功能。 所有这些信息都表示在 VkPhysicalDevice 句柄上,它是对 GPU 的引用。 例如,在专用游戏 PC 中,可能只有一个 VkPhysicalDevice 可用,即专用游戏 GPU。 在这种情况下,无需在 GPU 之间进行选择,因为只有一个。

更有趣的情况是在笔记本电脑等设备中。 笔记本电脑通常有 2 个 GPU,一个是 CPU 集成的(低功耗),另一个是专用 GPU(高功耗)。 在这种情况下,应用程序将需要决定使用哪个 GPU 进行渲染,并且最好将选择权留给用户,以防他可能想要使用功率较低的专用 GPU 以节省电池寿命。

除了选择要使用的 GPU 外,VkPhysicalDevice 还允许我们查询它具有的功能、GPU 的内存大小或可用的扩展。 这对于高级应用程序非常重要,在这些应用程序中,您想确切地知道您有多少可用的 VRAM,以及 GPU 是否支持高级功能。

VkDevice

一旦我们有了要使用的 GPU 的 VkPhysicalDevice,我们就可以从中创建 VkDevice。 这是 GPU 硬件上的实际 GPU 驱动程序,也是我们与所述 GPU 通信的方式。 除调试实用程序或初始化内容之外的大多数 Vulkan 命令都需要 VkDevice。 设备是使用您想要启用的扩展列表创建的。 强烈建议您不要启用您不需要的扩展,因为它们可能会导致驱动程序因检查额外内容而变慢。

您的引擎可以一次处理多个 VkDevice,这是从同一程序中使用多个 gpu 的方法。 本教程不会这样做,但如果您想执行跨多个 GPU 运行计算着色器之类的操作,了解这一点可能很有用。

交换链

初始化 GPU 很好,但我们实际上想在屏幕上执行一些渲染。 我们为此使用交换链。 交换链是一个操作系统/窗口系统提供的结构,其中包含一些我们可以绘制然后显示在屏幕上的图像。 交换链不在核心 Vulkan 规范中,因为它们是可选的,并且通常对于不同的平台是唯一的。 如果您要将 Vulkan 用于计算着色器计算或离线渲染,则无需设置交换链。

交换链是按给定大小创建的,如果窗口调整大小,您将不得不重新创建交换链。

交换链为其图像公开的格式在平台甚至 GPU 之间可能有所不同,因此您必须存储交换链想要的图像格式,因为以不同的格式渲染会导致伪影或崩溃。

交换链保存操作系统可访问的图像和图像视图列表,以显示到屏幕。 您可以使用更多或更少的图像创建交换链,但通常您只需要 2 或 3 个图像来执行双缓冲或三缓冲渲染。

创建交换链时最重要的事情是选择呈现模式,这控制交换链如何同步到屏幕显示。

您可以在 vulkan 规范页面上查看它们的完整列表和详细说明:Vulkan 规范:VkPresentModeKHR

  • VK_PRESENT_MODE_IMMEDIATE_KHR 使交换链不等待任何东西,并接受图像的即时推送。 这可能会导致撕裂,通常不建议使用。
  • VK_PRESENT_MODE_FIFO_KHR 这将有一个图像队列,用于在刷新间隔时呈现。 一旦队列已满,应用程序将必须等待直到队列通过显示图像弹出。 这是“强 VSync”呈现模式,它会将您的应用程序锁定到屏幕的 FPS。
  • VK_PRESENT_MODE_FIFO_RELAXED_KHR。 大部分与 Fifo VSync 相同,但 VSync 是自适应的。 如果您的应用程序的 FPS 低于屏幕的最佳 FPS,它将立即推送图像,这可能会导致撕裂。 例如,如果您的屏幕是 60 HZ 屏幕,并且您以 55 HZ 渲染,则这不会下降到下一个 vsync 间隔,从而使您的总体 FPS 像 Fifo 一样下降到 30,而是它将仅显示图像,仍然是 55 FPS,但有撕裂。
  • VK_PRESENT_MODE_MAILBOX_KHR。 这个模式有一个图像列表,当其中一个图像正在被屏幕显示时,您将连续渲染到列表中的其他图像。 每当需要显示图像时,它都会选择最新的图像。 如果您想要没有硬 vsync 的三缓冲,则可以使用此模式。

VK_PRESENT_MODE_IMMEDIATE_KHR 由于其撕裂而很少使用。 仅在极低延迟的情况下,允许撕裂可能很有用。

正常应用程序将使用 MAILBOX 或 2 种 FIFO 模式之一。 主要取决于您是否想要硬 vsync 或您更喜欢三缓冲。

在本指南中,我们将使用 FIFO_RELAXED 模式,因为它对我们的渲染速度实现了上限,并且由于我们不打算渲染太多对象,因此最好将帧速率限制住,而不是达到 5000 FPS,这可能会导致过热等问题。 在有一些实际工作要做的真实应用程序上,MAILBOX 可能会是更好的默认选择。

下一步: Vulkan 初始化代码