Condividi tramite


Procedure consigliate per la gestione delle risorse

Le trame gestite, note anche come gestione automatica delle trame, sono disponibili in DirectX dalla versione 6, con diverse revisioni e miglioramenti apportati nelle versioni successive. Al rilascio dell'API Direct3D 9, la gestione automatica delle risorse include il supporto per trame, vertex buffer e buffer di indice, tutti con un'interfaccia condivisa coerente. Usando Il gestore risorse Direct3D, le applicazioni possono semplificare notevolmente la gestione delle situazioni di dispositivo perso e possono basarsi sul sistema per gestire una quantità ragionevole di impegno eccessivo delle risorse di memoria video.

A volte gli sviluppatori hanno difficoltà a usare le risorse gestite, in parte a causa della natura astratta del sistema. Sebbene molti scenari comuni per le risorse siano adatti alle risorse gestite, alcuni casi offrono prestazioni migliori quando si usano risorse non gestite. Questo articolo illustra le procedure consigliate per gestire le risorse in genere, il comportamento delle risorse gestite e non gestite e fornisce alcuni dettagli sul modo in cui le risorse vengono in genere gestite dal runtime e dai driver.

Questo articolo illustra questi concetti:

Memoria video

Affinché il sistema video usi una risorsa, deve trovarsi in memoria accessibile alla GPU. La memoria video locale offre le migliori prestazioni per la GPU e alcune risorse (ad esempio, destinazioni di rendering e buffer depth/stencil) devono trovarsi nella memoria video locale. Con l'avvento di AGP, la GPU può anche accedere direttamente a una parte della memoria di sistema. Questa area di memoria, nota come apertura AGP, viene definita memoria video non locale e non è disponibile per altri scopi. La memoria video non locale può essere letta e scritta dalla CPU, che in genere non ha accesso ad alte prestazioni alla memoria video locale ed è quindi ideale per l'uso come risorsa di memoria condivisa. Una cosa importante da ricordare sulla memoria AGP è che, come la memoria video locale, viene invalidata in situazioni di dispositivo perso e gli asset persistenti presenti devono essere ripristinati.

Figura 1. Relazione tra GPU, CPU, RAM video e RAM di sistema

relazione tra GPU, CPU, RAM video e RAM di sistema

Alcune soluzioni video integrate usano un'architettura di memoria unificata (UMA), in cui la memoria principale è indirizzabile da tutti i componenti dei sistemi. Direct3D supporta UMA senza richiedere alcuna modifica all'applicazione, usando gli stessi hint per le configurazioni di memoria video locale. Per tali sistemi, le risorse si trovano sempre nella memoria di sistema e il driver è responsabile di garantire che le risorse funzionino in modo molto simile a quelle eseguite in un'architettura più tradizionale sfruttando al tempo stesso le proprietà di UMA e qualsiasi comportamento specifico dell'implementazione hardware.

Figura 2. GPU e CPU hanno uguale accesso alla RAM di sistema in un'architettura di memoria unificata

GPU e CPU hanno uguale accesso alla ram di sistema in un'architettura di memoria unificata

Risorse gestite

La maggior parte delle risorse deve essere creata come risorse gestite in POOL_MANAGED. Tutte le risorse verranno create nella memoria di sistema e quindi copiate in base alle esigenze nella memoria video. Le situazioni di dispositivo perso verranno gestite automaticamente dalla copia della memoria di sistema. Poiché non tutte le risorse gestite sono necessarie per adattarsi alla memoria video contemporaneamente, è possibile eseguire il over-commit della memoria in cui un set di lavoro di memoria video più piccolo di risorse è tutto ciò che è necessario per eseguire il rendering in un determinato fotogramma. Si noti che è probabile che la maggior parte di questa memoria di sistema di archiviazione di backup venga spostata su disco nel tempo, motivo per cui l'operazione di reimpostazione può essere lenta a causa della necessità di rimettere in pagina questi dati per ripristinare la memoria video persa.

