Condividi tramite


Barriere avanzate D3D12

L'interfaccia DDI per le barriere avanzate è disponibile in Windows 11 versione 22H2 WDK (WDDM 3.0). Per usare barriere avanzate nella versione 22H2 (o versioni precedenti del sistema operativo), è necessario installare l'SDK Agile 1.706.4-preview.

Le barriere avanzate D3D12 consentono agli sviluppatori di controllare in modo indipendente la sincronizzazione del lavoro gpu, le transizioni di layout delle trame e lo scaricamento della cache (accesso alla memoria delle risorse). Questa funzionalità offre un set di API e DDI Direct3D che consentono agli sviluppatori di controllare in modo indipendente la sincronizzazione del lavoro GPU, le transizioni di layout delle trame e lo scaricamento della cache (accesso alla memoria delle risorse).

Le barriere avanzate sostituiscono le barriere di risorse legacy con tipi di barriera più espressivi. Hanno le funzionalità seguenti:

  • Minore latenza di sincronizzazione.
  • Riduzione degli scaricamenti eccessivi della cache.
  • Nessuna misteriosa regola di promozione e decadimento.
  • Aliasing rapido e flessibile delle risorse (topologie di aliasing diverse).
  • Elimina durante la transizione delle barriere.
  • Supporto per la lettura/scrittura simultanea, inclusa la copia della stessa risorsa (auto-copia).
  • Supporto per i comandi Asincrona Discard, Copy, Resolve e Clear.

Le barriere avanzate non sono più semplici delle barriere di risorse legacy, ma sono meno ambigue e quindi più facili da usare per gli sviluppatori.

Creazione di report per il supporto di barriere avanzate

La funzionalità di barriere avanzate non è attualmente un requisito hardware o driver. Un driver indica il supporto impostando il membro EnhancedBarriersSupported di D3D12DDI_D3D12_OPTIONS_DATA_0089 su TRUE.

  • D3D12DDI_FEATURE_VERSION_VIDEO_0088_0 è il numero di versione che definisce l'implementazione preliminare delle attività cardine della barriera avanzata D3D12 introdotte in Windows 11.

Funzioni di callback delle barriere avanzate D3D12

I driver che indicano il supporto per le barriere avanzate implementano le funzioni di callback seguenti:

Dettagli di progettazione

I driver gestiscono in genere barriere di risorse legacy usando tre operazioni separate:

  1. Sincronizzare il lavoro della GPU.
  2. Eseguire le operazioni di scaricamento della cache necessarie.
  3. Eseguire le modifiche di layout necessarie.

Le barriere avanzate offrono agli sviluppatori la possibilità di controllare ognuna di queste operazioni separatamente.

Tipi di barriere avanzate

Esistono tre tipi di barriere avanzate :

Le barriere a intervalli sostituiscono le barriere di risorse legacy. Vengono fornite barriere a intervalli in modo che le barriere di risorse legacy possano essere completamente implementate senza perdite di prestazioni evidenti.

  • Tutti i tipi di barriera controllano la sincronizzazione del lavoro GPU e i tipi di accesso in lettura o scrittura prima e dopo la barriera.

  • Le barriere delle trame gestiscono anche il layout delle sottorisorse delle trame. La selezione delle sottorisorse può essere espressa come intervallo di sezioni mip, matrice e piano, oltre all'opzione unica o all'opzione familiare usata dalle barriere di risorse legacy.

  • Le barriere del buffer e le barriere globali controllano solo la sincronizzazione e l'accesso alle risorse e non influiscono sul layout delle risorse (i buffer non hanno un layout). Le barriere globali influiscono su tutta la memoria memorizzata nella cache in modo che possano essere costose e devono essere usate solo quando una barriera più con ambito non è sufficiente.

Barriere di trama

  • Controllare lo scaricamento della cache, il layout della memoria e la sincronizzazione per le sottorisorse delle trame.
  • Deve essere usato solo con le risorse di trama.
  • Consente la selezione di una singola sottorisorsa, di tutte le sottorisorse o di un intervallo coerente di sottorisorse, ovvero intervallo mip e intervallo di matrici.
  • Deve fornire un puntatore di risorsa non NULL valido.

Barriere buffer

  • Controllare lo scaricamento e la sincronizzazione della cache per le risorse del buffer.
  • Deve essere usato solo con le risorse del buffer.
  • A differenza delle trame, i buffer hanno una sola sottorisorsa e non hanno un layout che può essere sottoposto a transizione.
  • Deve fornire un puntatore di risorsa non NULL valido.

