Infrastruttura grafica DirectX (DXGI): Procedure consigliate

Microsoft DirectX Graphics Infrastructure (DXGI) è un nuovo sottosistema introdotto con Windows Vista che incapsula alcune delle attività di basso livello necessarie da Direct3D 10, 10.1, 11 e 11.1. Dal punto di vista di un programmatore Direct3D 9, DXGI include la maggior parte del codice per l'enumerazione, la creazione della catena di scambio e la presentazione che in precedenza è stata inserita nelle API Direct3D 9. Quando si porta un'app a DXGI e Direct3D 10.x e Direct3D 11.x, è necessario prendere alcune considerazioni per assicurarsi che il processo venga eseguito senza problemi.

Questo articolo illustra i problemi di conversione chiave.

Full-Screen problemi

Nella conversione da Direct3D 9 a DXGI e in Direct3D 10.x o Direct3D 11.x, i problemi associati al passaggio da finestra a modalità schermo intero spesso possono causare mal di testa per gli sviluppatori. I problemi principali si verificano perché le applicazioni Direct3D 9, a differenza delle applicazioni DXGI, richiedono un approccio più pratico per tenere traccia degli stili delle finestre e degli stati delle finestre. Quando il codice di modifica della modalità viene convertito per l'esecuzione in DXGI, spesso causa un comportamento imprevisto.

Spesso, le applicazioni Direct3D 9 hanno gestito la transizione in modalità schermo intero impostando la risoluzione del buffer anteriore, forzando il dispositivo in modalità esclusiva a schermo intero e quindi impostando le risoluzioni del buffer indietro in modo che corrispondano. Un percorso separato è stato usato per le modifiche alle dimensioni della finestra perché devono essere gestite dal processo della finestra ogni volta che l'applicazione ha ricevuto un messaggio di WM_SIZE.

DXGI tenta di semplificare questo approccio combinando i due casi. Ad esempio, quando il bordo della finestra viene trascinato in modalità finestra, l'applicazione riceve un messaggio di WM_SIZE. DXGI intercetta questo messaggio e ridimensiona automaticamente il buffer anteriore. Tutto ciò che l'applicazione deve eseguire è chiamare IDXGISwapChain::ResizeBuffers per ridimensionare il buffer indietro alle dimensioni passate come parametri in WM_SIZE. Analogamente, quando l'applicazione deve passare dalla modalità a schermo intero alla modalità finestra, l'applicazione può semplicemente chiamare IDXGISwapChain::SetFullscreenState. DXGI ridimensiona il buffer anteriore in modo che corrisponda alla modalità schermo intero appena selezionato e invia un messaggio WM_SIZE all'applicazione. L'applicazione chiama di nuovo ResizeBuffers, proprio come se il bordo della finestra fosse stato trascinato.

La metodologia della spiegazione precedente segue un percorso molto particolare. DXGI imposta la risoluzione a schermo intero sulla risoluzione desktop per impostazione predefinita. Molte applicazioni, tuttavia, passano a una risoluzione a schermo intero preferita. In tal caso, DXGI fornisce IDXGISwapChain::ResizeTarget. Questa operazione deve essere chiamata prima di chiamare SetFullscreenState. Anche se questi metodi possono essere chiamati nell'ordine opposto (SetFullscreenState , seguito da ResizeTarget), in questo modo un messaggio di WM_SIZE aggiuntivo deve essere inviato all'applicazione. In questo modo può anche causare un flickering, poiché DXGI potrebbe essere costretto a eseguire due modifiche in modalità. Dopo aver chiamato SetFullscreenState, è consigliabile chiamare di nuovo ResizeTarget con il membro RefreshRate di DXGI_MODE_DESC zero. Ciò equivale a un'istruzione no-operation in DXGI, ma può evitare problemi con la frequenza di aggiornamento, che vengono illustrati di seguito.

Quando in modalità schermo intero, Gestione finestre desktop (DWM) è disabilitato. DXGI può eseguire un capovolgimento per presentare il contenuto del buffer indietro invece di eseguire un blit, che farebbe in modalità finestrata. Questo miglioramento delle prestazioni può tuttavia essere annullato, se alcuni requisiti non vengono soddisfatti. Per assicurarsi che DXGI faccia un capovolgimento anziché un blit, il buffer anteriore e il buffer posteriore devono essere ridimensionati in modo identico. Se l'applicazione gestisce correttamente i relativi messaggi WM_SIZE, questo non deve essere un problema. Inoltre, i formati devono essere identici.

