PDA

Visualizza versione completa : Guide: GPU


MarcoGT
29-11-2007, 19.19.54
(recuperata dalla cache di S.Google)

Scritta in origine da Filippo

GPU = Graphics Processing Unit. Il richiamo all'acronimo CPU (Central Processing Unit) comunemente attribuito ai processori è evidente. La sigla GPU, per la cronaca, è stata introdotta per la prima volta da Nvidia in corrispondenza al lancio della GeForce 256, la prima scheda grafica conforme alle DirectX 7.0.

Per capire meglio lo scopo per cui esistono le GPU, è importante capire quali sono le operazioni che si debbono fare per visualizzare una scena 3D su uno schermo. Per questo scopo, ci viene in aiuto il concetto di "pipeline" che Marco ha già ben illustrato nei suoi interventi.

Il procedimento che parte da una descrizione matematica della scena 3D e perviene ad una immagine bidimensionale visualizzabile su uno schermo è chiamato, per l'appunto, "3D pipeline". E, come una catena di montaggio, esso consiste in vari stadi.

Questa catena di montaggio consta fondamentalmente di quattro passi.

Il primo è costituito in genere dall'applicazione stessa che crea/manipola la descrizione matematica della scena 3D che finirà a schermo. Secondo tale descrizione, ogni oggetto è definito da una sorta di "reticolo" tridimensionale (mesh), ovvero una composizione più o meno complessa di poligoni tra loro adiacenti e identificati dalle posizione dei rispettivi vertici. Pensate, a titolo di esempio, al pallone da calcio: la sua superficie è costituita dall'accostamento di vari pentagoni ed esagoni aventi dei lati in comune tra loro, in modo da formare appunto una superficie sferica, anche se i singoli costituenti (i pentagoni e gli esagoni) non sarebbero, in linea di principio, curvi.
Più precisamente, quando si indicano i poligoni impiegati per comporre la descrizione degli oggetti, si usa il termine di primitive. Le primitive più utilizzate sono i triangoli, a volte anche quadrilateri. Alla luce di tutto ciò, quindi, un qualunque oggetto tridimensionale sarà in genere matematicamente descritto come un insieme di vertici, i quali presi a tre a tre (nel caso di triangoli) o a quattro a quattro (nel caso di quadrilateri) definiranno le primitive che a loro volta creeranno il reticolo che descrive la forma dell'oggetto 3D. Questi vertici vengono definiti attraverso le loro coordinate tridimensionali; i valori di queste coordinate sono espressi in relazione ad un punto di riferimento (origine) che è indipendente per ogni singolo oggetto. A completamento della descrizione dell'oggetto, ogni primitiva vedrà associata una cosiddetta normale, ovvero un vettore che indica quale delle due facce della primitiva è quella che "guarda" verso l'esterno dell'oggetto e qual'è invece la faccia interna (Back-face). Questa informazione servirà in seguito per vari motivi, come vedremo.
Assieme ai vertici del reticolo, la descrizione della scena comprenderà ovviamente la posizione del punto di osservazione della scena stessa, nonché le posizioni dei vari oggetti nel mondo tridimensionale, e la posizione e la tipologia delle luci presenti nella scena.
Ad ogni nuovo frame 3D da visualizzare a schermo, sarà compito dell'applicazione aggiornare le posizioni degli oggetti e del punto di osservazione. Alcune applicazioni "furbe" (e sicuramente è il caso dei motori grafici dei giochi 3D, che devono funzionare in tempo reale) possono già in questo stadio effettuare una prima "scrematura" della scena 3D, evitando di passare i dati di oggetti che non si potranno sicuramente vedere, o perché nascosti da altri oggetti o perché al di fuori della visuale offerta dal punto di vista.

