Vulkan教程(15): Graphics pipeline之Render passes(渲染通道)
Vulkan官方英文原文: https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes
对应的Vulkan技术规格说明书版本: Vulkan 1.3.2
Setup
设置
Before we can finish creating the pipeline, we need to tell Vulkan about the framebuffer attachments that will be used while rendering. We need to specify how many color and depth buffers there will be, how many samples to use for each of them and how their contents should be handled throughout the rendering operations. All of this information is wrapped in a render pass object, for which we'll create a new createRenderPass function. Call this function from initVulkan before createGraphicsPipeline.
在我们完成管线创建之前,我们需要告诉Vulkan在渲染过程中将被使用的帧缓冲区附件的相关信息。我们需要指定将有多少个颜色和深度缓冲区(被应用),有多少(多重采样的)采样数用到这些缓冲区上以及在整个渲染操作中相关的内容如何处理。所有的这些信息都被 render pass 对象封装在内,为此,我们将创建一个 createRenderPass 函数。此函数在 initVulkan 函数中的 createGraphicsPipeline 函数之前调用。
void initVulkan() {createInstance();setupDebugMessenger();createSurface();pickPhysicalDevice();createLogicalDevice();createSwapChain();createImageViews();createRenderPass();createGraphicsPipeline();
}...void createRenderPass() {}
Attachment description
附件描述
In our case we'll have just a single color buffer attachment represented by one of the images from the swap chain.
在我们目前的例子中,我们只需要单个颜色缓冲区附件,它由swap chain中的一个图像表示。
void createRenderPass() {VkAttachmentDescription colorAttachment{};colorAttachment.format = swapChainImageFormat;colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
}
The format of the color attachment should match the format of the swap chain images, and we're not doing anything with multisampling yet, so we'll stick to 1 sample.
颜色缓冲区附件的格式应该和对应的 swap chain中的图像匹配,我们也不需要多重采样,因此我们将采样数设置为1。
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
The loadOp and storeOp determine what to do with the data in the attachment before rendering and after rendering. We have the following choices for loadOp:
VK_ATTACHMENT_LOAD_OP_LOAD: Preserve the existing contents of the attachment
VK_ATTACHMENT_LOAD_OP_CLEAR: Clear the values to a constant at the start
VK_ATTACHMENT_LOAD_OP_DONT_CARE: Existing contents are undefined; we don't care about them
In our case, we're going to use the clear operation to clear the framebuffer to black before drawing a new frame. There are only two possibilities for the storeOp:
VK_ATTACHMENT_STORE_OP_STORE: Rendered contents will be stored in memory and can be read later
VK_ATTACHMENT_STORE_OP_DONT_CARE: Contents of the framebuffer will be undefined after the rendering operation
We're interested in seeing the rendered triangle on the screen, so we're going with the store operation here.
loadOp 和storeOp 两个变量决定在渲染操作之前和之后,相关附件中的数据如何处理。这个loadOp 取值选项如下:
VK_ATTACHMENT_LOAD_OP_LOAD: 保存已经存在于当前附件中的内容,不会对它做任何其他操作
VK_ATTACHMENT_LOAD_OP_CLEAR: 起始阶段以一个常量值清理附件中内容(以常量值覆盖附件中的内容)
VK_ATTACHMENT_LOAD_OP_DONT_CARE: 存在的内容未定义,忽略它们
在我们目前的例子中,在绘制新的一帧画面之前,我们将用清除操作去清除帧缓冲区,使之呈现为黑色。对 storeOp变量来讲有两个可用的值:
VK_ATTACHMENT_STORE_OP_STORE: 渲染出来的内容将被存在内存中,用于后续的读取操作
VK_ATTACHMENT_STORE_OP_DONT_CARE: 在(已经渲染到目标的)渲染操作之后帧缓冲区中的内容被设定为未定义
我们想把三角形渲染到屏幕上,因此我们在这里选用存储操作。
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
The loadOp and storeOp apply to color and depth data, and stencilLoadOp / stencilStoreOp apply to stencil data. Our application won't do anything with the stencil buffer, so the results of loading and storing are irrelevant.
loadOp 和storeOp 这两个字段应用于颜色和深度数据(的相关操作),而 stencilLoadOp / stencilStoreOp 这两个字段则应用于模板数据(的相关操作)。我们的应用程序不需要用到模板缓冲区,因此模板的载入和存储在这里没啥影响。
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
Textures and framebuffers in Vulkan are represented by VkImage objects with a certain pixel format, however the layout of the pixels in memory can change based on what you're trying to do with an image.
Some of the most common layouts are:
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: Images used as color attachment
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: Images to be presented in the swap chain
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: Images to be used as destination for a memory copy operation
We'll discuss this topic in more depth in the texturing chapter, but what's important to know right now is that images need to be transitioned to specific layouts that are suitable for the operation that they're going to be involved in next.
Vulkan中的纹理和帧缓冲区都用某种像素格式的 VkImage 对象表示,但是内存中的像素布局可以基于你想用图像做什么去改变。
常用的布局如下所示:
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: 图像作为颜色附件
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: 图像在交换链中用于呈现
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: 图像用于内存拷贝的目标
我们会在纹理章节更深入的讨论这主题,但现在重要的是,要知道图像需要转换到适合后续相关操作的指定布局。
The initialLayout specifies which layout the image will have before the render pass begins. The finalLayout specifies the layout to automatically transition to when the render pass finishes. Using VK_IMAGE_LAYOUT_UNDEFINED for initialLayout means that we don't care what previous layout the image was in. The caveat of this special value is that the contents of the image are not guaranteed to be preserved, but that doesn't matter since we're going to clear it anyway. We want the image to be ready for presentation using the swap chain after rendering, which is why we use VK_IMAGE_LAYOUT_PRESENT_SRC_KHR as finalLayout.
这个initialLayout 字段指定图像在渲染通道相关操作之前用哪种布局。finalLayout 字段指定的图像布局是渲染通道操作结束后自动转换到的图像布局。initialLayout赋值为VK_IMAGE_LAYOUT_UNDEFINED 表示我们不关心图像之前的布局。此特殊值的附加说明是图像的内容不会保证被保留,不过也没关系,因为我们总会清除掉它。我们希望图像渲染完毕后使用 swap chain 来显示,这就是我们为什么用VK_IMAGE_LAYOUT_PRESENT_SRC_KHR 给finalLayout赋值的原因。
一些图像布局的细节请见:Image Layouts
Subpasses and attachment references
子通道和附件引用
A single render pass can consist of multiple subpasses. Subpasses are subsequent rendering operations that depend on the contents of framebuffers in previous passes, for example a sequence of post-processing effects that are applied one after another. If you group these rendering operations into one render pass, then Vulkan is able to reorder the operations and conserve memory bandwidth for possibly better performance. For our very first triangle, however, we'll stick to a single subpass.
一个单独的渲染通道有多个子通道组成。子通道是后续的渲染操作,它基于之前在渲染通道中的帧缓冲区内容,例如,一个接一个应用的一系列后处理效果。假如你把这些渲染操作组成一个渲染通道,那么Vulkan能重新排序这些操作,并且节省内存带宽以便性能更好。然而,对于我们第一个三角形,我们只需单个子通道。
Every subpass references one or more of the attachments that we've described using the structure in the previous sections. These references are themselves VkAttachmentReference structs that look like this:
每一个子通道引用一个或多个附件,这些附件我们使用前些章节中讲的结构体信息来描述。这些引用本身就是 VkAttachmentReference 结构体,如下所示:
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
The attachment parameter specifies which attachment to reference by its index in the attachment descriptions array. Our array consists of a single VkAttachmentDescription, so its index is 0. The layout specifies which layout we would like the attachment to have during a subpass that uses this reference. Vulkan will automatically transition the attachment to this layout when the subpass is started. We intend to use the attachment to function as a color buffer and the VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL layout will give us the best performance, as its name implies.
attachment 参数指定用附件描述数组中的序号来引用哪个附件。 我们的数组由单个VkAttachmentDescription结构体对象组成,因此序号为0。这个layout 字段指定我们希望的附件布局, 子通道中使用此附件的引用。当子通道开始之际,Vulkan自动转换附件到这种布局。我们打算用此附件实现颜色缓冲区的功能,并且VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL 布局性能最佳,就如其名字的含义。
The subpass is described using a VkSubpassDescription structure:
子通道用一个VkSubpassDescription 结构体描述:
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
Vulkan may also support compute subpasses in the future, so we have to be explicit about this being a graphics subpass. Next, we specify the reference to the color attachment:
Vulkan未来可能也会支持 compute subpasses 的功能,我们必须明确这是一个图形管线的子通道。接下来,我们指定颜色附件的引用:
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
The index of the attachment in this array is directly referenced from the fragment shader with the layout(location = 0) out vec4 outColor directive!
The following other types of attachments can be referenced by a subpass:
pInputAttachments: Attachments that are read from a shader
pResolveAttachments: Attachments used for multisampling color attachments
pDepthStencilAttachment: Attachment for depth and stencil data
pPreserveAttachments: Attachments that are not used by this subpass, but for which the data must be preserved
这个数组中附件的索引是被片段着色器直接用的,用 layout(location = 0) out vec4 outColor 的指令实现。
下面是能被子通道引用的其他附件类型:
pInputAttachments: 从shader中读取数据的附件
pResolveAttachments: 这类附件用于多重采用颜色附件
pDepthStencilAttachment: 深度和缓冲区数据附件
pPreserveAttachments: 这类附件不能被用于图形管线子通道,但是数据必须被保留
Render pass
渲染通道
Now that the attachment and a basic subpass referencing it have been described, we can create the render pass itself. Create a new class member variable to hold the VkRenderPass object right above the pipelineLayout variable:
现在已经介绍了附件和基本的子通道,我们能创建渲染通道本身了。在pipelineLayout 变量定义处之上创建一个新的类成员变量来持有 VkRenderPass 对象的引用:
VkRenderPass renderPass;
VkPipelineLayout pipelineLayout;
The render pass object can then be created by filling in the VkRenderPassCreateInfo structure with an array of attachments and subpasses. The VkAttachmentReference objects reference attachments using the indices of this array.
然后通过用若干附件和子通道填充 VkRenderPassCreateInfo 结构体来创建此渲染通道对象。VkAttachmentReference 对象用数组索引来引用这些附件。
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {throw std::runtime_error("failed to create render pass!");
}
Just like the pipeline layout, the render pass will be referenced throughout the program, so it should only be cleaned up at the end:
就如图形管线布局一样,渲染通道对象也被程序全程引用,因此最后记得销毁:
void cleanup() {vkDestroyPipelineLayout(device, pipelineLayout, nullptr);vkDestroyRenderPass(device, renderPass, nullptr);...
}
That was a lot of work, but in the next chapter it all comes together to finally create the graphics pipeline object!
真是不少工作,不过要在下一个章所有的相关对象最终一起创建处图形管线对象!
相关文章:
Vulkan教程(15): Graphics pipeline之Render passes(渲染通道)
Vulkan官方英文原文: https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes对应的Vulkan技术规格说明书版本: Vulkan 1.3.2Setup设置Before we can finish creating the pipeline, we need to tell Vulkan about the…...

