具有早期返回和分支的GLSL顶点着色器性能

时间:2018-05-02 21:45:38

标签: opengl-es glsl webgl

我有一个顶点着色器

void main (){

    vec4 wPos = modelMatrix * vec4( position , 1. );

    vWorldPosition = wPos.xyz;

    float mask = step(
        0.,
        dot(
            cameraDir, 
            normalize(normalMatrix * aNormal)
        )
    );

    gl_PointSize = mask * uPointSize;

    gl_Position = projectionMatrix * viewMatrix * wPos;

}

我不完全确定如何测试着色器的性能,并排除其他因素,如过度绘制。我想象一个大小为1的点,在屏幕空间中排列成网格,没有任何重叠会起作用吗?

否则我对这些调整感到好奇:

(删除step,删除乘法,介绍if else

void main (){

    if(dot(
         cameraDir, 
         normalize(normalMatrix * aNormal) //remove step
    ) < 0.) {
        gl_Position = vec4(0.,.0,-2.,.1); 
        gl_PointSize = 0.;
    } else {

        gl_PointSize = uPointSize; //remove a multiplication

        vec4 wPos = modelMatrix * vec4( position , 1. );

        vWorldPosition = wPos.xyz;
        gl_Position = projectionMatrix * viewMatrix * wPos;
    }

}

对比这样的事情:

void main (){

    if(dot(
         cameraDir, 
         normalize(normalMatrix * aNormal) 
    ) < 0.) {
        gl_Position = vec4(0.,.0,-2.,.1); 
        return;
    }

    gl_PointSize = uPointSize; 

    vec4 wPos = modelMatrix * vec4( position , 1. );

    vWorldPosition = wPos.xyz;

    gl_Position = projectionMatrix * viewMatrix * wPos;

}

这些着色器的行为会不同,为什么/如何?

我感兴趣的是,有什么东西可以量化性能上的差异。

  • 是否有一些价值,例如MAD的数量或其他代码显然会产生的其他东西?
  • 不同代的GPU会不同地处理这些差异吗?
  • 如果步骤版本保证最快,是否有一个已知的模式列表,可以避免如何避免分支,以及更喜欢哪些操作? (比如使用floor代替step也可能吗?)

float condition = clamp(floor(myDot + 1.),0.,1.); //is it slower?

2 个答案:

答案 0 :(得分:1)

有条件分支在GPU上很昂贵 - 通常比乘法更昂贵,因此修改后的着色器可能会更慢。

答案 1 :(得分:1)

有太多变量,所以答案是“它取决于”。一些GPU可以处理分支。有些不能和代码被编译器扩展,因此没有分支,只有数学乘以0而其他数学不是。然后有一些事情,比如平铺GPU,试图积极避免透支。我确定还有其他因素。

理论上,您可以运行着色器的百万或几百万次迭代并使用

计时
gl.readPixels(one pixel);
const start = performance.now();
...draw a bunch..
gl.readPixels(one pixel);
const end = performance.now();
const elapsedTime = end - start;

gl.readPixels是一个同步操作,因此它会停止GPU管道。 elapsedTime本身并不是实际的时间,因为它包括启动GPU并将其停止等等,但似乎您可以将一个着色器中的elapsedTime与另一个着色器进行比较以查看哪个更快。

换句话说,如果elapsedTime为10秒,则并不意味着您的着色器需要十秒钟。这意味着启动gpu,运行着色器并停止GPU需要10秒钟。这些秒数中有多少是开始的,有多少是停止的,有多少是你的着色器不可用。但是,如果一个着色器的elaspedTime为10秒而另一个着色器为11,那么可以说一个着色器比另一个着色器快。请注意,您可能希望让测试时间足够长,以便获得几秒钟的差异而不是微秒的差异。您还需要在多个GPU上进行测试,以确定速度差异是否始终为真。

请注意,在顶点着色器中调用return不会阻止生成顶点。事实上,gl_Position在这种情况下是未定义的。