I dati 3D manipolati dall'applicazione come descritto vengono quindi passati alla seconda fase, la cosiddetta "Geometry Phase". In questa fase avvengono diverse elaborazioni, volte a creare l'illusione del movimento, in aggiunta a quelle già fatte nella fase precedente nella quale venivano spostati gli oggetti e il punto di vista.
Appartengono a questa fase le operazioni di trasformazione geometrica, che sono fondamentalmente quattro: rotazione, traslazione, scaling (ingrandimento/riduzione) e skewing ("stiratura" è l'unico termine italiano che mi viene in mente dal significato simile).
In questo stadio, inoltre, vengono effettuate operazioni di trasformazione delle coordinate spaziali. Come si è visto prima, infatti, i vertici dei singoli oggetti sono descritti a partire da un punto di riferimento autonomo per ogni oggetto: serve pertanto riportare le coordinate dei vertici a valori che si riferiscano ad un'unica origine comune a tutta la scena. Questa trasformazione di coordinate si indica in genere come conversione da "spazio dei modelli" (Object Space) a "spazio del mondo" (World Space). Ma non è finita qui, perché dopo questa ha luogo un'altra conversione di coordinate, dove queste ultime vengono tutte espresse in funzione di una nuova origine che corrisponde al punto di osservazione della scena, e l'orientamento delle tre dimensioni cambia in modo che la terza dimensione, quella della profondità (z-axis) venga espressa in termini di distanza dal punto di osservazione stesso. Si parla in questo caso di conversione da spazio del mondo (World Space) a spazio della vista (View Space).
Una volta completata la catena di conversioni delle coordinate, si può procedere ad una selezione più precisa di cosa verrà mostrato e cosa no: viene verificato se esistono primitive che sono parzialmente o totalmente fuori dalla porzione visibile della scena (Triangle Clipping); vengono scartate anche le primitive la cui superficie non "guarda" verso l'osservatore, e sarà quindi coperta dalle altre primitive dello stesso oggetto che sono invece rivolte verso il punto di osservazione (Back-Face Culling).
Dopo che tutte queste trasformazioni sono avvenute, inizia la parte definita "Lighting". In questa fase vengono considerate le luci incluse nella descrizione della scena e la loro tipologia, che può essere:
Ambient = illuminazione globale, la cui provenienza non è specificata e che permea ogni punto della scena;
Point = illuminazione omnidirezionale, in cui la luce si irradia in ogni direzione a partire da un punto nello spazio;
Directional = illuminazione la cui origine si suppone a distanza infinita dal punto di osservazione, e quindi i raggi di luce sono tutti paralleli tra loro;
Spot = illuminazione avente origine in un punto, ma i cui raggi di luce si irradiano solo lungo una direzione predefinita, formando quindi un cono di luce.
Il tutto, combinato con le proprietà dei materiali da applicare agli oggetti (colore, riflessione, ecc.) e all'orientamento delle loro primivite (dedotto grazie ai vettori normali di cui si diceva prima) determina come verrà illuminato ogni oggetto e quale colore assumerà di conseguenza.
Tutto quanto abbiamo detto finora a proposito del secondo stadio, messo assieme, costituisce il famoso Transform & Lighting che le GPU supportano in hardware a partire dalle DirectX 7.0.

Siamo arrivati al terzo stadio, detto anche "Triangle Setup". L'operazione più importante che viene fatta in questo stadio è di adattare la scena fin qui elaborata, preparandola per essere "proiettata" su una superficie bidimensionale. Difatti, fin qui tutti i dati elaborati sono stati in tre dimensioni, ma bisogna ricordarsi che il fine ultimo è quello di ottenere un'immagine bidimensionale (quindi piatta) da mandare a schermo. Non solo: l'immagine piatta è anche caratterizzata da un ben determinato numero di pixels (in funzione della risoluzione a cui sta funzionando lo schermo) e quindi si deve passare da una scena descritta in termini di vertici ad una descritta in termini di pixels.

L'ultima fase è il rendering vero e proprio. In questa fase vengono ombreggiati gli oggetti, ovvero il colore e la luminosità di ogni singolo pixel vengono stabiliti in funzione: del modo in cui gli oggetti vengono illuminati; del modello matematico impiegato per stabilire come la luce interagisce con gli oggetti stessi (Flat, Gouraud o Phong, questi ultimi due dal nome del rispettivo inventore); dall'eventuale presenza di "decorazioni" delle primitive dell'oggetto, ovvero immagini da applicare alle facce dell'oggetto (le famose textures).

Bene, a parte il primo stadio della pipeline 3D, tutto il resto viene oggigiorno "smazzato" dalle GPU...

...continua...

MarcoGT
29-11-2007, 19.25.45
...continua...

La pipeline 3D che ho descritto è del tutto generica, e in sostanza riassume il percorso che qualunque motore 3D più o meno fa per pervenire ad un'immagine di una scena tridimensionale, includendo quindi anche i motori di rendering non real-time, ovvero quei motori di rendering che spingono al massimo sul realismo a scapito della velocità, e che sono quelli che in genere troviamo nei software di rendering tipo 3D Studio Max, Blender e simili.

Tornando al caso più specifico delle GPU, penso sia utile chiarire un attimo il concetto di SHADER che è entrato nel lessico comune a partire dall'introduzione delle DirectX 8.0.

Fino alle DirectX 7.0 incluse, infatti, le schede video 3D altro non erano se non degli acceleratori "rigidi", che acceleravano varie parti della pipeline 3D in modo fisso e predeterminato. L'unico grado di libertà che permetteva di distinguere un motore grafico da un altro era quindi dato dall'accuratezza, in termini di numero di vertici, numero e tipo di luci, e definizione delle textures impiegate, in quanto poi nel momento in cui tutto questo materiale era dato in pasto alle schede 3D, queste lo processavano praticamente tutte allo stesso modo.

Con l'arrivo delle DirectX 8.0 (e dell'hardware video che le supportava, nella fattispecie Nvidia GeForce 3 e ATI Radeon 8500) si è introdotto per la prima volta il concetto di acceleratore 3D programmabile. Questo significava che alcune operazioni fondamentali della pipeline 3D (il transform & lighting e gli algoritmi usati per modellare l'interazione tra luce e oggetti, per citare due esempi) non avvenivano più secondo una procedura fissa e uguale per tutte le schede 3D, bensì poteva anche essere eseguita per il tramite di una procedura programmabile stabilita da chi sviluppava il motore grafico. Questa procedura programmabile, definita SHADER, veniva implementata tramite un set di istruzioni riconosciuto dall'hardware della scheda 3D. Poiché il set di istruzioni era diverso a seconda che si volessero implementare procedure che agivano sui vertici degli oggetti 3D piuttosto che sui pixels della scena già proiettata su un'immagine bidimensionale, si è introdotto il concetto di VERTEX SHADERS e PIXEL SHADERS, rispettivamente. I Vertex Shaders sono tipicamente impiegati per le elaborazioni del secondo stadio della pipeline 3D (quindi il Transform & Lighting), mentre i Pixel Shaders riguardano l'ultimo stadio della pipeline (ombreggiatura, applicazione delle textures e relativi effetti speciali). Grazie agli Shaders, i programmatori erano finalmente liberi di sviluppare gli algoritmi di rendering per conto proprio, permettendo quindi una approfondita personalizzazione del motore grafico, e ovviamente la possibilità di ottenere effetti impossibili altrimenti. Naturalmente, gli algoritmi di elaborazione "fissi" presenti fino alle DirectX 7.0 sono rimasti per compatibilità. Per distinguerli dagli shaders programmabili, questi algoritmi rigidi vengono comunemente indicati come FIXED FUNCTIONS.

Sul discorso Shaders purtroppo è venuta a generarsi un po' di confusione, nel senso che spesso si usa il termine SHADER per indicare di volta in volta sia la procedura implementata dal motore grafico per eseguire un determinato algoritmo sulla scheda 3D, sia l'unità funzionale hardware della GPU che materialmente esegue la procedura. Quando si sentirà parlare di SHADER, quindi, bisognerà capire dal contesto se si intende la sequenza di istruzioni eseguite dalla GPU, o l'hardware della stessa GPU che esegue questa sequenza.

Il concetto di VERTEX/PIXEL SHADERS è rimasto pressoché invariato anche nelle successive DirectX 9.0. Di fatto, dalle DX8 alle DX9 è stata ampliata l'estensione del set di istruzioni disponibili per implementare vertex e pixel shaders, che hanno quindi guadagnato in potenzialità.

In generale, le varie revisioni delle specifiche standard stabilite da Micro$oft alle quali deve adeguarsi l'hardware che esegue gli shaders prendono il nome di SHADER MODEL, spesso abbreviato in SM. Con le DirectX 8.0 si è avuta la prima revisione, ovvero lo Shader Model 1.0; con le DirectX 9.0 è arrivata la seconda revisione, SM2.0. Le DirectX 9.0c hanno introdotto lo SM3.0, mentre le nuove DirectX 10 hanno portato lo SM4.0.

Lo SM3.0 e a maggior ragione lo SM4.0 offrono un set di istruzioni molto potente, quasi paragonabile in termini di flessibilità a quello impiegato dalle CPU dei nostri computer, fermo restando che il set di istruzioni supportato dalle schede 3D resta espressamente concepito per elaborazioni grafiche 3D. Tuttavia, la flessibilità dimostrata dallo SM3.0 in poi ha permesso di impiegare le GPU anche in ambiti che non sono strettamente quelli del rendering 3D. E' così nata una nuova disciplina, indicata come GP-GPU, acronimo che significa "General Purpose GPU": si tratta di attività di studio e ricerca per impiegare le GPU come potentissimi coprocessori per la soluzione di problemi complessi che poco o nulla hanno a che fare con la grafica 3D. Sia Nvidia che ATI hanno di recente introdotto schede add-on, che montano una o più GPU ma non hanno alcuna uscita video, e il cui utilizzo è destinato appunto a velocizzare l'elaborazione di determinati calcoli molto onerosi e che si prestano, per loro natura, ad essere "delegati" ad una GPU.

Con lo Shader Model 4.0 delle DirectX 10 la distinzione tra Vertex e Pixel Shaders è caduta, sostituita dal concetto di UNIFIED SHADER (ovvero hardware che esegue un set di istruzioni unico, indipendentemente dal fatto che venga impiegato per eseguire calcoli su vertici 3D o su pixels). Le schede video DX10 di Nvidia e ATI incorporano un certo numero di Unified Shaders (128 per le schede top di Nvidia, ben 320 per i modelli di punta di ATI) che vengono riallocati dinamicamente al volo dall'hardware della scheda 3D per eseguire di volta in volta shaders su vertici o shaders su pixel. Non solo, ma con le DirectX 10 si è anche definitivamente cancellata la compatibilità con il passato, rimuovendo dalle specifiche hardware tutte le Fixed Functions di cui si parlava prima. Se un gioco 3D che fa uso di Fixed Functions viene eseguito su un hardware 3D conforme alle DirectX 10, queste Fixed Functions dovranno necessariamente venire emulate con uno Shader equivalente, o peggio eseguite in software dalla CPU del computer.

Con questo credo si sia detto un po' tutto sulle GPU...