乐观锁、雪花算法、MyBatis-Plus多数据源
乐观锁、雪花算法、MyBatis-Plus多数据源e>雪花算法2、乐观锁a>场景b>乐观锁与悲观锁c>模拟修改冲突d>乐观锁实现流程e>Mybatis-Plus实现乐观锁七、通用枚举a>数据库表添加字段sexb>创建通用枚举类型c>配置扫描通用枚举d>测试九、多数据源1、创建…...

详解Redisson分布式限流的实现原理
我们目前在工作中遇到一个性能问题,我们有个定时任务需要处理大量的数据,为了提升吞吐量,所以部署了很多台机器,但这个任务在运行前需要从别的服务那拉取大量的数据,随着数据量的增大,如果同时多台机器并发…...
[python入门㊹] - python测试类
目录 ❤ 断言方法 assertEqual 和 assertNotEqual assertTrue 和 assertFalse assertIsNone 和 assertIsNotNone ❤ 一个要测试的类 ❤ 测试AnonymousSurvey类 ❤ setUp() 和 teardown() 方法 ❤ 断言方法 常用的断言方法: 方法 用途 assertEqual(a, b) 核实a …...

Web 框架 Flask 快速入门(二)表单
课程地址:Python Web 框架 Flask 快速入门 文章目录🌴 表单1、表单介绍2、表单的简单实现1. 代码2. 代码的执行逻辑3、使用wtf扩展实现4、bug记录:表单验证总是失败🌴 表单 1、表单介绍 当我们在网页上填写账号密码进行登录的时…...