Barriere globali

  • Controllare lo scaricamento e la sincronizzazione della cache per tutti i tipi di accesso alle risorse indicati in una singola coda di comandi.
  • Non hanno alcun effetto sul layout delle trame.
  • Sono necessari per fornire funzionalità simili alle barriere UAV NULL legacy e alle barriere di aliasing NULL/NULL.

Poiché le barriere globali non passano al layout delle trame, le barriere globali non possono essere usate nelle transizioni che altrimenti richiederebbero una modifica del layout. Ad esempio, una barriera globale non può essere usata per eseguire la transizione di una trama di accesso non simultaneo da D3D12DDI_BARRIER_ACCESS_RENDER_TARGET a D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE, poiché ciò richiederebbe anche una modifica da D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET a D3D12DDI_BARRIER_LAYOUT_SHADER_RESOURCE.

Sincronizzazione

I processori grafici sono progettati per eseguire il maggior numero possibile di operazioni in parallelo. Qualsiasi lavoro GPU che dipende dal lavoro precedente della GPU deve essere sincronizzato prima di accedere ai dati dipendenti.

L'interfaccia della barriera avanzata usa valori SyncBefore e SyncAfter espliciti come maschere di campo a bit logico. Una barriera deve attendere il completamento di tutti i comandi precedenti SyncBefore prima di eseguire la barriera. Analogamente, una barriera deve bloccare tutti gli ambiti SyncAfter successivi fino al completamento della barriera. D3D12DDI_BARRIER_SYNC specifica l'ambito di sincronizzazione della GPU rispetto alla barriera.

Per altre informazioni, vedere la specifica delle barriere avanzate.

Transizioni di layout

Le sottorisorse trama possono usare layout diversi per vari metodi di accesso. Ad esempio, le trame vengono spesso compresse quando vengono usate come destinazione di rendering o stencil di profondità e spesso non vengono compresse per i comandi di lettura o copia dello shader. Le barriere delle trame usano LayoutBefore e LayoutAfter D3D12DDI_BARRIER_LAYOUT valori per descrivere le transizioni di layout.

Le transizioni di layout sono necessarie solo per le trame, quindi vengono espresse solo nella struttura dei dati D3D12DDI_TEXTURE_BARRIER.

Sia LayoutBefore che LayoutAfter devono essere compatibili con il tipo di coda che esegue la barriera. Ad esempio, una coda di calcolo non può eseguire la transizione di una sottorisorsa all'esterno o all'esterno di D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET.

Per fornire un ordinamento delle barriere ben definito, il layout di una sottorisorsa dopo il completamento di una sequenza di barriere è il layout finaleAfter nella sequenza.

Transizioni di accesso

Poiché molte operazioni di scrittura GPU vengono memorizzate nella cache, qualsiasi barriera da un accesso in scrittura a un altro accesso in scrittura o un accesso in sola lettura potrebbe richiedere uno scaricamento della cache. Le API con barriera avanzata usano transizioni di accesso per indicare che la memoria di una sottorisorsa deve essere resa visibile per un nuovo tipo di accesso specifico. Analogamente alle transizioni di layout, alcune transizioni di accesso potrebbero non essere necessarie se è noto che la memoria della sottorisorsa associata è già accessibile per l'uso desiderato.

Le transizioni di accesso sono espresse nel modo seguente:

  • Per le trame, come parte della struttura D3D12DDI_TEXTURE_BARRIER.
  • Per i buffer, come parte della struttura D3D12DDI_BUFFER_BARRIER.

Le transizioni di accesso non eseguono la sincronizzazione. È previsto che la sincronizzazione tra gli accessi dipendenti venga gestita usando i valori SyncBefore e SyncAfter appropriati nella barriera.

AccessBefore reso visibile a un accessAfter specificato non garantisce che la memoria della risorsa sia visibile anche per un tipo di accesso diverso. Ad esempio:

MyTexBarrier.AccessBefore=D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS;
MyTexBarrier.AccessAfter=D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE;

Questa transizione di accesso indica che un accesso in lettura shader successivo dipende da un precedente non ordinato-access-write. Tuttavia, se l'hardware è in grado di leggere le risorse dello shader direttamente dalla cache UAV, il driver potrebbe effettivamente non scaricare la cache UAV.

D3D12DDI_BARRIER_ACCESS_COMMON

D3D12DDI_BARRIER_ACCESS_COMMON è un tipo di accesso speciale che indica qualsiasi accesso compatibile con il layout. La transizione a D3D12DDI_BARRIER_ACCESS_COMMON significa che i dati delle sottorisorse devono essere disponibili per qualsiasi accesso compatibile con il layout dopo una barriera. Poiché i buffer non hanno layout, D3D12DDI_BARRIER_ACCESS_COMMON significa semplicemente qualsiasi accesso compatibile con il buffer.

