Vulkan基础

news2024/12/29 9:07:24

目录

 

一、Vulkan开发理论基础知识

接口设计理念 Host&Device

基础设施——元数据和设备

 基础设施——交换链

​编辑交换链 SwapChain​编辑

渲染管线 Pipeline

RenderPass

CommandBuffer

二、Vulkan DescriptorSet

创建DescriptorPool

运行时绑定DescriptorSet

三、SPIR-V

Shader管线

SPIR-V


一、Vulkan开发理论基础知识

接口设计理念 Host&Device

客户端 + 服务端 / 逻辑段 + 渲染端 / CPU + GPU
Host:一切由CPU与内存为基础进行的操作,例如模型的读取,鼠标键盘的事件响应,游戏引擎碰撞的逻辑,定时器等等。
Device:一切由GPU与显存为基础的图形渲染、后处理等操作

基础设施——元数据和设备

  • Instance:渲染程序的元数据,存有Vulkan版本号,引擎版本号,是否启用Debug,启动哪些拓展等基础数据。
  • Surface:用来链接操作系统相关的窗口与Vulkan渲染出来的图像组件。GPU渲染完一帧将结果存入到显存中,想要显示到窗口中就需要Surface起到链接的作用,将渲染出来的图形组件放入窗口中。
  • PhysicalDevice:物理设备显卡,多显卡时可以根据特性挑选一张进行渲染
  • LogicalDevice:逻辑设备显卡,由逻辑设备在Host端远程发送句柄操控Device端的物理设备

在这里插入图片描述

 基础设施——交换链

水平消隐和垂直消隐

 

显示设备一般是从帧数据中读取显示的内容(RGB,纹理坐标…),然后一行一行的填充每个像素刷新屏幕

水平消隐:扫描完毕一行,回到下一行开头的时间

垂直消隐:一页扫描显示完毕,回到左上角的时间

存在的问题:

  1. 如果在垂直消隐来临之前就更新了Buffer中的数据,屏幕就会产生撕裂和花屏现象。在垂直消隐来临前,屏幕还没有完全刷新完,当改变Buffer时就会造成屏幕已经刷新的部分是上一帧的画面,即将刷新的是下一帧的画面,造成撕裂现象。
  2. 如果将Buffer的更新阻塞,直到垂直消隐来临才进行更新,那么 一帧的时间 = 刷新屏幕的时间 + 更新渲染Buffer的时间,速度会受到十分严重的影响。

解决方案——双Buffer缓存:

Buffer1:用于和屏幕空间交互,被读取显示到屏幕上
Buffer2:缓存GPU的渲染数据
当屏幕空间进入垂直消隐期间,就可以交换两个缓冲区,从而实现无缝对接与并行工作
此时 一帧的时间 = 刷新屏幕的时间,省去了等待更新渲染Buffer的时间
这个过程就是由交换链(SwapChain)进行管理的


交换链 SwapChain在这里插入图片描述

 交换链管理着显存当中的N个渲染Buffer,它们组成Buffer队列交替使用

在这里插入图片描述

渲染管线 Pipeline

Unity的渲染管线流程大致如下图

  • 渲染管线在Vulkan中属于一个对象,代表了从顶点一直到屏幕上生成像素的整个处理过程。
  • Pipeline对象的每个阶段都提供了很多参数可以进行设置,以产生多种多样的渲染效果。

RenderPass

RenderPass定义为一个渲染步骤,其不关心具体渲染的细节,只定义了渲染的大方向,定义渲染完毕的东西的去处,也就是渲染目标Render Targets

  • 功能:指定渲染目标,指定批次,指定依赖等
  • 在开启延迟渲染时,会将第一帧的结果暂存在缓冲区并作为下一帧的输入,第二帧的结果才真正显示到屏幕上,两个批次渲染一帧。
  • RenderPass在Vulkan中也是一个对象。

Vertex的描述方法

  • VkBuffer:GPU端开辟的一块显存,用于存放顶点数据
  • BindingDescription:描述VkBuffer数组的索引
    • VkBuffer可能不唯一,例如顶点可以将position存入到一个buffer中,color存到另一个buffer中,多个buffer以数组的形式传入管线,需要对每个buffer编号。
  • AttributeDescription:描述顶点数据结构内的属性排布
    • 对于单个顶点内部可能有多个属性,如图中就有position和color,需要编号进行指示。

