每次调用 glDrawArrays 函数时,如何避免 GPU 绘制到无效的屏幕外缓冲区?
How to avoid the GPU draw to the ineffectively offscreen buffer each time I call an `glDrawArrays` function?
我们正在使用 GPU
以 OpenGL ES
着色器语言进行图像处理,并将结果图像输出到屏幕外渲染缓冲区。我假设每次调用 glDrawArrays 时 GPU 都会更新帧。但是我们要绘制十多个数组,所以我认为这里可能存在潜在的性能问题。
那么我们如何避免 GPU
在所有十 glDrawArrays
完成后更新帧缓冲区。
我不确定你在问题中写的大部分内容到底是什么意思,但 99.9% 的答案是:不,GPU 不会 "update the frame buffer" 因为你多次调用glDrawArrays
.
重要的是要知道,减少绘制调用的数量会降低性能,但 "more then 10" 非常接近于只有一个绘制调用。您可能需要超过数百或数千次绘制调用,才能开始考虑通过减少绘制调用次数来进行优化。
那么让我们试着了解发生了什么,以及您似乎在这里提到的一些组件是什么:
帧缓冲区是您可以附加渲染缓冲区的缓冲区。那么什么是"updating the frame buffer"呢?这可以解释为附件已更改并且 FBO 已根据具有不同的附件进行了更新。或者附加缓冲区已更新,我们只能说它们已被绘制或已被清除。所以在第二个中我们可以说当您调用 glDrawArrays
时帧缓冲区已更新,因为渲染缓冲区已被绘制。请注意,深度缓冲区仍然是渲染缓冲区,并且仍在被绘制。
glDrawArrays
是通常需要大部分时间才能完成的绘图调用之一。抽签需要很长时间的原因很少,它们取决于场景。最常见的绘制图元是三角形,然后我们用它组合更复杂的形状,例如面部的 3D 模型。这样的模型可能包含数千个三角形,将它们绘制到缓冲区的 100x100 部分(很远)通常会因顶点过多而导致开销。我并不是说将它们绘制到 1000x1000 会减少时间(它会增加时间),但我是说您可以优化它们以使用不太详细的模型在距离较远或较小时进行绘制。但这可能不是你的情况,因为你正在进行图像处理。另一种情况是有很多要绘制的片段(像素)。在缓冲区中绘制一个占用 1000x1000 像素的矩形将重绘 1000*1000 像素。如果您需要写信给他们,没有什么可做的,但是例如,如果您有 1000x1000 缓冲区并绘制 100 个大小为 500x500 的矩形,您肯定会有开销并且可能会再次考虑优化(尽管它们并不总是可能的)。这里唯一剩下的就是绘图的复杂性。如果使用着色器,那么顶点着色器可能过于复杂(这种情况很少发生),片段着色器通常是瓶颈,但我相信您可以找到大量关于它的帖子。然后是混合;如果可能,只需禁用混合。这可能会对绘图性能产生巨大影响。
但在任何情况下,绘制调用只会绘制到当前附加到绑定帧缓冲区的渲染缓冲区。没有其他事情可以用它完成。没有其他更新。
所以你正在做一些图像处理......你应该更具体一点:
例如,如果您正在对其应用一些滤镜,例如模糊、颜色交换等,而 10 次绘制调用实际上意味着为您应用 10 个滤镜的每个滤镜重新绘制图像,那么优化非常明显:使用着色器并尝试合并过滤器,以便尽可能少地重新绘制图像。
如果您的处理方式会产生额外的数据,例如边缘检测、OCR...然后开始考虑减小图像的大小,将其重新绘制到较小的缓冲区,然后在那里施展魔法使用此缓冲区作为纹理,然后将其应用于原始图像。
此外,当您使用多个带有附加纹理的 FBO 不断重绘同一图像时,您可以检查一下纹理参数。如果源纹理和目标缓冲区的大小相同,您可以将参数设置为使用最近的纹理元素,而不是对纹理进行线性或三线性插值设置。
我们正在使用 GPU
以 OpenGL ES
着色器语言进行图像处理,并将结果图像输出到屏幕外渲染缓冲区。我假设每次调用 glDrawArrays 时 GPU 都会更新帧。但是我们要绘制十多个数组,所以我认为这里可能存在潜在的性能问题。
那么我们如何避免 GPU
在所有十 glDrawArrays
完成后更新帧缓冲区。
我不确定你在问题中写的大部分内容到底是什么意思,但 99.9% 的答案是:不,GPU 不会 "update the frame buffer" 因为你多次调用glDrawArrays
.
重要的是要知道,减少绘制调用的数量会降低性能,但 "more then 10" 非常接近于只有一个绘制调用。您可能需要超过数百或数千次绘制调用,才能开始考虑通过减少绘制调用次数来进行优化。
那么让我们试着了解发生了什么,以及您似乎在这里提到的一些组件是什么:
帧缓冲区是您可以附加渲染缓冲区的缓冲区。那么什么是"updating the frame buffer"呢?这可以解释为附件已更改并且 FBO 已根据具有不同的附件进行了更新。或者附加缓冲区已更新,我们只能说它们已被绘制或已被清除。所以在第二个中我们可以说当您调用 glDrawArrays
时帧缓冲区已更新,因为渲染缓冲区已被绘制。请注意,深度缓冲区仍然是渲染缓冲区,并且仍在被绘制。
glDrawArrays
是通常需要大部分时间才能完成的绘图调用之一。抽签需要很长时间的原因很少,它们取决于场景。最常见的绘制图元是三角形,然后我们用它组合更复杂的形状,例如面部的 3D 模型。这样的模型可能包含数千个三角形,将它们绘制到缓冲区的 100x100 部分(很远)通常会因顶点过多而导致开销。我并不是说将它们绘制到 1000x1000 会减少时间(它会增加时间),但我是说您可以优化它们以使用不太详细的模型在距离较远或较小时进行绘制。但这可能不是你的情况,因为你正在进行图像处理。另一种情况是有很多要绘制的片段(像素)。在缓冲区中绘制一个占用 1000x1000 像素的矩形将重绘 1000*1000 像素。如果您需要写信给他们,没有什么可做的,但是例如,如果您有 1000x1000 缓冲区并绘制 100 个大小为 500x500 的矩形,您肯定会有开销并且可能会再次考虑优化(尽管它们并不总是可能的)。这里唯一剩下的就是绘图的复杂性。如果使用着色器,那么顶点着色器可能过于复杂(这种情况很少发生),片段着色器通常是瓶颈,但我相信您可以找到大量关于它的帖子。然后是混合;如果可能,只需禁用混合。这可能会对绘图性能产生巨大影响。
但在任何情况下,绘制调用只会绘制到当前附加到绑定帧缓冲区的渲染缓冲区。没有其他事情可以用它完成。没有其他更新。
所以你正在做一些图像处理......你应该更具体一点:
例如,如果您正在对其应用一些滤镜,例如模糊、颜色交换等,而 10 次绘制调用实际上意味着为您应用 10 个滤镜的每个滤镜重新绘制图像,那么优化非常明显:使用着色器并尝试合并过滤器,以便尽可能少地重新绘制图像。
如果您的处理方式会产生额外的数据,例如边缘检测、OCR...然后开始考虑减小图像的大小,将其重新绘制到较小的缓冲区,然后在那里施展魔法使用此缓冲区作为纹理,然后将其应用于原始图像。
此外,当您使用多个带有附加纹理的 FBO 不断重绘同一图像时,您可以检查一下纹理参数。如果源纹理和目标缓冲区的大小相同,您可以将参数设置为使用最近的纹理元素,而不是对纹理进行线性或三线性插值设置。