Vulkan API的一般使用模式及使用需要的基本元素说明

网友投稿 576 2022-10-23

Vulkan API的一般使用模式及使用需要的基本元素说明

MoltenVK实际上是一个将Vulkan API映射到Metal API的一个框架,Vulkan这里只是相当于一个抽象层。

然而,为了得到一个更好的性能,Vulkan引入了一个非常冗余的API。相比于OpenGL驱动帮我们做了大量的工作,Vulkan与图像api相关的每一个细节,都需要从头设置,包括初始帧缓冲区的创建与缓冲、纹理内存的管理等等。因此,哪怕只画一个三角形,我们都要写数倍于OpenGL的代码。

由于Vulkan的使用非常冗长,这篇文章将主要介绍Vulkan API的一般使用模式以及画一个三角形所需要的基本元素。

Vulkan画三角形的各个步骤

1. Instance and physical device selection

Vulkan程序需要创建一个VkInstance来启用vulkan API.在创建Instance时你需要准确的描述你的应用程序的一些属性,以及你需要使用的各种API。在创建Instance之后,你需要查询硬件对vulkan的支持,并选择一个或者多个VkPhysicalDevices。你会查询各种硬件参数,比如显存和显卡兼容性,来选取最理想的设备。举个例子,相比集显,咱们更喜欢独显。

在决定使用哪块显卡之后,你需要创建一个VkDevice (logical device),在创建过程中你还要更详细的描述你用到的硬件特性(VkPhysicalDeviceFeatures),比如multi viewport rendering(该特性VR渲染非常有用)和64位浮点支持(科学计算和HDR都需要),你还需要制定你要使用的queue families。

大部分Vulkan操作, 比如绘制命令和内存/显存操作, 都需要通过提交到VkQueue之后异步执行。Queue是从queue family分配的,每个queue family中的Queue只支持某个特定集合的操作。举个例子,对于显卡,执行图形渲染、并行计算和内存交换可能是不同的queue family。在选择physical device时queue family的支持也是重要的参考之一。只支持科学计算不支持图形渲染的显卡有可能存在(事实上绘图相关的queue family是vulkan的扩张而非核心功能),但是这年头支持vulkan但不支持绘图的设备,其实也不多。

除非你不想显示图形(比如你只想离屏渲染),不然你还是需要创建一个窗口来显示的。你可以用各个平台native的API(win32,xlib,xcb,mir,wayland),或者GLFW、SDL等申请window。如果真的想渲染到一个窗口,还需要两样东西: window surface (VkSurfaceKHR) 和 swap chain (VkSwapChainKHR)。注意 KHR 后缀,有openGL开发经验的同学可能清楚,这个后缀表示一个KHR扩展。Vulkan API 是平台无关的, 所以需要一个标准化的 WSI (Window System Interface) 扩展来和窗口系统进行交互。Surface是一个window渲染目标的抽象,创建时需要一个native窗口的句柄(和openGL完全一样)。Swap chain是渲染一系列渲染目标(render target)的集合。他本来是保证我们渲染的image和屏幕上显示的image不是同一个(openGL双缓冲模型,目的是减少渲染时屏幕闪烁)。除了经典的双缓冲模型,还有三缓冲模型等。

4. Image views and framebuffers

在从swap chain获得image之后,我们应该绘制它。为了绘制image,我们需要把这个image用 VkImageView 以及 VkFramebuffer进行包装。VkImageView 指向被使用的 image ,而 VkFramebuffer 指向具体作为颜色、模板、深度目标的VkImageView。Swap chain中可能存在很多iamge,每个都需要创建image view还有framebuffer。在渲染时,我们需要选择正确的image进行绘制。

5. Render passes

Vulkan中的Render Pass描述了渲染过程中的image类型以及这些image包括他们的内容会如何被使用,在我们这个Hello Triangle程序中,我们只使用一个image作为颜色目标,并且在渲染前这个image的类型会被清除成一个固定的颜色。Render Pass只描述了image的类型,而VkFramebuffer才是真正绑定该image的对象。

6. Graphics pipeline

7. Command pools and command buffers

前文中已经提到了,Vulkan中的各种操作,都需要靠提交到一个命令队列(queue)的方式进行异步执行。而在提交到命令队列之前,需要在VkCommandBuffer中进行记录。命令缓冲和一个VkCommandPool关联,而VkCommandPool又和queue family关联。即便只画一个简单的三角形,我们也需要生成如下的command buffer: Begin the render pass Bind the graphics pipeline Draw 3 vertices End the render pass 因为framebuffer中的image由swap chain决定,每个可能的iamge都需要一个command buffer,这就需要创建大量的command buffer。也可以每帧重新生成command buffer,但是效率会低很多。

8. Main loop

在command buffer准备好了之后,主循环就简单多了。我们先使用vkAcquireNextImageKHR方法得到一个image。然后选择合适的command buffer再使用vkQueueSubmit执行。最后使用vkQueuePresentKHR方法向swap chain传递我们准备在屏幕上显示的image。另外需要注意的是提交到命令队列的命令是异步的,因此保证运行顺序,就是开发者的工作了。vulkan提供了用来同步的对象,比如semaphore,fence等。我们可以使用这些同步对象来保证运行的正确顺序。

总结

总而言之,画三角需要如下的步骤:

创建 VkInstance

创建 VkPhysicalDevice

创建 VkDevice 以及 VkQueue

创建 window, window surface 以及 swap chain

使用 VkImageView 包装swap chain中的images

创建 render pass

创建 framebuffers

创建 graphics pipeline

为每个可能用到的image创建command buffer,并记录draw commands

通过获取image,向image绘制,提交到swap chain的方式来绘制一帧

Vulkan Layers

Vulkan作为高性能API,为了降低驱动开销,只提供了非常有限的错误检查。如果默认情况下,它只包含非常有限的错误检查和调试功能。如果发生了错误,驱动会直接崩溃,而不是返回错误信息,或者显示异常等。

Vulkan允许您通过一个名为Validation Layer的特性进行通用的检查。Validation Layer是可以插入到API和图形驱动程序之间的代码片段,用于执行额外的函数参数检查和跟踪内存管理问题。好处是,您可以在开发过程中启用它们,然后在释放应用程序时完全禁用它们,而开销为零。任何人都可以编写自己的验证层,但是LunarG的Vulkan SDK提供了一组标准的验证层,另外还需要注册一个回调函数来接收来自Validation Layer的调试消息。

因为Vulkan实际上对于每一个步骤是非常明确的,所以相比于OpenGL,我们可以更快速的找出出错的地方。

而Google也提供了一些Validation Layers帮助我们做这些事情,如果要在项目中使用它们,只要修改gradle的构建,或者将二进制文件手动的添加到项目的JNI库目录里,这些so可以在ndk的以下目录找到:

${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs sourceSets { main { jniLibs { srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs" } } }

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:老黄历(老黄历万年历)
下一篇:urlencode在线(urlencode在线转码)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~