Il runtime mantiene un timestamp per l'ultima volta che viene usata una risorsa e quando un'allocazione di memoria video ha esito negativo per il caricamento di una risorsa gestita necessaria, rilascia le risorse in base a questo timestamp in modo LRU. L'utilizzo di SetPriority ha la precedenza sul timestamp, quindi le risorse usate più comunemente devono essere impostate su un valore di priorità più alto. Direct3D 9.0 include informazioni limitate sulla memoria video gestita dal driver, pertanto il runtime potrebbe dover rimuovere diverse risorse per creare un'area sufficientemente grande per consentire l'esito positivo dell'allocazione. Le priorità appropriate possono aiutare a eliminare le situazioni in cui qualcosa viene rimosso e quindi è necessario di nuovo poco dopo. L'applicazione può anche chiamare EvictManagedResources per forzare la rimozione di tutte le risorse gestite. Anche in questo caso, questa operazione può richiedere molto tempo per ricaricare tutte le risorse necessarie per il fotogramma successivo, ma è molto utile per le transizioni di livello in cui il working set cambia in modo significativo e per rimuovere la frammentazione della memoria video.

Un conteggio dei fotogrammi viene mantenuto anche per consentire al runtime di rilevare se la risorsa che ha appena scelto di rimuovere è stata usata in anticipo il fotogramma corrente, il che implica una situazione di thrashing in cui più risorse sono in uso in un singolo fotogramma rispetto a quelle che si adattano alla memoria video. In questo modo i criteri di sostituzione vengono attivati per passare a una modalità MRU anziché a LRU per il resto del frame, in quanto ciò tende a migliorare leggermente in tali condizioni. Questo comportamento di thrashing influirà in modo significativo sulle prestazioni di rendering. Si noti che la nozione di frame corrente è associata a EndScene, quindi qualsiasi applicazione che usa risorse gestite deve effettuare chiamate regolari a questo metodo.

Gli sviluppatori che cercano di trovare altre informazioni sul comportamento delle risorse gestite nell'applicazione possono usare la query dell'evento RESOURCEMANAGER tramite l'interfaccia IDirect3DQuery9 . Questa operazione funziona solo quando si usano i runtime di debug, pertanto queste informazioni non possono dipendere dall'applicazione, ma forniscono dettagli approfonditi sulle risorse gestite dal runtime.

Durante l'ottimizzazione e il debug delle applicazioni, è importante non associare l'applicazione troppo strettamente ai dettagli di implementazione del runtime o dei driver correnti. Le revisioni del driver o delle modifiche nell'hardware possono modificare significativamente il comportamento e le versioni future di Direct3D avranno una gestione delle risorse notevolmente migliorata e sofisticata.

risorse Driver-Managed

I driver Direct3D sono liberi di implementare la funzionalità delle trame gestite dal driver, indicate da D3DCAPS2_CANMANAGERESOURCE, che consente al driver di gestire la gestione delle risorse anziché il runtime. Per il driver (raro) che implementa questa funzionalità, il comportamento esatto del gestore risorse del driver può variare notevolmente ed è necessario contattare il fornitore del driver per informazioni dettagliate su come funziona per l'implementazione. In alternativa, è possibile assicurarsi che il runtime manager venga sempre usato specificando D3DCREATE_DISABLE_DRIVER_MANAGEMENT durante la creazione del dispositivo.

Risorse predefinite

Anche se le risorse gestite sono semplici, efficienti e facili da usare, in alcuni casi l'uso diretto della memoria video è preferibile o addirittura necessario. Tali risorse vengono create nella categoria POOL_DEFAULT. L'uso di tali risorse comporta complicazioni aggiuntive per l'applicazione. Il codice è necessario per gestire la situazione del dispositivo perso per tutte le risorse POOL_DEFAULT e le considerazioni sulle prestazioni devono essere prese in considerazione durante la copia dei dati in tali risorse. L'impossibilità di specificare USAGE_WRITEONLY o rendere bloccata una destinazione di rendering può anche imporre gravi sanzioni per le prestazioni.

La chiamata di Blocco su una risorsa POOL_DEFAULT è più probabile che la GPU si blocchi rispetto all'uso di una risorsa POOL_MANAGED, a meno che non usi determinati flag di hint. A seconda della posizione della risorsa, il puntatore restituito potrebbe essere a un buffer di memoria di sistema temporaneo oppure può essere un puntatore direttamente nella memoria AGP. Se si tratta di un buffer di memoria di sistema temporaneo, i dati dovranno essere trasferiti alla memoria video dopo la chiamata Di sblocco . Se la risorsa video non è di sola scrittura, i dati dovranno essere trasferiti nel buffer temporaneo durante il blocco. Se si tratta di un'area di memoria AGP, le copie temporanee vengono evitate, ma il comportamento della cache richiesto può comportare un rallentamento delle prestazioni.

