Compute Shader
Abbiamo menzionato un segreto di Pulcinella in conclusione al nostro articolo su CUDA : Microsoft non vuole farsi scappare il mercato delle GPGPU, e ora possiede il suo linguaggio per entrare in questa nuova arena. Il modello che hanno scelto, come l'OpenCL, sembra simile a CUDA, a conferma della buona scelta di nVidia. Il vantaggio, rispetto alla soluzione nVidia, risiede nella portabilità: un'unità Compute Shader, infatti, potrà lavorare con una GPU nVidia o ATI, e in futuro su Larrabee, e avrà più funzionalità per una migliore integrazione con Direct3D, anche se CUDA ha già una buona schiera di supporter. Non vogliamo però spendere altro tempo su questa questione, anche se è molto corposa. Fra un paio di mesi, invece, ci occuperemo di qualche dettaglio in più, con un articolo sull'OpenCL e il Compute Shader.
Compressione texture migliorata
Inclusa la prima volta nelle DirectX6, dieci anni fa, la compressione delle texture DXTC è stata in fretta spostata sulle GPU, e usata massicciamente dagli sviluppatori fin dalla sua nascita. Bisogna ammettere che la tecnologia sviluppata da S3 Graphics era ottima, e il costo hardware modesto, quindi il successo garantito. DXCT, però, non è stata progettata pensando a immagini HDR compresse o normal maps, e comincia a mostrare i suoi limiti. L'obiettivo delle Direct3D è quindi doppio: abilitare la compressione delle immagini HDR e ovviare alle limitazioni della classica modalità DXCT. Per farlo, Microsoft ha introdotto due modalità: BC6 per immagini HDR e BC7 per aumentare la qualità di compressione delle immagini LDR.
Con lo ShaderModel 5, Microsoft applica alcuni concetti della programmazione a oggetti al suo linguaggio shader, HLSL. Diversamente dalle precedenti versioni, che hanno introdotto nuove funzionalità (Dynamic Brancking, supporto integer, etc), l'obbiettivo in questo caso è facilitare il lavoro dei programmatori, risolvendo un problema comune ai motori grafici attuali: l'aumento del numero di shader causato dall'elevato numero di permutazioni. Supponiamo che un motore gestisca due tipi di materiali, plastica e metallo, e due tipi di luci: spot e omni. Un programmatore deve scrivere uno shader per ogni combinazione possibile :
renderPlasticSpot () ? // rendering plastic using spot light ?
renderPlasticOmni () ? // rendering plastic using omni light ?
renderMetalSpot() ? //rendering metal using spot light...
renderMetalOmni() ? //rendering metal using omni light ?
Questo esempio è molto semplice, con solo due materiali e due tipi di luce, ma nella realtà possono essercene varie dozzine. Ovviamente questo approccio può diventare presto ingestibile, con l'aumentare degli shader. C'è, di conseguenza, una quantità tremenda di codice duplicato, e ogni volta che bisogna intervenire per correggere un bug, bisogna ripetere la correzione con tutte le righe di shader presenti. Per risolvere questo problema, i programmatori usano quello che è comunemente chiamato un über?shader, che porta in sé tutte le combinazioni:
Render() #ifdef METAL // code specific to metal material #elif PLASTIC // code specific to plastic material #endif #ifdef SPOT // code specific to spot light #elif OMNI // code specific to omni light #endif
Questa soluzione risolve il problema di generazione di shader "al volo", da un frammento di codice comune. Il risvolto della medaglia è che rende la lettura delle shader difficile, e richiede maggior sforzo per assicurare che tutti i frammenti siano inseriti al posto giusto. Con le Direct3D 11 è ora possibile rendere il codice più leggibile usando un'interfaccia derivata e classi :
Light myLight; Material myMaterial; Render() myMaterial.render (); myLight.shade ();
Light e Material sono interfacce, e il codice è contenuto nelle classi derivate OmniLight e SpotLight, PlasticMaterial e MetalMaterial. Quindi il codice è tutto in un solo "posto", soluzione che rende la correzione dei bug più semplice, rapida ed economica. Allo stesso tempo, la leggibilità non ne soffre grazie alla migliore organizzazione del codice, che ricorda il concetto di funzione virtuale in un linguaggio a oggetti. Questa caratteristica sarà benvenuta dai programmatori, ma non avrà un impatto reale per i videogiocatori, tranne forse che nella rapidità nella correzione dei bug.