Index缓冲–顶点索引

  • 顶点索引:存储着构成三角形的点的索引,每三个索引对应的点构成一个三角形。
  • 索引VkBuffer: 顶点索引也会存进一个VkBuffer,即索引VkBuffer,在需要获取时,需要根据每个元素的大小进行分割,即根据顶点的类型得知一块元素的大小(uint16等)

CommandBuffer

在这里插入图片描述
CommandBuffer:存储本帧需要绘制的所有命令

  • 一般每个需要绘制的物体的命令都会先绘制到一个SecondaryCommandBuffer中,再统一绘制到PrimaryCommandBuffer中进而提交到任务队列,这个过程就是DrawCall。
  • 拆分成多个Secondary有利于进行多线程工作,提高效率。

 在这里插入图片描述

  参考:一、Vulkan开发理论基础知识_vulkan 开发_窗外听轩雨的博客-CSDN博客

二、Vulkan DescriptorSet

  • Descriptor
  • Descriptor Set
  • Descriptor Set Layout
  • Descriptor Pool
  • Pipeline Layout
  • Set and Binding in Shader

Descriptor是一个不透明的数据结构,代表一个着色器资源,如Buffer、Buffer View、Imgae、Sampler、Combined Image Sampler。Descriptor不是无意义的概念,Vulkan将通过Descriptor告诉GPU这些资源在哪里,以及着色器该如何访问这些资源。其实也就是认为Descriptor为一个句柄(Handle)或者一个指向资源的指针。

Descriptor会被组织成DescriptorSet,在Command Record过程中被绑定,以便在随后的DrawCall中使用。每个DescriptorSet的内容安排是由DescriptorSet Layout决定的,它决定了哪些Descriptor可以被存储在其中。如下图所示:

Vulkan Descriptor概念是在开发过程中经常遇到的性能瓶颈以及硬件商希望能足够的灵活的前提下设计的。当场景特别复杂的时候(几何多,材质复杂,参数多)的情况下同时带来了很多的资源绑定以及渲染状态设置行为:

// example for typical loops in rendering
for each view {
  bind view resources          // camera, environment...
  for each shader {
    bind shader pipeline  
    bind shader resources      // shader control values
    for each material {
      bind material resources  // material parameters and textures
      for each object {
        bind object resources  // object transforms
        draw object
      }
    }
  }
}

资源将组合为DescriptorSet并具有指定的布局,并且每个着色器可以使用多个DescriptorSet并可以单独绑定(DescriptorSet最少需要一个Descriptor)。开发者有责任管理DescriptorSet,以确保CPU不会更新GPU正在使用的DescriptorSet,并提供DescriptorSet Layout,在CPU端更新成本和GPU端访问成本之间实现最佳平衡。

传统的API将不得不在改变着色器时检查所有的资源绑定,而对哪些是被覆盖的,哪些是需要保留的,因为它没有足够信息可以用来判断并做出优化。如下图所示,DescriptorSet还允许你有部分兼容的PipelineLayout,只要这些PipelineLayout使用的DescriptorSet是相同的,已绑定DescriptorSet就会保持使用。这将大大减少资源绑定的次数。 

 把许多更新频率非常不同的资源放在同一个DescriptorSet中对整体性能不利。比如一个DescriptorSet有几个Texture和Uniform Buffer,其中只有一个资源需要变化,但仍需要更新整个DescriptorSet这将导致大量的数据被发送到GPU,而这些大部分数据实际上什么都没有修改。

创建DescriptorPool

