介绍:
与OpenGL,WebGL和Direct3D等API((Application Programming Interface, 应用程序编程接口))相比,valkan更偏向于底层,有更多的GPU控制接口,因此它有更好的性能和更小的驱动开销(通常用于游戏领域),但同样学习会更为困难(Vulkan类似于Direct3D或Metal)
valkan是Khronos Group行业协会(Intel、Nvidia等共同创立的)制定和维护的,一个图形API的规范(Specification)和标准(注:可以理解为规定独立声明,没有定义),和OpenGL和一样都是跨平台的
和opengl一样valkanSDK软件开发工具包同样不是由Khronos实现(Implement)的(虽然Khronos也提供了Vulkan的SDK……),通常由显卡的生产商实现
简介:
VulkanAPI->驱动程序软件(接收API调用传递过来的指令和数据,并进行转换)->硬件
对于openglAPI驱动程序会跟踪大量对象的状态,自动管理内存和同步,以及在程序运行时检查错误,
与opengl不同,VulkanAPI为了保持良好的CPU
性能,将状态跟踪、同步和内存管理交给了应用程序开发人员,同时将正确性检查交给各个层进行代理,而要想使用这些层必须手动启用。这些层在正常情况下不会在应用程序里执行。
Vulkan绘制三角形流程简述
步骤1:实例和物理设备选择
- APP程序通过VkInstance实例使用Vulkan API
- 选择其中一个或多个VkPhysicalDevices物理设备(硬件),通过查询选择一个适合我们的设备
步骤2:逻辑设备和队列族
- 创建VkDevice设备,描述VkPhysicalDeviceFeaturesVkPhysicalDeviceFeatures物理设备特性 VkPhysicalDeviceFeatures
- 创建一个QueueFamily队列家族,每个队列家族支持一个特定操作集合,
- QueueFamily负责分配VkQueue
- Command会提交到VkQueue中
步骤3:窗口表面和交换链
- 窗口创建:可以使用原生平台的窗口API或像GLFW或SDL这样的库来完成,此教程使用的是GLFW库
- 还需要两个组件来渲染到实际窗口:
VkSurfaceKHR,VkSwapchainKHR(
KHR后缀:表示它们属于Vulkan扩展) - 窗口表面(VkSurfaceKHR)跨平台抽象,它是由(原生窗口系统句柄)作为参数实例化得到
- Vulkan API 本身 完全与平台无关,因此需要WSI(Window System Interface,窗口系统接口):用于与原生的窗口管理器进行交互,不过GLFW已经帮我们处理了,所以不用我们关心
- 交换链(VkSwapChainKHR)渲染目标集合:保证我们正在渲染的图像和当前屏幕图像是两个不同的图像,这可以确保显示出来的图像是complete完整的
- 每帧:从交换链请求要渲染的图像->绘制显示->图像返回交换链
- 渲染目标数量(渲染的图像)和图像显示到屏幕的时机依赖于显示模式,常用的显示模式有双缓冲(vsync,垂直同步)(前台,后台缓冲区)和三重缓冲
步骤4:图像视图和帧缓冲
- 在 ->绘制显示-> 这一步骤,并不能直接绘制,需要将图像先包装进:
- VkImageView图像视图(可以引用图像的特定部分)
- VkFramebuffer帧缓冲(可以引用图像视图作为颜色,深度和模板目标),将特定图像绑定到 这些插槽
- 交换链中可能有多个不同的图像,我们可以预先为它们每一个都创建好图像视图和帧缓冲,然后在绘制时选择对应的那个。
步骤5:render pass渲染通道
- 渲染通道描述了渲染操作使用的图像类型,图像的使用方式,图像的内容如何处理
步骤6:图形管线
- 通过VkPipeline对象建立,描述了显卡的可配置状态,比如视口大小和深度缓冲操作,以及使用VkShaderModule着色器模块(图形管线的可编程部分)
- 之前的图形OpenglAPI的一个最大不同是几乎所有图形管线的配置都需要提前完成,
- 如果我们想要使用另外一个着色器或者顶点布局,就需要重新创建整个图形管线,
- 显然效率很低,这迫使我们提前创建出所有我们需要的图形管线,在需要时直接使用已经创建好的图形管线。
- 图形管线只有很少一部分配置可以动态修改,比如视口大小和清除颜色
- vulkan这样限制的原因,就像预编译相比于即时编译,驱动程序可以有更大的优化空间(性能提升)
步骤7:指令池和指令缓冲
- Vulkan的许多操作需要提交到VkQueue队列才能执行,但在提交到队列前,还需要提交到队列池的VkCommandPool分配VkCommandBuffer对象上
- 比如绘制三角形,就要在VkCommandBuffer添加开始渲染,绑定图形管线,绘制三角形,结束渲染的命令
- 我们可以提前为每个图像建立VkCommandBuffer指令缓冲,然后在绘制时,直接选择对应的指令缓冲使用
步骤8:主循环
- 使用vkAcquireNextImageKHR函数从交换链获取一张图像。
- 使用vkQueueSubmit函数提交图像对应的指令缓冲
- 使用vkQueuePresentKHR函数将图像返回给交换链,显示图像到屏幕
- 提交给队列的操作会被异步执行,需要采取同步措施比如信号量来确保操作按正确的顺序执行
- 上述3个函数,读取,绘制,返回,都要在前面执行完成后执行,否则可能会出现读写冲突
VulkanAPI简述
vulkan.h:包含所有 Vulkan 函数、枚举和结构体
函数具有小写前缀,枚举和结构等类型 具有vk前缀
API 大量使用 使用 structs
几乎所有函数都返回 VkResult
创建 或销毁对象将具有 VkAllocationCallbacks 参数,该参数允许您 对驱动程序内存使用自定义分配器
Vulkan因为偏底层,因此将包括非常有限的错误检查和调试 功能,驱动程序经常会崩溃,而不是返回 错误代码
Vulkan 允许您通过称为validation layers的功能启用广泛的检查
验证层可以插入的代码段 在 API 和图形驱动程序之间执行操作
Valkan和OpenGL
在低分辨率下,GPU的压力较小,此时 CPU 的调度和管理对整体性能的影响相对较大,Vulkan 能够减少 CPU 的负载,更好地发挥出硬件的潜力
在高分辨率,对 GPU 的性能要求更高,Valkan可以将渲染任务更有效地分配到 GPU 的多个核心和计算单元上,充分发挥 GPU 的并行处理能力,从而提高渲染的效率和速度。
Valkan是Opengl的取代品,但并不是opengl会被替代
OpenGL渲染介绍
- 主机端资源加载(图片解码、字体解析、3D模型解析,这一过程跟GPU没有太大关系)
- 设备端数据交互与管线准备:将必要的数据(Texture纹理上传,Shader的编译与Program的链接,VBO顶点数据的数据上传)传到GPU可以读到内存中去作为context上下文,以及准备GPU的指令
- 每帧循环的渲染:DrawCall(真正执行绘制任务的图形API,如glDrawArrays, glDrawElements),这个过程是GPU驱动产生GPU硬件所能识别的任务,并发送到内核,等待调度执行。
opengl是一个状态机:
因此数据交互时,不能放到另一个独立线程中完成
由于绘制时要改变上下文,OpenGL不支持多线程线程并行绘制
每帧循环的渲染,在驱动层重新建一个Command Buffer
Valkan渲染介绍:
- 找到设备VkDevice——创建上下文VkCommand buffer(负责Record记录,多线程)——创建命令队列VkQueue(负责Submit提交,异步执行)——准备任务——发送执行(GPU)
- Command buffer: VkViewport视口,VkDescriptorSet描述(VkImage纹理和常量)、VkPipeline管线(着色器模块和状态Option(depth, blend,cull face 等))和VkBuffer缓冲(vectex顶点,index索引,uniform全局)
- 每次调 vkCmd 就往command pool命令池, command buffer 命令队列塞内容进去,命令push_back完成之后就可以提交给queue执行了
- QueueFamily队列家族,Family里会有若干queue,常见的 Family 为三种:Graphic图形,Compute计算(几乎什么都可以做)和 Transfer内存传输
valkan的性能提升的原因(多线程高度并行化):
Vulkan则没有数据交互独立线程的问题
Vulkan可以并行创建Command Buffer
在应用层建好 Command Buffer,每帧绘制时添加sub上去
Vulkan更容易封装,各子模块之间互不影响,
valkan开发环境搭建
valkanSDK:
包括标头、标准验证层、调试工具 以及 Vulkan 函数的加载程序。加载程序在 驱动程序等
安装:
首先在LunarG网站下载SDK
验证
PC 显卡驱动程序是否支持Vulkan
:
进入安装SDK的目录,打开Bin32
目录运行vkcube.exe
演示程序
并且安装后会自动为你配置系统Path环境变量
VSIDE_Configuration_Dependent
下载最新版本的GLFW-64-bit,以便渲染
将GLFW静态库:
头文件放到include目录下
glfw3.lib
、glfw3dll.lib
、放到VulkanSDK
安装目录下的Lib文件夹下
动态库glfw3.dll
,放到Bin文件夹下(如果下载的是32-bit,则放在Lib32,Bin32)
项目模板:
在实际工作中,很多时候我们需要的是一个跟我们项目的业务更加契合的、可复用的项目模板
VulkanSDK……Templates\……,并拷贝到C:\Users\username\Documents\Visual Studio YYYY\Templates\ProjectTemplates\目录下
创建一个基于 VulkanCppWindowedProgram 的模板
点击运行,可以看到一个黑色的背景窗口(基于SDL2.dll窗口的程序)
我们将项目模板的main.cpp 文件替换为自己的