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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章