Accesso alle Risorse 2903 Visite) DirectX 11
Una delle cose fondamentali utilizzando DirectX è il poter accedere alle risorse contenuti nei buffer. Ad esempio può essere necessario poter leggere i vertici contenuti nelle mesh e magari modificarli.
Direct3D ha modificato in maniera sostanziale la gestione della memoria creando delle regole che possono inizialmente creare dei problemi ma che alla fine diventano un ottimo sistema di gestione. Ogni risorsa infatti è creata in modo da poter essere letta o scritta solamente dalla GPU o dalla CPU. Questo ad esempio può significare che una certa risorsa può essere creata per poter essere letta dalla GPU (esempio una texture quando viene mandata a video) e scritta dalla CPU (per poter essere modificata), oppure il contrario, oppure essere gestita solamente dalla GPU o solamente dalla CPU.
In Direct3D infatti esistono 4 tipi di usage, ossia le caratteristiche di utilizzo:
- Default : può essere letta e scritta solo dalla GPU (esempio di lettura è il vertex buffer, mentre quello in scrittura è un render target, ossia una texture su cui si fa il rendering)
- Immutable : può essere utilizzata solamente in lettura dalla GPU
- Dynamic : può essere letta dalla GPU e scritta dalla CPU (ad esempio per creare un vertex buffer che deve cambiare continuamente)
- Staging : può essere letta e scritta solo dalla CPU
Non tutte le risorse possono essere create in tutte le modalità. Ad esempio in Staging non possiamo creare una texture. Questo porterebbe a pensare che solo alcune tipologie di risorse possano essere lette. Inoltre come si vede solo la modalità Staging ha funzionalità di lettura da CPU e quindi è l'unica che può essere letta e modificata da codice, ma allo stesso tempo non si può utilizzare per il rendering.
In DirectX si utilizzano quindi le funzioni di Copy che permettono di copiare una risorsa tra buffer. Potete quindi copiare risorse da una risorsa di tipo Default, Immutable e Dynamic in una di tipo Staging, modificarla e ricopiarla sul buffer di origine.
L'unica risorsa su cui non si può andare a scrivere è solo quella definita come Immutable. Per creare una risorsa di staging si utilizza la classica forma di creazione di un buffer con BindFlags impostato a zero, usage a Staging ed CPUAccessFlags in lettura e scrittura. Ora verrà mostrato come copiare i dati da una risorsa in memoria Video (esempio un Vertex Buffer) e leggerne il contenuto
Buffer buffer= new Buffer(device, VertexBuffer.Description.SizeInBytes, ResourceUsage.Staging, BindFlags.None, CpuAccessFlags.Read | CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
A questo punto potete utilizzare le funzionalità di copia
DeviceContext.CopyResource(VertexBuffer, buffer);
Con questa istruzione ho copiato un vertexBuffer su un buffer in staging.
Ora dovrete andare a leggere le risorse. Per farlo si utilizza l'istruzione Map (simile alla lock di DirectX9)
DataStream stream;
DeviceContext.MapSubresource(buffer, MapMode.Read, SharpDX.Direct3D11.MapFlags.DoNotWait, out stream);
//Qui si potrà leggere
DeviceContext.UnmapSubresource(buffer, 0);
L'istruzione map restituisce un oggetto DataStream. Questo ha una serie di istruzioni per poter leggere e scrivere qualsiasi tipo di dato
Quando avete finito dovrete utilizzare l'istruzione UnMap per liberare le risorse. In questo modo l'array vertices non punterà più alle risorse del buffer.
A questo punto potete nuovamente copiare il buffer modificato sul buffer originario ed utilizzarlo per il rendering.
Vi lascio con un pò di consigli
- Nel caso di risorse dynamic, non effettuate il CopyResource su quest'ultimo. Le risorse dynamic possono essere scritte direttamente usando Map ed Unmap. Potete quindi bloccare la risorsa in Staging per leggere i dati ma usare il Map del buffer dinamico come destinazione. Questo farà risparmiare un bel pò di lavoro alla macchina
- Il processo di copia e soprattutto di Map ed Unmap sono eseguite in CPU, quindi non sono veloci quanto le altre operazione DirectX
- Per conoscere le caratteristiche dei buffer usate l'istruzione Description
- Usate risorse Dynamic per buffer con frequenti scritture, Default per le risorse da mandare a video alla massima velocità possibile. Utilizzate Immutable solo per motivi di sicurezza (nel caso non vogliate modificare il contenuto da altre parti del codice)
La copia tra risorse può avvenire solo tra buffer di pari dimensioni e formati (nel caso di texture)