2011-02-05 15 views
6

Actualmente estoy aprendiendo cómo crear sombreadores en GLSL para un motor de juego en el que estoy trabajando, y tengo una pregunta sobre el lenguaje que me desconcierta. Aprendí que en versiones de sombreado inferiores a 3.0 no se pueden usar variables uniformes en la condición de un ciclo. Por ejemplo, el siguiente código no funcionaría en versiones de sombreado anteriores a la 3.0.Comando GLSL break

for (int i = 0; i < uNumLights; i++) 
{ 
    ............... 
} 

Pero no es posible sustituir esto con un bucle con una cantidad fija de iteraciones, pero que contiene una sentencia condicional que podría romper el bucle si, en este caso, es mayor que uNumLights ?. Ej .:

for (int i = 0; i < MAX_LIGHTS; i++) 
{ 
    if(i >= uNumLights) 
     break; 
    .............. 
} 

¿No son equivalentes? ¿Debería este último funcionar en versiones anteriores de GLSL? Y si es así, ¿no es esto más eficiente y fácil de implementar que otras técnicas sobre las que he leído, como usar una versión diferente del sombreador para diferentes cantidades de luces?
Sé que esto podría ser una pregunta tonta, pero yo soy un principiante y no puedo encontrar una razón por la que esto no debería funcionar.

Respuesta

11

GLSL puede ser confuso en cuanto for() sugiere a usted que tiene que haber bifurcación condicional, aun cuando no se debe a que el hardware no es capaz de hacerlo en absoluto (que se aplica a if() de la misma manera).

Lo que realmente sucede en el hardware pre-SM3 es que el HAL dentro de su aplicación OpenGL desenrollar completamente el bucle, por lo que no es en realidad ningún salto más. Y, esto explica por qué tiene dificultades para hacerlo con no constantes.

Si bien es técnicamente posible hacerlo con no constantes de todos modos, la implementación tendría que volver a compilar el sombreador cada vez que cambie ese uniforme, y podría funcionar contra el recuento máximo de instrucciones si se le permite suministrar cualquier número.

Eso es un problema porque ... ¿entonces qué? Esa es una mala situación.

Si proporciona una constante demasiado grande, obtendrá un error de compilador de "demasiadas instrucciones" cuando cree el sombreador. Ahora, si proporciona un número tonto con un uniforme, y el HAL tiene que producir un nuevo código y corre contra este límite, ¿qué puede hacer OpenGL?
Probablemente haya validado su programa después de compilar y vincular, y probablemente haya consultado el registro de información del sombreador, y OpenGL siguió diciéndole que todo estaba bien. Esto es, de alguna manera, una promesa vinculante, no puede simplemente decidir de otra manera, de repente. Por lo tanto, debe asegurarse de que esta situación no pueda surgir, y la única solución factible es no permitir uniformes en condiciones en generaciones de hardware que no admitan la ramificación dinámica.
De lo contrario, debería haber alguna forma de validación dentro de glUniform que rechace los valores incorrectos. Sin embargo, dado que esto depende de una recompilación de sombreador exitosa (o fallida), esto significaría que tendría que ejecutarse sincrónicamente, lo que lo convierte en un enfoque "no ir".Además, tenga en cuenta que GL_ARB_uniform_buffer_object está expuesto en algunos hardware SM2 (por ejemplo, GeForce FX), lo que significa que puede lanzar un objeto de almacenamiento intermedio con contenido impredecible en OpenGL y aún así esperar que funcione de alguna manera. La implementación tendría que escanear la memoria del búfer en busca de valores no válidos después de desasignarlo, lo cual es una locura.

Similar a un bucle, una instrucción if() no se bifurca en el hardware SM2, aunque así lo parezca. En cambio, calculará ambas ramas y realizará un movimiento condicional.

2

(supongo que estás hablando de pixel shaders).
La segunda variante solo funcionará en gpu que admita el modelo de sombreado> = 3. Debido a que la bifurcación dinámica (como poner la variable uNumLights en la condición IF) no es compatible con gpu shader model < 3 tampoco.

Here puede comparar lo que es y no es compatible con diferentes modelos de sombreado.

+0

Actualmente estoy escribiendo sombreadores en una tarjeta de video anterior, que solo es compatible con el modelo de sombreador 2.0. Lo extraño es que la segunda variante sí funciona, o al menos se compila sin error. En cuanto a la funcionalidad, aún no estoy seguro si se detiene cuando se activa el comando break. El primero, por supuesto, no compila en absoluto. –

+0

Pero como @dm.skt explicó que la segunda variante no es efectiva debido al alto riesgo de compilación del sombreador. Así que no dependería de las construcciones de sintaxis que solo son compatibles con HAL (pero no en hardware) con éxitos de rendimiento :-) –