John ya ha escrito una gran respuesta, así que considera esta respuesta como una extensión de la suya.
Actualmente estoy trabajando mucho con sombreadores de cómputo para diferentes algoritmos. En general, descubrí que los sombreadores de cómputo pueden ser mucho más rápidos que su sombreador de píxeles equivalente o transformar alternativas basadas en retroalimentación.
Una vez que comprende cómo funcionan los sombreadores informáticos, también tienen mucho más sentido en muchos casos. El uso de sombreadores de píxeles para filtrar una imagen requiere configurar un framebuffer, enviar vértices, usar múltiples etapas de sombreado, etc. ¿Por qué debería ser necesario filtrar una imagen? Estar acostumbrado a representar quads de pantalla completa para el procesamiento de imágenes es sin duda la única razón "válida" para seguir usándolos en mi opinión. Estoy convencido de que un recién llegado al campo de los gráficos de cómputo consideraría que los sombreadores de cómputo son mucho más naturales para el procesamiento de imágenes que el procesamiento de texturas.
Su pregunta se refiere al filtrado de imágenes en particular, por lo que no explicaré demasiado sobre otros temas. En algunas de nuestras pruebas, solo configurar una retroalimentación de transformación o cambiar los objetos de framebuffer para representar una textura podría generar costos de rendimiento de alrededor de 0.2 ms. ¡Tenga en cuenta que esto excluye cualquier representación! En un caso, mantuvimos exactamente el mismo algoritmo portado para calcular sombreadores y vimos un aumento notable en el rendimiento.
Cuando se usan sombreadores informáticos, se puede usar más silicio en la GPU para hacer el trabajo real. Todos estos pasos adicionales son necesarios cuando se utiliza la ruta del sombreador de píxeles:
- Ensamblaje de vértices (lectura de los atributos de vértices, divisores de vértices, conversión de tipos, expandiéndolos a vec4, etc.)
- El sombreador de vértices debe programarse sin importar cuán mínimo sea
- El rasterizador tiene que calcular una lista de píxeles para sombrear e interpolar las salidas de vértice (probablemente solo coordenadas de textura para el procesamiento de imágenes)
- Todos los diferentes estados (prueba de profundidad, prueba alfa, tijera, mezcla) deben establecerse y administrarse
Se podría argumentar que todas las ventajas de rendimiento mencionadas anteriormente podrían ser negadas por un controlador inteligente. Estarías en lo correcto. Tal controlador podría identificar que está renderizando un quad de pantalla completa sin pruebas de profundidad, etc. y configurar una "ruta rápida" que omite todo el trabajo inútil realizado para admitir sombreadores de píxeles. No me sorprendería si algunos conductores hacen esto para acelerar los pases de postprocesamiento en algunos juegos AAA para sus GPU específicas. Por supuesto, puede olvidarse de dicho tratamiento si no está trabajando en un juego AAA.
Sin embargo, lo que el controlador no puede hacer es encontrar mejores oportunidades de paralelismo ofrecidas por la tubería del sombreador de cómputo. Tome el ejemplo clásico de un filtro gaussiano. Usando sombreadores de cálculo, puede hacer algo como esto (separando el filtro o no):
- Para cada grupo de trabajo, divida el muestreo de la imagen de origen entre el tamaño del grupo de trabajo y almacene los resultados en la memoria compartida del grupo.
- Calcule la salida del filtro utilizando los resultados de muestra almacenados en la memoria compartida.
- Escribir en la textura de salida
El paso 1 es la clave aquí. En la versión del sombreador de píxeles, la imagen de origen se muestrea varias veces por píxel. En la versión del sombreador de cómputo, cada fuente de texto se lee solo una vez dentro de un grupo de trabajo. Las lecturas de textura generalmente usan una caché basada en mosaicos, pero esta caché es aún mucho más lenta que la memoria compartida.
El filtro gaussiano es uno de los ejemplos más simples. Otros algoritmos de filtrado ofrecen otras oportunidades para compartir resultados intermedios dentro de grupos de trabajo utilizando memoria compartida.
Sin embargo, hay una trampa. Los sombreadores informáticos requieren barreras de memoria explícitas para sincronizar su salida. También hay menos salvaguardas para proteger contra accesos errantes a la memoria. Para los programadores con buenos conocimientos de programación paralela, los sombreadores de cómputo ofrecen mucha más flexibilidad. Sin embargo, esta flexibilidad significa que también es más fácil tratar los sombreadores de cómputo como el código C ++ ordinario y escribir código lento o incorrecto.
Referencias
- Página wiki de OpenGL Compute Shaders
- DirectCompute: Optimizaciones y mejores prácticas, Eric Young, NVIDIA Corporation, 2010 [pdf]
- Programación eficiente de sombreadores informáticos, Bill Bilodeau, AMD, 2011? [pps]
- DirectCompute para juegos: sobrecargue su motor con Compute Shaders, Layla Mah y Stephan Hodes, AMD, 2013, [pps]
- Optimizaciones de cómputo de sombreadores para GPU AMD: reducción paralela, Wolfgang Engel, 2014