Come funziona la Scheda Grafica all’interno di un PC

Spesso per parlare di scheda grafica è necessario fare prima chiarire un punto che crea molta confusione: la scheda grafica non è la GPU. Sembrerebbe una banalità, ma è l’errore più comune che si fa quando è il momento di guardare alle funzioni precise di una scheda grafica. Tant’è che appunto viene molto spesso identificata come fosse la stessa cosa della GPU, o meglio la Graphic Processor Unit.

Le due hanno funzioni ben definite, e ciò dipende soprattutto dalle loro posizioni all’interno del computer. Per cominciare è bene specificare dunque le seguenti:

  1. Definizione e posizione della scheda grafica;
  2. In che modo la scheda grafica è collegata al computer;
  3. Le funzioni della scheda grafica.

Definizione e posizione della scheda grafica

La scheda grafica è a tutti gli effetti definibile come un computer a sé stante all’interno del computer stesso. Questo poiché ha un suo processore principale e una memoria RAM elettronica che garantisce un’interfaccia input o output con il computer che la ospita. Oggi la memoria RAM elettronica è costituita dalla PCI Express 4.0.

Per aiutarci a visualizzare la struttura interna di una GPU classica si può visualizzare il seguente schema della GPU Nvidia GeForce 6800:

Seguendo il diagramma dall’alto verso il basso, di fatto ripercorriamo la classica pipeline di rendering 3D. In questo tipo di architettura, i Vertex Shader, come suggerisce il nome, si occupano di effettuare operazioni sui vertici e di predisporre le primitive. Tutta la prima parte della pipeline grafica viene eseguita qui. Setup della geometria e delle luci, trasformazione delle coordinate per il calcolo della prospettiva e applicazione delle prime texture. I dati elaborati dai Vertex Shader vengono quindi passati alle unità che montano i triangoli e si occupano di calcolare la visibilità degli elementi e al rastering per la suddivisione in Fragment.

Questi a loro volta saranno elaborati dai Pixel Shader che hanno invece il compito di “colorare” le primitive, applicando le texture e calcolando gli effetti di illuminazione sulle superfici in base alle caratteristiche del materiale da rappresentare, lo shading vero e proprio. L’uscita dei Pixel Shader a questo punto viene data in pasto ai ROP (Raster Operations Pipeline o Render Output Unit). Questi si occupano di costruire il frame assemblando tutti i contributi in base allo Z-Buffer e dando il tocco finale applicando i filtri di anti-aliasing, di fatto determinando il colore finale di ciascuno pixel che verrà visualizzato a schermo.

In che modo è collegata al computer

La prima azione da parte del computer è l’avvio di un’applicazione. Quest’ultima ha una mole di dati che viene trasferita alla scheda grafica. La quale ha come primissimo compito quello di visualizzare le immagini ricevute dal computer e mostrarle all’utente attraverso lo schermo. Per poter svolgere quest’azione, la scheda grafica sfrutta le apposite API, ovvero le Application Programming Interface. Già dal nome si può intuire la loro utilità: le API sono un insieme di procedure volte a compiere un determinato compito, ovvero quello che gli viene indicato dal computer e successivamente dalla scheda grafica. Per questa ragione vengono raggruppate sulla base delle azioni che sono in grado di svolgere.

I dati da elaborare vengono caricati dunque nella scheda grafica, e le API fanno il loro dovere di seguito, ma questo implica che il processore grafico, ovvero il GPU, possieda delle unità di calcolo dedicate a ciascun passaggio di informazioni che gli vengono inviate dal computer.

Questo processo si può definire come una catena di postazioni di lavoro all’interno del GPU. Le postazioni si dedicheranno dunque ognuna ad un passaggio di informazioni di blocco in blocco fino alla risoluzione finale.

Le GPU hanno ormai architetture moderne. Possiedono processori capaci di eseguire molti più compiti, e decisamente più complessi senza il bisogno di seguire la catena di montaggio che abbiamo citato in precedenza. Facendo uso di una sola unità di calcolo, in grado di eseguire dei programmi in autonomia, anche se di piccole dimensioni. Questi ultimi sono per l’appunto i shader precedentemente menzionati.

Il termine di shader però sta ad indicare anche altro. Non solo è il programma di calcolo che viene eseguito dalla GPU, ma è anche quell’elemento della GPU che lo fa funzionare.  In poche parole è come dire che si aiuta da solo ad eseguirsi.

Le funzioni della scheda grafica

Un aspetto molto importante del funzionamento della GPU, che diventerà preponderante nelle architetture di oggi è quello del ricircolo. I fragment vengono infatti processati a più passate, cambiando di volta in volta il set di istruzioni da eseguire. Verrà in seguito applicato il paradigma di computazione denominato SIMD, single instruction multiple data. Perciò i pixel shader cioè, a ogni giro dell’orologio vengono programmati per eseguire la stessa istruzione su un gran numero di fragment. Finito il ciclo di clock, i dati tornano allo stadio precedente della pipeline. Si impostano le nuove istruzioni da eseguire, e a questo punto i fragment vengono di nuovo rielaborati uno dietro l’altro.

