L'unità di elaborazione centrale (CPU) e l'unità di elaborazione grafica (GPU) del tuo computer interagiscono ogni momento in cui utilizzi il computer per offrirti un'interfaccia visiva nitida e reattiva. Continua a leggere per capire meglio come funzionano insieme.
fotografato da sskennel .
La sessione di domande e risposte di oggi ci arriva per gentile concessione di SuperUser, una suddivisione di Stack Exchange, un raggruppamento di siti web di domande e risposte guidato dalla comunità.
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.
Certamente un esempio molto semplice, ma penso che sia applicabile ad altre operazioni con schede grafiche.
Ero solo curioso e volevo conoscere l'intero processo dal doppio clic su Triangle.exe in Windows XP fino a quando non vedo il triangolo ruotare sul monitor. Cosa succede, come interagiscono CPU (che prima gestisce il file .exe) e GPU (che alla fine emette il triangolo sullo schermo)?
Immagino che coinvolto nella visualizzazione di questo triangolo rotante sia principalmente il seguente hardware / software, tra gli altri:
Hardware
- HDD
- Memoria di sistema (RAM)
- CPU
- Memoria video
- GPU
- display LCD
Software
- Sistema operativo
- API DirectX / OpenGL
- Nvidia Driver
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 passaggio (suppongo che andrebbe oltre lo scopo), ma una spiegazione che un tecnico 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 più membri della comunità abbiano risposto alla domanda, Oliver Salzburg ha fatto il possibile e ha risposto non solo con una risposta dettagliata ma anche 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 parlano tra loro. Forse farà luce su alcune aree.
La presentazione
Cosa ci vuole per avere quella singola immagine, che hai postato nella tua domanda, disegnata sullo schermo?
Esistono molti modi per disegnare un triangolo sullo schermo. Per semplicità, supponiamo che non siano stati utilizzati buffer dei vertici. (UN buffer dei vertici è un'area di memoria in cui si memorizzano 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 di poter 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 matrice Modelview corrente glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Disegnare usando i triangoli glBegin (GL_TRIANGLES); // Rosso glColor3f (1.0f, 0.0f, 0.0f); // Top Of Triangle (Front) glVertex3f (0,0f, 1,0f, 0,0f); // Verde glColor3f (0.0f, 1.0f, 0.0f); // Sinistra del triangolo (anteriore) glVertex3f (-1,0f, -1,0f, 1,0f); // Blu glColor3f (0.0f, 0.0f, 1.0f); // Right Of Triangle (Front) glVertex3f (1.0f, -1.0f, 1.0f); // Disegno fatto glEnd ();
Allora cosa ha fatto?
Quando scrivi un programma che vuole utilizzare la scheda grafica, di solito scegli un qualche tipo di interfaccia per il driver. Alcune interfacce ben note al driver sono:
- OpenGL
- Direct3D
- MIRACOLI
Per questo esempio ci atterremo a OpenGL. Adesso tuo interfaccia al driver è ciò che ti offre tutti gli strumenti necessari per creare il tuo programma parlare alla scheda grafica (o al driver, che poi parla alla carta).
Questa interfaccia è destinata a darti certezze utensili . Questi strumenti hanno la forma di un file API che puoi chiamare dal tuo programma.
Quell'API è ciò che vediamo essere utilizzato nell'esempio sopra. Diamo uno sguardo più da vicino.
L'impalcatura
Prima di poter davvero fare qualsiasi disegno effettivo, dovrai eseguire un file impostare . Devi definire il tuo viewport (l'area che verrà effettivamente renderizzata), la tua prospettiva (il camera nel tuo mondo), quale anti-aliasing utilizzerai (per smussare i bordi del tuo triangolo) ...
Ma non guarderemo niente di tutto ciò. Daremo solo uno sguardo alle cose che dovrai fare ogni fotogramma . Piace:
Cancellazione dello schermo
La pipeline grafica non cancellerà lo schermo per ogni fotogramma. Dovrai raccontarlo. Perché? Ecco perché:
Se non cancelli lo schermo, lo farai semplicemente
disegnare
ogni fotogramma. Ecco perché chiamiamo
glClear
con il
GL_COLOR_BUFFER_BIT
impostato. L'altro pezzo (
GL_DEPTH_BUFFER_BIT
) dice a OpenGL di cancellare il file
profondità
buffer. Questo buffer viene utilizzato per determinare quali pixel sono davanti (o dietro) altri pixel.
Trasformazione
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) vengono ruotati, scalati e traslati (spostati).
Successivamente, applichiamo la nostra matrice di proiezione. Questo sposta tutte le coordinate in modo che siano rivolte correttamente alla nostra telecamera.
Ora ci trasformiamo ancora una volta, con la nostra matrice Viewport. Lo facciamo per ridimensionare il nostro modello alla dimensione del nostro monitor. Ora abbiamo un insieme 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 un nuovo
elenco di triangoli
a chiamata
glBegin
con il
GL_TRIANGLES
costante.
Ci sono anche altre forme che puoi disegnare. Come un
striscia triangolare
o a
ventilatore a triangolo
. Si tratta principalmente di ottimizzazioni, poiché richiedono meno comunicazione tra la CPU e la GPU per disegnare la stessa quantità di triangoli.
Dopodiché, possiamo fornire un elenco di insiemi di 3 vertici che dovrebbero formare ogni triangolo. Ogni triangolo utilizza 3 coordinate (poiché siamo nello spazio 3D). Inoltre, fornisco anche un file
colore
per ogni vertice, chiamando
glColor3f
prima
chiamando
glVertex3f
.
L'ombra tra i 3 vertici (i 3 angoli del triangolo) è calcolata da OpenGL automaticamente . Interpolerà il colore su tutta la faccia del poligono.
Interazione
Ora, quando fai clic sulla finestra. L'applicazione deve solo acquisire il file messaggio della finestra che segnala il clic. Quindi puoi eseguire qualsiasi azione nel tuo programma che desideri.
Questo ottiene un molto più difficile una volta che vuoi iniziare a interagire con la tua scena 3D.
Devi prima sapere chiaramente in quale pixel l'utente ha cliccato sulla finestra. Quindi, prendendo il tuo prospettiva in considerazione, puoi calcolare la direzione di un raggio, dal punto del clic del mouse nella tua scena. Puoi quindi calcolare se c'è qualche oggetto nella tua 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 matrici
- Trasformazione basata sull'osso
La differenza è questa ossatura colpire single vertici . Le matrici influenzano sempre tutti i vertici disegnati nello 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 identità è quella che fornisce semplicemente nessuna trasformazione affatto. Quindi, qualunque cosa io disegni, è influenzata solo dalla mia prospettiva. Quindi, il triangolo non verrà ruotato affatto.
Se voglio ruotarlo ora, potrei fare i calcoli da solo (sulla CPU) e semplicemente chiamare
glVertex3f
con
altro
coordinate (che vengono ruotate). Oppure potrei lasciare che la GPU faccia tutto il lavoro, chiamando
glRotatef
prima di disegnare:
// Ruota il triangolo sull'asse Y glRotatef (amount, 0.0f, 1.0f, 0.0f);
quantità
è, ovviamente, solo un valore fisso. Se lo desidera
animate
, dovrai tenere traccia di
quantità
e aumentalo ogni fotogramma.
Allora, aspetta, cosa è successo a tutti i discorsi su Matrix prima?
In questo semplice esempio, non dobbiamo preoccuparci delle matrici. Chiamiamo semplicemente
glRotatef
e si prende cura di tutto questo per noi.
glRotateproduce una rotazione diangologradi attorno al vettore x y z. La matrice corrente (vedi glMatrixMode ) viene moltiplicato per una matrice di rotazione con il prodotto che sostituisce la matrice corrente, come se glMultMatrix sono stati chiamati 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 è che si parla molto per OpenGL. Ma non lo dice noi nulla. Dov'è la comunicazione?
L'unica cosa che OpenGL ci dice in questo esempio è quando è finito . Ogni operazione richiederà un certo tempo. Alcune operazioni richiedono tempi incredibilmente lunghi, altre sono incredibilmente veloci.
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 frame, molto probabilmente non è affatto un problema.
Cancellazione dello schermo può richiedere un millisecondo o peggio (tieni presente che di solito hai solo circa 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 praticamente solo chiedere a OpenGL le capacità del nostro adattatore grafico (risoluzione massima, anti-aliasing massimo, profondità di colore massima, ...).
Ma possiamo anche riempire una texture con pixel che hanno ciascuno un colore specifico. Ogni pixel ha quindi un valore e la trama è un gigantesco "file" pieno di dati. Possiamo caricarlo nella scheda grafica (creando un buffer di texture), quindi caricare un file shader , dì a quello shader di usare la nostra texture come input ed eseguire alcuni calcoli estremamente pesanti sul nostro "file".
Possiamo quindi "rendere" il risultato del nostro calcolo (sotto forma di nuovi colori) in una nuova texture.
È così che puoi far funzionare la GPU per te in altri modi. Presumo che CUDA funzioni in modo simile a quell'aspetto, ma non ho mai avuto l'opportunità di lavorarci.
Abbiamo davvero toccato solo leggermente l'intero argomento. La programmazione grafica 3D è una bestia infernale.
Hai qualcosa da aggiungere alla spiegazione? Suona nei commenti. Vuoi leggere altre risposte da altri utenti esperti di tecnologia Stack Exchange? Dai un'occhiata al thread di discussione completo qui .