您的位置:首页 > 其它

vulakn教程--Drawing a Triangle--Pipeline--Render passes

2016-09-15 21:29 926 查看
原文链接 : vulkan-tutorial

Render Pass

在创建
Pipeline
之前我们必须告诉
Vulkan
在渲染时要使用的
FrameBuffer
附件(
attachments
),需要定义使用color buffer 以及 depth buffer attachments的数量,要使用多少个采样(samples)以及应该如何处理采样的内容。所有这些信息都可以填写在Render Pass里。

Attachment description

在我们的应用里只使用了一个color buffer attachment,我们用
Swap Chain
里的一个
image
来表示这个
buffer
。先来看一下需要用到的结构:

typedef struct VkAttachmentDescription {
VkAttachmentDescriptionFlags flags;
VkFormat format;
VkSampleCountFlagBits samples;
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
VkAttachmentLoadOp stencilLoadOp;
VkAttachmentStoreOp stencilStoreOp;
VkImageLayout initialLayout;
VkImageLayout finalLayout;
} VkAttachmentDescription;


// subpass 执行前对color或depth attachment内容做何种处理
typedef enum VkAttachmentLoadOp {
VK_ATTACHMENT_LOAD_OP_LOAD = 0, //±£´æÒÑÓеÄÄÚÈÝ
VK_ATTACHMENT_LOAD_OP_CLEAR = 1, //Çå¿Õ
VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, // ²»ÔÚºõ
} VkAttachmentLoadOp;


// subpass 执行后做何种处理
typedef enum VkAttachmentStoreOp {
VK_ATTACHMENT_STORE_OP_STORE = 0,  //保存
VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, //
} VkAttachmentStoreOp;


现在我们来填充这个结构 :

VkAttachmentDescription colorAttachment = {};
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;


因为我们不使用multiSampling ,所以这里samples 取值 _1_BIT 。

colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;


loadOp
storeO
表示渲染前和渲染后要做的动作,在我们的例子中,写入新片原(fragment)之前先清空FrameBuffer,使FrameBuffer变为黑色。我们想让渲染后的三角形显示到屏幕上,所以这里我们将
storeOp
设置为保存。

colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;


stencil..Op应用于stencil data ,这里我们不需要关心。

colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;


Vulkan
中,用具有特定像素格式的
VkImage
表示纹理(texture)和
FrameBuffer
,而像素在内存中的布局(
layout
)随着我们使用Image 的目的不同是可以改变的。一些常见的
layout
有:

VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
: Images 用作 color attachment

VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
: 表示一个要被显示的swap chain image源

VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
: images 作为内存拷贝操作的目的

我们将在文理(texture)部分再详细讲解这部分,现在仅需要明确的是image 在每个后续的操作中都要转变成特定的
layout


initial / finalLaout
表示渲染前后image的layout,
VK_IMAGE_LAYOUT_UNDEFINED
表示我们不在乎之前的layout,而
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
表示在渲染后,使用Swpa Chain 时,image 处于可显示的
layout


Subpasses and attachment references

一个Render Pass 由一系列的
subPass
组成,并由
subpass
处理随后的渲染操作,代表渲染的一个阶段,渲染命令存储在一个Render Pass的诸多
subpass
中,一个subpass的动作取决于上一个subpass 的处理结果,如果我们把它们打包成一个Render Pass ,Vulkan 能够为我们重新排序它们的执行顺序,节省内存带宽,从而可能获取更好的性能。

每一个
Subpass
引用一个或多个我们在前一节用
VkAttachmentDescription
描述的attachment(s) ,每一个引用用
VkAttachmentReference
描述:

VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;


attachment
表示此
VkAttachmentReference
代表哪一个
attachment
,它的值是一个索引(index),这里我们只有一个
VkAttachmentDescription
,所以索引是0, 同时这个attachment 和Frame Shader 里的:
layout(location = 0) out vec4 outColor
相对应。
layout
表示subpass 在执行时希望此atatchment具有的layout,Vulkan将自动为我们完成attachment的转换。我们想使用color buffer attachment,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
选项还会做些优化。

Subpass
本身用
VkSubpassDescription
表示:

VkSubpassDescription subPass = {};
subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;


pipelineBindPoint
表示要绑定的Pipeline类型,这里只支持两种类型:计算(compute)和图形(graphics),这里我们选择图形Pipeline。 然后我们告诉
subpass
它所引用的
attachment


subPass.colorAttachmentCount = 1;
subPass.pColorAttachments = &colorAttachmentRef;


Subpass
还可以引用的
attachment
有:

pInputAttachments: 从着色器中读取的 attachment

pResolveAttachments: multiple color attachment

pDepthStencilAttachment: depth and stencil data 的attachment

pPreserveAttachments: 不被Subpass 使用,但出于某种原因需要保存

Create Render pass

Attachment 和 Subpass 都已经声明好了,现在开始创建Render Pass:

VDeleter<VkRenderPass> renderPass {device, vkDestroyRenderPass};
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subPass;
//需要一个VkDevice 参数 即:Logical Device
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
throw std::runtime_error("failed to create render pass!");
}


不知道你的思绪是否有点混乱,让我们来理清一下。创建Render Pass 需要Subpass 和Attachment, 现在就简单的理解为Render Pass 包含Subpass 数组和 Attachment数组吧。Render Pass的工作需要Subpass 来完成, 每一个Subpass 可以操作多个Attachment ,怎么从Attachment数组中表示哪些attachment会被某个Subpass处理呢,所以我们需要一个VkAttachmentReference来描述attachment在Attachment数组中的小标和处理时的layout。

Create Pipeline

先回顾一下这一章我们都做了什么:

着色器阶段: 我们定义了 Shader module, 这是可编程部分。

配置固定功能状态(fixed-function state): Pipeline 所需要的input assembly, rasterizer, viewport and color blending 配置, 这是不可编程部分。

Pipeline layout: 主要是Uniform 变量,这些变量可以在绘画阶段动态改变。

Render pass : Attachment 的定义以及他们的使用。

现在已经到了本章的最终阶段 ->创建
Pipeline
:

VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;

pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = nullptr; // Optional
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr; // Optional

pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0; //subpass索引,表示pipeline 将会使用renderPass 里的哪个subpass.

pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1; // Optional


Vulkan允许我们从已有的Pipeline派生新的Pipeline, 它们有很多相似点会使新Pipeline的创建花费更少。这里我们没有已存在的Pipeline。

// 创建Pipeline
VDeleter<VkPipeline> graphicsPipeline {device, vkDestroyPipeline};
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}


让我们来看看这个函数:

VkResult vkCreateGraphicsPipelines(
VkDevice device,
VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkGraphicsPipelineCreateInfo* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines);


它允许我们传入多个
createInfo
来创建多个Pipeline, 第二个参数
pipelineCache
允许存储和重用数据,加速pipeine的创建过程。

原文源码 : source code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息