Ciò consente da una parte di parallelizzare l’elaborazione dei dati, dall’altra di fare un uso efficiente della memoria, precaricando istruzioni e texture nelle apposite cache e utilizzandole per processare una grande quantità di dati come i milioni di pixel che compongono un’immagine.

In tutto questo, il singolo Pixel Shader è uncore” tutto sommato semplice. Nel caso esemplificativo della GeForce 6800 era costituito da due unità di calcolo floating point a 32 bit. Il tutto affiancato da un’unità specializzata per il campionamento ed elaborazione delle texture e una per il calcolo dell’effetto della nebbia. Il diagramma comprende anche in questo caso un ricircolo per permettere di effettuare più operazioni durante lo stesso ciclo di clock sullo stesso dato.

Questo tipo di architettura presenta però alcune inefficienze che hanno portato ad un certo punto dell’evoluzione delle GPU a richiedere un cambio di approccio. Come in una CPU, le istruzioni vengono elaborate a cicli di clock: a ogni giro dell’orologio tutti gli elementi del processore eseguono il loro compito a patto di avere dati da elaborare. Nel caso della GPU, un Pixel Shader potrà elaborare i diversi fragment di una primitiva solo se il Vertex Shader ha finito di costruire tutti i poligoni da renderizzare. Se il frame prevede una geometria estremamente complessa con moltissimi triangoli di piccole dimensioni, può verificarsi che l’elaborazione dei vertici duri più cicli di clock, lasciando i Pixel Shader senza dati su cui lavorare.

Viceversa, se ad essere saturi sono i Pixel Shader perché ci sono pochi triangoli ma con ampie superfici da riempire e tanti effetti da calcolare, saranno i Vertex Shader a perdere cicli di clock in attesa che le elaborazioni a valle vengano completate. Tutto ciò è naturalmente necessario alla comprensione del funzionamento di un’odierna GPU. E’ costituita essenzialmente da un gran numero di blocchi fondamentali programmabili denominati Stream Processor, per utilizzare la terminologia dei principali produttori di schede grafiche.

Come si può vedere a differenza del diagramma dei paragrafi precedenti, la pipeline grafica di cui abbiamo parlato fino ad ora qui non è più riconoscibile in quello di seguito:

Ci sono dei blocchi funzionali specializzati, riconosciamo delle Texture Unit, e l’ultimo stadio finale è sempre costituito da unità denominate ROP. Per il resto non c’è niente di riconducibile ai passaggi fondamentali che abbiamo illustrato quando abbiamo affrontato la pipeline grafica.

Questo perché gli shader delle precedenti generazioni di GPU sono stati tutti sostituiti dallo Stream Multi-Processor (o Compute Unit nel gergo di AMD), completamente programmabile e che può eseguire vertex, geometry o pixel shader a seconda del carico di lavoro del momento, dando massima flessibilità e rendendo molto più semplice sfruttare sempre al massimo le risorse computazionali a disposizione.

La filosofia è quella di parallelizzare ma anche di condividere le risorse più preziose come memoria cache, unità di calcolo speciali (le SFU, special function unit, che calcolano funzioni esponenziali o trigonometriche), texture mapping unit, motivo per cui i singoli Stream Processor che contengono le unità di calcolo in virgola mobile di base (i calcolatori veri e propri) sono aggregati in Stream Multi-Processor e quindi ad un livello ancora più alto in TPC. Ad ogni livello di raggruppamento, corrisponde la condivisione di determinate risorse, nel nostro esempio, al livello più alto, le Texture Unit e relative cache.

Questa nuova tipologia di architettura ha tutto un nuovo modo di funzionare. Viene estremizzato il concetto di ricircolo che già veniva in parte implementato nella generazione precedente di GPU. A seconda del carico di lavoro i dati (che siano vertici, linee, triangoli o fragment) vengono organizzati in stream e dati in pasto all’array di Stream Multi-Processor che funzioneranno come vertex, geometry o pixel shader. A ogni ciclo di clock, il sistema programma le singole unità SP per eseguire lo stesso set di istruzioni su tutto lo stream di dati in ingresso.

Se l’output del processo non è il pixel finale e deve andare incontro a nuove elaborazioni, ritorna nel calderone e verrà ridato di nuovo in pasto all’array. Questo nel frattempo verrà riprogrammato per eseguire le nuove istruzioni e così via. Quando si arriva al risultato finale e il fragment diventa un pixel, esce dal ciclo ed entra nel ROP per essere scritto all’interno del frame. Ciclo dopo ciclo viene ancora eseguita la stessa pipeline grafica che abbiamo imparato a conoscere, ma riutilizzando le stesse risorse hardware.

Questo approccio consente di massimizzare l’efficienza del paradigma SIMD e il calcolo parallelo.

COMMENTI