La specifica di D3D12DDI_BARRIER_ACCESS_COMMON come AccessBefore in una barriera implica il set di tutti i tipi di accesso in scrittura. L'uso di D3D12DDI_BARRIER_ACCESS_COMMON come AccessBefore è sconsigliato perché potrebbe comportare costosi scaricamenti della cache imprevisti. Gli sviluppatori sono invece invitati a usare solo i bit di accesso in scrittura più strettamente necessari per limitare correttamente il sovraccarico delle barriere. Quando AccessBefore è impostato su D3D12DDI_BARRIER_ACCESS_COMMON, viene generato un avviso del livello di debug.

Accesso simultaneo a coda singola

Le barriere avanzate consentono operazioni simultanee di lettura/scrittura nello stesso buffer o nella stessa trama di accesso simultaneo nella stessa coda di comandi.

I buffer e le risorse con accesso simultaneo supportano sempre l'accesso in scrittura da una coda con accessi in lettura simultanei, non indipendenti da una o più code. Questo supporto è dovuto al fatto che tali risorse usano sempre il layout COMMON e non presentano pericoli di lettura/scrittura, poiché le letture non devono dipendere da scritture simultanee. Le regole di barriera delle risorse legacy non consentono la combinazione di bit di stato di scrittura con altri bit di stato. Di conseguenza, le risorse non possono essere lette contemporaneamente e scritte nella stessa coda usando barriere di risorse legacy.

Il criterio one-writer-at-a-time si applica ancora perché due aree di scrittura apparentemente non sovrapposte potrebbero ancora avere righe di cache sovrapposte.

Intervalli di sottorisorse

È comune per gli sviluppatori che vogliono eseguire la transizione di una gamma di sottorisorse. Un esempio consiste nel eseguire la transizione di una catena mip completa per una determinata matrice di trame o un singolo livello mip per tutte le sezioni di matrice. Le barriere avanzate consentono agli sviluppatori di eseguire la transizione logicamente a intervalli adiacenti di sottorisorse usando la struttura D3D12DDI_BARRIER_SUBRESOURCE_RANGE. Le barriere di transizione dello stato delle risorse legacy forniscono solo agli sviluppatori la possibilità di eseguire la transizione di tutti gli stati di sottorisorsa o di una singola sottorisorsa in modo atomico.

Calcolo e layout diretti delle code

Per le code dirette e di calcolo è garantito che i seguenti layout di barriera avanzata siano uguali:

  • D3D12DDI_BARRIER_LAYOUT_GENERIC_READ
  • D3D12DDI_BARRIER_LAYOUT_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_LAYOUT_SHADER_RESOURCE
  • D3D12DDI_BARRIER_LAYOUT_COPY_SOURCE
  • D3D12DDI_BARRIER_LAYOUT_COPY_DEST

Una sottorisorsa in uno di questi layout può essere usata in code dirette o code di calcolo senza una transizione di layout.

In alcuni hardware, le barriere di transizione del layout nelle code dirette possono essere notevolmente più veloci se anche gli accessi precedenti o successivi si trovano in code dirette. È consigliabile accedere alle risorse nelle code dirette usando i layout seguenti:

  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE
  • D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_DEST

Le varianti di layout DIRECT_QUEUE non sono compatibili con le code di calcolo e non possono essere usate nelle barriere dell'elenco di comandi di calcolo. Tuttavia, sono compatibili con le operazioni di calcolo nelle code dirette.

Accesso senza barriere

Poiché non devono essere presenti comandi in sospeso o operazioni di scaricamento della cache tra i limiti di ExecuteCommandLists, i buffer potrebbero essere inizialmente accessibili in un ambito ExecuteCommandLists senza una barriera. Analogamente, le sottorisorse delle trame potrebbero anche essere inizialmente accessibili senza una barriera nelle condizioni seguenti:

  • Il layout della sottorisorsa è compatibile con il tipo di accesso.
  • Tutti i metadati di compressione necessari vengono inizializzati.

Le sottorisorse di trama nel layout D3D12DDI_BARRIER_LAYOUT_COMMON (o un layout comune specifico della coda, ad esempio D3D12DDI_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON) che non hanno operazioni di lettura o scrittura potenzialmente in sospeso possono essere accessibili in un flusso di comandi ExecuteCommandLists senza una barriera usando uno dei tipi di accesso seguenti:

  • D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE
  • D3D12DDI_BARRIER_ACCESS_COPY_SOURCE
  • D3D12DDI_BARRIER_ACCESS_COPY_DEST