È necessario prestare attenzione a scrivere una riga di dati full cache in qualsiasi puntatore alla memoria di apertura AGP per evitare la penalità del combing di scrittura, che provoca un ciclo di lettura/scrittura e l'accesso sequenziale dell'area di memoria è preferibile. Se l'applicazione deve accedere casualmente ai dati durante la creazione e non si vuole usare una risorsa gestita per il buffer, è consigliabile usare invece una copia della memoria di sistema. Dopo aver creato i dati, è possibile trasmettere il risultato nella memoria della risorsa bloccata per evitare di pagare una penalità elevata per l'operazione di combinazione di scrittura della cache.

Il flag LOCK_NOOVERWRITE può essere usato per aggiungere dati in modo efficiente per alcune risorse, ma idealmente è possibile evitare più chiamate di blocco e sblocco alla stessa risorsa. L'uso appropriato dei vari flag di blocco è importante per ottenere prestazioni ottimali, perché usa un modello descrittivo per la cache dell'accesso ai dati quando si riempie la memoria bloccata.

Uso di risorse sia gestite che predefinite

La combinazione di allocazioni di risorse gestite e POOL_DEFAULT può causare la frammentazione della memoria video e confondere la visualizzazione della memoria video disponibile per le risorse gestite. Idealmente, è consigliabile creare tutte le risorse POOL_DEFAULT prima di usare POOL_MANAGED risorse o usare la chiamata EvictManagedResources prima di allocare risorse non gestite. Tenere presente che tutte le allocazioni effettuate da POOL_DEFAULT che risiedono nella memoria video riquadrino la memoria per la durata della risorsa non disponibile per l'uso da parte del gestore risorse o per qualsiasi altro scopo.

Si noti che, a differenza delle versioni precedenti di Direct3D, il runtime della versione 9 rimuove automaticamente alcune risorse gestite prima di rinunciare a un'allocazione di risorse non gestita non riuscita per una mancanza di memoria video, ma ciò può potenzialmente creare ulteriore frammentazione e persino forzare una risorsa in una posizione non ottimale (ad esempio, con una trama statica nella memoria video non locale). Anche in questo caso, è consigliabile allocare tutte le risorse non gestite necessarie in anticipo e prima di usare qualsiasi risorsa gestita.

Risorse predefinite dinamiche

I dati generati e aggiornati ad alta frequenza non hanno bisogno dell'archivio di backup perché tutte le informazioni verranno ricreate durante il ripristino del dispositivo. Tali dati vengono in genere creati meglio in POOL_DEFAULT, specificando l'hint USAGE_DYNAMIC, in modo che il driver possa prendere decisioni di ottimizzazione durante l'inserimento della risorsa, sapendo che verrà aggiornato spesso. Questo significa in genere inserire la risorsa in memoria video non locale e quindi è in genere molto più lento per la GPU accedere alla memoria video locale. Per le architetture UMA, il driver potrebbe scegliere una posizione specifica per le risorse dinamiche per ottimizzare l'accesso in scrittura della CPU.

Questo utilizzo è tipico per soluzioni di interfaccia software e sistemi particellari basati sulla CPU che compilano buffer di vertici/indici e il flag LOCK_DISCARD garantisce che gli stalli non vengano creati nei casi in cui la risorsa è ancora in uso dal frame precedente. L'uso di una risorsa gestita in questo caso aggiornerebbe un buffer di memoria di sistema, che verrà quindi copiato nella memoria video e quindi usato per un solo fotogramma o due prima di essere sostituito. Per i sistemi con memoria video non locale, la copia aggiuntiva viene eliminata dall'uso appropriato di questo modello dinamico.

Le trame standard non possono essere bloccate e possono essere aggiornate solo tramite UpdateSurface o UpdateTexture. Alcuni sistemi supportano trame dinamiche, che possono essere bloccate e usano il modello di LOCK_DISCARD, ma è necessario controllare un bit di funzionalità (D3DCAPS2_DYNAMICTEXTURES) prima di usare tali risorse. Per trame altamente dinamiche (video o procedurali), l'applicazione può creare POOL_DEFAULT e POOL_SYSTEMMEM risorse e gestire gli aggiornamenti della memoria video usando UpdateTexture. Per gli aggiornamenti molto frequenti e parziali, è probabile che il paradigma UpdateTexture sia la scelta migliore.

