I have implemented a two pass Gaussian blur shader in GLSL like this:
...
const float[] weights = float[](0.382928, 0.241732, 0.060598, 0.005977, 0.000229);
vec2 offset = vec2(1.0f) / vec2(textureSize(image, 0));
vec3 result = texture(image, vec3(io_textureCoordinates, layer)).rgb * weights[0];
if(horizontal) {
for(int i = 1; i < weights.length(); i++){
result += texture(image, vec3(io_textureCoordinates + vec2(offset.x * float(i), 0.0f), layer)).rgb * weights[i];
result += texture(image, vec3(io_textureCoordinates - vec2(offset.x * float(i), 0.0f), layer)).rgb * weights[i];
}
} else {
for(int i = 1; i < weights.length(); i++){
result += texture(image, vec3(io_textureCoordinates + vec2(0.0f, offset.y * float(i)), layer)).rgb * weights[i];
result += texture(image, vec3(io_textureCoordinates - vec2(0.0f, offset.y * float(i)), layer)).rgb * weights[i];
}
}
...
Where variable horizontal and layer are uniforms (the image is a texture2DArray, but this is not that important). I use a 9x9 kernel (variable weights, the first weight is the center) and first I blur the image horizontally, then I change the horizontal uniform to false and rerun the shader to blur the image vertically. It works fine, but the performance is really bad. I don't know why, because I don't do anything special. The variable horizontal is a uniform, so it remains the same for every pixel in a draw call, so each shader core executes the the same path for every pixel.
Then I changed the code a little bit, like this:
...
const float[] weights = float[](0.382928, 0.241732, 0.060598, 0.005977, 0.000229);
vec2 offset = vec2(1.0f) / vec2(textureSize(image, 0));
vec3 result = texture(image, vec3(io_textureCoordinates, layer)).rgb * weights[0];
vec2 ofs = horizontal ? vec2(offset.x, 0) : vec2(0, offset.y);
for(int i = 1; i < weights.length(); i++){
result += texture(image, vec3(io_textureCoordinates + ofs * float(i), layer)).rgb * weights[i];
result += texture(image, vec3(io_textureCoordinates - ofs * float(i), layer)).rgb * weights[i];
}
...
It's almost the same, I just use horizontal in another place, but the performance is much better. Can someone explain what is the difference between the two shaders what causes a big difference in performance? I thought that maybe the first version executes both sides of the if-else, which means two times more texture sampling, however the second version is much faster even if I execute it two times more.
I'm using WebGL 2 and Nvidia GTX 1050M.