Vulkan大闷锅之RenderPass

Render Pass(渲染通道?),提供渲染过程所需的信息。手动配置一堆静态数据(减少动态开销?)。Render Pass由一系列Subpass聚合而成,每个Subpass携带特定的Attachment——笼统地分为Color Attachment或Depth Attachment。这些信息将决定后续Buffer中的数据如何被对待。

先创建2个Attachment,分别表示色彩和深度:

VkAttachmentDescription attachments[2];
attachments[0].format = format;
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;
attachments[0].flags = 0;

attachments[1].format = depth_format;
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;
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;
attachments[1].flags = 0;

创建Subpass不能直接引用Attachment。需要先创建VkAttachmentReference

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

VkAttachmentReference depth_reference = {};
depth_reference.attachment = 1;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_reference;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = &depth_reference;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;

上述Reference配置了Attachment的数组索引,真实数据将在Render Pass创建时引入:

VkRenderPassCreateInfo rp_info = {};
rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rp_info.pNext = nullptr;
rp_info.attachmentCount = 2;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = nullptr;
VkRenderPass render_pass;
res = vkCreateRenderPass(device, &rp_info, nullptr, &render_pass);
assert(res == VK_SUCCESS);

使用时还需要创建Frame Buffer来粘合Render Pass与相关的Swapchain:

VkImageView attach_views[2];
attach_views[1] = depth.view;

VkFramebufferCreateInfo fb_info = {};
fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fb_info.pNext = nullptr;
fb_info.renderPass = render_pass;
fb_info.pAttachments = attach_views;
fb_info.width = WIDTH;
fb_info.height = HEIGHT;
fb_info.layers = 1;

VkFramebuffer *framebuffers = (VkFramebuffer *)malloc(swapchainImageCount * sizeof(VkFramebuffer));
assert(framebuffers);
for (uint32_t i = 0; i < swapchainImageCount; ++i)
{
  attach_views[0] = swapchainBuffers[i].view;
  res = vkCreateFramebuffer(device, &fb_info, nullptr, &framebuffers[i]);
  assert(res == VK_SUCCESS);
}

FrameBuffer主要目的是离屏渲染,同时方便了后期制作,比如说无边框窗口。它在OpenGL中是可选的,Vulkan必须创建。

原本的可选组件,现在必须手动设置,哪怕为空,这大概是的Vulkan的设计思路。

其余内容,请关注后续博文。

Leave a Reply

Your email address will not be published. Required fields are marked *