¿No es esto exactamente lo que estaba haciendo OpenGL sin el sombreador de geometría?
No lo es. El GS es un paso opcional , no un paso que tiene un valor predeterminado.
Para que OpenGL ejecute un sombreador de geometría , debe realizar lo que se conoce como " ensamblaje primitivo ". Cuando renderiza una serie de triángulos a través de GL_TRIANGLE_STRIP
, OpenGL hará cosas internas para convertir cada 3 vértices adyacentes en un triángulo individual, modificando el orden de bobinado adecuadamente.
Normalmente, cuando no se utiliza un GS, este proceso se realiza una vez. Sin embargo, cuando utiliza un GS, debe realizarse antes de que se ejecute el GS. Pero también debe realizarse después del GS, porque un GS puede generar un tipo primitivo totalmente diferente (por ejemplo, quads).
Así que ahora estás haciendo que el sistema básicamente haga un montón de trabajo extra por nada. Después de todo, OpenGL no puede asumir que su GS no está haciendo nada (ese es un problema indecidible).
Además, varias optimizaciones ya no funcionan en presencia de un GS. Considere la representación indexada.
Cada índice de un búfer de matriz de elementos producirá las mismas salidas de un sombreador de vértices. Por lo tanto, la GPU a menudo almacenará en caché estas salidas en un caché posterior a T&L . Si ve un índice que ya está en la caché, el VS no se ejecuta nuevamente; solo obtiene datos del caché.
Qué es"? "Es" es ... la unidad de ensamblaje primitiva . Sí, esa cosa que se ejecuta dos veces cuando usas un GS. El índice de almacenamiento en caché? Solo funciona para las entradas de GS.
Entonces, ¿qué pasa con las salidas de la GS? Bueno, eso depende del hardware. Pero tiene que ir a algún tipo de memoria intermedia. Y ahí radica el problema: ese búfer no está indexado en absoluto. Es como una situación de glDrawArrays.
Entonces, si envía un búfer de índice de 0, 1, 2, 0, 2, 3
, esto se traduciría en 4 vértices en el caché posterior a T&L. Pero el búfer de vértices posterior a GS ahora tiene 6 vértices. El búfer posterior a GS usa más espacio. Entonces, si pasa por la molestia de hacer correctamente las listas o tiras de triángulos optimizadas después de T&L, y se voltea en un GS de transferencia como el suyo, básicamente eliminó aproximadamente la mitad de sus ganancias de rendimiento de esa optimización.
No fue inútil, pero duele.
A esto se agrega el hecho de que muchas GPU de clase GL 3.x (también conocidas como: DX10) tenían buffers posteriores a GS bastante pequeños. Cuanto más pequeño es el búfer, menos invocaciones de GS puede tener activas simultáneamente. Por lo tanto, su hardware efectivamente cuellos de botella en el GS. Debido a que la teselación es una gran característica del hardware de clase 4.x, la mayoría de dichos hardware tienen amortiguadores suficientes para hacer viable el uso más pesado de GS.
Por lo tanto, es más probable que usar un GS genere un cuello de botella en el procesamiento de vértices de su código. Por supuesto, siempre puede usar eso a su favor al hacer que sus sombreadores de vértices y fragmentos sean más complejos, ya que es solo un rendimiento gratuito en ese punto.
Para obtener más información sobre las ralentizaciones inducidas por GS, lea este artículo .
Aquí hay una regla básica sobre los GS: nunca use un GS porque cree que hará que el renderizado sea más rápido . Debe usarlo cuando haga posible lo que está tratando de hacer . Si lo que intenta hacer es una optimización, use otra cosa.
Las excepciones generales a esto son:
layout(points) in;
? ¿O es el tamaño de salida fijo? O tal vez ambos?