C++基础(5) - 复合类型(上)
文章目录数组1、什么是数组2、数组的声明3、数组的初始化4、数组的访问5、二维数组6、memset —— 给数组中每一个元素赋同样的值字符串(字符数组)1、string.h 头文件1.1 strlen()1.2 strcmp()1.3 strcpy()1.4 strcat()string 类简介1、C11 字符串初始化…...
java重写(@Override)介绍及实例说明
1.概述方法的重写(override)是封装的特性之一。在子类中可以根据需要对基类中继承来的方法进行重写。重载和重写没有任何关系。作用:通过重写,子类既可以继承父类的东西,又可以灵活的扩充。1.override注解是告诉编译器…...

基于STM32的虚拟示波器
仓库地址 https://github.com/shuai132/ScopeMCU ScopeMCU Oscilloscope for MCU MCU: STM32F103C8Tx 需配合ScopeGUI使用 截图说明见wiki 最新版Releases Introduction 用最少的硬件成本,做一个实用的虚拟示波器。 这是硬件部分,基于STM32最小…...

搭建云端vscode-server,使用web ide进行远程开发
使用乌班图系统,搭建自己的网页vs code开发环境github地址:GitHub - coder/code-server: VS Code in the browser安装脚本curl -fsSL https://code-server.dev/install.sh | sh出现deb package has been installed.表示已经正确安装。测试启动2.1修改配置…...

