在Vulkan中,渲染通道 Render Pass
是一个描述渲染过程中使用的附件的对象,可以包含多个 subpass
和附件依赖关系
假设我们需要创建一个render pass,它包含2个附件、1个子通道、2个子通道依赖
步骤如下:
initialLayout
、finalLayout
指定的是该附件在Renderpass之前和之后的布局,这个布局会在渲染过程中发生改变,不过最终布局还是会变成 finalLayout
指定的那样void setupRenderPass()
{// 两个附件的描述符std::array attachments = {};attachments[0].format = VK_FORMAT_B8G8R8A8_UNORM; attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; // 不使用多重采样attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在渲染通道开始时清除此附件attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // 在渲染通道结束后保留其内容(以供显示)attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 不使用模板,所以不需要加载attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;// 同上attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 渲染通道开始时的布局。初始布局并不重要,所以我们使用未定义的布局attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // 渲染通道结束时转换到的布局,由于我们想将颜色缓冲区呈现到交换链,因此我们转换为PRESENT_KHR布局attachments[1].format = VK_FORMAT_D32_SFLOAT_S8_UINT; attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在第一个子通道开始时清除深度attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 渲染通道结束后我们不需要深度(DONT_CARE可以提高性能)attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 没使用模板attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 理由同上attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // 转换为深度/模板附件的布局
subpass
中的初始布局VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
是一个指定图像布局的枚举值,表示图像在当前子通道中被用作颜色附件时的最优布局。这个布局是对颜色附件进行优化的,以便最大化图形渲染的性能。这个布局在颜色附件被用作输入附件时是不合适的,因为它会使输入附件的读取性能变慢。后面的深度附件引用也同理 // Setup attachment referencesVkAttachmentReference colorReference = {};colorReference.attachment = 0; colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference depthReference = {};depthReference.attachment = 1; depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
子通道的处理过程中,附件引用的布局在创建引用的时候就指定过了
VkSubpassDescription subpassDescription = {};subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;subpassDescription.colorAttachmentCount = 1; subpassDescription.pColorAttachments = &colorReference; // 颜色附件引用subpassDescription.pDepthStencilAttachment = &depthReference;// 深度附件引用
VK_SUBPASS_EXTERNAL
是一个特殊的常数,它代表所有在实际渲染通道之外执行的命令COLOR_ATTACHMENT_OPTIMAL
转换为 TRANSFER_SRC_OPTIMAL
以进行图像数据拷贝 // Setup subpass dependenciesstd::array dependencies;dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;dependencies[0].dstSubpass = 0;dependencies[0].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;dependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;dependencies[0].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;dependencies[0].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;dependencies[0].dependencyFlags = 0;dependencies[1].srcSubpass = VK_SUBPASS_EXTERNAL;dependencies[1].dstSubpass = 0;dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependencies[1].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependencies[1].srcAccessMask = 0;dependencies[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;dependencies[1].dependencyFlags = 0;
// Create the actual renderpassVkRenderPassCreateInfo renderPassInfo = {};renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;renderPassInfo.attachmentCount = static_cast(attachments.size()); // renderpass附件数renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; // subpass个数renderPassInfo.pSubpasses = &subpassDescription; renderPassInfo.dependencyCount = static_cast(dependencies.size()); // subpass dependencies个数renderPassInfo.pDependencies = dependencies.data(); VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass));
}