Desenhar e atualizar ordem em gráficos 3D

7

Em todos os exemplos de código que eu observei, o loop do jogo se parece com isso:

while(true)
{
   InputAndUpdate();
   Draw();

   SwapBuffers();
}

No entanto, isso não destrói o paralelismo entre a CPU e a GPU? Após a chamada dos buffers de troca, a GPU ficará ociosa enquanto a CPU estiver lidando com entradas e atualizações. Então, quando a CPU terminar de emitir comandos de desenho, aguarda até que a GPU termine de renderizar. Por que não é feito assim? :

while(true)
{
   Draw(); //First issue the draw commands
   InputAndUpdate(); //Update while the GPU is busy rendering

   SwapBuffers(); //Now block and wait for the GPU to finish
}
Hannesh
fonte
Isso é algo que eu nunca considerei. +1 pergunta interessante.
The Duck Comunista
O primeiro. Ao fazer o segundo, você aumenta o atraso da entrada em um quadro completo, possivelmente mais dependendo de como você obtém a entrada em primeiro lugar e a sincronização em V. Certifique-se sempre para não aumentar o atraso de entrada
Peter Ølsted

Respostas:

5

Isso seria verdade, a menos que você tenha um buffer traseiro extra para renderizar (buffer duplo). Isso permite que a CPU continue e faça coisas sem ter que esperar a troca real do buffer (o que normalmente seria o caso, pois você não poderia começar a modificar o buffer traseiro até que ele fosse copiado para o buffer frontal sem risco de corrompendo o que você acabou de renderizar). Quando uma chamada ou troca é efetuada, a solicitação entra em um buffer de comandos que a GPU pode processar, permitindo que a CPU continue fazendo outras coisas enquanto a GPU está atrasada. É assim que o hardware moderno obtém paralelismo. Eu acredito que o D3D tem um limite de quantos quadros você pode render antes de um "Swap" bloquear (você '

O conceito de um loop de jogo como os dois exemplos acima é bastante antigo. Com a introdução de várias unidades de processamento na CPU, você pode estar fazendo renderização em um thread enquanto faz algum trabalho de "atualização" em um ou mais outros. Você pode querer examinar o conceito de filas de tarefas para ajudar a maximizar toda a potência de processamento da CPU disponível.

Roger Perkins
fonte
-1

a solução que você sitou não faz com que a CPU e a GPU funcionem parrarel, apenas muda a ordem em que elas estão esperando uma pela outra, pois como a outra resposta implica desenhar, sempre coloque seus resultados em um backbuffer e, usando swapbuffers, você apenas altera o que é necessário. monitore o shooting com a última coisa desenhada, para aproveitar todo o potencial da CPU e da GPU, você deve chamar draw e update em dois threads diferentes e usar outro segundo buffer para o que a CPU está fazendo (para que, quando a CPu estiver gerando atualização, resulte no buffer 2 GPU lida no Buffer 1 e quando a CPU está trabalhando com o Buffer 1, a GPu usa o Buffer 2 da mesma forma que os buffers de troca que a GPU usa para evitar alterações no quadro já desenhado)

Ali1S232
fonte
@ Gajet, você está sugerindo um buffer duplo de todos os dados do jogo no lado da CPU também?
Maik Semder
algo assim, mas nem todos os dados, apenas o que pode ser movido. de modo que tanto GPU e CPU ler de CPUbuffer [0] e cada um fazer seus cálculos e guardar os seus resultados em buffer de memória / CPUBuffer [1], e quando ambas as suas obras terminou eles começar a ler a partir CPUBuffer [1]
Ali1S232
Isso é um exagero, impraticável e acaba em uma base de código confusa, pois a entidade do jogo terá propriedades normais e com buffer duplo relevantes para a renderização. Existem soluções muito mais fáceis para a comunicação do segmento do jogo para o segmento de renderização, como filas de comandos. -1 para sugerindo este
Maik Semder
concordado, mas acho que é a única maneira de você usar totalmente o poder da CPU e da GPU simultaneamente, o exemplo de filas de comando não funcionará, pois toda vez que a CPU terminar um quadro de geração de dados, deverá fornecer todos os dados à GPU, e isso significa que você precisa aguardar que a CPU termine de funcionar e copie todo o buffer nesse momento, lembre-se de que nada no mundo deve mudar enquanto a GPU está desenhando o mundo; portanto, se você usar filas de comando, não haverá alteração na CPU e na GPU esperando um pelo outro.
Ali1S232
O fato de um esperar o outro terminar não significa que eles não correm em paralelo, sim, mas o primeiro que termina precisa esperar, pois a renderização e a atualização do jogo devem ser sincronizadas. Mas eles correm completamente em paralelo. Portanto, a sugestão de buffer duplo resolve um problema que não existe.
Maik Semder 22/05