绑定帧缓冲区对象有多昂贵,即使用glBindFramebuffer(GL_FRAMEBUFFER,...)?我在谷歌上找不到任何关于每帧更改帧缓冲器实际的次数。我问,因为我正在编写一个2D渲染器,它支持C ++中的后期处理,并且在每次绘制调用(多边形,线条,图像)开始时显式绑定帧缓冲区是最优雅的代码路径,但到目前为止我还没有有足够的东西来衡量它。在每次绘制调用开始时绑定帧缓冲区的替代方法是始终保持绑定,除非我需要绘制到屏幕,但这需要我不将调用交错到两个不同的渲染器实例(这是可行的,但限制性的。)
我找到了this question,但它已经超过四年了(引用的文字已经过了五年)并且它并没有完全回答同一个问题。每帧多次绑定和解绑FBO导致的性能损失足以保证手动管理哪个帧缓冲区被绑定?
答案 0 :(得分:6)
由于性能特征经常出现这种情况,因此没有简单的答案。它在很大程度上取决于硬件架构,驱动程序优化和使用条件。
首先给你tl; dr:切换渲染表面可以相当便宜且非常昂贵。我的建议如下:
我不愿意给出每帧开关数量无害的数字。主要是因为我没有它们,我不想猜。而且因为它取决于很多因素。我从一个非常可靠的消息来源得知,在至少一个平台上,每帧只有2或3个交换机会对性能产生非常大的负面影响。除了这个非常糟糕的情况,我的直觉会告诉我,我会尽量避免切换超过10-100次。但这真的只是一种猜测,而且你可以获得更多,尤其是如果你的目标是有限的一套硬件,这绝对是可能的。
您的问题听起来像涵盖两种不同的情况。让我分开讨论一下:
根据您的描述,听起来您部分拥有此使用模式:
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glDraw...(...);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glDraw...(...);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
在这种情况下,您进行glBindFramebuffer()
次调用,但所有渲染都会转到相同的帧缓冲区。我希望大多数驱动程序检测到这些绑定调用是多余的,而不是做任何认真的工作。尽管有时候司机是否应该发现多余的状态变化存在哲学上的争议,但他们大多都会这样做。
这取决于您在这种情况下对GPU /驱动程序供应商的信任程度。除非我对它进行了基准测试,否则在这样的情况下,我倾向于处于偏执的一面。如果在我的软件架构中有任何合理的方法,我会避免冗余调用。
正如我在介绍中提到的,这里发生的是高度GPU和驱动程序相关。只是将状态切换到点渲染到另一个目标是便宜的。但它可以有更多。
您经常需要与活动渲染目标关联的其他内存分配。典型示例包括用于早期深度测试的缓冲区和压缩颜色缓冲区。当您切换到不同的渲染目标时,这些分配会发生什么情况取决于硬件架构,驱动程序实现以及可能的其他条件:
使用平铺式架构会变得更加有趣,这些架构以各种方式在移动设备上得到广泛使用。平铺体系结构的关键卖点是它们每个像素只能运行一次片段着色器,并且必须将每个tile只写入帧缓冲一次,这样可以减少写入帧缓冲区的总内存带宽,并且还可以大大提高这些写入的局部性因为整个瓷砖是立刻写的。
据我所知,用于存储将为每个图块渲染的三角形的图块内存通常是片上存储器。因此,如果您切换帧缓冲区,则必须:
我不知道哪种方法最常用(如果我这样做,我可能无法分享)。但是它们听起来都非常昂贵,如果频繁发生,就会失败使用基于磁贴的架构的整个目的。
答案 1 :(得分:4)
绑定帧缓冲区对象的成本有多贵
不是很多。基本上,OpenGL实现的工作量不会超过双缓冲交换后的工作量。
真正伤害性能的是切换FBO的附件,因为每次发生这种情况都必须检查FBO的有效性,这是一项代价高昂的操作。
有趣的顶点阵列对象(VAO),在现有的OpenGL实现中切换是昂贵的,到目前为止,业界的常见做法是重新绑定缓冲区对象和顶点属性指针/偏移。我只是提到这个,因为表面FBO和VAO的外观和行为非常相似,但它们现在表现出截然不同的性能配置文件。
答案 2 :(得分:0)
是的,这是你应该担心的事情。 一遍又一遍地(冗余地)绑定相同的FBO并不慢,但是在不同的FBO之间不断切换实际上非常慢。在我的电脑上大约25微秒(GTX 460 + i7 870)。这与FBO只有一个或两个附件(颜色和深度) 我不能说MRT有多快/慢。 如果切换FBO很快,Nvidia就不会发布 this 。