Como a CPU e a GPU interagem para renderizar gráficos de computador?

Índice:

Como a CPU e a GPU interagem para renderizar gráficos de computador?
Como a CPU e a GPU interagem para renderizar gráficos de computador?

Vídeo: Como a CPU e a GPU interagem para renderizar gráficos de computador?

Vídeo: Como a CPU e a GPU interagem para renderizar gráficos de computador?
Vídeo: Como não ser RASTREADO por Sites / PROTEJA sua Localização / Dicas de Segurança! - YouTube 2024, Novembro
Anonim
A Unidade central de processamento (CPU) e a Unidade de processamento gráfico (GPU) do seu computador interagem a cada momento em que você usa seu computador para fornecer uma interface visual nítida e responsiva. Leia para entender melhor como eles funcionam juntos.
A Unidade central de processamento (CPU) e a Unidade de processamento gráfico (GPU) do seu computador interagem a cada momento em que você usa seu computador para fornecer uma interface visual nítida e responsiva. Leia para entender melhor como eles funcionam juntos.

foto por sskennel.

A sessão de perguntas e respostas de hoje nos é oferecida por cortesia do SuperUser, uma subdivisão do Stack Exchange, um agrupamento de comunidades de perguntas e respostas da comunidade.

A questão

Leitor de SuperUser Sathya colocou a questão:

Aqui você pode ver uma captura de tela de um pequeno programa C ++ chamado Triangle.exe com um triângulo giratório baseado na API OpenGL.

É certamente um exemplo muito básico, mas acho que é aplicável a outras operações de cartões gráficos.
É certamente um exemplo muito básico, mas acho que é aplicável a outras operações de cartões gráficos.

Eu estava apenas curioso e queria saber todo o processo de duplo clique em Triangle.exe no Windows XP até que eu possa ver o triângulo girando no monitor. O que acontece, como a CPU (que primeiro lida com o arquivo.exe) e a GPU (que finalmente gera o triângulo na tela) interagem?

Eu acho que envolvido na exibição deste triângulo rotativo é principalmente o seguinte hardware / software entre outros:

Hardware

  • HDD
  • Memória do sistema (RAM)
  • CPU
  • Memória de vídeo
  • GPU
  • tela de LCD

Programas

  • Sistema operacional
  • API DirectX / OpenGL
  • Nvidia Driver

Alguém pode explicar o processo, talvez com algum tipo de fluxograma para ilustração?

Não deve ser uma explicação complexa que cubra cada passo (suponha que isso vá além do escopo), mas uma explicação que um cara de TI intermediário pode seguir.

Tenho certeza de que muitas pessoas que se chamariam de profissionais de TI não poderiam descrever esse processo corretamente.

A resposta

Embora vários membros da comunidade tenham respondido à pergunta, Oliver Salzburg foi além e respondeu não apenas com uma resposta detalhada, mas também com excelentes gráficos de acompanhamento.
Embora vários membros da comunidade tenham respondido à pergunta, Oliver Salzburg foi além e respondeu não apenas com uma resposta detalhada, mas também com excelentes gráficos de acompanhamento.

Imagem por JasonC, disponível como papel de parede aqui.

Ele escreve:

Eu decidi escrever um pouco sobre o aspecto de programação e como os componentes conversam entre si. Talvez isso possa esclarecer algumas áreas.

A apresentação

O que é preciso para ter essa única imagem, que você postou na sua pergunta, desenhada na tela?