在Vulkan当中是通过VkDescriptorPool来管理所有的DescriptorSet并分配DescriptorSet。并且DescriptorPool是外部同步的,这意味不能在多个线程中同时分配和/或释放同一池中的DescriptorSet。

  • 首先我们先确定层级关系,Set 高于Descriptor。一个Set下有若干个Binding Point,Binding Point下有一个Descriptor Array,Descriptor Array中含有一个或多个Descriptor,最终利用Command绑定的单位是Set.
  • 在DescriptorSetLayout的指导下,利用Descriptor Pool提供的Descriptors,组装成一个符合DescriptorSetLayout的Set(即图中红色的DescriptorSet A)。
  • 此时,DescriptorSet A中不包含任何的数据,只是一个空框架。接下来,我们根据WriteDescriptorSet来写入信息
  • binding和DescriptorSetLayoutBinding0.binding相对应
  • 0 <= ArrayElement < DescriptorSetLayoutBinding0.Count,表示写入Array中的第几个对象,这里我们只想写入index=1位置(对应DescriptorSetA.Bind0.DescriptorArray[1]),图中只写入了一个,理论上可以写入连续的多个Descriptor。

正是通过DescriptorBinding,DescriptorSet才实现了Shader和资源的绑定,方便了Shader对资源的读写操作。在Shader可以根据相对应的Binding去访问到相应的数据。

运行时绑定DescriptorSet

这里对应的Command就是vkCmdBindDescriptorSets。至于为什么是BindDescriptorSets而不是BindDescriptorSet,显然,在图中也有所体现,Pipeline Layout的Set不止一个,允许一次绑定多个也是合情合理。

而在Shader中,我们最终通过:

layout(set = 0, binding = 0) uniform MyBuffer 
{    
    mat4 model;
    mat4 view;
    mat4 proj; 
} ubo[]; 
void main()
{
    mat4 trans = ubo[1].proj * ubo[1].view * ubo[1].model;
    //...
}
来获取我们写入的对应数据。

问:为什么我在Vulkan中找不到VkDescriptor这样一个Handle?

答:Vulkan并不单独处理一个Descriptor,所有的操作都以Descriptor Set为单位,不论是Bind到Pipeline还是更新Set中的一个Descriptor。所以Vk并没有给出一个Descriptor的Handle,而是以WriteDescriptorSet的形式来完成一个Buffer和Descriptor的binding工作

三、SPIR-V

Vulkan是一个底层3D图形API,允许开发者获得硬件底层控制能力,同时减少性能开销,Vulkan为开发人员提供通常留给驱动程序的控制能力,如线程管理,内存管理和错误检查等等功能。

Shader管线

Vulkan中shader渲染管线和OpenGL是相同的,至少需要顶点着色器(Vertex Shader)和片元着色器(Fragment Shader),其他的着色器stage的缺失是没有问题的。

每一层的输出结果将会是下一层的输入,在最后一层片元着色器前,会进行光栅化,所谓光栅化就是将几何数据经过一系列变换后最终转化为像素的过程,光栅化后的结果会被送入片元着色器。VkPipelineStageFlagBits

SPIR-V

Vulkan编译是需要外部GLSL编译器做前半段预编译,然后shader会以中间形式存在,这种中间形态就是SPIR-V(Standard Portable Intermediate Representation),在程序运行的时候,SPIR-V会完全编译。

  1. SPIR-V有几个明显的优势,开发者再也不会暴露shader源文件,语法错误也会在SPIR-V步骤就会显示,而不是运行时才会报错,因为有预编译过程,程序运行也会更快。
  2. 在编译SPIR-V二进制码时,我们需要用到glslangValidator进行编译。glslangValidator是Khronos Group定制的GLSL参考编译器,命令行编译模式方便了用户直接测试GLSL语法而绕过C/C++的相关依赖库编译,也不需要在主文件编写大量初始化代码。 

.vert Vertex
.tesc Tessellation Control
.tese Tessellation Evaluation .geom Geometry
.frag Fragment
.comp Compute 

 下面准备创建着色器模块,在开始将代码传递到管线之前,我们需要将其包装到VkShaderModule对象中,创建一个createShaderModule方法。该方法会接收一个字节码缓冲作为参数,创建一个VkShaderModule出来。创建着色器模块是很容易的,只需要指定一个指向到缓冲的指针,以及它的长度。这些信息都在VkShaderModuleCreateInfo结构体中,有一点要注意的是字节码的大小是用字节指定的,但是字节码指针是uint32_t类型的指针而不是char类型的指针,类似以下代码:

  • 传入spv数据,传出VkShaderModule 
 VkShaderModule createShaderModule(const std::vector<char>& code) {
        VkShaderModuleCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
        createInfo.codeSize = code.size();
        createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());

        VkShaderModule shaderModule;
        if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
            throw std::runtime_error("failed to create shader module!");
        }

        return shaderModule;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/910509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Egg.js + Joi 进行接口参数验证

