就像以前的图形API一样,Vulkan被设计为基于GPU的跨平台抽象。这些API的大多数问题在于,在设计API的时代就采用了图形硬件,而图形硬件大多仅限于可配置的固定功能。程序员必须以标准格式提供顶点数据,并且在照明和阴影选项方面受GPU制造商的支配。
随着图形卡体系结构的成熟,它们开始提供越来越多的可编程功能。所有这些新功能都必须以某种方式与现有API集成在一起。这导致不够理想的抽象,并且在图形驱动程序方面进行了大量猜测,以将程序员的意图映射到现代图形体系结构。这就是为什么要进行如此多的驱动程序更新以提高游戏性能的原因,有时甚至是很大的幅度。由于这些驱动程序的复杂性,应用程序开发人员还需要处理供应商之间的不一致问题,例如着色器接受的语法 。除了这些新功能,过去十年来还涌现了具有强大图形硬件的移动设备。这些移动GPU根据其能源和空间要求具有不同的体系结构。一个这样的示例就是平铺渲染,它可以通过为程序员提供对该功能的更多控制权来提高性能。源自这些API的时代的另一个限制是有限的多线程支持,这可能会导致CPU方面的瓶颈。
Vulkan通过从头开始设计用于现代图形体系结构来解决这些问题。通过允许程序员使用更详细的API明确指定其意图,它减少了驱动程序开销,并允许多个线程并行创建和提交命令。通过使用单个编译器切换到标准字节代码格式,它可以减少着色器编译中的不一致。最后,它通过将图形和计算功能统一为一个API来认可现代图形卡的通用处理能力。
说白了Vulkan 支持多线程。或者说对多线程的支持度跟高。
Vulkan应用程序首先通过来设置Vulkan API VkInstance。通过描述您的应用程序和将要使用的所有API扩展来创建实例。创建实例后,您可以查询Vulkan支持的硬件,并选择一个或多个***VkPhysicalDevice***用于操作。您可以查询诸如VRAM大小和设备功能之类的属性以选择所需的设备,例如更喜欢使用专用的图形卡。
选择正确的硬件设备后,您需要创建一个VkDevice (逻辑设备),在其中更具体地描述 VkPhysicalDeviceFeatures将要使用的设备,例如多视口渲染和64位浮点数。您还需要指定要使用的队列系列。通过Vulkan执行的大多数操作(例如绘制命令和内存操作)都可以通过将其提交给对象来异步执行VkQueue。队列是从队列族分配的,每个队列族在其队列中支持一组特定的操作。例如,可能有用于图形,计算和内存传输操作的单独队列系列。队列系列的可用性也可以用作物理设备选择的区别因素。支持Vulkan的设备有可能不提供任何图形功能,但是当今所有具有Vulkan支持的图形卡通常都将支持我们感兴趣的所有队列操作。
除非您只对屏幕外渲染感兴趣,否则将需要创建一个窗口来呈现渲染的图像。可以使用本机平台API或GLFW和SDL之类的库来创建Windows 。在本教程中,我们将使用GLFW,但在下一章中将详细介绍。
我们还需要两个组件才能实际渲染到窗口:窗口表面(VkSurfaceKHR)和交换链(VkSwapchainKHR)。请注意KHR后缀,这意味着这些对象是Vulkan扩展的一部分。Vulkan API本身与平台完全无关,这就是为什么我们需要使用标准化的WSI(窗口系统接口)扩展与窗口管理器进行交互的原因。该表面是要渲染到的窗口上的跨平台抽象,通常通过提供对本机窗口句柄的引用(例如HWND在Windows上)来实例化。幸运的是,GLFW库具有内置函数来处理特定于平台的细节。
交换链是渲染目标的集合。其基本目的是确保我们当前要渲染的图像与屏幕上当前的图像不同。确保仅显示完整的图像非常重要。每次我们要绘制框架时,我们都必须要求交换链为我们提供要渲染的图像。当我们完成绘制框架时,图像将返回到交换链,以便在某些时候显示在屏幕上。用于将完成的图像呈现到屏幕的渲染目标的数量和条件取决于当前模式。当前常见的模式是双缓冲(vsync)和三缓冲。我们将在交换链创建一章中对此进行研究。
某些平台允许您直接渲染到显示器,而无需通过VK_KHR_display和VK_KHR_display_swapchain扩展名与任何窗口管理器进行交互。这些使您可以创建代表整个屏幕的表面,并且可以用于实现自己的窗口管理器。
要绘制从交换链获取的图像,我们必须将其包装到 VkImageView和中VkFramebuffer。图像视图引用要使用的图像的特定部分,而帧缓冲区引用要用于颜色,深度和模板目标的图像视图。由于交换链中可能有许多不同的图像,因此我们将抢先为其创建图像视图和帧缓冲区,并在绘制时选择正确的图像视图和帧缓冲区。
Vulkan中的渲染过程描述了渲染操作期间使用的图像类型,将如何使用它们以及应该如何对待它们的内容。在我们最初的三角形渲染应用程序中,我们将告诉Vulkan,我们将使用单个图像作为颜色目标,并希望在绘制操作之前将其清除为纯色。渲染过程仅描述图像的类型,而VkFramebuffer实际上将特定图像绑定到这些插槽。
Vulkan中的图形管道是通过创建VkPipeline对象来设置的。它描述了图形卡的可配置状态,例如视口大小和深度缓冲区操作以及使用VkShaderModule 对象的可编程状态。该VkShaderModule对象从着色器字节代码创建的。驱动程序还需要知道管道中将使用哪些渲染目标,我们通过引用渲染过程来指定这些目标。
与现有API相比,Vulkan最显着的功能之一就是几乎所有图形管道配置都需要预先设置。这意味着,如果要切换到其他着色器或稍微更改顶点布局,则需要完全重新创建图形管线。这意味着VkPipeline您必须为渲染操作所需的所有不同组合预先创建许多对象。只能动态更改某些基本配置,例如视口大小和清晰的颜色。还需要明确描述所有状态,例如,没有默认的颜色混合状态。
好消息是,由于您要进行的是提前编译与即时编译等效,因此驱动程序有更多的优化机会,并且运行时性能更可预测,因为大型状态更改(例如切换到不同的图形管道变得非常明确。
如前所述,我们要在Vulkan中执行的许多操作(例如绘图操作)都需要提交到队列中。这些操作首先需要记录到中,VkCommandBuffer然后才能提交。这些命令缓冲区是从VkCommandPool与特定队列系列相关联的分配的。要绘制一个简单的三角形,我们需要使用以下操作记录命令缓冲区:
由于帧缓冲区中的图像取决于交换链将为我们提供的特定图像,因此我们需要为每个可能的图像记录一个命令缓冲区,并在绘制时选择正确的图像。另一种方法是每帧再次记录命令缓冲区,效率不高。
现在,绘图命令已经包装到命令缓冲区中,主循环非常简单。我们首先使用来从交换链获取图像vkAcquireNextImageKHR。然后,我们可以为该图像选择适当的命令缓冲区并使用来执行它vkQueueSubmit。最后,我们将图片返回到交换链,以使用呈现在屏幕上vkQueuePresentKHR。
提交到队列的操作是异步执行的。因此,我们必须使用诸如信号量之类的同步对象来确保正确的执行顺序。必须设置绘制命令缓冲区的执行以等待图像获取完成,否则可能会发生我们开始渲染到仍在读取以在屏幕上呈现的图像的情况。将 vkQueuePresentKHR依次调用需要等待渲染完成,为此,我们将使用正在呈现完成后,标志着一个第二旗语。
简而言之,要绘制第一个三角形,我们需要:
这一篇都是网上下载的废话,其实可以不用细看,但是得过一遍,有一个大概的了解就好了。