为啥片段着色器比渲染纹理更快?

Posted

技术标签:

【中文标题】为啥片段着色器比渲染纹理更快?【英文标题】:Why fragment shader is faster than just rendering texture?为什么片段着色器比渲染纹理更快? 【发布时间】:2012-12-11 03:33:08 【问题描述】:

我检查了一些东西,我得到了关于 C++ & OpenGL & GLSL 性能的奇怪结果。

在第一个程序中,我使用片段着色器将像素绘制到纹理上,然后渲染纹理。 纹理的 mag\min 为 GL_NEAREST

在第二个程序中,我使用片段着色器并直接渲染到屏幕上。

为什么第二个程序更快?渲染纹理不是比重复相同的动作更快吗?

这就像拍摄 AAA 游戏的视频,然后在同一台计算机上显示,视频的 FPS 较低。

片段着色器是:

uniform int mx,my;

void main(void) 
    vec2 p=gl_FragCoord.xy;
    p-=vec2(mx,my);
    if (p.x<0.0)
        p.x=-p.x;
    if (p.y<0.0)
        p.y=-p.y;
    float dis=sqrt(p.x*p.x+p.y*p.y);
    dis+=(abs(p.x)+abs(p.y))-(abs(p.x)-abs(p.y));
    p.x/=dis;
    p.y/=dis;
    gl_FragColor=vec4(p.x,p.y,0.0,1.0);

【问题讨论】:

直接将其渲染到屏幕不会涉及任何纹理读取,因此这很可能会更快。离屏渲染不一定更快,但更实用。片段着色器也可以写入多个纹理。需要正确的分析。您如何确定哪个更快? @Grimmy clock_tclock 在 SwapBuffers 之前和之后。 【参考方案1】:

与通常的性能问题一样,真正确定的唯一方法是使用分析器。

也就是说,我的猜测是,这主要是处理带宽与内存带宽的问题。为了渲染纹理,处理器必须从内存的一部分读取数据,并将相同的数据写回内存的另一部分。

要直接从着色器渲染,处理器只需将输出写入内存,而不必从内存中读取数据。

因此,这是一个更快的问题:从内存中读取特定数据,还是使用处理单元生成它?着色器中的数学运算非常简单(本质上唯一复杂的部分是sqrt)——所以至少对于您的特定硬件,计算结果似乎比从内存中读取结果要快一些(至少考虑到其他内存访问同时进行等)

请注意,两者(着色器与纹理)具有完全不同的特征。无论创建纹理涉及的计算多么简单或复杂,读取纹理的速度几乎都是恒定的。不是说显而易见的,但是如果计算很简单,着色器会运行得很快,但如果计算变得复杂,就会减慢(可能很多)。在您提到的 AAA 游戏中,可以公平地猜测,至少有一些着色器使用了足够复杂的计算,它们几乎肯定会比纹理读取慢。在相反的极端情况下,一个非常简单的着色器(例如,只是将片段颜色从输入传递到输出的着色器)可能比从纹理中读取要快得多。

【讨论】:

我同意。由于着色器/纹理处理之间的时间差异,我们有诸如光照贴图之类的技术,它使用纹理在场景周围生成灯光,因为它的计算效率比在着色器中执行相同的操作要高效得多,并且可以节省大量处理时间,尤其是在控制台上.这一切都归结为机器的设置,唯一能保证最佳效果的方法就是亲自尝试。 那么小texture2D 比所有代码都慢?没有更快的替代品吗?我不介意在渲染中不需要模糊纹理的质量。 @FijiWiji:是的,纹理访问很慢。瓶颈是可用的内存带宽,这是硬件限制。您可以使纹理更小,以减少带宽需求,但仅此而已。换个角度来看:使用冷纹理缓存,现代 GPU 需要多达 200 个时钟周期才能完成内存访问。 200 个时钟周期,其中可以计算很多。由于这些延迟,GPU 有非常大的纹理缓存,但如果纹理提取的模式不好,这些缓存将毫无用处。 @datenwolf 我不能像数组一样直接访问它? @FijiWiji:实际上直接访问纹理,因为在原始数组中甚至比使用纹理提取函数还要慢。为了快速,纹理访问地址必须正确对齐。纹理缓存大大提高了对齐、行为良好的访问模式的内存吞吐量。

以上是关于为啥片段着色器比渲染纹理更快?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的着色器中的 GLSL 纹理坐标不是线性的?

为啥我的 Ray March 片段着色器反射纹理查找会减慢我的帧速率?

GLSL:无法从 FBO 读取纹理并使用片段着色器渲染到另一个 FBO

纹理上的片段着色器

在片段着色器中,为啥我不能使用平面输入整数来索引 sampler2D 的统一数组?

从片段着色器中的地形高程数据计算法线