Há muitas maneiras de desenhar um triângulo na tela. Para simplificar, suponhamos que nenhum buffer de vértice tenha sido usado. (UMA buffer de vérticeé uma área de memória em que você armazena as coordenadas. Vamos supor que o programa tenha dito ao pipeline de processamento de gráficos sobre cada vértice (um vértice é apenas uma coordenada no espaço) em uma linha.

Masantes de podermos desenhar qualquer coisa, primeiro temos que executar alguns andaimes. Veremos porque mais tarde:

// Clear The Screen And The Depth Buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset The Current Modelview Matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Drawing Using Triangles glBegin(GL_TRIANGLES); // Red glColor3f(1.0f,0.0f,0.0f); // Top Of Triangle (Front) glVertex3f( 0.0f, 1.0f, 0.0f); // Green glColor3f(0.0f,1.0f,0.0f); // Left Of Triangle (Front) glVertex3f(-1.0f,-1.0f, 1.0f); // Blue glColor3f(0.0f,0.0f,1.0f); // Right Of Triangle (Front) glVertex3f( 1.0f,-1.0f, 1.0f); // Done Drawing glEnd();

Então, o que isso fez?

Quando você escreve um programa que deseja usar a placa gráfica, normalmente você escolhe algum tipo de interface para o driver. Algumas interfaces conhecidas para o driver são:

  • OpenGL
  • Direct3D
  • CUDA

Para este exemplo, vamos ficar com o OpenGL. Agora seu interface para o driver é o que lhe dá todas as ferramentas que você precisa para fazer o seu programa conversa para a placa gráfica (ou o driver, que então conversas para o cartão).

Esta interface é obrigada a dar-lhe certas Ferramentas. Essas ferramentas tomam a forma de uma API que você pode chamar do seu programa.

Essa API é o que vemos sendo usado no exemplo acima. Vamos olhar mais de perto.

O andaime

Antes que você possa realmente fazer qualquer desenho real, você terá que executar um configuração. Você precisa definir sua viewport (a área que será realmente renderizada), sua perspectiva Câmera em seu mundo), o anti-aliasing que você estará usando (para suavizar a borda do seu triângulo) …

Mas não vamos olhar para nada disso. Vamos dar uma olhada nas coisas que você terá que fazer cada quadro. Gostar:

Limpar a tela

O pipeline gráfico não vai limpar a tela para você em cada quadro. Você terá que contar. Por quê? Isso é por que:

Image
Image

Se você não limpar a tela, simplesmente desenhar cada quadro. É por isso que ligamos

glClear

com o

GL_COLOR_BUFFER_BIT

conjunto. O outro bit (

GL_DEPTH_BUFFER_BIT

) diz ao OpenGL para limpar o profundidadeamortecedor. Esse buffer é usado para determinar quais pixels estão na frente (ou atrás) de outros pixels.

Transformação

 Fonte da imagem
Fonte da imagem

Transformação é a parte em que pegamos todas as coordenadas de entrada (os vértices do nosso triângulo) e aplicamos nossa matriz ModelView. Esta é a matriz que explica como nossos modelo (os vértices) são girados, dimensionados e traduzidos (movidos).

Em seguida, aplicamos nossa matriz de projeção. Isso move todas as coordenadas para que elas olhem corretamente para a câmera.

Agora nos transformamos mais uma vez, com a nossa matriz Viewport. Fazemos isso para escalar nossa modelo para o tamanho do nosso monitor. Agora temos um conjunto de vértices que estão prontos para serem renderizados!

Nós voltaremos à transformação um pouco depois.

Desenhando

Para desenhar um triângulo, podemos simplesmente dizer ao OpenGL para iniciar um novo lista de triângulos chamando

glBegin

com o

GL_TRIANGLES

constante. Existem também outras formas que você pode desenhar. Como uma faixa triangular ou um triângulo.Estas são principalmente otimizações, pois requerem menos comunicação entre a CPU e a GPU para desenhar a mesma quantidade de triângulos.

Depois disso, podemos fornecer uma lista de conjuntos de 3 vértices que devem compor cada triângulo. Cada triângulo usa 3 coordenadas (como se estivéssemos no espaço 3D). Além disso, também forneço cor para cada vértice, chamando

glColor3f

antes chamando

glVertex3f

A sombra entre os 3 vértices (os 3 cantos do triângulo) é calculada pelo OpenGL automaticamente. Ele irá interpolar a cor em toda a face do polígono.

Interação

Agora, quando você clica na janela. O aplicativo só precisa capturar a mensagem da janela que sinaliza o clique. Então você pode executar qualquer ação em seu programa que você deseja.

Isso ganha um muito mais difícil quando você quiser começar a interagir com sua cena 3D.

