Condividi tramite


Copia e accesso ai dati delle risorse

I flag di utilizzo indicano come l'applicazione intende usare i dati delle risorse per inserire le risorse nell'area di memoria più efficiente possibile. I dati delle risorse sono copiati tra le risorse in modo che la CPU o la GPU possano accedervi senza influire sulle prestazioni.

Non è necessario considerare le risorse come create nella memoria video o nella memoria di sistema o decidere se il runtime deve gestire la memoria. Con l'architettura di WDDM (Windows Display Driver Model), le applicazioni creano risorse Direct3D con flag di utilizzo diversi per indicare come l'applicazione intende usare i dati delle risorse. Questo modello di driver virtualizza la memoria usata dalle risorse; è responsabilità del sistema operativo, del driver o del gestore della memoria inserire le risorse nell'area di memoria più efficiente possibile, in base all'utilizzo previsto.

Il caso predefinito è che le risorse siano disponibili per la GPU. In alcuni casi i dati delle risorse devono essere disponibili per la CPU. La copia dei dati delle risorse in modo che il processore appropriato possa accedervi senza influire sulle prestazioni richiede una certa conoscenza del funzionamento dei metodi API.

Copia dei dati delle risorse

Le risorse vengono create in memoria quando Direct3D esegue una chiamata Create. Possono essere creati in memoria video, memoria di sistema o qualsiasi altro tipo di memoria. Poiché il modello di driver WDDM virtualizza questa memoria, le applicazioni non devono più tenere traccia del tipo di risorse di memoria in cui vengono create.

Idealmente, tutte le risorse si trovano nella memoria video in modo che la GPU possa avere accesso immediato a tali risorse. Tuttavia, a volte è necessario che la CPU legga i dati della risorsa o per consentire alla GPU di accedere ai dati delle risorse in cui è stata scritta la CPU. Direct3D gestisce questi diversi scenari richiedendo all'applicazione di specificare un utilizzo e quindi offre diversi metodi per copiare i dati delle risorse quando necessario.

A seconda della modalità di creazione della risorsa, non è sempre possibile accedere direttamente ai dati sottostanti. Ciò può significare che i dati della risorsa devono essere copiati dalla risorsa di origine a un'altra risorsa accessibile dal processore appropriato. In termini di Direct3D, le risorse predefinite possono essere accessibili direttamente dalla GPU, le risorse dinamiche e di gestione temporanea possono essere accessibili direttamente dalla CPU.

Dopo aver creato una risorsa, non è possibile modificarne l'utilizzo. Copiare piuttosto il contenuto di una risorsa in un'altra risorsa creata con un utilizzo diverso. Copiare i dati delle risorse da una risorsa a un'altra o copiare dati dalla memoria a una risorsa.

Esistono due tipi principali di risorse: mappabile e non mappabile. Le risorse create con utilizzi dinamici o di gestione temporanea sono mappabili, mentre le risorse create con utilizzi predefiniti o non modificabili non sono mappabili.

La copia di dati tra risorse non mappabili è molto veloce perché questo è il caso più comune ed è stato ottimizzato per ottenere prestazioni buone. Poiché queste risorse non sono direttamente accessibili dalla CPU, sono ottimizzate in modo che la GPU possa modificarle rapidamente.

La copia dei dati tra le risorse mappabili è più problematica poiché le prestazioni dipendono dall'utilizzo con cui è stata creata la risorsa. Ad esempio, la GPU può leggere una risorsa dinamica abbastanza rapidamente, ma non può scriverla, mentre la GPU non può leggere o scrivere direttamente nella gestione temporanea delle risorse.

Le applicazioni che desiderano copiare dati da una risorsa con utilizzo predefinito a una risorsa con utilizzo di gestione temporanea (per consentire alla CPU di leggere i dati, ovvero il problema di readback GPU) devono farlo con attenzione. Vedere Accesso ai dati delle risorse di seguito.

Accesso ai dati delle risorse

Per accedere a una risorsa è necessario eseguire il mapping della risorsa; il mapping significa essenzialmente che l'applicazione sta tentando di concedere alla CPU l'accesso alla memoria. Il processo di mapping di una risorsa in modo che la CPU possa accedere alla memoria sottostante può causare alcuni colli di bottiglia delle prestazioni e, per questo motivo, è necessario prestare attenzione a come e quando eseguire questa attività.

Le prestazioni possono interrompersi se l'applicazione tenta di eseguire il mapping di una risorsa in un momento errato. Se l'applicazione tenta di accedere ai risultati di un'operazione prima del completamento dell'operazione, si verificherà un blocco della pipeline.

L'esecuzione di un'operazione di mapping in un momento errato potrebbe causare un grave calo delle prestazioni forzando la GPU e la CPU a eseguire la sincronizzazione tra loro. Questa sincronizzazione si verificherà se l'applicazione vuole accedere a una risorsa prima che la GPU venga completata la copia in una risorsa mappata dalla CPU.

Considerazioni sulle prestazioni

