A few days ago, I ran into this when messing around on Shadertoy. I was curious and some solutions to the various problems I faced, so I may as well post what I've made here for you.
Note, however, that I have never benchmarked this and I don't know how fast it works. But I've heard that different drivers/hardware/etc. implement sRGB conversion differently, so I wanted to make my own, correct implementation... And as far as I can tell, I succeeded. It does not use if
s and operates on entire color vectors at a time.
The trick with bvec
s was learned from here. He says it won't work on most GLSL ES versions, but it seems to work well in the browsers I've tested (including Chrome on my Pixel). Still something to consider, especially since my uses are pretty limited (just making test images for my desktop, though I did test on my phone too).
I'm sure somebody could make a more optimal version that's just as accurate, especially as I'm very new to GLSL in general. However, since nobody was really giving you actual code (except to suggest x1/2.2 and the like), and my own code seemed to follow the general advice of avoiding branches, I figured I may as well post it.
// Converts a color from linear light gamma to sRGB gamma
vec4 fromLinear(vec4 linearRGB)
{
bvec4 cutoff = lessThan(linearRGB, vec4(0.0031308));
vec4 higher = vec4(1.055)*pow(linearRGB, vec4(1.0/2.4)) - vec4(0.055);
vec4 lower = linearRGB * vec4(12.92);
return mix(higher, lower, cutoff);
}
// Converts a color from sRGB gamma to linear light gamma
vec4 toLinear(vec4 sRGB)
{
bvec4 cutoff = lessThan(sRGB, vec4(0.04045));
vec4 higher = pow((sRGB + vec4(0.055))/vec4(1.055), vec4(2.4));
vec4 lower = sRGB/vec4(12.92);
return mix(higher, lower, cutoff);
}