¿Se conservan los datos de la GUI acelerada por hardware en la GPU?

8

Estoy investigando cómo funciona la mayoría de las bibliotecas GUI aceleradas por hardware. En realidad, solo me interesan los backends de renderizado aquí. Estoy tratando de descubrir cuál sería la mejor manera de intentar escribir el mío como una especie de proyecto paralelo. Estoy tratando de obtener el máximo rendimiento aquí en lugar de características demasiado sofisticadas. Quiero poder dibujar primitivas, texto y animación.

Algunas buenas bibliotecas que conozco son Qt, Skia y Cairo (aunque no estoy seguro de cuál es el estado de HWA). También he mirado a NanoVG, que es una pequeña biblioteca que parece tener un seguimiento decente. Sin embargo, no pude lograr un rendimiento decente con NanoVG ...

Lo único que me llamó la atención fue que todas estas bibliotecas parecen hacer uso del concepto de "pintura", donde parece que cada forma primitiva se dibuja desde cero una y otra vez. Lo que quiero decir con eso es que, desde las API, no parece que las formas se hayan creado como "objetos" en la GPU o lo que sea la terminología y luego se dejen allí para que se representen "automáticamente". En otras palabras, no se dejan en la memoria de la GPU por ser redibujados en algún bucle grande. Para elaborar, parece que para cada rectángulo, es decir, que necesita dibujarse, se configura un estado OpenGL completo solo para representar ese rectángulo y luego se destruye nuevamente. Sin embargo, parece que estas formas renderizadas se representan al menos en sus destinos finales, lo que permite que la GPU componga toda la escena.

La forma en que esperaba que funcionaran estas bibliotecas es almacenando toda la escena en la GPU (disculpe la horrible terminología). Por ejemplo, las primitivas se triangularían y se dejarían en la memoria, donde después de un proceso complejo se utilizaría para tener un bucle de representación principal para la escena. Además, habría mecanismos para actualizar los atributos o eliminar o agregar primitivas. Esta es una descripción bastante vaga, pero creo que entiendes la idea.

Lo que me gustaría preguntar ahora es si hay algún beneficio de rendimiento para el enfoque de "pintura" en comparación con el enfoque de "guardado" (de nuevo, no tengo idea si hay nombres propios para estas cosas ...). ¿Algunos mecanismos de almacenamiento en caché complejos tal vez? ¿O es mucho más sencillo trabajar con esto?

Me doy cuenta de que el enfoque "guardado" podría usar más memoria en la GPU, pero ¿todas las llamadas de OpenGL necesarias para el enfoque de "pintura" no son muy caras? Supongo que uno podría compensar esto almacenando en caché las formas renderizadas, pero ¿la GPU realmente proporciona uno con un beneficio tan grande al hacer una rasterización tan única (o no muy regular) en comparación con la CPU, especialmente dada la comunicación ¿gastos generales? Además, ¿esta sobrecarga de comunicación no plantea serios problemas para las animaciones cuando se debe dibujar para cada cuadro?

Estoy bastante seguro de que NanoVG no tiene un mecanismo de almacenamiento en caché interno y supongo que esto podría ser responsable de su rendimiento mediocre. Qt, por otro lado, parece tener un excelente rendimiento, por lo que debe estar haciendo algo bien. Google también parece ser capaz de darle un buen uso a Skia.

PD. No soy un profesional de ningún tipo y recientemente comencé a aprender OpenGL.

EDITAR: ¿Otra posibilidad que he pensado es que tal vez el enfoque de "pintura" se consideró necesario simplemente por los beneficios de la memoria? La razón por la que creo que es porque todas estas bibliotecas, por supuesto, se iniciaron en una era diferente y también se dirigen a plataformas integradas, lo que significa que la memoria de la GPU podría ser tan escasa en las plataformas de destino (ed) y que usar la menor cantidad posible podría ser Más importante que el rendimiento. Sin embargo, una vez más, en una situación como esta, no estoy convencido de que la rasterización de GPU cuadro por cuadro dada la sobrecarga de comunicación supere a una CPU, especialmente teniendo en cuenta el recuento de píxeles probablemente bajo en plataformas con tan poca memoria.

