Elenchi di comandi di supporto
Questa sezione si applica solo a Windows 7 e versioni successive e Windows Server 2008 R2 e versioni successive di Windows.
Il runtime Direct3D usa la DDI Direct3D 11 seguente per gli elenchi di comandi:
La funzione CalcPrivateCommandListSize determina le dimensioni dell'area privata del driver di visualizzazione in modalità utente per un elenco di comandi.
La funzione CreateCommandList crea un elenco di comandi.
La funzione RecycleCommandList ricicla un elenco di comandi.
La funzione RecycleCreateCommandList crea un elenco di comandi e rende un handle DDI inutilizzato in precedenza completamente valido.
La funzione DestroyCommandList elimina definitivamente un elenco di comandi.
La funzione RecycleDestroyCommandList notifica al driver che è necessaria la distruzione leggera di un elenco di comandi.
La funzione CommandListExecute esegue un elenco di comandi.
Le semantiche per le funzioni CommandListExecute, CalcPrivateCommandListSize, CreateCommandList e DestroyCommandList del driver sono principalmente autoesplicative, basate su altre funzioni DDI simili e sulla documentazione dell'API per l'DDI corrispondente.
Dopo che il runtime Direct3D chiama correttamente la funzione CreateCommandList o RecycleCreateCommandList del driver nel contesto posticipato specificato nel membro hDeferredContext della struttura D3D11DDIARG_CREATECOMMANDLIST a cui punta il parametro pCreateCommandList, il runtime Direct3D esegue la sequenza di distruzione seguente nel contesto posticipato:
Il runtime Direct3D "chiude" tutti gli handle di oggetti posticipati aperti. Si noti che questi handle potrebbero essere ancora associati al contesto posticipato.
Il runtime elimina definitivamente il contesto posticipato.
Durante la chiamata a CreateCommandList o RecycleCreateCommandList, tutte le chiamate effettuate dal driver alle funzioni di callback DDI per l'aggiornamento dello stato continuano a divulgare lo stato corrente del contesto posticipato. Tuttavia, durante la "chiusura" e la distruzione del contesto posticipato, tutte le chiamate all'istruzione DDI di aggiornamento dello stato riflettono che non è associato alcun elemento (ovvero subito dopo la chiamata a CreateCommandList o RecycleCreateCommandList, tutto è implicitamente non associato).
Un contesto posticipato può anche essere abbandonato in modo esplicito dall'applicazione o a causa di una condizione di errore da parte dell'API o del driver. Per questi casi, il runtime Direct3D esegue la sequenza seguente:
Il runtime Direct3D chiama la funzione AbandonCommandList del driver.
Il runtime annulla l'associazione gestisce dal contesto posticipato uno alla sola.
Il runtime "chiude" tutti gli handle di oggetti posticipati aperti.
Il runtime ricicla o elimina definitivamente il contesto posticipato.
La sequenza precedente è simile alla sequenza di distruzione di un contesto immediato. La chiamata alla funzione AbandonCommandList del driver consente al driver di applicare lo stato a qualsiasi driver preferisca.
Durante la chiamata alla funzione CommandListExecute del driver, il driver deve eseguire la transizione dello stato del contesto posticipato per renderlo equivalente allo stato al momento della creazione del dispositivo. Questa operazione è nota anche come operazione di cancellazione dello stato. Durante la chiamata alla funzione CommandListExecute del driver, tuttavia, tutte le chiamate effettuate dal driver alle funzioni di callback DDI per l'aggiornamento dello stato riflettono comunque lo stato di ciò che è stato associato durante l'ultima chiamata DDI a una funzione driver. Durante la successiva chiamata DDI a una funzione driver, tutte le chiamate effettuate dal driver alle funzioni di callback DDI di aggiornamento stato mostrano lo stato corrente come completamente vuoto, che riflette la transizione di stato implicita da CommandListExecute. Questo fatto differisce leggermente dalla semantica e dal comportamento tipici delle funzioni di callback DDI di aggiornamento dello stato. Se il driver aveva chiamato una funzione di callback DDI per l'aggiornamento dello stato durante una chiamata a una delle funzioni SetShader del driver, la funzione di callback DDI per l'aggiornamento dello stato visualizzerebbe come già associato il nuovo shader associato. Questa divergenza del comportamento di callback DDI per l'aggiornamento dello stato offre maggiore flessibilità al driver per riflettere lo stato precedente durante CommandListExecute.
L'API Direct3D versione 11 garantisce che nessuna query sia stata modificata (ovvero se QueryBegin o QueryEnd sia stata chiamata) dall'elenco dei comandi e sia stata "iniziata" solo dal contesto che tenta di eseguire l'elenco di comandi. L'API garantisce anche che nessun elenco di comandi che ha registrato la mappa di una risorsa dinamica venga eseguito in un contesto con la stessa risorsa attualmente mappata. Prima che un'applicazione chiami la funzione FinishCommandList, il runtime Direct3D chiama la funzione QueryEnd e ResourceUnmap DDI del driver su qualsiasi query o risorsa dinamica che contiene ancora una query avviata o una risorsa mappata aperta perché FinishCommandList termina implicitamente gli intervalli di query e annulla il mapping di qualsiasi risorsa mappata.
Ottimizzazione per elenchi di comandi di piccole dimensioni
Un'ottimizzazione del riciclo della memoria per gli elenchi di comandi di piccole quantità di memoria può essere importante per ridurre la contesa tra le chiamate di funzione DDI dell'elenco di comandi e ridurre il sovraccarico dell'elaborazione delle chiamate necessarie per gli elenchi di comandi. L'overhead di elaborazione intrinseco in ogni elenco di comandi è significativo. Questa ottimizzazione è destinata agli elenchi di comandi in cui il sovraccarico di elaborazione necessario per gli elenchi di comandi domina il tempo cpu e lo spazio di memoria necessario per gli elenchi di comandi. Un elenco di comandi di quantità di memoria ridotta, ad esempio, è un singolo comando grafico, ad esempio CopyResource. La quantità di memoria necessaria per CopyResource è costituita da due puntatori. Tuttavia, CopyResource richiede comunque la stessa quantità di elaborazione delle chiamate dell'elenco di comandi di un elenco di comandi di grandi dimensioni. Quando gli elenchi di comandi di piccole dimensioni di memoria vengono generati ad alta frequenza, il sovraccarico di elaborazione necessario per il runtime per chiamare le funzioni CreateCommandList, DestroyCommandList, CreateDeferredContext e DestroyDevice(D3D10) del driver diventa sempre più importante. La memoria a cui si fa riferimento è la memoria di sistema che contiene strutture di dati del driver, che include la memoria per gli handle DDI.
La funzione RecycleCommandList del driver deve notificare al driver quando gli handle del driver non vengono usati (ma non sono ancora eliminati) e quando vengono riutilizzati gli handle di driver inutilizzati in precedenza. Questa notifica si applica sia agli handle di elenco di comandi che a handle di contesto posticipato. L'unica memoria a cui deve essere riciclato il driver è la memoria a cui punta l'handle DDI. Anche se l'obiettivo di RecycleCommandList è riciclare la memoria associata all'handle, per l'efficienza il driver ha la massima flessibilità di scegliere la memoria da riciclare. Il driver non può modificare le dimensioni dell'area di memoria in cui l'elenco di comandi di contesto immediato gestisce i punti. Questa dimensione è il valore restituito di CalcPrivateCommandListSize. Il driver non può inoltre modificare le dimensioni dell'area di memoria in cui il punto di manipolazione locale dell'elenco dei comandi di contesto. Questa dimensione è il valore restituito di CalcDeferredContextHandleSize.
Le funzioni DDI DDI RecycleCreateCommandList e RecycleCreateDeferredContext del driver devono restituire codici di errore di memoria insufficiente come E_OUTOFMEMORY valori HRESULT. Queste funzioni non forniscono tali codici di errore tramite chiamate alla funzione pfnSetErrorCb. Questo requisito del driver impedisce al runtime di usare la sincronizzazione a livello di dispositivo per verificare la presenza di errori di contesto immediati da queste funzioni driver create-type. Il controllo di questi errori sarebbe una fonte di conflitti irreversibili per gli elenchi di comandi di piccole quantità di memoria.
Le distinzioni tra le funzioni RecycleDestroyCommandList, RecycleCommandList e RecycleCreateCommandList del driver sono importanti. Le loro caratteristiche includono quanto segue.
RecycleDestroyCommandList
Il runtime chiama la funzione RecycleDestroyCommandList del driver per notificare al driver che è necessaria la distruzione leggera. Ovvero, il driver non deve ancora deassegnare la memoria per l'handle dell'elenco di comandi DDI. La funzione RecycleDestroyCommandList del driver è a thread libero proprio come la funzione DestroyCommandList del driver.
RecycleCommandList
La funzione RecycleCommandList del driver informa il driver che il runtime ha integrato un handle dell'elenco di comandi nella cache del contesto posticipato. La funzione fornisce quindi al driver l'opportunità di integrare la memoria associata all'elenco di comandi nella cache del contesto posticipato. Il runtime chiama la funzione RecycleCommandList del driver dal thread di contesto posticipato. La funzione DDI RecycleCommandList riduce la necessità del driver di eseguire la sincronizzazione propria.
RecycleCreateCommandList
Il runtime chiama la funzione RecycleCreateCommandList del driver per rendere un handle DDI non usato in precedenza completamente valido.
Queste funzioni DDI di riciclo offrono opportunità di ottimizzazione per aiutare a riciclare le risorse per gli elenchi di comandi di piccole quantità di memoria. Lo pseudocodice seguente illustra l'implementazione del runtime tramite il flusso di chiamate di funzione dall'API all'DDI :
::FinishCommandList()
{
// Empty InterlockedSList, integrating into the cache
Loop { DC::pfnRecycleCommandList }
If (Previously Destroyed CommandList Available)
{ IC::pfnRecycleCreateCommandList }
else
{
IC::pfnCalcPrivateCommandListSize
IC::pfnCreateCommandList
IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
}
Loop { DC::pfnDestroy* (context-local handle destroy) }
IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)
CommandList::Destroy()
{
// If DC still alive, almost always recycle:
If (DC still alive)
{ IC::pfnRecycleDestroyCommandList }
Else
{ IC::pfnDestroyCommandList }
// Add to InterlockedSList
}
Il diagramma di stato seguente mostra la validità di un handle di elenco comandi DDI con contesto immediato. Lo stato verde rappresenta un handle che può essere usato con CommandListExecute.