¿Modificar una textura (pintar sobre ella) se considera un "cambio de estado"?

11

La convención en gráficos es que realizar menos cambios de estado es mejor que realizar más cambios de estado (cambio de sombreadores, búferes de encuadernación, texturas de encuadernación, etc.). Para las texturas, es más rápido renderizar muchos polígonos usando un atlas único (para renderizar sprites / texto) que unir individualmente una nueva textura para cada polígono.

¿Esto es cierto si continuamente estoy pintando a través de una textura glTexSubImage2D? Tengo un flujo de datos que ingresa (a través de una red) que se somete a procesamiento y luego se pinta a una textura fila por fila. Los datos se presentan visualmente en un desplazamiento sin fin.

¿Sería mejor pintar con una textura renderizada en un rectángulo grande (desplazando los datos pintados a la vista)? La idea aquí es que tendría una (o dos) texturas ligadas en un momento dado mientras continúo pintando.

¿O debo pintar muchos rectángulos pequeños (solo revelando el rectángulo cuando se pinta)? Supongo que uniría una textura por rectángulo.

TheBuzzSaw
fuente

Respuestas:

11

Actualizar un área de memoria en el dispositivo gráfico (una textura, búfer y similares) no es lo mismo que cambiar un estado de representación.

Lo que hace que un cambio de estado de procesamiento sea costoso es la cantidad de trabajo que el controlador tiene que hacer para validar los nuevos estados y reordenar la tubería. Lo más probable es que también incurra en alguna sincronización entre la CPU y el dispositivo gráfico. Sin embargo, la cantidad de datos transferidos entre los dispositivos debe ser pequeña para un cambio de estado (probablemente solo unos pocos comandos).

Por otro lado, para una actualización de textura / búfer, el costo principal radica en la transferencia de datos en sí. En teoría, a menos que esté leyendo los datos de textura en la CPU después de la actualización, no debería haber sincronización ni paradas de canalización. Sin embargo, se debe considerar otro aspecto: la sobrecarga API. Incluso si la cantidad de datos que está enviando al dispositivo gráfico es pequeña, si lo hace con la frecuencia suficiente, eventualmente el costo de comunicarse con el controlador / dispositivo será mayor que el costo de la transferencia de datos. Esa es otra razón por la que el procesamiento por lotes es tan importante al optimizar un renderizador.

Entonces, en mi caso, el mejor enfoque, me parece, sería mantener una copia de la textura de la memoria del sistema que actualice cada vez que lleguen nuevos datos. Establezca una bandera sucia y consolide tantas actualizaciones como sea posible en una glTexSubImagepara toda la textura (o una gran parte secuencial de la misma). También puedes jugar con Pixel Buffer Objects e intentar hacer una transferencia de datos asincrónica para reducir las paradas de canalización tanto como sea posible. Si puede implementar algún tipo de almacenamiento en búfer doble, puede escribir en una copia de la textura mientras se procesa la otra. Este tutorialexplora ese escenario. Ese es mi enfoque intuitivo, trataría de reducir el número de llamadas a la API y "actualizar" las actualizaciones de textura. Dicho esto, esto es muy especulativo, y tendría que hacer un perfil y compararlo con otros enfoques, como hacer varias actualizaciones pequeñas, para saber con certeza cuál es el más eficiente en su caso de uso.

Como nota al margen, esta presentación de NVidia también es relevante y proporciona muchas buenas ideas: acercarse a Zero Driver Overhead en OpenGL .

glampert
fuente
55
No lo sé con certeza, pero definitivamente sospecharía que glTexSubImage en una textura que se ha procesado en el último cuadro o dos detendrá la tubería, ya que los controladores de PC a menudo intentan amortiguar un cuadro o dos, y no es probable querer hacer copias de texturas completas debido a una pequeña actualización. Por lo tanto, esperaría que las texturas (u objetos de búfer de píxeles) sean dobles o triples para obtener el máximo rendimiento.
John Calsbeek