Inoltre, un buffer o una trama che usa un layout comune specifico della coda può usare D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS senza una barriera.

I buffer e le trame di accesso simultaneo (trame create con il flag di D3D12DDI_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS) possono essere inizialmente accessibili in un flusso di comandi ExecuteCommandLists senza una barriera usando uno dei tipi di accesso seguenti:

  • D3D12DDI_BARRIER_ACCESS_VERTEX_BUFFER
  • D3D12DDI_BARRIER_ACCESS_CONSTANT_BUFFER
  • D3D12DDI_BARRIER_ACCESS_INDEX_BUFFER
  • D3D12DDI_BARRIER_ACCESS_RENDER_TARGET
  • D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS
  • D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE
  • D3D12DDI_BARRIER_ACCESS_STREAM_OUTPUT
  • D3D12DDI_BARRIER_ACCESS_INDIRECT_ARGUMENT
  • D3D12DDI_BARRIER_ACCESS_COPY_DEST
  • D3D12DDI_BARRIER_ACCESS_COPY_SOURCE
  • D3D12DDI_BARRIER_ACCESS_RESOLVE_DEST
  • D3D12DDI_BARRIER_ACCESS_RESOLVE_SOURCE
  • D3D12DDI_BARRIER_ACCESS_PREDICATION

È anche possibile effettuare accessi successivi senza una barriera senza più di un tipo di accesso in scrittura. Tuttavia, ad eccezione di D3D12DDI_BARRIER_ACCESS_RENDER_TARGET, le barriere devono essere usate per scaricare scritture sequenziali nella stessa risorsa.

Copia self-resource

Anche se non correlato esclusivamente alle barriere avanzate, la possibilità di consentire copie da un'area di una sottorisorsa a un'altra area non intersecante è una funzionalità altamente richiesta. Con barriere avanzate, una sottorisorsa con un layout comune può essere usata sia come origine che come destinazione nella stessa chiamata CopyBufferRegion o CopyTextureRegion. Le copie tra aree di memoria di origine e di destinazione intersecanti producono risultati non definiti. Il livello di debug DEVE convalidare in base a tali risultati. La progettazione delle barriere di risorse legacy non consente a una sottorisorsa di trovarsi nello stato D3D12DDI_RESOURCE_STATE_COPY_SOURCE e D3D12DDI_RESOURCE_STATE_COPY_DEST contemporaneamente e quindi non può copiarsi in se stesso.

Inizializzazione dei metadati delle risorse inserita

La progettazione della barriera di risorse legacy richiede Clear, Copy o Discard per inizializzare le risorse di trama con alias appena posizionate e attivate prima di essere usate come risorsa Stencil di destinazione di rendering o profondità. Questo requisito è dovuto al fatto che le risorse di Destinazione di rendering e Stencil profondità usano in genere metadati di compressione che devono essere inizializzati affinché i dati siano validi. Lo stesso vale per le trame riservate con il mapping dei riquadri appena aggiornato.

Le barriere avanzate supportano un'opzione di eliminazione come parte di una barriera. Il layout della barriera passa da D3D12DDI_BARRIER_LAYOUT_UNDEFINED a qualsiasi layout potenzialmente compresso (ad esempio, D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET, D3D12DDI_BARRIER_LAYOUT_DEPTH_STENCIL, D3D12DDI_BARRIER_LAYOUT_UNORDERED_ACCESS) DEVE inizializzare i metadati di compressione quando D3D12DDI_TEXTURE_BARRIER_FLAG_DISCARD è presente nel membro D3D12DDI_TEXTURE_BARRIER::Flags.

Oltre alle risorse di destinazione e profondità/stencil di rendering, esistono ottimizzazioni di compressione delle trame UAV simili che il modello di barriera legacy non supporta.

Ordinamento delle barriere

Le barriere vengono accodate in ordine di inoltro (ordine di chiamata API, barrier-group-index, barrier-array-index). Più barriere sulla stessa sottorisorsa devono funzionare come se le barriere siano completate nell'ordine in coda.

Barriere in coda con ambiti SyncAfter corrispondenti che potenzialmente scrivono nella stessa memoria devono completare tutte le scritture nell'ordine in coda. Questo requisito evita le gare di dati sulle barriere che supportano l'aliasing delle risorse. Ad esempio, una barriera che disattiva una risorsa deve scaricare tutte le cache prima di un'altra barriera che attiva una risorsa diversa nella stessa memoria, cancellando i metadati.