In che modo CPU e GPU interagiscono con Render Computer Graphics?
L'unità di elaborazione centrale (CPU) e l'unità di elaborazione grafica (GPU) del computer interagiscono ogni volta che si utilizza il computer per fornire un'interfaccia visiva nitida e reattiva. Continua a leggere per capire meglio come lavorano insieme.
fotografato da sskennel.
La sessione di domande e risposte di oggi ci viene fornita per gentile concessione di SuperUser, una suddivisione di Stack Exchange, un raggruppamento di domande e risposte di community-drive.
La domanda
Il lettore SuperUser Sathya ha posto la domanda:
Qui puoi vedere uno screenshot di un piccolo programma C ++ chiamato Triangle.exe con un triangolo rotante basato sull'API OpenGL.
Si tratta di un esempio molto semplice, ma penso che sia applicabile ad altre operazioni con le schede grafiche.
Ero solo curioso e volevo conoscere l'intero processo facendo doppio clic su Triangle.exe sotto Windows XP fino a quando non riesco a vedere il triangolo che ruota sul monitor. Cosa succede, come interagiscono la CPU (che prima gestisce l'exe) e la GPU (che alla fine emette il triangolo sullo schermo)?
Immagino che la visualizzazione di questo triangolo rotante sia principalmente il seguente hardware / software, tra gli altri:
Hardware
- HDD
- Memoria di sistema (RAM)
- processore
- Memoria video
- GPU
- display LCD
Software
- Sistema operativo
- API DirectX / OpenGL
- Driver Nvidia
Qualcuno può spiegare il processo, magari con una sorta di diagramma di flusso per l'illustrazione?
Non dovrebbe essere una spiegazione complessa che copre ogni singolo passo (suppongo che vada oltre lo scopo), ma una spiegazione che un ragazzo IT intermedio può seguire.
Sono abbastanza sicuro che molte persone che si chiamerebbero anche professionisti IT non potrebbero descrivere correttamente questo processo.
La risposta
Sebbene molti membri della comunità abbiano risposto alla domanda, Oliver Salzburg ha fatto il massimo e ha risposto non solo con una risposta dettagliata ma con un'eccellente grafica di accompagnamento.
Immagine di JasonC, disponibile come sfondo qui.
Lui scrive:
Ho deciso di scrivere un po 'sull'aspetto della programmazione e su come i componenti si parlano tra loro. Forse farà luce su alcune aree.
La presentazione
Che cosa serve per avere anche quella singola immagine, che hai postato nella tua domanda, disegnata sullo schermo?
Ci sono molti modi per disegnare un triangolo sullo schermo. Per semplicità, supponiamo che non siano stati utilizzati buffer di vertice. (UN buffer dei verticiè un'area di memoria in cui memorizzi le coordinate. Supponiamo che il programma abbia semplicemente detto alla pipeline di elaborazione grafica di ogni singolo vertice (un vertice è solo una coordinata nello spazio) in una riga.
Ma, prima che possiamo disegnare qualsiasi cosa, dobbiamo prima eseguire alcune impalcature. Vedremo perché dopo:
// Cancella lo schermo e il buffer di profondità glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reimposta la Modelview Matrix attuale glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Disegnare usando i triangoli 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 ();
Quindi cosa ha fatto?
Quando scrivi un programma che vuole utilizzare la scheda grafica, di solito scegli un tipo di interfaccia per il driver. Alcune interfacce ben note al driver sono:
- OpenGL
- Direct3D
- CUDA
Per questo esempio continueremo con OpenGL. Adesso tuo interfaccia al driver è ciò che ti dà tutti gli strumenti necessari per realizzare il tuo programma parlare alla scheda grafica (o al driver, che quindi trattativa alla carta).
Questa interfaccia è destinata a darti certezze utensili. Questi strumenti prendono la forma di un'API che puoi chiamare dal tuo programma.
Quell'API è ciò che vediamo essere usato nell'esempio sopra. Diamo un'occhiata più da vicino.
The Scaffolding
Prima che tu possa davvero fare un disegno reale, dovrai eseguire un impostare. Devi definire il tuo viewport (l'area che verrà effettivamente renderizzata), la tua prospettiva (il telecamera nel tuo mondo), quale anti-aliasing userai (per appianare il bordo del tuo triangolo) ...
Ma non vedremo nulla di tutto ciò. Daremo solo una sbirciatina alle cose che dovrai fare ogni frame. Piace:
Cancellare lo schermo
La pipeline grafica non cancellerà lo schermo per ogni fotogramma. Dovrai dirlo. Perché? Ecco perché:
Se non si cancella lo schermo, lo farai semplicemente attirare ogni frame Ecco perché chiamiamo glClear
con ilGL_COLOR_BUFFER_BIT
impostato. L'altro bit (GL_DEPTH_BUFFER_BIT
) dice a OpenGL di cancellare il profonditàbuffer. Questo buffer viene utilizzato per determinare quali pixel si trovano davanti (o dietro) altri pixel.
Trasformazione
Fonte immagine
La trasformazione è la parte in cui prendiamo tutte le coordinate di input (i vertici del nostro triangolo) e applichiamo la nostra matrice ModelView. Questa è la matrice che spiega come il nostro modello (i vertici) sono ruotati, ridimensionati e tradotti (spostati).
Successivamente, applichiamo la nostra matrice di proiezione. Ciò sposta tutte le coordinate in modo che facciano fronte alla nostra macchina fotografica correttamente.
Ora trasformiamo ancora una volta, con la nostra matrice Viewport. Facciamo questo per ridimensionare il nostro modello alle dimensioni del nostro monitor. Ora abbiamo un set di vertici pronti per essere renderizzati!
Torneremo alla trasformazione un po 'più tardi.
Disegno
Per disegnare un triangolo, possiamo semplicemente dire a OpenGL di iniziare una nuova lista di triangoli a chiamata glBegin
con il GL_TRIANGLES
costante.
Ci sono anche altre forme che puoi disegnare. Come una striscia triangolare o un ventilatore a triangolo. Si tratta principalmente di ottimizzazioni, in quanto richiedono meno comunicazioni tra CPU e GPU per disegnare la stessa quantità di triangoli.
Dopodiché, possiamo fornire un elenco di serie di 3 vertici che dovrebbero costituire ciascun triangolo. Ogni triangolo usa 3 coordinate (dato che siamo nello spazio 3D). Inoltre, fornisco anche un colore per ogni vertice, chiamandoglColor3f
prima chiamata glVertex3f
.
L'ombra tra i 3 vertici (i 3 angoli del triangolo) viene calcolata da OpenGLautomaticamente. Interpola il colore su tutta la faccia del poligono.
Interazione
Ora, quando fai clic sulla finestra. L'applicazione deve solo acquisire il messaggio della finestra che segnala il clic. Quindi puoi eseguire qualsiasi azione nel programma che desideri.
Questo ottiene a lotto più difficile una volta che si desidera iniziare a interagire con la scena 3D.
Per prima cosa devi sapere chiaramente a quale pixel l'utente ha fatto clic sulla finestra. Quindi, prendendo il tuo prospettivain considerazione, è possibile calcolare la direzione di un raggio, dal punto del clic del mouse nella scena. È quindi possibile calcolare se qualsiasi oggetto nella scena interseca con quel raggio. Ora sai se l'utente ha fatto clic su un oggetto.
Quindi, come lo fai ruotare?
Trasformazione
Sono a conoscenza di due tipi di trasformazioni che vengono generalmente applicate:
- Trasformazione basata su matrice
- Trasformazione basata sull'osso
La differenza è questa ossatura affetto singolo vertici. Le matrici influenzano sempre tutti i vertici disegnati allo stesso modo. Diamo un'occhiata a un esempio.
Esempio
In precedenza, abbiamo caricato il nostro matrice identità prima di disegnare il nostro triangolo. La matrice di identità è quella che fornisce semplicemente nessuna trasformazione affatto. Quindi, qualunque cosa io tragga, è influenzata solo dalla mia prospettiva. Quindi, il triangolo non verrà ruotato affatto.
Se voglio ruotarlo ora, potrei fare il calcolo da solo (sulla CPU) e semplicemente chiamare glVertex3f
conaltro coordinate (che sono ruotate). Oppure potrei lasciare che la GPU faccia tutto il lavoro, chiamando glRotatef
prima del disegno:
// Ruota il triangolo sull'asse Y glRotatef (quantità, 0.0f, 1.0f, 0.0f);
quantità
è, ovviamente, solo un valore fisso. Se lo desidera animare, dovrai tenerne traccia quantità
e aumentalo ogni fotogramma.
Quindi, aspetta, quello che è successo a tutte le matrici parlano prima?
In questo semplice esempio, non dobbiamo preoccuparci delle matrici. Chiamiamo semplicemente glRotatef
e si prende cura di tutto ciò per noi.
glRotate
produce una rotazione diangolo
gradi attorno al vettore x y z. La matrice corrente (seeglMatrixMode) viene moltiplicata per una matrice di rotazione con il prodotto che sostituisce la matrice corrente, come se glMultMatrix fosse chiamata con la seguente matrice come argomento: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 + 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
Bene, grazie per quello!
Conclusione
Ciò che diventa ovvio è, ci sono molte parole a OpenGL. Ma non sta dicendo noi nulla. Dov'è la comunicazione?
L'unica cosa che OpenGL ci sta dicendo in questo esempio è quando è finito. Ogni operazione richiederà un certo periodo di tempo. Alcune operazioni impiegano incredibilmente a lungo, altre sono incredibilmente veloci.
L'invio di un vertice alla GPU sarà così veloce, non saprei nemmeno come esprimerlo. L'invio di migliaia di vertici dalla CPU alla GPU, ogni singolo fotogramma, è, molto probabilmente, nessun problema.
Cancellare lo schermo può richiedere un millisecondo o peggio (tieni presente che di solito hai solo 16 millisecondi di tempo per disegnare ogni fotogramma), a seconda di quanto è grande il tuo viewport. Per cancellarlo, OpenGL deve disegnare ogni singolo pixel nel colore che vuoi cancellare, che potrebbe essere milioni di pixel.
Oltre a questo, possiamo semplicemente chiedere a OpenGL le funzionalità del nostro adattatore grafico (risoluzione massima, anti-aliasma max, profondità di colore massima, ...).
Ma possiamo anche riempire una trama con pixel che hanno ciascuno un colore specifico. Ogni pixel contiene quindi un valore e la trama è un "file" gigante pieno di dati. Possiamo caricarlo nella scheda grafica (creando un buffer di texture), quindi caricare uno shader, dire a quello shader di usare la nostra texture come input ed eseguire calcoli estremamente pesanti sul nostro "file".
Possiamo quindi "rendere" il risultato del nostro calcolo (sotto forma di nuovi colori) in una nuova trama.
È così che puoi far funzionare la GPU per te in altri modi. Presumo che CUDA funzioni in modo simile a questo aspetto, ma non ho mai avuto l'opportunità di lavorare con esso.
Abbiamo davvero toccato solo un po 'l'argomento. La programmazione grafica 3D è una bestia infernale.
Fonte dell'immagine
Hai qualcosa da aggiungere alla spiegazione? Sound off nei commenti. Vuoi leggere più risposte dagli altri utenti di Stack Exchange esperti di tecnologia? Controlla la discussione completa qui.