Vulkan 学习(11)---- Vulkan RenderPass 创建

RenderPass 概述

Vulkan 渲染通道(RenderPass) 定义了整个渲染管线一次执行的过程,包括了渲染所使用的所有资源和操作的描述(比如指定渲染管线的渲染目标,告诉管线要渲染到哪里)

RenderPass 本质上是一个渲染流程的完整描述(管理渲染流程),包括如何渲染这些数据的元数据和指令,但是不包括实际的数据(图像),通过与 FrameBuffer 结合来获取实际的图像数据

Vulkan编程,RenderPass是必不可少的,它必须包含一个或者多个子通道(SubPass)

每个子通道表示一个渲染阶段,并且都是使用 RenderPass 中定义的资源描述这个阶段的渲染的步骤

RenderPass 是通过附件(Attachment)的形式描述图像资源,包括颜色附件(Color Attachment)、深度/模板附件(Depth/Stencil Attachment)、用于多重采样的的解析附件(Resolve Attachment)和输入附件(Input Attachment)等,

RenderPassFrameBuffer 的关系密切,FrameBuffer 代表了 RenderPass 使用的具体内存集合,定义了 RenderPass 中每个 ImageView 与附件的对应关系

RenderPass 使得开发者能够更精细的控制渲染过程,优化性能,同时适应现代GPU架构的特点

Vulkan tutorial:
Render passes in Vulkan describe the type of images that are used during rendering operations, how they will be used, and how their contents should be treated. In our initial triangle rendering application, we’ll tell Vulkan that we will use a single image as color target and that we want it to be cleared to a solid color right before the drawing operation.

(Render pass 主要标志如何和 image 交互,是作为颜色,深度,模板附件还是其他作用等)
Note:可以理解为 RenderPass 定义了对 vkImage的操作关系

RenderPass 创建

vkCreateRenderPass 的函数原型如下:

VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(
    VkDevice                                    device,
    const VkRenderPassCreateInfo*               pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkRenderPass*                               pRenderPass);

关键结构 VkRenderPassCreateInfo 的结构:

