Estou tendo problemas para distinguir a diferença prática entre ligar glFlush()
e glFinish()
.
Os documentos dizem isso glFlush()
e glFinish()
enviarão todas as operações em buffer para OpenGL para que se possa ter certeza de que todas serão executadas, a diferença é que glFlush()
retorna imediatamente onde como glFinish()
blocos até que todas as operações sejam concluídas.
Depois de ler as definições, concluí que, se fosse usá- glFlush()
las, provavelmente teria o problema de enviar mais operações ao OpenGL do que ele poderia executar. Então, só para tentar, troquei meu glFinish()
por a glFlush()
e eis que meu programa rodou (pelo que eu pude ver) exatamente o mesmo; taxas de quadros, uso de recursos, tudo era o mesmo.
Portanto, estou me perguntando se há muita diferença entre as duas chamadas ou se meu código não faz com que elas sejam executadas de maneira diferente. Ou onde um deve ser usado contra o outro. Também descobri que o OpenGL teria alguma chamada glIsDone()
para verificar se todos os comandos em buffer para a glFlush()
estão completos ou não (para que não se enviem operações para o OpenGL mais rápido do que podem ser executadas), mas não consegui encontrar tal função .
Meu código é o loop de jogo típico:
while (running) {
process_stuff();
render_stuff();
}
Como as outras respostas sugeriram, realmente não há uma boa resposta de acordo com as especificações. A intenção geral
glFlush()
é que, após chamá-lo, a CPU host não tenha nenhum trabalho relacionado ao OpenGL a fazer - os comandos terão sido enviados para o hardware gráfico. A intenção geral doglFinish()
é que, depois de retornar, não resta trabalho restante e os resultados devem estar disponíveis também em todas as APIs não OpenGL apropriadas (por exemplo, leituras do framebuffer, capturas de tela, etc ...). Se isso é realmente o que acontece, depende do driver. A especificação permite uma tonelada de latitude quanto ao que é legal.fonte
Eu sempre fiquei confuso sobre esses dois comandos também, mas esta imagem deixou tudo claro para mim: Aparentemente, alguns drivers de GPU não enviam os comandos emitidos para o hardware, a menos que um certo número de comandos tenha sido acumulado. Neste exemplo, esse número é 5 .
A imagem mostra vários comandos OpenGL (A, B, C, D, E ...) que foram emitidos. Como podemos ver na parte superior, os comandos ainda não foram emitidos, porque a fila ainda não está cheia.
No meio, vemos como
glFlush()
afeta os comandos enfileirados. Diz ao driver para enviar todos os comandos enfileirados ao hardware (mesmo se a fila ainda não estiver cheia). Isso não bloqueia o thread de chamada. Apenas sinaliza ao driver que podemos não estar enviando comandos adicionais. Portanto, esperar que a fila se encha seria uma perda de tempo.Na parte inferior, vemos um exemplo usando
glFinish()
. Quase faz a mesma coisa queglFlush()
, exceto que faz o thread de chamada esperar até que todos os comandos tenham sido processados pelo hardware.Imagem retirada do livro "Advanced Graphics Programming Using OpenGL".
fonte
glFlush
eglFinish
faço, e não posso dizer o que essa imagem está dizendo. O que está do lado esquerdo e do lado direito? Além disso, essa imagem foi lançada em domínio público ou sob alguma licença que permite publicá-la na Internet?Se você não viu nenhuma diferença de desempenho, significa que você está fazendo algo errado. Como alguns outros mencionaram, você não precisa chamar nenhum dos dois, mas se chamar glFinish, estará perdendo automaticamente o paralelismo que a GPU e a CPU podem alcançar. Deixe-me mergulhar mais fundo:
Na prática, todo o trabalho que você envia para o driver é agrupado e enviado para o hardware potencialmente muito mais tarde (por exemplo, na hora do SwapBuffer).
Então, se você está chamando glFinish, você está essencialmente forçando o driver a enviar os comandos para a GPU (que ele agrupou até então, e nunca pediu à GPU para trabalhar), e paralisar a CPU até que os comandos enviados sejam completamente executado. Portanto, durante todo o tempo em que a GPU funciona, a CPU não (pelo menos neste segmento). E o tempo todo que a CPU faz seu trabalho (principalmente comandos em lote), a GPU não faz nada. Então sim, glFinish deve prejudicar seu desempenho. (Esta é uma aproximação, já que os drivers podem começar a ter a GPU funcionando em alguns comandos se muitos deles já estiverem em lote. Não é típico, pois os buffers de comando tendem a ser grandes o suficiente para conter muitos comandos).
Agora, por que você chamaria glFinish então? As únicas vezes que usei foram quando tinha erros de driver. Na verdade, se um dos comandos que você envia para o hardware travar a GPU, sua opção mais simples para identificar qual comando é o culpado é chamar glFinish após cada sorteio. Dessa forma, você pode restringir o que exatamente desencadeia a falha
Como uma observação lateral, APIs como Direct3D não oferecem suporte a um conceito de acabamento.
fonte
glFlush realmente data de um modelo cliente-servidor. Você envia todos os comandos gl através de um pipe para um servidor gl. Esse tubo pode amortecer. Assim como qualquer arquivo ou E / S de rede pode armazenar em buffer. glFlush diz apenas "envie o buffer agora, mesmo que ainda não esteja cheio!". Em um sistema local, isso quase nunca é necessário porque uma API OpenGL local dificilmente fará um buffer e apenas emite comandos diretamente. Além disso, todos os comandos que causam a renderização real farão um flush implícito.
O glFinish, por outro lado, foi feito para medir o desempenho. Tipo de PING para o servidor GL. Ele faz um roundtrips de um comando e espera até que o servidor responda "Estou ocioso".
Hoje em dia, os motoristas locais modernos têm ideias bastante criativas sobre o que significa estar ocioso. É "todos os pixels foram desenhados" ou "minha fila de comandos tem espaço"? Além disso, como muitos programas antigos espalhavam glFlush e glFinish por todo o código sem razão, como codificação vodu, muitos drivers modernos simplesmente os ignoram como uma "otimização". Não posso culpá-los por isso, realmente.
Resumindo: trate glFinish e glFlush como nenhum ops na prática, a menos que você esteja codificando para um antigo servidor SGI OpenGL remoto.
fonte
Dê uma olhada aqui . Resumindo, diz:
Outro artigo descreve outras diferenças:
glFlush
glFinish
força o OpenGL a executar comandos excelentes, o que é uma má ideia (por exemplo, com VSync)Resumindo, isso significa que você nem mesmo precisa dessas funções ao usar buffer duplo, exceto se sua implementação de swap-buffers não liberar automaticamente os comandos.
fonte
Não parece haver uma maneira de consultar o status do buffer. Existe esta extensão da Apple que poderia servir ao mesmo propósito, mas não parece ser multiplataforma (ainda não tentei). À primeira vista, parece antes de
flush
você empurrar o comando fence; você pode então consultar o status dessa cerca conforme ela se move pelo buffer.Gostaria de saber se você poderia usar
flush
antes de armazenar comandos em buffer, mas antes de começar a renderizar o próximo quadro que você chamarfinish
. Isso permitiria que você começasse a processar o próximo quadro enquanto a GPU funciona, mas se não for feito quando você voltar,finish
o bloqueará para garantir que tudo esteja em um estado novo.Eu não tentei isso, mas tentarei em breve.Eu tentei em um aplicativo antigo que tem um uso bastante uniforme de CPU e GPU. (Usado originalmente
finish
.)Quando mudei para
flush
no final efinish
no início, não houve problemas imediatos. (Tudo parecia bem!) A capacidade de resposta do programa aumentou, provavelmente porque a CPU não estava parada esperando pela GPU. Definitivamente, um método melhor.Para efeito de comparação, retirei
finished
do início do quadro, saindoflush
, e o desempenho foi o mesmo.Então, eu diria use
flush
efinish
, porque quando o buffer está vazio na chamada parafinish
, não há impacto no desempenho. E estou supondo que se o buffer estivesse cheio, você deveria querer definish
qualquer maneira.fonte
A questão é: você quer que seu código continue rodando enquanto os comandos OpenGL estão sendo executados, ou apenas rodando após seus comandos OpenGL terem sido executados.
Isso pode ser importante em casos, como em atrasos de rede, para ter determinada saída de console somente após as imagens terem sido desenhadas ou algo semelhante.
fonte