Además, he leído en http://blog.qt.io/blog/2010/01/06/qt-graphics-and-performance-opengl/ que Qt aparentemente combina el código de sombreador de segmentos precodificados en tiempo de ejecución antes de "pintar" y luego espera que el compilador OGL incorpore el código correctamente en tiempo de ejecución. Esto me parece aún más sobrecarga de inicialización OGL ...

Gerharddc
fuente
2
TL; DR; no haría daño aquí
Kromster

Respuestas:

6

Guardar toda la ventana como un solo objeto en la GPU (sería un montón de rectángulos guardados como VBO) y luego representarlo en una sola llamada de sorteo de OpenGL sería rápido, pero tiene varias desventajas:

  • Toda la geometría debería representarse con un solo sombreador. Tener sombreadores separados (para copia opaca, copia transparente, degradado, ...) es más útil.
  • Toda la geometría podría usarse solo a partir de una cantidad limitada de texturas. Incluso si usa atlas, necesita muchas texturas para la GUI. (Piezas del tema GUI, íconos, fuentes, ...)
  • Debe reconstruir y volver a cargar todo el objeto en la GPU después de cada cambio.
  • Cada widget debe ser capaz de producir su pieza de geometría que es más difícil de abstraer que la pintura 2D.
  • En algunas GPU puede renderizar material 2D (rellenando el área con color, copiando de una imagen a otra, ...) con comandos 2D, que es más rápido que usar una tubería 3D.

Si lo divide en varios objetos, finalmente terminará con uno o pocos rectángulos por objeto. Es más fácil y rápido renderizarlos sin ningún objeto almacenado.

Lo que hacen los marcos de la GUI es rastrear qué partes exactas de la ventana cambiaron y volver a pintar solo ellas. La imagen anterior se almacena en caché en la GPU. Este enfoque se puede usar con varios backends de dibujo, no solo renderizado acelerado OpenGL / DirectX.

Si desea consultar el ejemplo de una biblioteca GUI que genera geometrías que puede alimentar a OpengGL (o en una API 3D diferente), mire el librocket . En realidad, puede hornear geometrías estáticas juntas y renderizarlas en una sola llamada de dibujo, pero cualquier elemento que cambie con frecuencia o que necesite renderizar con su propio sombreador debe permanecer separado.

michalsrb
fuente
OK gracias. ¿Se almacena en caché todo el marco anterior como una imagen o todos los elementos se almacenan en caché en un atlas? La razón por la que pregunto es porque no veo cómo el almacenamiento en caché del marco admitiría, por ejemplo, la traducción de un solo elemento. Sin embargo, mantener un atlas sería, por supuesto, un gran esfuerzo.
Gerharddc
Todo el contenido de la ventana generalmente se almacena en caché. Apuesto a que algunos marcos de GUI también almacenan en caché algunas etapas intermedias, el contenido de cualquier elemento desplazable sería un buen candidato. No creo que la traducción sea una operación común en la GUI, aparte de las áreas desplazables. La mayoría de los repintes son pequeños y están en su lugar causados ​​por los widgets que cambian en hower o clic, cambian el texto, ... Cosas como diálogos y menús son ventanas técnicamente separadas, los compositores de ventanas modernos se encargan de moverlos sin repintarlos.
michalsrb
Supongo que eso tiene sentido. ¿Eso significaría que toda la ventana tendría que volver a dibujarse si inesperadamente moviera algo como un botón?
Gerharddc
Eso realmente depende de cómo se implemente el marco específico. Pero es probable que mover un botón desencadene algún tipo de actualización de diseño y gran parte de la ventana, si no completa, tendrá que volver a pintarse.
michalsrb