Joi 是一款强大的 JavaScript 数据验证库&#xff0c;用于验证和转换数据的格式。无论是在后端还是前端开发中&#xff0c;数据验证都是确保数据完整性和一致性的关键步骤。Joi 提供了一种简洁而灵活的方式来定义验证规则&#xff0c;以确保输入数据满足预期要求。 本文将介绍如…

md5加密/md5加盐加密

maven <!--MD5加密 对铭文信息进行加密操作--><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId></dependency>工具类 import org.apache.commons.codec.binary.Hex;import java.security.Mess…

图像分割unet系列------TransUnet详解

图像分割unet系列------TransUnet详解 1、TransUnet结构2、我关心的问题3、总结与展望TransUnet发表于2021年,它是对UNet非常重要的改进,专为医学图像分割任务设计,特别用于在医学图像中分割器官或病变等解剖结构。 1、TransUnet结构 TransUNet在U-Net模型的基础上引入了混合…

第五章:平衡二叉树

系列文章目录 文章目录 系列文章目录前言1、平衡二叉树的介绍1.1 AVL树的概念1.2 AVL树的性质 2、平衡二叉树的插入2.1 平衡二叉树的插入步骤2.2 平衡二叉树的旋转2.2.1 左单旋2.2.2 右单旋2.2.3 左右双旋2.2.4 右左双旋 3、平衡二叉树的检验4、平衡二叉树的删除5、整体代码 前…

Java并发编程第5讲——volatile关键字(万字详解)

volatile关键字大家并不陌生&#xff0c;尤其是在面试的时候&#xff0c;它被称为“轻量级的synchronized”。但是它并不容易完全被正确的理解&#xff0c;以至于很多程序员都不习惯去用它&#xff0c;处理并发问题的时候一律使用“万能”的sychronized来解决&#xff0c;然而如…

Postman如何做接口自动化测试?

前言 什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 例如GUI自动化测试&#xff0c;模拟人去操作软件界面&#xff0c;把人从简单重复的劳动中解放出来。 本质是用代码去测试另一段代码&#xff0c;属于一种软件开发工作&#xff0c;已经开发完…

v8引擎编译全过程

环境vs2019 cmd 命令行需要设置成为代理模式 set http_proxyhttp://127.0.0.1:10809 set https_proxyhttp://127.0.0.1:10809 这个必须带上&#xff0c;不然报错&#xff0c;告诉编译器win系统的模式 set DEPOT_TOOLS_WIN_TOOLCHAIN0 源码 GitHub: GitHub - v8/v8: The…

还不知道怎么提示LLM?ChatGPT提示入门

文章目录 简介&#xff1a;什么是人工智能&#xff1f;什么是提示过程&#xff1f;为什么会出现这样的差异&#xff1f; 为什么需要提示过程&#xff1f;1) 文章摘要2) 数学问题求解 如何进行提示过程&#xff1f;角色提示&#xff1a;多范例提示&#xff1a;无范例提示单范例提…

糖尿病视网膜病灶分割(Diabetic Retinopathy Multi-lesion Segmentation)-RTNet论文总结

论文&#xff1a;RTNet: Relation Transformer Network for Diabetic Retinopathy Multi-lesion Segmentation 目录 一、背景和出发点 二、创新点 三、方法实现 A. 概述 B. 全局transformer模块&#xff08;GTB&#xff09; C. 关系transformer模块&#xff08;RTB&#…

【Linux操作系统】深入探索Linux系统编程中的信号集操作函数

在Linux系统编程中&#xff0c;信号集操作函数是非常重要的工具&#xff0c;它们允许我们对信号进行管理和控制。本篇博客将详细介绍Linux系统编程中的信号集操作函数&#xff0c;包括信号集的创建、添加和删除信号&#xff0c;以及对信号集进行操作的常用函数。通过深入了解这…

华为Atlas的迭代关系、性能特点与典型应用场景