Il problema per la maggior parte delle applicazioni è la frequenza di aggiornamento. La frequenza di aggiornamento specificata nella chiamata a ResizeTarget deve essere una frequenza di aggiornamento enumerata dall'oggetto IDXGIOutput utilizzato dalla catena di scambio. DXGI può calcolare automaticamente questo valore se l'applicazione zero out il membro RefreshRate di DXGI_MODE_DESC passato a ResizeTarget. È importante non presupporre che determinate tariffe di aggiornamento siano sempre supportate e che semplicemente un valore hard-code sia supportato. Spesso gli sviluppatori scelgono 60 Hz come frequenza di aggiornamento, non sapendo che la frequenza di aggiornamento enumerata dal monitor è circa 60.000/1.001 Hz dal monitor. Se la frequenza di aggiornamento non corrisponde alla frequenza di aggiornamento prevista di 60, DXGI è costretta a eseguire un blit in modalità schermo intero anziché un capovolgimento.

L'ultimo problema che spesso gli sviluppatori affrontano è come modificare le risoluzioni a schermo intero mentre rimangono in modalità schermo intero. La chiamata a ResizeTarget e SetFullscreenState a volte riesce, ma la risoluzione a schermo intero rimane la risoluzione desktop. Inoltre, gli sviluppatori possono creare una catena di scambio a schermo intero e dare una risoluzione specifica, solo per trovare che DXGI impostazione predefinita per la risoluzione desktop indipendentemente dai numeri passati. Se non diversamente indicato, DXGI viene predefinito per la risoluzione desktop per le catene di scambio a schermo intero. Quando si crea una catena di scambio a schermo intero, il membro Flag della struttura DXGI_SWAP_CHAIN_DESC deve essere impostato su DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH per eseguire l'override del comportamento predefinito di DXGI. Questo flag può essere passato anche a ResizeTarget per abilitare o disabilitare questa funzionalità in modo dinamico.

Più monitoraggi

Quando si usa DXGI con più monitor, sono disponibili due regole da seguire.

La prima regola si applica alla creazione di due o più catene di scambio a schermo intero su più monitor. Quando si creano catene di scambio, è preferibile creare tutte le catene di scambio come finestrate e quindi impostarle su schermo intero. Se le catene di scambio vengono create in modalità schermo intero, la creazione di una seconda catena di scambio causa l'invio di una modifica della modalità alla prima catena di scambio, che potrebbe causare la terminazione della modalità schermo intero.

La seconda regola si applica agli output. Prestare attenzione agli output usati durante la creazione di catene di scambio. Con DXGI, l'oggetto IDXGIOutput controlla che monitora la catena di scambio usa quando diventa a schermo intero. A differenza di DXGI, Direct3D 9 non aveva alcun concetto di output.

Stili di finestra e DXGI

Le applicazioni Direct3D 9 hanno avuto un sacco di lavoro da eseguire quando si passa tra le modalità a schermo intero e finestrato. Gran parte di questo lavoro ha coinvolto la modifica degli stili delle finestre per aggiungere e rimuovere bordi, per aggiungere barre di scorrimento e così via. Quando le applicazioni vengono convertite in DXGI e Direct3D 10.x o Direct3D 11.x, questo codice viene spesso lasciato sul posto. A seconda delle modifiche apportate, il passaggio tra le modalità può causare un comportamento imprevisto. Ad esempio, quando si passa alla modalità finestra, l'applicazione potrebbe non avere più una cornice di finestra o un bordo finestra, nonostante abbia codice che imposta in modo specifico questi stili. Ciò si verifica perché DXGI gestisce ora gran parte di questo stile che cambia da solo. L'impostazione manuale degli stili di finestra può interferire con DXGI e questo può causare un comportamento imprevisto.

Il comportamento consigliato consiste nell'eseguire il minor numero possibile di operazioni e consentire a DXGI di gestire la maggior parte dell'interazione con le finestre. Tuttavia, se l'applicazione deve gestire il proprio comportamento di finestra, IDXGIFactory::MakeWindowAssociation può essere usato per indicare a DXGI di disabilitare una delle relative operazioni di gestione automatica delle finestre.

Multithreading e DXGI

È necessario prestare particolare attenzione quando si usa DXGI in un'applicazione multithreading per assicurarsi che i deadlock non si verifichino. A causa dell'interazione con la finestra di DXGI, in alcuni casi invia messaggi di finestra alla finestra dell'applicazione associata. DXGI ha bisogno delle modifiche di finestra da eseguire prima che possa continuare, quindi userà SendMessage, ovvero una chiamata sincrona. L'applicazione deve elaborare il messaggio della finestra prima che SendMessage restituisca.

In un'applicazione in cui DXGI chiama e la pompa dei messaggi si trovano nello stesso thread (o un'applicazione a thread singolo), è necessario eseguire poco. Quando la chiamata DXGI si trova nello stesso thread della pompa del messaggio, SendMessage chiama WindowProc della finestra. Questa operazione ignora la pompa dei messaggi e consente di continuare l'esecuzione dopo la chiamata a SendMessage. Tenere presente che le chiamate IDXGISwapChain , ad esempio IDXGISwapChain::P resent, sono considerate anche chiamate DXGI; DXGI può rinviare il lavoro da ResizeBuffers o ResizeTarget fino alla chiamata di Present .