Linux clock子系统及驱动实例
文章目录基本概念CLK子系统时钟API的使用clock驱动实例1、时钟树2、设备树3、驱动实现fixed_clk固定时钟实现factor_clk分频时钟实现gate_clk门控时钟实现基本概念 晶振:晶源振荡器 PLL:Phase lock loop,锁相环。用于提升频率 OSC:…...

GIS数据格式坐标转换(地球坐标WGS84、GCJ-02、火星坐标、百度坐标BD-09、国家大地坐标系CGCS2000)
文章目录前言一、坐标系1.地球坐标 (WGS84)2.国测局坐标系(GCJ-02、火星坐标系)3.百度坐标(BD-09)4.国家大地2000坐标系(CGCS2000)二、百度坐标系(BD-09) 与火星坐标系(GCJ-02)的转换1.核心代码2.转换验证百度地图高德地图腾讯地图三、火星坐标系 (GCJ-02) 与百度坐标系 (BD-09…...
流媒体传输系列文章汇总
流媒体传输系列文章汇总 文章目录流媒体传输系列文章汇总引言流媒体交互协议详解视频封装协议详解流媒体环境搭建其他引言 从去年开始编写有关流媒体传输相关知识的文章,已发表文章22篇,阅读量也超过了10万,为了方便各位阅读,本文…...

“万字“ Java I/O流讲解
Java I/O流讲解 每博一文案 谁让你读了这么多书,又知道了双水村以外还有一个大世界,如果从小你就在这个天地里,日出而作,日落而息。 那你现在就会和众乡亲抱同一理想:经过几年的辛劳,像大哥一样娶个满意的…...
数据库(Spring)事务的四种隔离级别
文章目录Spring(数据库)事务隔离级别分为四种(级别递减)1、Serializable(串行化)2、REPEATABLE READ(可重复读)3、READ COMMITTED(读以提交)4、Read Uncommit…...

RabbitMQ详解(一):RabbitMQ相关概念
RabbitMQ是目前非常热门的一款消息中间件,不管是互联网大厂还是中小企业都在大量使用。作为一名合格的开发者,有必要对RabbitMQ有所了解,本系列是RabbitMQ快速入门文章,主要内容包括RabbitMQ是什么、RabbitMQ核心概念、五种消息模…...

ICLR 2023 | GReTo:以同异配关系重新审视动态时空图聚合
©PaperWeekly 原创 作者 | 周正阳单位 | 中国科学技术大学论文简介动态时空图数据结构在多种不同的学科中均普遍存在,如交通流、空气质量观测、社交网络等,这些观测往往会随着时间而变化,进而引发节点间关联的动态时变特性。本文的主要…...
线程池分享总结
线程池介绍 可以复用线程池的每一个资源 控制资源的总量 为什么要使用线程池 问题一:反复创建线程开销大 问题二:过多的线程会占用太多内存 解决以上两个问题的思路 • 用少量的线程——避免内存占用过多 • 让这部分线程都保持工作,且可…...

AOSP Android11系统源码和内核源码
推荐阅读 商务合作 安全产品 安全服务 2023年招聘 安全培训服务 软件定制服务 Android系统定制服务 安全/软件开发的课程列表 1.下载repo工具 (1).创建bin,并加入到PATH中 mkdir ~/binPATH~/bin:$PATH (2).安装依赖库 sudo apt-get install bison g-mult…...

layui框架学习(6:基础菜单)
菜单是应用系统的必备元素,虽然网页中的导航也能作为菜单使用,但菜单和导航的样式和用途有所不同(不同之处详见参考文献5)。Layui中用不同的预设类定义菜单和导航的样式,同时二者依赖的模块也不一样。本文主要学习和记…...
第十三届蓝桥杯 C++ B组省赛 C 题——刷题统计(AC)
1.刷题统计 1.题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 aaa 道题目, 周六和周日每天做 bbb 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 nnn 题? 2.输入格式 输入一行包含三个整数 a,ba,ba,b 和 nnn. 3.输出…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...
计算机系统结构复习-名词解释2
1.定向:在某条指令产生计算结果之前,其他指令并不真正立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方,那么就可以避免停顿。 2.多级存储层次:由若干个采用不同实现技术的存储…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器
从本章节开始,进入到函数有多个参数的情况,前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参,ECX是整型的第一个参数的寄存器,那么多个参数的情况下函数如何传参,下面展开介绍参数为整型时候的几种情…...