Shader的if优化

Shader使用GPU来运算的,判断语句会使GPU中的硬件单元不能单纯的做计算,还需要去做逻辑判断,导致不能大规模数据通过相同的逻辑结构来做并行计算。

GPU不得不根据判断语句构建多个流水线阶段,在流水线之间根据临时计算的值来做跳转。

简单的if可以使用step这种函数来替换掉。

例子1

例如:

float offset(float x){
        if(x < 0.1) return 0.0;
        else if(x < 0.2) return x-0.1;
        else if(x < 0.7) return 0.1;
        else if(x <= 1.0) return (1.0-x)/3.0;
    }

使用step替换之后:

float offset(float x){
        float x_1 = step(x,0.1);//x < 0.1 return 1 else return 0
        float x_2 = step(x,0.2);//x < 0.2 return 1 else return 0                        
        float x_3 = step(x,0.7);//x < 0.7 return 1 else return 0                      
        float x_4 = step(x,1.0);//x < 1.0 return 1 else return 0
        return x_1*0.0 + (1-x_1)*x_2*(x-0.1) + (1-x_1)*(1-x_2)*x_3*0.1 +  (1-x_1)*(1-x_2)*(1-x_3)*x_4*(1.0-x)/3.0;
}

例子2

想使用shader来写一个四方格往四周扩散的效果:
这里写图片描述
若使用if语句:

void main() {

        float pts_1 = sin(pts/600);

        vec2 newCoord = texcoord;

        if(texcoord.x < 0.5 && texcoord.y < 0.5){
            newCoord = (texcoord - vec2(0.0,0.0) )*2;
            newCoord = newCoord + vec2(abs(pts_1),abs(pts_1));
        }
        else if(texcoord.x > 0.5 && texcoord.y < 0.5){
            newCoord = (texcoord - vec2(0.5,0.0) )*2;
            newCoord = newCoord + vec2(-abs(pts_1),abs(pts_1));
        }
        else if(texcoord.x < 0.5 && texcoord.y > 0.5){
            newCoord = (texcoord - vec2(0.0,0.5) )*2;
            newCoord = newCoord + vec2(abs(pts_1),-abs(pts_1));
        }
        else if(texcoord.x > 0.5 && texcoord.y > 0.5){
            newCoord = (texcoord - vec2(0.5,0.5) )*2;
            newCoord = newCoord + vec2(-abs(pts_1),-abs(pts_1));
        }

        if(newCoord.x < 0.01 || newCoord.x > 0.99 ) newCoord = texcoord;
        if(newCoord.y < 0.01 || newCoord.y > 0.99 ) newCoord = texcoord;

        gl_FragColor = vec4(texture2D(texture, newCoord.xy).rgb, 1.0);
}

优化之后:

void main() {

        float pts_1 = sin(pts/600);

        vec2 newCoord = texcoord;

        float x_1 = step(texcoord.x,0.5);//x < 0.5 return 1 else return 0
        float y_1 = step(texcoord.y,0.5);//y < 0.5 return 1 else return 0                        
        newCoord = (newCoord - vec2((1.0-x_1)*0.5,(1.0-y_1)*0.5) )*2;//分为四个方格
        newCoord = newCoord +  vec2(2.0*(x_1-0.5)*abs(pts_1),2.0*(y_1-0.5)*abs(pts_1));//随着时间往四周移动

        if(newCoord.x < 0.01 || newCoord.x > 0.99 ) newCoord = texcoord;
        if(newCoord.y < 0.01 || newCoord.y > 0.99 ) newCoord = texcoord;

        gl_FragColor = vec4(texture2D(texture, newCoord.xy).rgb, 1.0);
}

主要就可以构建大量逻辑相同的并行运算单元,将数据并行的投入其中。

发布了137 篇原创文章 · 获赞 22 · 访问量 12万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章