c++ - texture - Organizar sombreadores GLSL en motor OpenGL
texture in opengl c++ (3)
Cual es mejor ?
Tener un programa de sombreado con muchos uniformes que especifiquen las luces que usar, o mapeos que hacer (por ejemplo, necesito una malla para mapear paralaje, y otra paralaje / especular mapeada). Haría una lista de uniformes en caché para transferencias perezosas, y solo cambiaría un par de uniformes por cada malla siguiente si fuera necesario.
Para tener una gran cantidad de programas de sombreado para cada caso necesario, cada uno con una pequeña cantidad de uniformes, y hacer el enlace perezoso con glUseProgram para cada malla si es necesario. Aquí supongo que las mallas están correctamente agrupadas, para evitar interruptores redundantes.
En general, la opción 2 será más rápida / mejor a menos que tenga una cantidad realmente grande de programas. También puede usar objetos de búfer compartidos entre programas para que no tenga que restablecer ningún valor cuando cambie de programa.
Además, una vez que vincula un programa, puede liberar todos los sombreadores que ha vinculado al programa. Esto liberará todo el código fuente y cualquier información previa al enlace que mantenga el controlador, dejando solo el programa completamente enlazado en la memoria.
Tiendo a creer que depende de la aplicación específica. Y sí, ya que sería más eficiente decir ejecutar 100 programas donde cada uno puede tener de 2 a 16 uniformes cada uno; puede ser mejor tener un intercambio de los dos. Me inclinaría a pensar que decir, tal vez, de 10 a 20 programas para sus técnicas de sombreado más comunes sería suficiente o un poco más. Por ejemplo, es posible que desee tener un programa / sombreador para hacer todo su mapeo de relieve, uno para hacer todos sus efectos de niebla, uno para hacer reflexiones, uno para hacer refracciones.
Ahora, fuera del alcance de su pregunta, creo que también correspondería aquí, una cosa para incorporar en su motor sería una configuración de clase BatchProcess & BatchManager para reducir la cantidad de CPU - llamadas de GPU sobre el bus ya que esto también sería eficiente . No creo que haya una solución que se adapte a todas las preguntas, ya que creo que sería específico de la aplicación así como establecer la relación entre cuántos lotes (cubos) de vértices (primitivos) tendría su motor y cuántos vértices que contendría cada uno de esos lotes.
Para intentar dejar esto un poco más claro: un juego puede tener 4 contenedores o lotes donde cada lote puede contener hasta 10,000 vértices para que se considere completo antes de que BatchManager decida vaciar ese cubo enviando todos esos vértices a la tarjeta gráfica para que la tubería de Representación se procese y dibuje, donde un juego diferente puede tener 10 cubos con 5,000 vértices, u otro juego podría tener 8 cubos con 12,0000 vértices.
Así que podría haber una compensación de tratar de combinar los dos de acuerdo a sus necesidades. Si tiene 1 programa individual con cientos de uniformes; el programa individual es más fácil de administrar dentro de la canalización, pero los sombreadores serían demasiado difíciles de leer y administrar. Por otra parte, tener sombreadores con muy pocos uniformes es bastante fácil de leer y administrar, pero tener 100s de programas es un poco más difícil de administrar en la CPU antes de vincularlos y enviarlos para que se reproduzcan correctamente. Personalmente, trataría de encontrar un término medio para que tenga suficientes programas para hacer cada tarea específica que sea completamente única entre sí, como hacer densidad de niebla en uno y un mapeo de sombra volumétrica en otro donde cada programa tiene suficientes uniformes para hacer los cálculos requeridos.
El próximo paso sería hacer algunas pruebas de benchmark para ver dónde se equilibran su eficiencia y su sobrecarga para hacer los ajustes apropiados.
La mayoría de los motores modernos que conozco tienen un "caché de sombreado" y usan la segunda opción, porque aparentemente es más rápido.
También puedes echar un vistazo al ARB_shader_subroutine que permite un enlace dinámico. Pero creo que solo está disponible en hardware de clase DX11.