È consigliabile considerare un PC come un computer in esecuzione come architettura parallela con due tipi principali di processori: uno o più CPU e uno o più GPU. Come in qualsiasi architettura parallela, le prestazioni migliori si ottengono quando ogni processore è pianificato con attività sufficienti per impedire che funzioni inattive e quando il lavoro di un processore non è in attesa del lavoro di un altro.

Lo scenario peggiore per il parallelismo GPU/CPU è la necessità di forzare un processore ad attendere i risultati del lavoro svolto da un altro. Direct3D rimuove questo costo rendendo asincroni i metodi di copia; la copia non è necessariamente eseguita dal momento in cui il metodo restituisce.

Il vantaggio di questo è che l'applicazione non paga il costo delle prestazioni della copia effettiva dei dati fino a quando la CPU non accede ai dati, ovvero quando viene richiamato Map. Se il metodo Map viene richiamato dopo che i dati sono stati effettivamente copiati, non si verifica alcuna perdita di prestazioni. D'altra parte, se il metodo Map viene chiamato prima che i dati siano stati copiati, si verificherà un blocco della pipeline.

Le chiamate asincrone in Direct3D (che sono la maggior parte dei metodi e soprattutto le richieste di rendering) vengono archiviate in ciò che viene denominato buffer dei comandi. Questo buffer è interno al driver grafico e viene usato per eseguire in batch richieste all'hardware sottostante in modo che il passaggio costoso dalla modalità utente alla modalità kernel in Microsoft Windows si verifichi il più raramente possibile.

Il buffer dei comandi viene svuotato, causando così una commutazione in modalità utente/kernel, in una delle quattro situazioni seguenti.

  1. Viene richiamato Presente .
  2. Viene richiamato Svuota.
  3. Il buffer dei comandi è pieno; la sua dimensione è dinamica ed è controllata dal sistema operativo e dal driver grafico.
  4. La CPU richiede l'accesso ai risultati di un comando in attesa dell'esecuzione nel buffer dei comandi.

Tra le quattro situazioni precedenti, il numero quattro è il più critico per le prestazioni. Se l'applicazione invia una chiamata per copiare una risorsa o una sottorisorsa, questa chiamata viene accodata nel buffer dei comandi.

Se l'applicazione tenta quindi di eseguire il mapping della risorsa di gestione temporanea che era la destinazione della chiamata di copia prima dello scaricamento del buffer dei comandi, si verificherà un blocco della pipeline, perché non solo la chiamata al metodo Copia dovrà essere eseguita, ma dovranno esserlo anche tutti gli altri comandi memorizzati nel buffer. In questo modo la GPU e la CPU verranno sincronizzate perché la CPU sarà in attesa di accedere alla risorsa di gestione temporanea, mentre la GPU svuota il buffer dei comandi e infine riempie la risorsa necessaria per la CPU. Al termine della copia, la CPU inizierà ad accedere alla risorsa di gestione temporanea, ma durante questo periodo la GPU sarà inattiva.

Questa operazione in fase di esecuzione comporta un grave peggioramento delle prestazioni. Per questo motivo, il mapping delle risorse create con l'utilizzo predefinito deve essere eseguito con attenzione. L'applicazione deve attendere abbastanza tempo per svuotare il buffer dei comandi e quindi completare l'esecuzione di tutti questi comandi prima di cercare di eseguire il mapping della corrispondente risorsa di gestione temporanea.

Quanto tempo deve attendere l'applicazione? Almeno due fotogrammi perché ciò consentirà il parallelismo tra le CPU e la GPU da sfruttare al massimo. Il funzionamento della GPU è che mentre l'applicazione sta elaborando il frame N inviando chiamate al buffer dei comandi, la GPU sta eseguendo le chiamate dal frame precedente, N-1.

Pertanto, se un'applicazione intende eseguire il mapping di una risorsa che ha origine nella memoria video e copia una risorsa nel frame N, questa chiamata inizierà effettivamente a essere eseguita al frame N+1, quando l'applicazione invia chiamate per il fotogramma successivo. La copia deve essere completata al termine dell'elaborazione del frame N+2 dell'applicazione.

Frame Stato GPU/CPU
N
  • La CPU esegue le chiamate di rendering per il fotogramma corrente.
N + 1
  • GPU che esegue chiamate inviate dalla CPU durante il frame N.
  • La CPU esegue le chiamate di rendering per il fotogramma corrente.
N + 2
  • La GPU ha completato l'esecuzione delle chiamate inviate dalla CPU durante il frame N. Risultati pronti.
  • GPU che esegue chiamate inviate dalla CPU durante il frame N+1.
  • La CPU esegue le chiamate di rendering per il fotogramma corrente.
N + 3
  • La GPU ha terminato l'esecuzione delle chiamate inviate dalla CPU durante il frame N+1. Risultati pronti.
  • GPU che esegue chiamate inviate dalla CPU durante il frame N+2.
  • La CPU esegue le chiamate di rendering per il fotogramma corrente.
N + 4 ...

 

Risorse