Primeiro você precisa saber claramente em qual pixel o usuário clicou na janela. Então, levando o seu perspectivaem conta, você pode calcular a direção de um raio, desde o ponto do clique do mouse na sua cena. Você pode então calcular se algum objeto em sua cena intercepta com esse raio. Agora você sabe se o usuário clicou em um objeto.

Então, como você faz girar?

Transformação

Estou ciente de dois tipos de transformações que são geralmente aplicadas:

  • Transformação baseada em matriz
  • Transformação baseada em osso

A diferença é que ossos afetar único vértices. Matrizes sempre afetam todos os vértices desenhados da mesma maneira. Vamos ver um exemplo.

Exemplo

Mais cedo, nós carregamos nossa matriz de identidade antes de desenhar o nosso triângulo. A matriz de identidade é aquela que simplesmente fornece sem transformação em absoluto. Então, o que quer que eu desenhe, só é afetado pela minha perspectiva. Então, o triângulo não será girado.

Se eu quiser girar agora, eu poderia fazer as contas sozinho (na CPU) e simplesmente chamar

glVertex3f

comde outros coordenadas (que são giradas). Ou eu poderia deixar a GPU fazer todo o trabalho, chamando

glRotatef

antes de desenhar:

// Rotate The Triangle On The Y axis glRotatef(amount,0.0f,1.0f,0.0f);

amount

é, evidentemente, apenas um valor fixo. Se você quiser animar, você terá que acompanhar

amount

e aumentá-lo a cada quadro.

Então, espere, o que aconteceu com toda a conversa da matriz antes?

Neste exemplo simples, não precisamos nos preocupar com matrizes. Nós simplesmente chamamos

glRotatef

e cuida de tudo isso para nós.

glRotate

produz uma rotação de

angle

graus em torno do vetor x y z. A matriz atual (seeglMatrixMode) é multiplicada por uma matriz de rotação com o produto substituindo a matriz atual, como ifglMultMatrix foram chamados com a seguinte matriz como seu argumento:

x 2 ⁡ 1 - c + cx ⁢ y ⁡ 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - + c + z ⁢ sy 2 ⁡ 1 - + c + c cy z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1

Bem, obrigado por isso!

Conclusão

O que se torna óbvio é que há muita conversa para OpenGL. Mas não está dizendo nos qualquer coisa. Onde está a comunicação?

A única coisa que o OpenGL está nos dizendo neste exemplo é quando estiver feito. Cada operação levará um certo tempo. Algumas operações demoram incrivelmente longas, outras são incrivelmente rápidas.

Enviando um vértice para a GPU será tão rápido, eu nem sei como expressá-lo. Enviar milhares de vértices da CPU para a GPU, todos os quadros, provavelmente não é problema.

Limpar a tela pode levar um milissegundo ou pior (lembre-se, você normalmente só tem cerca de 16 milissegundos de tempo para desenhar cada quadro), dependendo de quão grande é o seu viewport. Para limpá-lo, o OpenGL precisa desenhar todos os pixels da cor que você deseja limpar, que podem ser milhões de pixels.

Além disso, podemos apenas perguntar ao OpenGL sobre as capacidades do nosso adaptador gráfico (resolução máxima, anti-aliasing máximo, profundidade de cor máxima,…).

Mas também podemos preencher uma textura com pixels, cada um com uma cor específica. Cada pixel mantém um valor e a textura é um "arquivo" gigante cheio de dados. Podemos carregar isso na placa gráfica (criando um buffer de textura), então carregar um shader, dizer ao shader para usar nossa textura como uma entrada e executar alguns cálculos extremamente pesados em nosso “arquivo”.

Podemos então "renderizar" o resultado de nossa computação (na forma de novas cores) em uma nova textura.

É assim que você pode fazer a GPU funcionar para você de outras formas. Presumo que o CUDA tenha um desempenho semelhante àquele aspecto, mas nunca tive a oportunidade de trabalhar com ele.

Nós realmente apenas tocamos ligeiramente o assunto. A programação de gráficos 3D é um inferno de uma fera.

 Fonte da imagem
Fonte da imagem

Tem algo a acrescentar à explicação? Soe fora nos comentários. Quer ler mais respostas de outros usuários do Stack Exchange com experiência em tecnologia? Confira o tópico de discussão completo aqui.

Recomendado: