Shader

Alcune delle unità di elaborazione della pipeline permettono di sostituire i programmi predefiniti (dal costruttore o dal driver) con programmi definiti dall'applicazione utente. Ciascuno di questi brevi programmi è chiamato "Shader", e le unità che li eseguono sono dette "Shader Processors". Uno shader è inizializzato ed eseguito una volta per ogni elemento (o gruppo di elementi) presente nel buffer di origine, e può in genere produrre un numero variabile (anche nessuno) di elementi in uscita.
Il "tipo" di uno shader indica lo shader processor che dovrà eseguirlo, cioè il punto della pipeline in cui deve essere inserito per funzionare.

Il vantaggio principale dell'utilizzo degli shader programmabili, nella maggior parte delle applicazioni, è l'efficienza.
Essi permettono di trasferire una certa quantità di elaborazione dalla CPU alla GPU. È un vantaggio notevole in termini di prestazioni, sia perchè permette alla CPU di dedicarsi ad altri compiti (come la simulazione di complessi modelli fisici), sia perché la GPU è più ottimizzata per grandi quantità di calcolo parallelo. Tra l'altro, questo è il motivo per cui non esistono emulatori di shader processor che usano soltanto la CPU: sarebbero troppo lenti. Inoltre, molte funzioni della Fixed Function Pipeline sono inutili in molti casi, come ad esempio il supporto per 8 fonti di luce. Queste funzioni possono essere disattivate in modo più efficiente sostituendo gli shader che le implementano con shader specifici che contengono solo le funzioni veramente necessarie.

Come vantaggio secondario, capita spesso che con gli shader programmabili sia possibile implementare effetti che non sarebbe possibile ottenere altrimenti (non senza riscrivere l'intera pipeline grafica via software). Questo accade perché gli shader possono sfruttare informazioni parzialmente elaborate a cui normalmente non si ha accesso all'inizio della pipeline. Ad esempio, uno shader che agisce alla fine della pipeline è già a conoscenza dell'effettiva suddivisione in pixel che la primitiva avrà sullo schermo.

Di seguito sono riportati brevemente i tipi di shader definiti fino ad oggi (Giugno 2011), corrispondenti alla versione GLSL 4.0 del 10 marzo 2010. Queste specifiche sono destinate a cambiare molto rapidamente, man mano che sempre più parti della pipeline diventano modificabili.
Nel futuro, la Fixed Function Pipeline sarà abolita, e l'uso degli shader diverrà obbligatorio per accedere a qualunque tipo di accelerazione grafica sulla GPU.

Vertex Shader: Un vertex shader sostituisce le prime operazioni della pipeline grafica. Esso riceve in ingresso un singolo vertice, com'è definito dall'applicazione, e applica le trasformazioni di modello, di vista e di proiezione. Può inoltre modificare gli attributi, calcolare la normale e il colore.

Tessellation Control Shader (o Hull Shader): Un tessellation control shader si colloca dopo il vertex shader. Questo shader può elaborare solo un tipo di primitiva, il tipo patch, definito appositamente per questo uso. Una patch è una primitiva che può essere composta da un qualunque numero di vertici.
Il tessellation control shader viene chiamato per ogni vertice della primitiva, ma al contrario del vertex shader può leggere tutti i vertici della patch durante la sua esecuzione, non solo i dati del vertice corrente.
Lo scopo principale è quello di istruire il Tessellator, che ha il compito di suddividere ciascuna primitiva della patch in ulteriori primitive. Questo permette di aumentare dinamicamente la risoluzione della patch durante l'esecuzione.

Tessellation Evaluation Shader (o Domain Shader): Il Tessellation Evaluation Shader viene istanziato una volta per ogni vertice prodotto dal Tessellator e ha il compito di calcolare gli attributi di ciascuno dei vertici prodotti. Come il Tessellation Control Shader, ha accesso a tutti i vertici della primitiva.

Geometry Shader: Un geometry shader si colloca subito dopo l'assemblaggio delle primitive. Esso riceve in ingresso una primitiva (definita come lista ordinata di vertici) e produce in uscita un qualunque numero di primitive.

Fragment Shader (o Pixel Shader): Un fragment shader è eseguito una volta per ogni frammento, cioè ciascuno dei pixel in cui una primitiva viene scomposta, prima del blending. Perciò un fragment shader è (a meno di ottimizzazioni) eseguito indipendentemente dal fatto che il suo frammento sia visualizzato oppure no (a causa del fallimento del depth test, per esempio).

Lo schema della pipeline visto in precedenza si trasforma:

Immagine di pipeline con shaders


Copyright © 2011 Riccardo Monica
Eccetto ove espressamente indicato altrimenti, il contenuto di questa pagina è disponibile secondo la licenza Creative Commons Attribuzione - Condividi allo stesso modo 3.0.