Residency

Un oggetto viene considerato residente quando è accessibile dalla GPU.

Budget di residenza

Le GPU non supportano ancora l'errore di pagina, quindi le applicazioni devono eseguire il commit dei dati in memoria fisica mentre la GPU può accedervi. Questo processo è noto come "creazione di qualcosa di residente" e deve essere eseguito sia per la memoria fisica del sistema che per la memoria video discreta fisica. In D3D12 la maggior parte degli oggetti API incapsula una quantità di memoria accessibile tramite GPU. La memoria accessibile tramite GPU viene resa residente durante la creazione dell'oggetto API e rimossa dalla distruzione degli oggetti API.

La quantità di memoria fisica disponibile per il processo è nota come budget per la memoria video. Il budget può variare notevolmente man mano che i processi in background si riattivano e dormono; e fluttuano notevolmente quando l'utente passa a un'altra applicazione. L'applicazione può ricevere una notifica quando il budget cambia ed esegue il polling sia del budget corrente che della quantità di memoria attualmente utilizzata. Se un'applicazione non rimane entro il proprio budget, il processo verrà bloccato in modo intermittente per consentire l'esecuzione di altre applicazioni e/o le API di creazione restituiranno un errore. L'interfaccia IDXGIAdapter3 fornisce i metodi relativi a questa funzionalità, in particolare QueryVideoMemoryInfo e RegisterVideoMemoryBudgetChangeNotificationEvent.

Le applicazioni sono incoraggiate a usare una prenotazione per indicare la quantità di memoria che non possono andare senza. Idealmente, le impostazioni grafiche "basse" specificate dall'utente, o qualcosa di ancora più basso, è il valore giusto per tale prenotazione. L'impostazione di una prenotazione non darà mai a un'applicazione un budget superiore a quello che normalmente riceverebbe. Al contrario, le informazioni sulla prenotazione consentono al kernel del sistema operativo di ridurre rapidamente l'impatto delle situazioni di utilizzo elevato della memoria. Anche la prenotazione non è garantita per l'applicazione quando l'applicazione non è l'applicazione in primo piano.

Risorse heap

Mentre molti oggetti API incapsulano una memoria accessibile dalla GPU, gli heap e le risorse dovrebbero essere il modo più significativo in cui le applicazioni utilizzano e gestiscono la memoria fisica. Un heap è l'unità di livello più bassa per gestire la memoria fisica, quindi è consigliabile avere familiarità con le proprietà di residenza.

  • Gli heap non possono essere resi parzialmente residenti, ma esistono soluzioni alternative con risorse riservate.
  • Gli heap devono essere preventivati come parte di un determinato pool. Gli adattatori UMA hanno un pool, mentre gli adattatori discreti hanno due pool. Anche se è vero che il kernel può spostare alcuni heap su schede discrete dalla memoria video alla memoria di sistema, lo fa solo come ultima risorsa estrema. Le applicazioni non devono basarsi sul comportamento eccessivo del kernel e devono invece concentrarsi su una gestione del budget ottimale.
  • Gli heap possono essere rimossi dalla residenza, che consente di visualizzare il contenuto su disco. Tuttavia, la distruzione degli heap è una tecnica più affidabile per liberare la residenza in tutte le architetture degli adattatori. Negli adattatori in cui il campoMaxGPUVirtualAddressBitsPerProcess di D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT è vicino alle dimensioni del budget, Evict non recupererà in modo affidabile la residenza.
  • La creazione dell'heap può essere lenta; ma è ottimizzato per l'elaborazione dei thread in background. È consigliabile creare heap nei thread in background per evitare di recuperare il thread di rendering. In D3D12 più thread possono chiamare in modo sicuro le routine di creazione simultaneamente.

D3D12 introduce maggiore flessibilità e ortogonalità nel modello di risorse per abilitare più opzioni per le applicazioni. Esistono tre tipi generali di risorse in D3D12: commit, posizione e riserva.

  • Le risorse di cui è stato eseguito il commit creano una risorsa e un heap contemporaneamente. L'heap è implicito e non può essere accessibile direttamente. L'heap viene ridimensionato in modo appropriato per individuare l'intera risorsa all'interno dell'heap.
  • Le risorse inserite consentono il posizionamento di una risorsa in corrispondenza di un offset diverso da zero all'interno di un heap. Gli offset devono in genere essere allineati a 64 KB; ma alcune eccezioni esistono in entrambe le direzioni. Le risorse MSAA richiedono l'allineamento dell'offset di 4 MB e l'allineamento dell'offset di 4 KB è disponibile per trame di piccole dimensioni. Le risorse inserite non possono essere rilocate o mappate direttamente in un altro heap; ma consentono una semplice rilocazione dei dati delle risorse tra heap. Dopo aver creato una nuova risorsa inserita in un heap diverso e aver copiato i dati delle risorse, sarà necessario usare nuovi descrittori di risorse per la nuova posizione dei dati delle risorse.
  • Le risorse riservate sono disponibili solo quando l'adattatore supporta risorse affiancate livello 1 o versione successiva. Quando disponibili, offrono le tecniche di gestione della residenza più avanzate disponibili; ma non tutti gli adattatori attualmente li supportano. Consentono di riesecure il mapping di una risorsa senza richiedere la rigenerazione dei descrittori delle risorse, la residenza a livello di mip parziale e gli scenari di trama di tipo sparse e così via. Non tutti i tipi di risorse sono supportati anche quando sono disponibili risorse riservate, quindi un gestore di residenza completamente generale basato su pagine non è ancora fattibile.

Priorità di residenza

