Uso di handle DDI di Context-Local
Questa sezione si applica solo a Windows 7 e versioni successive e Windows Server 2008 R2 e versioni successive del sistema operativo Windows.
Ogni oggetto (ad esempio, risorsa, shader e così via) include handle DDI locali del contesto.
Si supponga che un oggetto venga usato con tre contesti posticipati. In questa situazione, quattro handle fanno riferimento allo stesso oggetto (un handle per ogni contesto posticipato e un altro handle per il contesto immediato). Poiché ogni contesto può essere manipolato contemporaneamente da un thread, un handle locale di contesto garantisce che più thread CPU non si concorrono su memoria simile (intenzionalmente o non intenzionalmente). Gli handle locali di contesto sono intuitivi anche perché il driver probabilmente deve modificare gran parte di questi dati associati logicamente per ogni contesto (ad esempio, l'oggetto potrebbe essere associato dal contesto e così via).
Esiste ancora la distinzione di un handle di contesto immediato rispetto a un handle di contesto posticipato. In particolare, l'handle di contesto immediato è garantito essere il primo handle allocato e l'ultimo handle eliminato. L'handle di contesto immediato corrispondente viene fornito durante l'apertura di ogni handle di contesto posticipato per collegarli insieme. Attualmente non esiste alcun concetto di un oggetto con un handle DDI per dispositivo, ovvero un handle creato prima e eliminato dopo l'handle di contesto immediato e viene fatto riferimento solo in ordine di creazione dell'handle di contesto.
Alcuni handle hanno relazioni di dipendenza con altri handle, ad esempio le visualizzazioni hanno una dipendenza dalla risorsa corrispondente. L'ordinamento di creazione e distruzione garantisce che esista per il contesto immediato venga esteso anche agli handle di contesto posticipati, ovvero il runtime crea un handle di risorse locale del contesto prima che il runtime crei gli handle di visualizzazione locale del contesto a tale risorsa e il runtime elimina un handle di risorse locale del contesto dopo che il runtime elimina tutti gli handle di visualizzazione locali del contesto a tale risorsa. Quando il runtime crea un handle locale del contesto, il runtime fornisce anche gli handle delle dipendenze locali di contesto corrispondenti.
Organizzazione dei dati driver
Esistono alcune preoccupazioni sull'organizzazione dei dati dei driver che necessitano di attenzione. Come Direct3D versione 10, la corretta localizzazione dei dati può ridurre le mancate cache tra l'API e il driver. La corretta localizzazione dei dati può anche impedire il thrashing della cache, che si verifica quando vengono risolti più parti di dati con accesso frequente allo stesso indice della cache ed esaurire l'associazione della cache. L'DDI è stato progettato da Direct3D versione 10 per evitare che tali problemi manifestino dal driver che informa l'API la quantità di memoria necessaria per soddisfare un handle e l'API che assegna il valore dell'handle. Tuttavia, i nuovi problemi correlati al thread influiscono sulla progettazione DDI nell'intervallo di tempo Direct3D versione 11.
Naturalmente, gli handle locali di contesto consentono di associare i dati degli oggetti per contesto, evitando problemi di contesa tra thread. Tuttavia, poiché tali dati vengono replicati per ogni contesto posticipato, le dimensioni di tali dati sono un problema importante. Ciò fornisce la razionalizzazione naturale per condividere i dati di sola lettura tra l'handle immediato del contesto e gli handle di contesto posticipati. Durante la creazione di handle di contesto posticipati, viene fornito l'handle di contesto immediato per stabilire la connessione tra handle. Tuttavia, tutti i dati che si trovano fuori dal contesto posticipato gestiscono vantaggi di localizzazione con i dati api e il livello aggiuntivo di indiretto per i dati di sola lettura impedisce che i vantaggi della localizzazione vengano estesi ai dati di sola lettura. Alcuni dati di sola lettura possono essere replicati in ogni area di gestione del contesto se i vantaggi della localizzazione giustificano la duplicazione dei dati. Tuttavia, la memoria che esegue il backing di ogni handle di contesto posticipato deve essere considerata a tale livello premium che potrebbe essere utile spostare i dati non adiacenti dall'handle se tali dati sono relativamente grandi e non accessibili come altri dati. Idealmente, il tipo di dati associati a ogni handle di contesto posticipato sarebbe comunque tutti dati ad alta frequenza; pertanto, i dati non sarebbero sufficienti per considerare la rilocazione necessaria. Naturalmente, il driver deve bilanciare queste motivazioni in conflitto.
Per rendere compatibile in modo efficiente la progettazione dei dati del driver con Direct3D versione 10, ma non divergente nell'implementazione, i dati di sola lettura devono trovarsi contigui (ma comunque separati da e dopo) i dati di gestione immediata del contesto. Se il driver usa questa progettazione, il driver deve essere consapevole che la spaziatura della riga di cache è necessaria tra i dati di gestione immediata del contesto e i dati di sola lettura. Poiché un thread potrebbe modificare ogni contesto gestisce spesso i dati (se non contemporaneamente), le penali di condivisione false si verificano tra i dati di gestione immediata del contesto e i dati di gestione del contesto posticipato se non viene usata la spaziatura della riga di cache. La progettazione del driver deve essere consapevole delle penali di false condivisione che manifestino se i puntatori vengono stabiliti e attraversati regolarmente tra aree di memoria di gestione del contesto.
Il runtime Direct3D usa gli handle locali di contesto posticipati seguenti:
La funzione CheckDeferredContextHandleSizes verifica le dimensioni degli spazi di memoria privata del driver che contengono i dati di handle dei gestori di contesti posticipati.
La funzione CalcDeferredContextHandleSize determina le dimensioni dell'area di memoria per un contesto posticipato.
Per il runtime Direct3D per recuperare le dimensioni dell'handle di contesto posticipato richieste dal driver, è necessario usare le funzioni DDI precedenti. Subito dopo la creazione di un oggetto per il contesto immediato, il runtime chiama CalcDeferredContextHandleSize per eseguire query sul driver per la quantità di spazio di archiviazione richiesto dal driver per soddisfare gli handle di contesto posticipati a questo oggetto. Tuttavia, l'API Direct3D deve ottimizzare l'allocatore di memoria CLS determinando il numero di dimensioni di handle univoche e i relativi valori sono accessibili; il runtime chiama la funzione CheckDeferredContextHandleSizes del driver per ottenere queste informazioni. Pertanto, durante l'istanza del dispositivo, l'API richiede una matrice di dimensioni di handle di contesto posticipati tramite il doppio polling. Il primo polling consiste nel richiedere il numero di dimensioni restituite, mentre il secondo polling passa in una matrice per recuperare il valore di ogni dimensione. Il driver deve indicare la quantità di memoria necessaria per soddisfare un handle insieme al tipo di handle. Il driver può restituire più dimensioni associate a un tipo di handle specifico. Tuttavia, non è definito per il driver di restituire mai un valore da CalcDeferredContextHandleSize che non è stato restituito in modo corrispondente nella matrice CheckDeferredContextHandleSizes .
Per quanto riguarda la creazione degli handle DDI, vengono usati i metodi di creazione nel contesto posticipato. Ad esempio, esaminare le funzioni CreateBlendState(D3D10_1) e DestroyBlendState . HDEVICE punta naturalmente al contesto posticipato appropriato (rispetto al contesto immediato); altri puntatori struttura CONST sono NULL (presupponendo che l'oggetto non abbia dipendenze); e, l'handle D3D10DDI_HRT* è un handle D3D10DDI_H* per l'oggetto contesto immediato corrispondente.
Per gli oggetti con dipendenze (ad esempio, le viste hanno una relazione di dipendenza sulla risorsa corrispondente), il puntatore della struttura che fornisce l'handle di dipendenza non è NULL. Tuttavia, l'unico membro valido della struttura è l'handle di dipendenza; mentre il resto dei membri viene riempito con zero. Ad esempio, la funzione D3D11DDIARG_CREATESHADERRESOURCEVIEW puntatore in una chiamata alla funzione CreateShaderResourceView(D3D11) del driver non sarà NULL quando il runtime chiama questa funzione in un contesto posticipato. In questa chiamata CreateShaderResourceView(D3D11) il runtime assegna l'handle locale di contesto appropriato per la risorsa al membro hDrvResource di D3D11DDIARG_CREATESHADERRESOURCEVIEW. Il resto dei membri di D3D11DDIARG_CREATESHADERRESOURCEVIEW, tuttavia, è pieno di zero.
Il codice di esempio seguente illustra come il runtime Direct3D converte la richiesta di creazione di un'applicazione e il primo uso del contesto posticipato per le chiamate al driver di visualizzazione in modalità utente per creare contesti immediati rispetto a posticipati. La chiamata dell'applicazione a ID3D11Device::CreateTexture2D avvia il codice di runtime nella sezione "Creazione risorse" seguente. La chiamata dell'applicazione a ID3D11Device::CopyResource avvia il codice di runtime nella sezione "Utilizzo risorse contesto posticipato".
// Device Create
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );
// Resource Create
s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );
// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );
Problemi con pfnSetErrorCb
Nessuna delle funzioni di creazione restituisce un codice di errore, che sarebbe stato ideale per il modello di threading Direct3D versione 11. Tutte le funzioni di creazione usano pfnSetErrorCb per recuperare i codici di errore dal driver. Per ottimizzare la compatibilità con il modello driver Direct3D versione 10, non sono state introdotte nuove funzioni di creazione DDI che restituiscono codici di errore. Al contrario, il driver deve continuare a usare il contesto unificato/immediato D3D10DDI_HRTCORELAYER handle con pfnSetErrorCb durante le funzioni di creazione. Quando il driver supporta gli elenchi di comandi, il driver deve usare il file pfnSetErrorCb appropriato associato al contesto corrispondente. Ovvero, gli errori di contesto posticipati devono passare alla chiamata di contesto posticipata specifica a pfnSetErrorCb con l'handle corrispondente e così via.
I contesti posticipati possono restituire E_OUTOFMEMORY tramite una chiamata a pfnSetErrorCb da funzioni DDI che in precedenza hanno consentito solo D3DDDIERR_DEVICEREMOVED (ad esempio Draw, SetBlendState e così via), poiché le richieste di memoria del contesto posticipate aumentano in modo perpetuo con ogni chiamata a una funzione DDI. L'API Direct3D attiva una rimozione del contesto locale, per aiutare il driver con un caso di errore di questo tipo, che in modo efficace rimuove l'elenco di comandi parzialmente compilato. L'applicazione continua a determinare che sta registrando un elenco di comandi; Tuttavia, quando l'applicazione chiama la funzione FinishCommandList , FinishCommandList restituisce un codice di errore di E_OUTOFMEMORY.