typedef struct VkRenderPassCreateInfo {
    VkStructureType                   sType;
    const void*                       pNext;
    VkRenderPassCreateFlags           flags;
    uint32_t                          attachmentCount; // 附件数量
    const VkAttachmentDescription*    pAttachments; // 附件描述
    uint32_t                          subpassCount; // 子通道数量
    const VkSubpassDescription*       pSubpasses; // 子通道描述
    uint32_t                          dependencyCount; // 子通道依赖数量
    const VkSubpassDependency*        pDependencies; // 子通道依赖描述
} VkRenderPassCreateInfo;`
附件描述

附件描述(Attachement Description) 定义了在渲染过程中使用的图像资源,包括它们的格式,样本数、加载和存储操作等
比如定义一个深度附件和模板附件:

// 定义颜色附件描述
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = VK_FORMAT_R8G8B8A8_UNORM; // 交换链图像格式
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; // 采样数
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在渲染前清除附件
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // 在渲染后存储附件内容
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 不关心模板加载操作
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 不关心模板存储操作
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 初始布局
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // 最终布局

// 定义深度模板附件描述
VkAttachmentDescription depthAttachment = {};
depthAttachment.format = VK_FORMAT_R8G8B8A8_UNORM;
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; // 采样数
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在渲染前清除附件
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 渲染后不需要存储附件内容
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 不关心模板加载操作
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 不关心模板存储操作
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 初始布局
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // 最终布局
附件说明

RenderPass 是通过附件(Attachment)的形式描述图像资源,包括颜色附件(Color Attachment)、深度/模板附件(Depth/Stencil Attachment)、用于多重采样的的解析附件(Resolve Attachment)和输入附件(Input Attachment)等

  • 颜色附件
    是片段着色器的输出目标,存储渲染输出的颜色信息,通常对应屏幕或者离屏渲染目标

  • 深度和模板附件
    用于存储深度和模板的值,用于模板和深度测试

  • 解析附件
    用于多重采样抗锯齿的颜色附件解析,将多重采样的颜色附件解析为单采样目标

  • 输入附件
    允许子通道读取前一子通道的附件数据,主要用于多子通道渲染技术,可以高效的利用片上缓存

子通道和子通道描述

VkSubpassDescription 是用于定义子通道的结构体,每个子通道表示一个渲染阶段:

typedef struct VkSubpassDescription {
    VkSubpassDescriptionFlags       flags;// 子通道描述的附加标志,目前必须为0
    VkPipelineBindPoint             pipelineBindPoint; // 管线绑定点,必须是 VK_PIPELINE_BIND_POINT_GRAPHICS
    uint32_t                        inputAttachmentCount;// 输入附件的数量
    const VkAttachmentReference*    pInputAttachments; // 输入附件数组 
    uint32_t                        colorAttachmentCount; // 颜色附件数量
    const VkAttachmentReference*    pColorAttachments; // 颜色附件数组
    const VkAttachmentReference*    pResolveAttachments; // 解析附件数组
    const VkAttachmentReference*    pDepthStencilAttachment; // 深度附件数组
    uint32_t                        preserveAttachmentCount;
    const uint32_t*                 pPreserveAttachments;
} VkSubpassDescription;

子通道描述了渲染管道一个阶段及其输入输出附件:

// 定义颜色附件引用
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0; // 绑定到第一个附件描述
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // 最佳颜色附件布局

// 定义深度模板附件引用
VkAttachmentReference depthAttachmentRef = {};
depthAttachmentRef.attachment = 1; // 绑定到第二个附件描述
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // 最佳深度模板附件布局

// 定义子通道描述
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; // 图形管线绑定点
subpass.colorAttachmentCount = 1; // 颜色附件数量
subpass.pColorAttachments = &colorAttachmentRef; // 颜色附件引用
subpass.pDepthStencilAttachment = &depthAttachmentRef; // 深度模板附件引用
子通道依赖

TBD

RenderPass 的创建流程可以用下图表示:
RenderPass Create

参考代码
 // 定义颜色附件描述
 VkAttachmentDescription colorAttachment = {};
 colorAttachment.format = VK_FORMAT_R8G8B8A8_UNORM; // 交换链图像格式
 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; // 采样数
 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在渲染前清除附件
 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // 在渲染后存储附件内容
 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 不关心模板加载操作
 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 不关心模板存储操作
 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 初始布局
 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // 最终布局

 // 定义深度模板附件描述
 VkAttachmentDescription depthAttachment = {};
 //depthAttachment.format = findDepthFormat(physicalDevice); // 深度模板格式
 depthAttachment.format = VK_FORMAT_R8G8B8A8_UNORM;
 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; // 采样数
 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // 在渲染前清除附件
 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 渲染后不需要存储附件内容
 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // 不关心模板加载操作
 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 不关心模板存储操作
 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // 初始布局
 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // 最终布局

 // 定义颜色附件引用
 VkAttachmentReference colorAttachmentRef = {};
 colorAttachmentRef.attachment = 0; // 绑定到第一个附件描述
 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // 最佳颜色附件布局
 
 // 定义深度模板附件引用
 VkAttachmentReference depthAttachmentRef = {};
 depthAttachmentRef.attachment = 1; // 绑定到第二个附件描述
 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // 最佳深度模板附件布局

 // 定义子通道描述
 VkSubpassDescription subpass = {};
 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; // 图形管线绑定点
 subpass.colorAttachmentCount = 1; // 颜色附件数量
 subpass.pColorAttachments = &colorAttachmentRef; // 颜色附件引用
 subpass.pDepthStencilAttachment = &depthAttachmentRef; // 深度模板附件引用

 // 定义子通道依赖
 // 子通道依赖数组,用于布局转换
 //std::array<VkSubpassDependency, 2> dependencies;
 VkSubpassDependency dependencies[2];
 // 第一个依赖关系
 dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; // 外部到第一个子通道的依赖
 dependencies[0].dstSubpass = 0; // 目标子通道索引为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; // 目标子通道索引为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; // 无额外依赖标志


 // 创建 RenderPass
 VkAttachmentDescription attachments[] = { colorAttachment, depthAttachment }; // 定义附件数组
 
 VkRenderPassCreateInfo renderPassInfo = {};
 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 renderPassInfo.attachmentCount = 2; // 附件数量
 renderPassInfo.pAttachments = attachments; // 附件描述
 renderPassInfo.subpassCount = 1; // 子通道数量
 renderPassInfo.pSubpasses = &subpass; // 子通道描述
 renderPassInfo.dependencyCount = 2; // 子通道依赖数量
 renderPassInfo.pDependencies = dependencies; // 子通道依赖描述
 
 if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
     throw std::runtime_error("failed to create render pass!");
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值