当前位置: 首页 > news >正文

Vulkan官方教程(一)

前言

本文首先是对 Vulkan 的简单介绍,以及其主要解决的问题。之后我们来看一下如果画一个三角形都需要什么。获得一个整体认识之后,在理解后续的内容会有很大帮助。最后,我们将介绍 Vulkan API 的结构以及其一般使用方式。

起源

需要什么?

接下来我们通过一个程序看一下画一个三角形的几个步骤。其中提到所有概念都会在后续进行详细阐述。暂时我们先对各个组件及它们的关系有一个大致了解。

步骤一、实例与硬件设备选择

一个 Vulkan 程序开始于一个创建 VkInstance(实例) 的 Vulkan API。一个实例是通过对你的应用程序的描述以及将要使用的任何 API 扩展来创建的。实例创建之后可以通过它来查询 Vulkan 所支持的设备及这些设备的功能特性(比如 VRAM 大小),然后选择你想要使用哪些设备,比如选择使用专业图形显卡。

步骤二、逻辑设备和队列簇

选定合适的物理设备之后需要创建一个 VkDevice(逻辑设备),来描述我们要具体使用哪些 VkPhysicalDeviceFeatures(物理设备特性),比如多视口渲染和 64 位浮点计算等。此外还需要具体指定使用哪一个队列簇。使用 Vulkan 大部分操作,比如绘图指令和内存操作,都是通过提交给 VkQueue(队列)来异步执行的。队列是从队列簇中分配,每一个队列簇中的队列支持一组特定操作。比如,有的队列簇中队列支持绘图,有的是专门做计算或内存转储操作。队列簇的不同能力可以作为选择物理设备的区分标准。一个设备支持 Vulkan 但不具备任何图形功能情况也是有可能的,但如今所有支持 Vulkan 的显卡基本都支持我们所关注的所有队列操作。

步骤三、窗口面和交换链

除非你只对离屏渲染感兴趣,否则你都需要创建一个窗口来进行图片渲染。可以通过调用原生平台接口(ABI),或第三方库(比如 GLFW、SDL)来创建窗口,根据具体需求来选择。

在窗口中进行渲染之前我们还需要两样东西:VkSurfaceKHR(窗口面)和 VkSwapchainKHR(交换链)。KHR 后缀表示其是 Vulkan 的一部分扩展。由于 Vulkan 是平台无关的,因此我们需要 WSI(Window System Interface 窗口系统接口)扩展来与窗口管理器进行交互。

窗口面是在窗口之上构建的用于进行渲染的一个跨平台的窗口层抽象,通过提供一个本地窗口句柄的引用(如 Windows 中的 HWND)来创建。幸运的是像 GLFW 这种都提供了内建的函数来处理这些细节。

交换链是一个渲染目标集合。其主要目的是确保我们当前正在生成的图像与当前显示在屏幕上的图像有所不同。这一点非常重要,即要确保只展示生成完成的图像。每次我们想要绘制一个帧时,都必须向交换链请求提供一张可供渲染的图像。当我们完成绘制帧之后,图像就会被送回交换链,以便在稍后某个时间呈现在屏幕上。渲染目标的数量以及将完成图像呈现到屏幕上的时机取决于当前的模式。通用模式为双缓冲区(vsync)和三缓冲区。

个别平台允许你使用 VK_KHR_display 和 VK_KHR_display_swapchain 这两个扩展直接在屏幕上渲染而不用跟任意窗口管理器打交道。该功能允许你创建一个覆盖整个屏幕的界面,比如用于实现你自己的窗口管理器

步骤四、图像视图和帧缓冲区

要将从交换链中获得的图像绘制出来,我们需要将其封装到 VkImageView(图形视图) 和 VkFrameBuffer(帧缓冲区)。图像视图引用要使用的图像的特定部分,而帧缓冲区引用要用于颜色、深度和模板目标的图像视图。由于交换链中可能有许多不同的图像,我们将预先为每个图像创建图像视图和帧缓冲,并在绘制时选择正确的那一个。

步骤五、渲染通道

Vulkan 中的渲染通道描述了渲染操作过程中使用的图像的类型、使用方式以及图像内容的处理方式。在我们最初的三角形渲染应用中,我们会告诉 Vulkan,我们将使用单张图片作为颜色目标,并希望在绘制操作之前将其清除为纯色。然而渲染通道只能描述图像的类型, VkFramebuffer 实际上是将特定图像绑定到这些插槽中。

步骤六、图形管线

在 Vulkan 中图形管线是通过创建 VkPipeline 对象设置的。它描述了图形卡的配置状态,比如视口大小、和深度缓冲区操作,以及使用 VkShaderModule 对象的程序运行状态。VkShaderModule 对象由着色字节码创建。驱动需要知道要使用图形管线的中哪些渲染目标,而这些信息我们通过引用渲染通道来确定。

这其中与现有 API 最大的区别是,在 Vulkan 中图形管线的大多数配置要提前设置。这意味着如果你要切换着色器或稍微改动顶点布局,都需要重新创建图形管线。这将导致你不得不为了不同渲染操作提前创建大量的图形管线。只有一些基本配置,比如视口大小、清除颜色,可以动态设置。所有的状态都需要进行明确描述,例如,并不存在默认的混合状态。

