Eu tenho um aplicativo de teste OpenGL simples em C, que desenha coisas diferentes em resposta às principais entradas. (Mesa 8.0.4, tentado com o Mesa-EGL e com o GLFW, Ubuntu 12.04LTS em um PC com NVIDIA GTX650). Os sorteios são bem simples / rápidos (tipo de triângulo rotativo). Meu código de teste não limita a taxa de quadros de forma alguma, apenas se parece com isso:
while (true)
{
draw();
swap_buffers();
}
Eu cronometrei isso com muito cuidado e acho que o tempo entre uma eglSwapBuffers()
(ou a glfwSwapBuffers
mesma coisa) chamada para a próxima é de ~ 16,6 milissegundos. O tempo de depois de uma chamada para eglSwapBuffers()
antes da próxima chamada é apenas um pouco menor que isso, mesmo que o que é desenhado seja muito simples. O tempo que a chamada dos buffers de troca demora é bem inferior a 1 ms.
No entanto, o tempo entre o aplicativo alterar o desenho, em resposta ao pressionamento de tecla e a alteração que realmente aparece na tela é> 150ms (aproximadamente 8 a 9 quadros). Isso é medido com uma gravação de câmera da tela e teclado a 60fps.
Portanto, as perguntas:
Onde os sorteios são armazenados em buffer entre uma chamada para trocar buffers e realmente aparecer na tela? Por que o atraso? Parece que o aplicativo está desenhando muitos quadros à frente da tela o tempo todo.
O que um aplicativo OpenGL pode fazer para causar um empate imediato na tela? (ou seja: sem buffer, apenas bloqueie até que o sorteio seja concluído; não preciso de alta taxa de transferência, preciso de baixa latência)
O que um aplicativo pode fazer para tornar o sorteio imediato acima o mais rápido possível?
Como um aplicativo pode saber o que realmente está na tela agora? (Ou quanto tempo / quantos quadros o atraso atual do buffer?)
Respostas:
Qualquer função da API de desenho chamada da CPU será enviada ao buffer do anel de comando da GPU para ser executada posteriormente pela GPU. Isso significa que as funções do OpenGL são principalmente funções sem bloqueio. Portanto, a CPU e a GPU estarão trabalhando em paralelo.
O mais importante a ser observado é que seu aplicativo pode ser vinculado à CPU ou GPU. Depois que você chama glFinish, a CPU espera que a GPU conclua seus comandos de desenho, se a GPU estiver demorando mais e puder / estiver causando a paralisação da CPU, seus aplicativos estarão vinculados à GPU. Se a GPU terminar de desenhar comandos e a CPU estiver demorando muito para glFinish, seu aplicativo estará vinculado à CPU.
E note que há uma diferença entre
glFlush
eglFinish
.glFlush
: indica que todos os comandos que foram enviados anteriormente ao GL devem ser concluídos em tempo finito.glFinish
: força todos os comandos GL anteriores a serem concluídos. Concluir não retorna até que todos os efeitos dos comandos emitidos anteriormente no cliente GL e no estado do servidor e no framebuffer sejam totalmente realizados. "glXSwapBuffers executa um glFlush implícito antes de retornar. Os comandos OpenGL subsequentes podem ser emitidos imediatamente após a chamada glXSwapBuffers, mas não são executados até que a troca de buffer seja concluída.
O tempo real do quadro provavelmente será determinado por qual das duas CPU / GPU está demorando mais tempo para concluir seu trabalho.
fonte
both low framerate (exactly same as monitor refresh rate??
no, a menos que você esteja usando explicitamente o VSync.O OpenGL nunca atualiza a tela, tecnicamente.
Existe uma API do sistema de janelas separada da GL (por exemplo, GLX, WGL, CGL, EGL) que faz isso. Os swaps de buffer usando essas APIs geralmente invocam implicitamente,
glFlush (...)
mas em algumas implementações (por exemplo, o rasterizador GDI no Windows), ele faz um totalglFinish (...)
:* No lado esquerdo, é o caminho do CDI (hardware)
SwapBuffers (...)
. No lado direito, o caminho da GDI (software).Se você tiver o VSYNC ativado e o buffer duplo, qualquer comando que modifique o buffer de fundo antes que ocorra uma troca pendente deverá parar até a troca. Há uma profundidade limitada na fila de comandos; portanto, esse comando interrompido acabará causando um congestionamento de tráfego no pipeline. Isso pode significar que, em vez de bloquear
SwapBuffers (...)
o aplicativo, ele bloqueia algum comando GL não relacionado até o VBLANK rolar. O que realmente se resume é quantos buffers de retorno você possui em sua cadeia de swap.Desde que todos os buffers traseiros estejam cheios de quadros concluídos ainda a serem movidos para a frente, os buffers swap implicitamente causarão o bloqueio. Infelizmente, não há como controlar explicitamente o número de buffers de retaguarda usados pela maioria das APIs do sistema de janelas GL (além de 0 com buffer único ou 1 com buffer duplo). O driver é livre para usar 2 buffers traseiros, se desejar (buffer triplo), mas você não pode solicitar isso no nível do aplicativo usando algo como GLX ou WGL.
fonte
glFinish (...)
imediatamente após a troca de buffers. Isso limpará a fila de comandos, mas também significa que a GPU e a CPU serão sincronizadas (o que não é bom se você quiser manter a GPU funcionando sempre).Presumo que você esteja familiarizado com este experimento ?
Essencialmente, John Carmack estava fazendo algo semelhante, gravando a tela e sincronizando os pixels enviados para a tela. Ele descobriu que boa parte da latência veio da tela. Outros fatores foram o atraso de entrada do teclado, drivers de vídeo e / ou a execução do próprio programa.
fonte