Se la chiamata DXGI e la pompa dei messaggi sono su thread diversi, è necessario prestare attenzione ad evitare deadlock. Quando la pompa del messaggio e SendMessage si trovano in thread diversi, SendMessage aggiunge un messaggio alla coda dei messaggi della finestra e attende che la finestra elabora tale messaggio. Se la procedura della finestra è occupato o non viene chiamata dalla pompa dei messaggi, il messaggio potrebbe non essere mai elaborato e DXGI attenderà in modo indefinito.

Ad esempio, se un'applicazione con la relativa pompa di messaggi su un thread e il relativo rendering su un'altra, potrebbe voler modificare le modalità. Il thread della pompa del messaggio indica al thread di rendering di modificare le modalità e attendere il completamento della modifica della modalità. Tuttavia, il thread di rendering chiama funzioni DXGI, che a sua volta chiama SendMessage, che blocca fino a quando la pompa del messaggio elabora il messaggio. Si verifica un deadlock perché entrambi i thread sono bloccati e sono in attesa tra loro. Per evitare questo problema, non bloccare mai la pompa del messaggio. Se un blocco non è inevitabile, tutte le interazioni DXGI devono verificarsi nello stesso thread della pompa del messaggio.

Gamma e DXGI

Sebbene gamma possa essere gestita meglio in Direct3D 10.x o Direct3D 11.x usando trame SRGB, la rampa gamma può comunque essere utile agli sviluppatori che vogliono un valore gamma diverso da 2.2 o che usano un formato di destinazione di rendering che non supporta SRGB. Tenere presente due problemi durante l'impostazione della rampa gamma attraverso DXGI. Il primo problema è che i valori della rampa passati in IDXGIOutput::SetGammaControl sono valori float, non valori WORD . Assicurarsi inoltre che il codice convertito da Direct3D 9 non tenti di convertire in valori WORD prima di passare questi a SetGammaControl.

Il secondo problema è che, dopo aver modificato la modalità a schermo intero, SetGammaControl potrebbe non risultare funzionante, dipendente dall'oggetto IDXGIOutput usato. Quando si passa alla modalità schermo intero, DXGI crea un nuovo oggetto di output e usa l'oggetto per tutte le operazioni successive sull'output. Se si chiama SetGammaControl in un output enumerato prima di un commutatore in modalità schermo intero, la chiamata non viene indirizzata verso l'output usato da DXGI. Per evitare questo problema, chiamare IDXGISwapChain::GetContainingOutput per ottenere l'output corrente e quindi chiamare SetGammaControl su questo output per ottenere il comportamento corretto.

Per informazioni sull'uso della correzione gamma, vedere Uso della correzione gamma.

DXGI 1.1

Il runtime Direct3D 11 incluso in Windows 7 e installato in Windows Vista include la versione 1.1 di DXGI. Questo aggiornamento aggiunge definizioni per diversi nuovi formati (in particolare BGRA, distorsione X2 a 10 bit e compressione delle trame BC6H e BC7 di Direct3D 11), nonché una nuova versione delle interfacce factory e adapter DXGI (CreateDXGIFactory1, IDXGIFactory1, IDXGIAdapter1) per enumerare le connessioni desktop remoto.

Quando si usa Direct3D 11, il runtime userà DXGI 1.1 per impostazione predefinita quando si chiama D3D11CreateDevice o D3D11CreateDeviceAndSwapChain con un puntatore NULL IDXGIAdapter . La combinazione di uso di DXGI 1.0 e DXGI 1.1 nello stesso processo non è supportata. Anche la combinazione di istanze di oggetti DXGI da factory diverse nello stesso processo non è supportata. Pertanto, quando si usa DirectX 11, qualsiasi uso esplicito delle interfacce DXGI usa un IDXGIFactory1 creato dal punto di ingresso CreateDXGIFactory1 in "DXGI.DLL" per garantire che l'applicazione usi sempre DXGI 1.1.

DXGI 1.2

Il runtime Direct3D 11.1 incluso in Windows 8 include anche la versione 1.2 di DXGI.

DXGI 1.2 abilita queste funzionalità:

  • rendering stereo

  • Formati a 16 bit per pixel

    • DXGI_FORMAT_B5G6R5_UNORM e DXGI_FORMAT_B5G5R5A1_UNORM sono ora completamente supportati
    • è stato aggiunto un nuovo formato di DXGI_FORMAT_B5G5R5A1_UNORM
  • formati video

  • nuove interfacce DXGI

Per altre info sulle funzionalità DXGI 1.2, vedi Miglioramenti di DXGI 1.2.