[译]Vulkan教程(15)图形管道基础之RenderPass

Render passes

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,渲染时要使用哪些帧缓存附件。我们需要指定,有多少颜色和深度buffer,多少采样,它们的内容应当如何处理throughout渲染操作。所有这些信息被封装到一个render pass对象,for which我们创建一个新的createRenderPass 函数。在initVulkan 中调用这个函数before createGraphicsPipeline

void initVulkan() {
createInstance();
setupDebugCallback();
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.

在我们的案例中,我们只有1个颜色buffer附件-由交换链的一个image代表。

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.

颜色附件的format 应当匹配交换链image的格式,我们不打算做任何多重采样的事,所以采样为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

loadOp 和storeOp 决定了怎么处理附件中的数据before渲染和after渲染。我们有下述选择for loadOp

  • VK_ATTACHMENT_LOAD_OP_LOAD:保留附件现存的内容。
  • VK_ATTACHMENT_LOAD_OP_CLEAR:开始时用一个常量值清空附件。
  • VK_ATTACHMENT_LOAD_OP_DONT_CARE:现存内容是未定义的,我们不在乎它是什么。

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

在我们的案例中,我们计划用清空操作to清空帧缓存为黑色before绘制新一帧。只有2个选项for storeOp

  • VK_ATTACHMENT_STORE_OP_STORE:渲染的内容会被保存到内存,供稍后读取。
  • VK_ATTACHMENT_STORE_OP_DONT_CARE:帧缓存的内容会是未定义的after渲染操作。

We're interested in seeing the rendered triangle on the screen, so we're going with the store operation here.

我们希望看到屏幕上选人出三角形,所以我们选择store操作。

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 应用到模板数据。我们的app与模板buffer没有关系,所以家族和保存的结果是无所谓的。

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.

Vulkan中的纹理和帧缓存由VkImage 对象代表with某个像素格式,但是像素在内存的布局可以基于你想用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

常见的布局如下:

  • VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:image用做颜色附件。
  • VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:交换链中要呈现的image。
  • VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:要用做内存复制操作的目标的image。

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.

我们将在纹理章节深入讨论这个话题,但现在重要的是,image需要被转移到特定的布局that适合接下来它们要进行的操作。

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 指定了image要用那个布局before renderPass开始。finalLayout指定了当renderPass结束时要自动转移到什么布局。用VK_IMAGE_LAYOUT_UNDEFINED  for initialLayout 意味着,我们不关心image之前在用什么布局。这个特殊值的警告含义是,image的内容不保证会被保存,但是这没关系,因为反正我们要清空它。我们在渲染后使用交换链,是想让image准备好呈现(到屏幕),这就是我们用VK_IMAGE_LAYOUT_PRESENT_SRC_KHR 作为finalLayout的原因。

Subpasses and attachment references subpass和附件引用

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.

一个render pass可以包含多个子pass。子pass是跟在前面pass之后的渲染操作that依赖于帧缓存的内容,例如一个后处理步骤that依次应用。如果你将这些渲染操作分组到一个render pass,那么Vulkan就可以重排序这些操作,节省内存带宽for可能的更好的性能。对于我们的第一个三角形,我们只用1个subpass即可。

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:

每个subpass引用一个或多个附件that我们用结构体描述过。这些引用本身是VkAttachmentReference 结构体,它们看起来如下:

VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = ;
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 参数用附件描述数组的索引指定要引用那个附件。我们的数组包含仅1个VkAttachmentDescription,所以其索引为0layout 指定了我们希望在subpass期间让附件用什么布局。当subpass开始时,Vulkan会自动将附件转移到指定的布局。我们想用附件as一个颜色buffer,VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL 布局会给我们最好的性能,如其名所述。

The subpass is described using a VkSubpassDescription structure:

Subpass用一个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可能也支持计算subpass,所以我们必须显式地说明这是一个图形subpass。下一步,我们指定要用的颜色附件:

subpass.colorAttachmentCount = ;
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!

这个数组中的附件的索引是直接被Fragment shader中的layout(location = 0) out vec4 outColor 指令引用的!

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

下述附件类型也可以被subpass引用:

  • pInputAttachments:从shader中读取的附件。
  • pResolveAttachments:用于多重采样的颜色附件。
  • pDepthStencilAttachment:用于深度和模板数据的附件。
  • pPreserveAttachments:这个subpass不用,但是数据必须为其保留的附件。

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 pipelineLayoutvariable:

现在附件和引用它的subpass已经描述好了,我们可以创建render pass本身了。创建新的类成员变量to记录这个VkRenderPass 对象-在pipelineLayoutvariable变量上方:

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.

然后就可以创建render pass对象by填入VkRenderPassCreateInfo 结构体with一个附件数组和subpass。VkAttachmentReference 对象指向使用指定索引的附件。

VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = ;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = ;
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:

像管道布局一样,render pass会在整个程序中被引用,所以应该在最后清理:

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!

做了很多工作,但是下一章它们将拼装起来to创建图形管道对象!

C++ code / Vertex shader / Fragment shader

[译]Vulkan教程(15)图形管道基础之RenderPass的更多相关文章

  1. [译]Vulkan教程(16)图形管道基础之总结

    [译]Vulkan教程(16)图形管道基础之总结 Conclusion 总结 We can now combine all of the structures and objects from the ...

  2. [译]Vulkan教程(14)图形管道基础之固定功能

    [译]Vulkan教程(14)图形管道基础之固定功能 Fixed functions 固定功能 The older graphics APIs provided default state for m ...

  3. [译]Vulkan教程(13)图形管道基础之Shader模块

    [译]Vulkan教程(13)图形管道基础之Shader模块 Shader modules Unlike earlier APIs, shader code in Vulkan has to be s ...

  4. [译]Vulkan教程(12)图形管道基础之入门

    [译]Vulkan教程(12)图形管道基础之入门 Introduction 入门 Over the course of the next few chapters we'll be setting u ...

  5. [译]Vulkan教程(04)基础代码

    [译]Vulkan教程(04)基础代码 General structure 通用结构 In the previous chapter you've created a Vulkan project w ...

  6. [译]Vulkan教程(33)多重采样

    [译]Vulkan教程(33)多重采样 Multisampling 多重采样 Introduction 入门 Our program can now load multiple levels of d ...

  7. [译]Vulkan教程(18)命令buffers

    [译]Vulkan教程(18)命令buffers Command buffers 命令buffer Commands in Vulkan, like drawing operations and me ...

  8. [译]Vulkan教程(10)交换链

    [译]Vulkan教程(10)交换链 Vulkan does not have the concept of a "default framebuffer", hence it r ...

  9. [译]Vulkan教程(03)开发环境

    [译]Vulkan教程(03)开发环境 这是我翻译(https://vulkan-tutorial.com)上的Vulkan教程的第3篇. In this chapter we'll set up y ...

随机推荐

  1. Django(一):url路由配置和模板渲染

    urls.py路由用法 url基本概念 url格式 urls.py的作用 url解析过程 include的作用 kwarg的作用 name的作用 URL概念 URL(Uniform Resoure L ...

  2. 如何禁止chrome浏览器http自动转成https

    Chrome 浏览器 地址栏中输入 chrome://net-internals/#hsts 在 Delete domain security policies 中输入项目的域名,并 Delete 删 ...

  3. 二、Vue 页面渲染过程

    前言 上篇博文我们依葫芦画瓢已经将hello world 展现在界面上啦,但是是不是感觉新虚虚的,总觉得这么多文件,项目怎么就启动起来了呢?怎么访问到8080 端口就能进入到我们的首页呢.整个的流程是 ...

  4. [从今天开始修炼数据结构]图的最小生成树 —— 最清楚易懂的Prim算法和kruskal算法讲解和实现

    接上文,研究了一下算法之后,发现大话数据结构的代码风格更适合与前文中邻接矩阵的定义相关联,所以硬着头皮把大话中的最小生成树用自己的话整理了一下,希望大家能够看懂. 一.最小生成树 1,问题 最小生成树 ...

  5. Neety的基础使用及说明

    BIO(缺乏弹性伸缩能力,并发量小,容易出现内存溢出,出现宕机 每一个客户端对应一个线程 伪异步IO:创建线程池,由线程池里边的线程负责连接处理,M个个请求进来时,会在线程池创建N个线程.容易出现线程 ...

  6. Redis面试热点工程架构篇之数据同步

    温馨提示 更佳阅读体验:[决战西二旗]|Redis面试热点之工程架构篇[2] 前言 前面用了3篇文章介绍了一些底层实现和工程架构相关的问题,鉴于Redis的热点问题还是比较多的,因此今天继续来看工程架 ...

  7. 《Java练习题》进阶练习题(二)

    编程合集: https://www.cnblogs.com/jssj/p/12002760.html 前言:不仅仅要实现,更要提升性能,精益求精,用尽量少的时间复杂度和空间复杂度解决问题. [程序58 ...

  8. JS获取包含当前节点本身的代码内容(outerHtml)

    原生JS DOM的内置属性 outerHTML 可用来获取当前节点的html代码(包含当前节点),且此属性可使用jQuery的prop()获取 <div id="demo-test-0 ...

  9. Android 项目优化(七):阿里巴巴Android开发手册整理总结

    本来之前觉得Android项目优化系列的文章基本整理完毕了,但是近期看了一下<阿里Android开发手册>有了很多收获,想再整理一篇,下面就开始吧. 先在这里列一下之前整理的文章及链接: ...

  10. linux mysql 数据库复制

    一.主服务器配置 1.配置文件my.cnf的修改 [root@localhost mysql]# vim /etc/my.cnf #在[mysqld]中添加:server-id=1log_bin=ma ...