帧缓冲

在过去的几个章节中,我们已经讨论了很多关于帧缓冲的内容,并且我们已经设置了渲染通道以期望一个与交换链图像格式相同的单个帧缓冲,但我们实际上还没有创建任何帧缓冲。

在渲染通道创建期间指定的附件通过将它们包装到 VkFramebuffer 对象中来绑定。帧缓冲对象引用表示附件的所有 VkImageView 对象。在我们的例子中,这只有一个:颜色附件。但是,我们必须用于附件的图像取决于交换链在检索用于演示的图像时返回的图像。这意味着我们必须为交换链中的所有图像创建帧缓冲,并在绘制时使用与检索到的图像相对应的帧缓冲。

为此,创建另一个 std::vector 类成员来保存帧缓冲

std::vector<VkFramebuffer> swapChainFramebuffers;

我们将在一个新的函数 createFramebuffers 中为这个数组创建对象,该函数在创建图形管线之后从 initVulkan 中调用

void initVulkan() {
    createInstance();
    setupDebugMessenger();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createRenderPass();
    createGraphicsPipeline();
    createFramebuffers();
}

...

void createFramebuffers() {

}

首先调整容器大小以保存所有帧缓冲

void createFramebuffers() {
    swapChainFramebuffers.resize(swapChainImageViews.size());
}

然后,我们将迭代图像视图并从中创建帧缓冲

for (size_t i = 0; i < swapChainImageViews.size(); i++) {
    VkImageView attachments[] = {
        swapChainImageViews[i]
    };

    VkFramebufferCreateInfo framebufferInfo{};
    framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
    framebufferInfo.renderPass = renderPass;
    framebufferInfo.attachmentCount = 1;
    framebufferInfo.pAttachments = attachments;
    framebufferInfo.width = swapChainExtent.width;
    framebufferInfo.height = swapChainExtent.height;
    framebufferInfo.layers = 1;

    if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
        throw std::runtime_error("failed to create framebuffer!");
    }
}

如你所见,创建帧缓冲非常简单。我们首先需要指定帧缓冲需要与哪个 renderPass 兼容。你只能将帧缓冲与它兼容的渲染通道一起使用,这大致意味着它们使用相同数量和类型的附件。

attachmentCountpAttachments 参数指定应绑定到渲染通道 pAttachment 数组中相应附件描述的 VkImageView 对象。

widthheight 参数是不言自明的,而 layers 指的是图像数组中的层数。我们的交换链图像是单个图像,因此层数是 1

我们应该在删除图像视图和它们所基于的渲染通道之前删除帧缓冲,但只能在我们完成渲染之后

void cleanup() {
    for (auto framebuffer : swapChainFramebuffers) {
        vkDestroyFramebuffer(device, framebuffer, nullptr);
    }

    ...
}

我们现在已经达到了里程碑,我们拥有渲染所需的所有对象。在下一章中,我们将编写第一个实际的绘制命令。