Windows 10 Creators Update consente agli sviluppatori di influenzare gli heap e le risorse che saranno preferiti per rimanere residenti quando la pressione della memoria richiede che alcune delle sue risorse vengano abbassate di livello. Ciò consente agli sviluppatori di creare applicazioni con prestazioni migliori sfruttando le conoscenze che il runtime non può dedurre dall'utilizzo delle API. Si prevede che gli sviluppatori diventino più comodi e in grado di specificare le priorità man mano che passano dall'uso di risorse con commit alle risorse di riserva e affiancate.

L'applicazione di queste priorità deve essere più semplice rispetto alla gestione di due budget di memoria dinamici, abbassando e promuovendo manualmente le risorse, perché le applicazioni possono già farlo. Di conseguenza, la progettazione dell'API di priorità di residenza è naturalmente granulare con priorità predefinite ragionevoli assegnate a ogni heap o risorsa durante la creazione. Per altre informazioni, vedere ID3D12Device1::SetResidencyPriority e l'enumerazione D3D12_RESIDENCY_PRIORITY.

Con le priorità, gli sviluppatori devono:

  • Aumentare la priorità di alcuni heap eccezionali per attenuare meglio l'impatto delle prestazioni di questi heap abbassati prima o più frequentemente rispetto ai modelli di accesso naturale richiesti. Questo approccio dovrebbe essere sfruttato dalle applicazioni convertite da API grafiche come Direct3D 11 o OpenGL, il modello di gestione delle risorse è notevolmente diverso da quello di Direct3D 12.
  • Eseguire l'override di quasi tutte le priorità dell'heap con lo schema di bucket dell'applicazione, fisso, in base alla conoscenza della frequenza di accesso del programmatore o dinamica; uno schema fisso è più semplice da gestire rispetto a quello dinamico, ma può essere meno efficace e richiedere l'intevenzione del programmatore quando i modelli di utilizzo cambiano nel corso dello sviluppo. Questo approccio dovrebbe essere sfruttato dalle applicazioni create con la gestione delle risorse in stile Direct3D 12, ad esempio quelle che usano la libreria di residenza (in particolare schemi dinamici).

Algoritmo di priorità predefinito

Un'applicazione non può specificare priorità utili per qualsiasi heap che tenta di gestire senza prima eseguire la ricerca dell'algoritmo di priorità predefinito. Questo avviene perché il valore di assegnazione di una particolare priorità a un heap è derivato dalla priorità relativa ad altri heap con priorità che competono per la stessa memoria.

La strategia scelta per generare priorità predefinite consiste nel classificare gli heap in due bucket, favorendo (dando priorità più alta a) heap che si presuppone vengano scritti frequentemente dalla GPU rispetto agli heap che non lo sono.

Il bucket ad alta priorità contiene heap e risorse create con flag che li identificano come destinazioni di rendering, buffer depth-stencil o viste di accesso non ordinate ( UAV). Questi valori di priorità vengono assegnati nell'intervallo a partire da D3D12_RESIDENCY_PRIORITY_HIGH; per classificare ulteriormente le priorità tra questi heap e le risorse, i 16 bit più bassi della priorità vengono impostati sulle dimensioni dell'heap o della risorsa diviso per 10 MB (saturazione per 0xFFFF per heap estremamente grandi). Questa definizione di priorità aggiuntiva favorisce heap e risorse più grandi.

Il bucket con priorità bassa contiene tutti gli altri heap e risorse, a cui viene assegnato un valore di priorità di D3D12_RESIDENCY_PRIORITY_NORMAL. Non viene tentata un'ulteriore definizione delle priorità tra questi heap e le risorse.

Gestione della residenza della programmazione

Le applicazioni semplici possono essere in grado di ottenere semplicemente creando risorse di cui è stato eseguito il commit fino a quando non si verificano errori di memoria insufficiente. In caso di errore, l'applicazione può distruggere altre risorse o oggetti API di cui è stato eseguito il commit per consentire l'esito positivo di altre creazioni di risorse. Tuttavia, anche le applicazioni semplici sono fortemente consigliate per controllare le modifiche negative del budget e distruggere gli oggetti API inutilizzati approssimativamente una volta un frame.

La complessità di una progettazione della gestione della residenza aumenta quando si tenta di ottimizzare le architetture degli adattatori o di incorporare le priorità di residenza. Il budget discreto e la gestione di due pool di memoria discreta saranno più complessi rispetto alla gestione di una sola e l'assegnazione di priorità fisse su larga scala può diventare un onere di manutenzione se i modelli di utilizzo si evolvono. L'overflow delle trame nella memoria di sistema aggiunge maggiore complessità, perché la risorsa errata nella memoria di sistema può influire gravemente sulla frequenza dei fotogrammi. Inoltre, non esiste alcuna funzionalità semplice per identificare le risorse che potrebbero trarre vantaggio da una larghezza di banda GPU superiore o tollerare una larghezza di banda GPU inferiore.

Le progettazioni ancora più complesse eseguiranno query sulle funzionalità dell'adattatore corrente. Queste informazioni sono disponibili in D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT, D3D12_FEATURE_DATA_ARCHITECTURE, D3D12_TILED_RESOURCES_TIER e D3D12_RESOURCE_HEAP_TIER.

È probabile che più parti di un'applicazione finiranno usando tecniche diverse. Ad esempio, alcune trame di grandi dimensioni e i percorsi di codice usati raramente possono usare risorse di cui è stato eseguito il commit, mentre molte trame possono essere designate con una proprietà di streaming e usano una tecnica generale di risorse posizionate.

ID3D12Heap

Gestione della memoria