衔接上文&#xff0c;本篇主要讲解华为Atlas训练卡的迭代关系。以及迭代后的训练卡性能特点与典型应用场景。 Atlas 300T A2 训练卡的迭代关系为Atlas 300T Pro升级到Atlas 300T A2。相比之下&#xff0c;Atlas 300T A2 性能特点&#xff1a; ○ 高度集成 AI算力、通用算力、…

无人机巡检输电线路是什么,怎么巡?

在今日科技迅速发展的时代&#xff0c;无人机为输电线路巡检提供了一种高效、安全且准确的解决方案。那么&#xff0c;为什么无人机巡检输电线路如此关键呢&#xff1f;以下是对这一问题的深入剖析。 1. 提高工作效率 传统的巡检模式与现实挑战&#xff1a;在过去&#xff0c;输…

shell脚本语句(画矩形、三角形、乘法表和小游戏)(#^.^#)

目录 一、语句 一、条件语句 一、以用户为例演示 一、显示当前登录系统的用户信息 二、显示有多少个用户 二、单分支if 一、输入脚本 二、验证结果 三、双分支if 一、输入脚本 二、验证结果 四、多分支if 一、输入脚本 二、验证 二、循环语句 一、shell版本的循环…

【Freertos基础入门】深入浅出信号量

文章目录 前言一、Freertos的信号量是什么&#xff1f;二、二进制信号量和计数型信号量是什么&#xff1f;三、信号量初步了解1.二进制信号量的使用2.give和take是什么&#xff1f;3.为什么需要动态和静态创建的方式&#xff1f; 四、二进制信号量示例代码总结 前言 本系列基于…

docker之镜像与数据卷

镜像 简介 1.镜像是一种轻量级、可执行的独立软件包&#xff0c;用来打包软件运行环境和基于环境开发的软件&#xff0c;他包含运行某个软件所需的所有内容&#xff0c;包括代码、运行时库、环境变量、配置文件 2.将所有的应用和环境11&#xff0c;直接打包成docker镜像&…

健康检测智能睡眠床垫方案

《2022中国睡眠质量调查报告》调查结果显示&#xff0c;16&#xff05;的被调查者存在夜间睡眠时间不足6个小时&#xff0c;表现为24点以后才上床睡觉&#xff0c;并且在6点之前起床&#xff1b;有83.81&#xff05;的被调查者经常受到睡眠问题困扰&#xff0c;其中入睡困难占2…

文心一言 VS 讯飞星火 VS chatgpt (79)-- 算法导论7.4 4题

四、请用go语言&#xff0c;证明:RANDOMIZED-QUICKSORT 期望运行时间是 Ω(nlgn)。 文心一言&#xff1a; 首先&#xff0c;为了证明RANDOMIZED-QUICKSORT的期望运行时间是Ω(nlg n)&#xff0c;我们需要证明在最坏的情况下&#xff0c;该算法的运行时间是O(nlg n)。然后&…

无涯教程-PHP.INI File Configuration函数

PHP配置文件php.ini是影响PHP功能的最终且最直接的方法。每次初始化PHP时都会读取php.ini文件。换句话说,无论是模块版本的httpd重新启动还是CGI版本的每次脚本执行都重新启动。如果未显示您的更改,请记住停止并重新启动httpd。 该配置文件已注释完整。键区分大小写,关键字值不…

阿里云服务器-修改ecs操作系统,把window系统更换成Linux操作系统

其他sql格式也在更新中&#xff0c;可直接查看这个系列&#xff0c;要是没有你需要的格式&#xff0c;可在评论或私信我 总目录 目录-后期更新打算 hive的nvl中的子查询 总目录我这个是window&#xff0c;默认应该都是window&#xff0c;我需要改成Linux系统第一步&#xff…

浅谈搭建CobaltStrike云服务器可能会遇到的一些问题

1.文件上传 若要将本机的文件上传至云服务器&#xff0c;你需通过Xshell来实现 先在xshell连接云服务器&#xff0c;命令行中执行rz命令&#xff0c;即可实现文件上传 若没有rz命令,则需用到以下命令进行安装(二选一): 适用于redhat linux: yum install lrzsz适用于centos或u…