Estou fazendo uma pesquisa sobre como a maioria das bibliotecas GUI aceleradas por hardware funcionam. Na verdade, só me preocupo com os recursos de renderização deles aqui. Estou tentando descobrir qual seria a melhor maneira de tentar escrever o meu próprio como uma espécie de projeto paralelo. Estou tentando obter o melhor desempenho aqui, em vez de recursos excessivamente sofisticados. Quero desenhar primitivos, texto e animação.
Algumas boas bibliotecas que eu conheço são Qt, Skia e Cairo (embora não tenha certeza de qual é o estado da HWA). Também observei o NanoVG, que é uma pequena biblioteca que parece ter um número razoável de seguidores. Não consegui alcançar um desempenho decente com o NanoVG ...
A única coisa que me impressionou foi que todas essas bibliotecas parecem fazer uso do conceito de "pintura", onde parece que cada forma primitiva é desenhada do zero várias vezes. O que quero dizer com isso é que, a partir das APIs, não parece que as formas sejam criadas como "objetos" na GPU ou seja qual for a terminologia e depois deixadas para serem renderizadas "automaticamente". Em outras palavras, eles não são deixados na memória da GPU por serem redesenhados em algum loop grande. Para elaborar, parece que, para cada retângulo que precisa ser desenhado, um estado OpenGL inteiro é configurado apenas para renderizar esse retângulo e depois é destruído novamente. Parece que essas formas renderizadas são renderizadas pelo menos em seus destinos finais, permitindo que a GPU componha a cena inteira.
A maneira como eu esperava que essas bibliotecas funcionassem é armazenando a cena inteira na GPU (desculpe a horrível terminologia). Por exemplo, as primitivas seriam trianguladas e deixadas na memória onde, após algum processo complexo, seria usado para ter um loop de renderização principal para a cena. Além disso, haveria mecanismos para atualizar atributos ou excluir ou adicionar primitivas. Esta é uma descrição bastante vaga, mas acho que você entendeu.
O que eu gostaria de perguntar agora é se existe algum benefício no desempenho da abordagem "pintura" em comparação à abordagem "salva" (novamente, não faço ideia se existem nomes adequados para essas coisas ...). Alguns mecanismos de cache intrincados, talvez? Ou isso é muito mais simples de se trabalhar?
Sei que a abordagem "salva" pode usar mais memória na GPU, mas todas as chamadas do OpenGL necessárias para a abordagem "pintura" não são muito caras? Eu acho que alguém pode compensar isso armazenando em cache as formas renderizadas, mas a GPU realmente oferece um benefício tão grande ao fazer uma rasterização única (ou não muito regular) em comparação com a CPU, especialmente devido à comunicação a sobrecarga? Além disso, essa sobrecarga de comunicação não apresenta sérios problemas para animações quando o desenho precisa ser feito para cada quadro?
Estou certo de que o NanoVG não possui um mecanismo interno de armazenamento em cache e eu assumiria que isso poderia ser responsável por seu desempenho bastante sem brilho. O Qt, por outro lado, parece ter um excelente desempenho, portanto deve estar fazendo algo certo. O Google também parece ser capaz de fazer bom uso do Skia.
PS. Não sou profissional de nenhum tipo e só recentemente comecei a aprender o OpenGL.
Edição: Outra possibilidade que eu pensei é que talvez a abordagem "pintura" foi considerada necessária apenas por causa dos benefícios de memória? A razão pela qual eu acho que é porque todas essas bibliotecas foram iniciadas em uma era diferente e também têm como alvo plataformas incorporadas, o que significa que a memória da GPU pode ser tão escassa nas plataformas de destino e que usar o mínimo possível delas mais importante que o desempenho. Mais uma vez, porém, em uma situação como essa, não estou convencido de que a rasterização de GPU quadro a quadro, devido à sobrecarga de comunicação, supere a CPU, especialmente considerando a provavelmente baixa contagem de pixels em plataformas com pouca memória.
Além disso, li em http://blog.qt.io/blog/2010/01/06/qt-graphics-and-performance-opengl/ que o Qt aparentemente combina código shader de segmentos pré-codificados em tempo de execução antes de "pintar" e então espera que o compilador OGL incline o código corretamente no tempo de execução. Isso soa como ainda mais sobrecarga de inicialização do OGL para mim ...