好消息是,相对于即时编译,你在做的等同于提前编译,可以做更多针对驱动的优化,运行时表现也更加可预测,因为像图形管线切换这种重大的改变会非常清晰。

步骤七、指令池和指令缓冲区

正如之前提到的,许多操作,比如像绘图指令,都需要提交到队列,但在提交之前需要记录到 VkCommandBuffer(指令缓冲区)。而指令缓冲区又是通过关联了特定队列簇的 VkCommandPool 中分配的。绘制一个三角形,我们需要将以下操作记入指令缓冲区:

  • 开启渲染通道
  • 绑定图形管线
  • 绘制三个顶点
  • 关闭渲染通道

由于帧缓冲区中的图像依赖于交换链提供给我们的特定图像,我们需要在指令缓冲区中记录每一个可能的图像,并在绘制时选定一个合适的。另一种选择是在指令缓冲区中记录每一帧的信息,但这会影响效率。

步骤八、主循环

现在绘制指令已经被打包到指令缓冲区,那么主循环也就呼之欲出了。首先我们需要使用 VkAcquireNextImageKHR 这个扩展从交换链中请求一张图像,然后为这张图像从指令缓冲区中选择合适的指令交给 vkQueueSubmit 执行,最后,我们将图像返回到交换链,以便使用VkQueuePresentKHR在屏幕上显示。

所有提交给队列的指令均异步执行,因此我们需要使用同步信号量来保证执行的顺序。绘图命令缓冲区的执行必须设置为等待图像采集完成。否则,我们可能会开始渲染到仍在读取并显示在屏幕上图像。VkQueuePresentKHR调用反过来需要等待渲染完成,为此我们将使用第二个信号量,在渲染完成后发出信号。

总结

以上简短的介绍帮我们对绘制一个三角形相关的工作有了一个初步的认识。但一个真正的应用包含更多步骤,比如顶点缓冲区的分配,创建统一的缓冲区和上传纹理图像等,但由于 Vulkan 的学习曲线比较陡峭,所以先从简单的开始吧。鉴于此,我偷懒起始将顶点坐标内嵌至顶点着色器中,而不是使用顶点缓冲区。因为操作顶点缓冲区首先要熟悉指令缓冲区。

简言之,绘制一个三角形,我们需要:

  • 创建一个 VkInstance;
  • 选择兼容的图形卡(VkPhysicalDevice);
  • 创建一个 VkDevice 和 VkQueue 用于绘制和呈现;
  • 创建一个窗口(window),窗口面(window surface)和交换链(swap chain);
  • 打包交换链图像到图像视图(VkImageView);
  • 创建指定了渲染目标和应用方式的渲染通道(Render pass);
  • 为渲染通道创建帧缓冲区(framebuffer);
  • 建立图形管线(pipeline);
  • 分配指令缓冲区(VkCommandBuffer),并将每一种交换链图像用到的绘制命令记入指令缓冲区;
  • 通过请求图像,提交正确的绘制指令缓冲区并将绘制完成的图像返还给交换链以完成图像绘制。

步骤比较多,但每一步都会尽量简明,如果你对其中某一步骤以及其与整个流程的关系感到困惑,请返回到相应地方再次查看。

http://www.lqws.cn/news/455383.html

相关文章:

  • 服务器手动安装并编译R环境库包:PROJ→RGDAL
  • Spring AI 项目实战(九):Spring Boot + Spring AI Tools + DeepSeek 进阶实战——调用第三方系统(附完整源码)
  • 小白的进阶之路系列之十七----人工智能从初步到精通pytorch综合运用的讲解第十部分
  • OneCode 核心组件——APICaller介绍
  • 医疗机器人的精密控制核心:计算机视觉与运动学的深度协同
  • GDI绘制
  • 漂流瓶小游戏流量主微信小程序开源
  • C#中的QUIC实现
  • Rust 学习笔记:Unsafe Rust
  • QT的一些介绍
  • Abel 变换,离散型分部积分
  • Python爬虫:多线程环境下503错误的并发控制优化
  • 人工智能之数学基础:等价矩阵、合同矩阵、相似矩阵
  • MySQL查询语句的通配符*
  • Tkinter基础函数知识点整理
  • 人工分选终将淘汰?自动化如何重构电池制造品质红线?
  • haproxy 代理/负载均衡器学习二 配置文件介绍
  • Linux之线程同步与互斥
  • 【内存】Linux 内核优化实战 - vm.max_map_count
  • [Nginx] 配置中的sendfile参数详解:从传统 IO 到零拷贝的性能优化
  • torchmd-net开源程序是训练神经网络潜力
  • 从头搭建环境安装k8s遇到的问题
  • 宽带中频10.4G采集卡
  • Day37 早停策略和模型权重的保存
  • LeetCode 680.验证回文串 II
  • Python内存使用分析工具深度解析与实践指南(上篇)
  • GoogLeNet:图像分类神经网络的深度剖析与实践
  • chili3d笔记19 读取dxf
  • 大话软工笔记—功能的概要设计
  • 数据库part2---子查询