Può essere utile quanto le risorse dinamiche, prestare attenzione durante la progettazione di sistemi che si basano principalmente sull'invio dinamico. Le risorse statiche devono essere inserite in POOL_MANAGED per garantire un buon utilizzo della memoria video locale e per rendere più efficiente l'uso del bus limitato e della larghezza di banda di memoria principale. Per le risorse semi-statiche, è possibile che il costo di un caricamento occasionale nella memoria video locale sia molto inferiore al traffico del bus costante generato rendendoli dinamici.

Risorse di memoria di sistema

Le risorse possono essere create anche in POOL_SYSTEMMEM. Anche se non possono essere usati dalla pipeline grafica, possono essere usati come origini per aggiornare POOL_DEFAULT risorse usando UpdateSurface o UpdateTexture. Il comportamento di blocco è semplice, anche se i blocchi possono verificarsi se sono in uso da uno dei metodi indicati in precedenza.

Sebbene risiedano nella memoria di sistema, POOL_SYSTEMMEM risorse sono limitate agli stessi formati e funzionalità (ad esempio le dimensioni massime) supportate dal driver di dispositivo. Il tipo di risorsa POOL_SCRATCH è un'altra forma di risorsa di memoria di sistema che può usare tutti i formati e le funzionalità supportati dal runtime, ma non è accessibile dal dispositivo. Le risorse scratch sono destinate principalmente all'uso da parte degli strumenti di contenuto.

Figura 3. Risorse di memoria nella RAM video, apertura AGP e RAM di sistema

risorse di memoria in ram video, aperture agp e ram di sistema

Suggerimenti generali

Ottenere i dettagli tecnici dell'implementazione corretta della gestione delle risorse consente di raggiungere gli obiettivi di prestazioni per l'applicazione. La pianificazione del modo in cui le risorse vengono presentate a Direct3D e alla progettazione dell'architettura per caricare i dati in modo tempestivo è un'attività più complessa. Quando si effettuano queste decisioni per l'applicazione, è consigliabile eseguire alcune procedure consigliate:

  • Pre-elaborare tutte le risorse. L'uso di una conversione e un'ottimizzazione costosi del tempo di caricamento per le risorse è utile durante lo sviluppo, ma in questo modo si verifica un notevole carico di prestazioni nei computer degli utenti. Le risorse pre-elaborate sono più veloci da caricare, più velocemente da usare e offrono la possibilità di eseguire operazioni off-line sofisticate.
  • Evitare di creare molte risorse per frame. Le interazioni del driver necessarie possono serializzare la CPU e la GPU e le operazioni coinvolte sono pesanti, perché spesso richiedono transizioni del kernel. Distribuire la creazione in più fotogrammi o riutilizzare le risorse senza crearle/rilasciarle. Idealmente, è consigliabile attendere diversi fotogrammi prima di bloccare o rilasciare risorse usate di recente per il rendering.
  • Alla fine del frame assicurarsi di annullare il binding di tutti i canali di risorse, ovvero origini di flusso, fasi della trama e indici correnti. In questo modo si garantisce che i riferimenti a risorse dangling vengano rimossi prima che il gestore risorse mantenga le risorse residenti che non sono più in uso.
  • Per le trame, usare formati compressi (ad esempio, DXTn) con mappe mip e prendere in considerazione l'uso di un atlas con trama. Questi riducono notevolmente i requisiti di larghezza di banda e possono ridurre le dimensioni complessive delle risorse, rendendole quindi più efficienti.
  • Per la geometria, usare la geometria indicizzata perché consente di comprimere le risorse del buffer dei vertici e l'hardware video moderno è fortemente ottimizzato per il riutilizzo dei vertici. Utilizzando vertex shader programmabili, è possibile comprimere le informazioni sui vertici ed espanderlo durante l'elaborazione dei vertici. Anche in questo caso, ciò consente di ridurre i requisiti di larghezza di banda e rende più efficienti le risorse del buffer dei vertici.
  • Evitare di ottimizzare eccessivamente la gestione delle risorse. Le revisioni future dei driver, dell'hardware e del sistema operativo possono causare problemi di compatibilità se l'applicazione è ottimizzata troppo per una combinazione specifica. Poiché la maggior parte delle applicazioni è associata alla CPU, la gestione basata su CPU costosa in genere causa più problemi di prestazioni rispetto a quelli risolti.

Gestione delle risorse

Dispositivi persi

Ottimizzazioni delle prestazioni

Risorse delle trame compresse

Query

D3DUSAGE

D3DPOOL

D3DCREATE