帧缓冲区和交换链到底是啥?

Posted

技术标签:

【中文标题】帧缓冲区和交换链到底是啥?【英文标题】:What exactly are framebuffers and swapchains?帧缓冲区和交换链到底是什么? 【发布时间】:2021-04-28 10:58:38 【问题描述】:

所以我对帧缓冲区的概念有点困惑。我已经完成了研究,但我总是发现不同的定义,通常是这两个:

帧缓冲区是多个不同图像的数组。但这个定义,或者至少对我来说,听起来更像是交换链:一系列帧缓冲区

帧缓冲区是形成单个图像的像素数组,有点像位图(但从我读过的内容来看,它可以包含更多信息而不仅仅是颜色,比如深度值和东西),当该位图被管道填充时,它会排队等待呈现。这对我来说更有意义,因为这样交换链也有意义:帧缓冲区的集合,因此可以有一个用作渲染目标,另一个用于呈现,在双缓冲的情况下,并且交换链处理以正确的时间交换它们以提高帧率稳定性

以下哪个是正确的?因为我厌倦了每次寻找一些信息时都会听到不同的东西。

请记住,我正在学习 Vulkan,完全没有图形经验(我知道不建议这样做)所以我现在对概念比对代码更感兴趣

【问题讨论】:

【参考方案1】:

用 Vulkan 的说法,VkFramebuffer 是一个引用图像的容器,这些图像可用作渲染通道实例中的附件。渲染通道附件是渲染操作的目的地。因此,如果您想渲染到特定图像,在某些时候,您需要将其推入VkFramebuffer 并调用vkCmdBeginRenderPass

交换链与帧缓冲区无关(技术上)。交换链是您不拥有的一系列图像。您可以要求显示引擎借用其中一个图像一段时间,在此期间您可以渲染给它或交换链允许您对其图像执行的任何其他操作。一段时间后,您可以告诉显示引擎将您使用过的图像显示到特定的显示器上,之后您将无法使用该交换链图像,直到您再次借用它。

因此,尽管它们都有“一系列图像”,但它们绝不相同。帧缓冲区在渲染操作期间渲染到它们的所有图像(与渲染通道的子通道附件用法一致)。您不应同时借用交换链的所有图像。您一次只能借一个(每个显示表面一个)。

现在,由于交换链图像只能以显示引擎允许的方式使用,并且显示引擎需要允许您使用它的唯一方式是作为颜色附件,如果您实际上想在显示设备中查看结果(Vulkan 不需要),来自交换链的图像将在某个时候以VkFramebuffer 结束。

【讨论】:

但是为什么图片需要放在两个不同的地方呢?帧缓冲区图像和交换链图像有什么区别?,图像首先经过哪些? ...这太多了 @Karlos:你问的问题都没有道理。您将 VkFramebuffer 中的图像放置在那里,用作渲染过程中的附件。交换链中的图像由 显示引擎(又名:不是您)放置在那里,由您的应用程序借用并根据需要呈现。这是两个完全不同的东西,目的完全不同。没有重叠。 交换链图像是实际的图像,在内存中有(可能有?)为它们分配的空间,而帧缓冲图像更像是指向要绘制的内容的链接。【参考方案2】:

它的历史演变过程有点问题。

从历史上看,帧缓冲区是一帧的所有内容,而且它在很大程度上是不透明的。这包括颜色缓冲区、深度缓冲区(以及 Vulkan 中的新功能:输入缓冲区)。

历史上也没有那么多的预处理和计算,而且事情都与屏幕相关联。因此与交换链的关联。但是 Vulkan 很容易成为无头的,所以这没有任何意义。

因此,有时“帧缓冲区”可互换地用于“颜色缓冲区交换链图像”。但通常(特别是 Vulkan 对象)意味着“需要特别考虑的帧缓冲区”;不仅是颜色缓冲,而且不管它们是否最终出现在屏幕上。

【讨论】:

【参考方案3】:

我在你现在的位置,不久前,所以也许我可以从菜鸟的角度解释一下。

当您准备使用 Vulkan 在 GPU 上渲染帧时,您需要在 GPU 上的一些内存块中执行这些绘图操作。这些内存块称为图像。要在 GPU 上渲染事物,您可以使用 Shader 程序。这些着色器程序需要知道它们将绘制到哪个内存块中——换句话说,绘制到哪个图像中。一个着色器可以绘制多个图像。在片段着色器中,它会是这样的:

layout(location 0) out vec4 imgA;
layout(location 1) out vec4 imgB;

vec4,在这种情况下,是图像的每个像素具有的通道数量(例如 RGBA)。因此,您将向每个像素写入 4 个分量。每个location 代表不同的图像。

因此,每个(片段)着色器都可以写入 1 个或多个图像。但是,着色器也可以从传递给它们的图像中读取。这通常用于将图像构建为一系列步骤,然后您稍后将它们组合在一起。想象一下像 Adob​​e Photoshop 图像这样的东西,它由一系列图层组成。不同的 Passes/Renderpasses/Subpasses 代表一个新的层或效果。如果片段着色器写入 1 个输出图像,那么这就像 1 个新层。如果它写入 2 个输出图像,那么它就像那个着色器的 2 层,依此类推。这些图像可以作为输入传递给同一帧内的后续着色器。在框架构建过程的最后一步,您抓取所有之前制作的图像并将它们组合成最终图像,然后(通常)通过将其写入交换链图像将其显示到屏幕上。

所以,VkFramebuffer 是一个类似于列表的结构,用于组织我们将提供给着色器进行绘图操作的图像集。其中一些图像将用作输入,其他图像将用作输出等。

当你创建一个VkRenderpass 对象时,你告诉它会有 X 数量的输入图像、彩色图像、深度图像等。但你没有告诉它哪些实际图像使用(如用于这些图像的实际 RAM)。 VkFramebuffer 是您将实际图像(内存/RAM)绑定到 VkRenderpass 的位置。

所以,VkFramebuffer 是一种将实际图像绑定到 VkRenderpass 中的占位符的方法。

交换链是 GPU 上一系列预制的内存块(图像)。它具有特殊的特性,写入它就像直接写入窗口表面(有点)。因为它们只是图像(尽管有特殊要求),它们可以绑定到VkFramebuffers,从而被着色器写入。

【讨论】:

以上是关于帧缓冲区和交换链到底是啥?的主要内容,如果未能解决你的问题,请参考以下文章

快速交换帧缓冲区 OpenGL

vfb-虚拟帧缓冲区的目的是啥?

多个视口与多个帧缓冲区之间的使用差异是啥?

openGL 中的帧速率和绘制流程

将我的场景渲染到帧缓冲区对象(FBO)然后将该 FBO 渲染到屏幕所需的步骤是啥?

防止 OpenGL 缓冲帧