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

GLSL vertex shader performance with early return and branching

我有一个顶点着色器

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 的点,在屏幕 space 中排列成网格,没有任何重叠会起作用吗?

否则我对这些调整很好奇:

(删除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;

}

这些着色器的行为是否会有所不同,why/how?

如果有什么东西可以量化性能差异,我很感兴趣。

.

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

条件分支在 GPU 上的开销很大——通常比乘法开销大得多,因此您修改后的着色器可能更慢。

变量太多,所以答案是 "it depends"。一些 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 秒,这并不意味着您的着色器花费了 10 秒。这意味着启动 gpu、运行 着色器和停止 GPU 需要 10 秒。这些秒中有多少是开始的,有多少是停止的,有多少是你的着色器不可用。但是,如果一个着色器的 elaspedTime 是 10 秒而另一个着色器是 11 秒,那么可以肯定地说一个着色器比另一个快。请注意,您可能想让测试时间足够长,以便得到秒级的差异而不是微秒级的差异。您还需要在多个 GPU 上进行测试,看看速度差异是否始终成立。

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