Lo que causa la ramificación en GLSL depende del modelo de GPU y la versión del controlador OpenGL.
La mayoría de las GPU parecen tener una forma de operación de "seleccionar uno de dos valores" que no tiene costo de ramificación:
n = (a==b) ? x : y;
y a veces incluso cosas como:
if(a==b) {
n = x;
m = y;
} else {
n = y;
m = x;
}
se reducirá a unas pocas operaciones de valor de selección sin penalización de ramificación.
Algunas GPU / Drivers tienen (¿tuvieron?) Una pequeña penalización en el operador de comparación entre dos valores, pero una operación más rápida en comparación con cero.
Donde podría ser más rápido hacer:
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
en lugar de comparar (tmp1 != tmp2)
directamente, pero esto depende mucho de la GPU y del controlador, por lo que, a menos que esté apuntando a una GPU muy específica y no a otras, recomiendo usar la operación de comparación y dejar ese trabajo de optimización al controlador OpenGL ya que otro controlador podría tener un problema con la forma más larga y sea más rápido con la forma más simple y legible.
Las "ramas" tampoco son siempre malas. Por ejemplo, en la GPU SGX530 utilizada en OpenPandora, este sombreador scale2x (30 ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
if ((D - F) * (H - B) == vec3(0.0)) {
gl_FragColor.xyz = E;
} else {
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
}
Terminó dramáticamente más rápido que este sombreador equivalente (80 ms):
lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
lowp vec2 p = fract(pos);
lowp vec3 tmp1 = p.x < 0.5 ? D : F;
lowp vec3 tmp2 = p.y < 0.5 ? H : B;
lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;
Nunca se sabe de antemano cómo funcionará un compilador GLSL específico o una GPU específica hasta que lo compare.
Para agregar el punto de referencia (incluso aunque no tenga números de sincronización reales y código de sombreador para presentarle esta parte), actualmente lo uso como mi hardware de prueba habitual:
- Intel HD Graphics 3000
- Gráficos Intel HD 405
- nVidia GTX 560M
- nVidia GTX 960
- AMD Radeon R7 260X
- nVidia GTX 1050
Como una amplia gama de modelos de GPU diferentes y comunes para probar.
Probar cada uno de ellos con controladores OpenGL y OpenCL de código abierto de Windows, Linux y propietarios de Linux.
Y cada vez que intento micro-optimizar el sombreador GLSL (como en el ejemplo SGX530 anterior) o las operaciones de OpenCL para una combinación particular de GPU / Controlador , termino dañando el rendimiento en más de una de las otras GPU / Controladores.
Entonces, aparte de reducir claramente la complejidad matemática de alto nivel (por ejemplo: convertir 5 divisiones idénticas en un solo recíproco y 5 multiplicaciones en su lugar) y reducir las búsquedas de textura / ancho de banda, lo más probable es que sea una pérdida de tiempo.
Cada GPU es muy diferente de las demás.
Si estaría trabajando específicamente en (a) consolas de juegos con una GPU específica, esta sería una historia diferente.
El otro aspecto (menos significativo para los desarrolladores de juegos pequeños pero aún notable) es que los controladores de la GPU de la computadora podrían algún día reemplazar silenciosamente sus sombreadores ( si su juego se vuelve lo suficientemente popular ) con los reescritos personalizados optimizados para esa GPU en particular. Hacer que todo funcione para ti.
Lo harán para juegos populares que se usan con frecuencia como puntos de referencia.
O si le das a tus jugadores acceso a los sombreadores para que puedan editarlos ellos mismos fácilmente, algunos de ellos podrían exprimir algunos FPS adicionales para su propio beneficio.
Por ejemplo, hay paquetes de sombreado y textura hechos por los fanáticos para que Oblivion aumente drásticamente la velocidad de fotogramas en hardware que de otro modo apenas se podría reproducir.
Y, por último, una vez que su sombreador se vuelve lo suficientemente complejo, su juego casi se completa y comienza a probar en diferentes hardware, estará lo suficientemente ocupado simplemente arreglando sus sombreadores para que funcionen en una variedad de GPU, ya que se debe a varios errores que no podrá tener tiempo para optimizarlos a ese grado.