DXGI 概觀
Microsoft DirectX Graphics Infrastructure (DXGI) 辨識圖形的某些部分會比其他部分更慢。 DXGI 的主要目標是管理可與 DirectX 圖形執行時間無關的低階工作。 DXGI 提供未來圖形元件的通用架構;利用 DXGI 的第一個元件是 Microsoft Direct3D 10。
在舊版 Direct3D 中,直接3D 執行時間包含低階工作,例如列舉硬體裝置、將轉譯的畫面格呈現至輸出、控制 Gamma 和管理全螢幕轉換。 這些工作現在會在 DXGI 中實作。
DXGI 的目的是要與核心模式驅動程式和系統硬體通訊,如下圖所示。
應用程式可以直接存取 DXGI,或在 D3D11_1.h、D3D11.h、D3D10_1.h 或 D3D10.h 中呼叫 Direct3D API,以為您處理 DXGI 的通訊。 如果您的應用程式需要列舉裝置或控制資料呈現至輸出的方式,您可以直接使用 DXGI。
本主題包含下列各節。
若要查看 Direct3D 11 硬體支援的格式:
- Direct3D 功能層級 12.1 硬體的 DXGI 格式支援
- Direct3D 功能層級 12.0 硬體的 DXGI 格式支援
- Direct3D 功能層級 11.1 硬體的 DXGI 格式支援
- Direct3D 功能層級 11.0 硬體的 DXGI 格式支援
- Direct3D 10Level9 格式的硬體支援
- Direct3D 10.1 格式的硬體支援
- Direct3D 10 格式的硬體支援
列舉配接器
配接器是電腦硬體和軟體功能的抽象概念。 您的電腦上通常有許多介面卡。 有些裝置是在硬體 (實作,例如您的視訊卡) ,有些則實作在軟體 (,例如 Direct3D 參考轉譯器) 。 配接器會實作圖形應用程式所使用的功能。 下圖顯示具有單一電腦的系統、兩張介面卡 () 和三個輸出監視器。
列舉這些硬體片段時,DXGI 會為每個輸出 (或監視) 建立 IDXGIOutput1 介面,以及每個視訊卡的 IDXGIAdapter2 介面, (即使它是內建在主機板) 中的視訊卡也一樣。 列舉是使用IDXGIFactory 介面呼叫 IDXGIFactory::EnumAdapters來傳回一組代表視訊硬體的IDXGIAdapter介面。
DXGI 1.1 新增 了 IDXGIFactory1 介面。 IDXGIFactory1::EnumAdapters1 會傳回一組代表視訊硬體的 IDXGIAdapter1 介面。
如果您想要在使用 Direct3D API 時選取特定的視訊硬體功能,建議您反復呼叫 D3D11CreateDevice 或 D3D11CreateDeviceAndSwapChain 函式搭配每個介面卡控制碼和可能的硬體 功能層級。 如果指定的配接器支援功能層級,此函式就會成功。
列舉Windows 8配接器的新資訊
從Windows 8開始,一律會出現名為 「Microsoft Basic Render Driver」 的介面卡。 此介面卡的 VendorId 為 0x1414 ,以及 0x8c的 DeviceID。 此配接器也會在其DXGI_ADAPTER_DESC2結構的Flags成員中設定DXGI_ADAPTER_FLAG_SOFTWARE值。 此配接器是沒有顯示輸出的僅限轉譯裝置。 DXGI 永遠不會傳回此介面卡 的DXGI_ERROR_DEVICE_REMOVED 。
如果電腦的顯示驅動程式無法運作或停用,電腦的主要 (Null) 介面卡也可能稱為「Microsoft Basic Render Driver」。但此配接器具有輸出,且未設定 DXGI_ADAPTER_FLAG_SOFTWARE 值。 作業系統和應用程式預設會使用此配接器。 如果已安裝或啟用顯示器驅動程式,應用程式可以接收此介面卡 的DXGI_ERROR_DEVICE_REMOVED ,然後必須重新列舉介面卡。
當電腦的主要顯示配接器是 「Microsoft Basic Display Adapter」 (WARP 配接器) 時,該電腦也有第二張介面卡。 第二張介面卡是沒有顯示輸出且 DXGI 永遠不會傳回 DXGI_ERROR_DEVICE_REMOVED的轉譯裝置。
如果您想要使用 WARP 進行轉譯、計算或其他長時間執行的工作,建議您使用僅限轉譯的裝置。 您可以呼叫 IDXGIFactory1::EnumAdapters1 方法,以取得僅限轉譯裝置的指標。 當您在D3D11CreateDevice的DriverType參數中指定D3D_DRIVER_TYPE_WARP時,也會建立僅轉譯裝置,因為 WARP 裝置也會使用僅限轉譯的 WARP 配接器。
簡報
您的應用程式工作是轉譯畫面,並要求 DXGI 將這些畫面呈現至輸出。 如果應用程式有兩個可用的緩衝區,它可以轉譯一個緩衝區,同時呈現另一個緩衝區。 應用程式可能需要兩個以上的緩衝區,視轉譯畫面的時間或簡報所需的畫面播放速率而定。 建立的緩衝區集稱為交換鏈結,如下所示。
交換鏈結有一個前端緩衝區和一或多個後端緩衝區。 每個應用程式都會建立自己的交換鏈結。 為了將資料呈現至輸出的速度最大化,交換鏈結幾乎一律會在顯示子系統的記憶體中建立,如下圖所示。
顯示器子系統 (通常是視訊卡,但可以在主機板上實作,) 包含 GPU、數位轉類比轉換器 (DAC) 和記憶體。 交換鏈結會配置在此記憶體中,讓呈現速度非常快。 顯示子系統會將前端緩衝區中的資料呈現至輸出。
交換鏈結設定為以全螢幕或視窗模式繪製,這不需要知道輸出是視窗化還是全螢幕。 全螢幕模式交換鏈結可以藉由切換顯示器解析度來優化效能。
建立交換鏈結
Direct3D 9 與 Direct3D 10 之間的差異:Direct3D 10 是使用 DXGI 的第一個圖形元件。 DXGI 有一些不同的交換鏈結行為。
|
交換鏈結的緩衝區是以特定大小和特定格式建立。 應用程式會 (指定這些值,或者您可以在啟動時從目標視窗繼承大小) ,然後選擇性地修改這些值,因為視窗大小變更以回應使用者輸入或程式事件。
建立交換鏈結之後,您通常會想要將影像轉譯成它。 以下是一個程式碼片段,可設定 Direct3D 內容以轉譯成交換鏈結。 此程式碼會從交換鏈結擷取緩衝區、從該緩衝區建立轉譯目標檢視,然後在裝置上設定它:
ID3D11Resource * pBB;
ThrowFailure( pSwapChain->GetBuffer(0, __uuidof(pBB),
reinterpret_cast<void**>(&pBB)), "Couldn't get back buffer");
ID3D11RenderTargetView * pView;
ThrowFailure( pD3D11Device->CreateRenderTargetView(pBB, NULL, &pView),
"Couldn't create view" );
pD3D11DeviceContext->OMSetRenderTargets(1, &pView, 0);
應用程式將框架轉譯成交換鏈結緩衝區之後,請呼叫 IDXGISwapChain1::P resent1。 然後,應用程式就可以轉譯下一個影像。
交換鏈結的小心和饋送
轉譯影像之後,請呼叫 IDXGISwapChain1::P resent1 並轉譯下一個影像。 這就是您的責任範圍。
如果您先前稱為 IDXGIFactory::MakeWindowAssociation,使用者可以按Alt-Enter鍵組合,DXGI 會在視窗模式和全螢幕模式之間轉換您的應用程式。 建議使用 IDXGIFactory::MakeWindowAssociation,因為強烈建議使用者的標準控制機制。
雖然您不需要撰寫比已描述更多的程式碼,但幾個簡單的步驟可讓應用程式更具回應性。 最重要的考慮是調整交換鏈結緩衝區的大小,以回應輸出視窗的大小調整。 當然,應用程式的最佳路由是回應WM_SIZE,並呼叫 IDXGISwapChain::ResizeBuffers,傳遞訊息參數中包含的大小。 當應用程式拖曳視窗的框線時,此行為明顯可讓應用程式對使用者做出良好的回應,但它也是啟用順暢全螢幕轉換的功能。 每當發生這類轉換時,您的視窗就會收到WM_SIZE訊息,而呼叫 IDXGISwapChain::ResizeBuffers 是交換鏈結有機會重新配置緩衝區的儲存體,以獲得最佳呈現。 這就是為什麼在呼叫 IDXGISwapChain::ResizeBuffers之前,應用程式必須釋放現有緩衝區上具有的任何參考。
無法呼叫 IDXGISwapChain::ResizeBuffers 以回應切換至全螢幕模式, (最自然地回應WM_SIZE) ,可能會排除翻轉的優化,其中 DXGI 可以直接交換顯示的緩衝區,而不是複製全螢幕的資料。
IDXGISwapChain1::P resent1 會通知您,如果您的輸出視窗完全透過 DXGI_STATUS_OCCLUDED遮蔽。 發生這種情況時,建議您讓應用程式進入待命模式 (,方法是呼叫 IDXGISwapChain1::P resent1 搭配 DXGI_PRESENT_TEST) ,因為用來轉譯畫面的資源會浪費。 使用 DXGI_PRESENT_TEST 可防止任何資料呈現,同時仍執行遮蔽檢查。 一旦 IDXGISwapChain1::P resent1 傳回S_OK,您應該結束待命模式;請勿使用傳回碼切換至待命模式,因為這麼做會使交換鏈結無法放棄全螢幕模式。
Direct3D 11.1 執行時間可從 Windows 8 開始提供翻轉模型交換鏈結 (,也就是在swapEffect成員中設定DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL值DXGI_SWAP_CHAIN_DESC或DXGI_SWAP_CHAIN_DESC1) 。 當您將框架呈現至具有翻轉模型交換鏈結的輸出時,DXGI 會將來自所有管線狀態位置的背景緩衝區解除系結,例如寫入回緩衝區 0 的輸出合併轉譯目標。 因此,建議您在轉譯回後端緩衝區之前,立即呼叫 ID3D11DeviceCoNtext::OMSetRenderTargets 。 例如,請勿呼叫 OMSetRenderTargets ,然後執行計算著色器工作,最終不會轉譯至資源。 如需翻轉模型交換鏈結及其優點的詳細資訊,請參閱 DXGI 翻轉模型。
注意
在 Direct3D 10 和 Direct3D 11 中,您不需要呼叫 IDXGISwapChain::GetBuffer ,在呼叫 IDXGISwapChain1::P resent1 之後擷取備份緩衝區 0,因為為了方便起見,後端緩衝區的身分識別會變更。 這不會在 Direct3D 12 中發生,而且您的應用程式必須改為手動追蹤緩衝區索引。
處理視窗大小調整
您可以使用 IDXGISwapChain::ResizeBuffers 方法來處理視窗調整大小。 呼叫 ResizeBuffers之前,您必須釋放交換鏈結緩衝區的所有未完成參考。 通常保存交換鏈結緩衝區參考的物件是轉譯目標檢視。
下列範例程式碼示範如何從 WindowProc 處理常式內呼叫 ResizeBuffers ,以取得WM_SIZE訊息:
case WM_SIZE:
if (g_pSwapChain)
{
g_pd3dDeviceContext->OMSetRenderTargets(0, 0, 0);
// Release all outstanding references to the swap chain's buffers.
g_pRenderTargetView->Release();
HRESULT hr;
// Preserve the existing buffer count and format.
// Automatically choose the width and height to match the client rect for HWNDs.
hr = g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
// Perform error handling here!
// Get buffer and create a render-target-view.
ID3D11Texture2D* pBuffer;
hr = g_pSwapChain->GetBuffer(0, __uuidof( ID3D11Texture2D),
(void**) &pBuffer );
// Perform error handling here!
hr = g_pd3dDevice->CreateRenderTargetView(pBuffer, NULL,
&g_pRenderTargetView);
// Perform error handling here!
pBuffer->Release();
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL );
// Set up the viewport.
D3D11_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pd3dDeviceContext->RSSetViewports( 1, &vp );
}
return 1;
選擇 DXGI 輸出和大小
根據預設,DXGI 會選擇包含視窗大部分工作區的輸出。 這是 DXGI 在回應 alt-enter 時,唯一可供 DXGI 使用的選項。 如果應用程式自行選擇移至全螢幕模式,則可以呼叫 IDXGISwapChain::SetFullscreenState ,並傳遞明確的 IDXGIOutput1 (或 Null,如果應用程式很滿意讓 DXGI 決定) 。
若要在全螢幕或視窗化時調整輸出大小,建議您呼叫 IDXGISwapChain::ResizeTarget,因為此方法也會調整目標視窗的大小。 由於目標視窗已調整大小,因此作業系統會傳送 WM_SIZE,而您的程式碼會自然呼叫 IDXGISwapChain::ResizeBuffers 以回應。 因此,需要浪費心力來調整緩衝區大小,然後調整目標大小。
全螢幕模式偵錯
只有在絕對需要時,DXGI 交換鏈結才會全螢幕模式。 這表示您可以使用多個監視器對全螢幕應用程式進行偵錯,只要偵錯視窗不會與交換鏈結的目標視窗重迭即可。 或者,您可以藉由不設定 DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH 旗標來防止模式完全切換。
如果允許模式切換,每當另一個視窗遮蔽其輸出視窗時,交換鏈結就會放棄全螢幕模式。 遮蔽檢查會在IDXGISwapChain1::P resent1期間執行,或由目的為watch的個別執行緒執行,以查看應用程式是否沒有回應 (,且不再呼叫IDXGISwapChain1::P resent1) 。 若要停用個別執行緒造成參數的能力,請將下列登錄機碼設定為任何非零值。
HKCU\Software\Microsoft\DXGI\DisableFullscreenWatchdog
終結交換鏈結
您無法以全螢幕模式釋放交換鏈結,因為這麼做可能會建立執行緒爭用 (,這會導致 DXGI 引發非持續性的例外狀況) 。 在釋放交換鏈結之前,請先使用 IDXGISwapChain::SetFullscreenState ( ( FALSE、 Null ) ) 切換至視窗模式,然後呼叫 IUnknown::Release。
使用旋轉監視器
應用程式不需要擔心監視方向,DXGI 會在簡報期間視需要旋轉交換鏈結緩衝區。 當然,這個額外的輪替可能會影響效能。 若要獲得最佳效能,請執行下列動作來處理應用程式中的旋轉:
- 使用 DXGI_SWAP_CHAIN_FLAG_NONPREROTATED。 這會透過改變其投影矩陣) ,通知 DXGI 應用程式將產生旋轉的影像 (。 請注意,此旗標只有在全螢幕模式時才有效。
- 在其旋轉大小中配置每個交換鏈結緩衝區。 如有需要,請使用 IDXGIOutput::GetDesc 來取得這些值。
藉由在應用程式中執行旋轉,DXGI 只會執行複本,而不是複製和旋轉。
從 Windows 8 開始提供的 Direct3D 11.1 執行時間提供翻轉模型交換鏈結 (,也就是在DXGI_SWAP_CHAIN_DESC1) 的SwapEffect成員中設定DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL值的交換鏈結。 若要將翻轉模型交換鏈結提供的簡報優化最大化,建議您讓應用程式將內容導向,以符合內容在內容完全佔用輸出時所在的特定輸出。 如需翻轉模型交換鏈結及其優點的詳細資訊,請參閱 DXGI 翻轉模型。
切換模式
DXGI 交換鏈結可能會在進行全螢幕轉換時變更輸出的顯示模式。 若要啟用自動顯示模式變更,您必須在交換鏈結描述中指定 DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH 。 如果顯示模式自動變更,DXGI 會選擇最適中的模式, (大小和解析度不會變更,但色彩深度可能會) 。 調整交換鏈結緩衝區的大小不會造成模式切換。 交換鏈結會隱含承諾,如果您選擇完全符合目標輸出所支援顯示模式的背景緩衝區,則會在該輸出上進入全螢幕模式時切換至該顯示模式。 因此,您可以選擇背景緩衝區大小和格式來選擇顯示模式。
全螢幕效能提示
當您在全螢幕應用程式中呼叫 IDXGISwapChain1::P resent1 時,交換鏈結會翻轉 (,而不是將後端緩衝區的內容) 到前端緩衝區。 這需要使用列舉顯示模式建立交換鏈結, (在 DXGI_SWAP_CHAIN_DESC1) 中指定的。 如果您無法列舉顯示模式,或在描述中不正確地指定顯示模式,交換鏈結可能會改為執行位區塊傳輸 (bitblt) 。 bitblt 會造成額外的延展複製,以及一些增加的視訊記憶體使用量,而且很難偵測。 若要避免這個問題,請列舉顯示模式,並在建立交換鏈結之前正確初始化交換鏈結描述。 這可確保在全螢幕模式中翻轉時的效能上限,並避免額外的記憶體負荷。
多執行緒考慮
當您在具有多個執行緒的應用程式中使用 DXGI 時,必須小心避免建立死結,其中兩個不同的執行緒正在等待彼此完成。 發生這種情況有兩種情況。
- 轉譯執行緒不是訊息幫浦執行緒。
- 執行 DXGI API 的執行緒與建立視窗的執行緒不同。
當您使用全螢幕交換鏈結時,請務必在轉譯執行緒上等候訊息幫浦執行緒。 例如,從轉譯執行緒呼叫 IDXGISwapChain1::P resent1 ( ,) 可能會導致轉譯執行緒等候訊息幫浦執行緒。 發生模式變更時,如果 Present1 呼叫 ::SetWindowPos () 或 ::SetWindowStyle () ,而且其中一個方法呼叫 ::SendMessage () ,就可能發生此案例。 在此案例中,如果訊息幫浦執行緒有一個保護它的重要區段,或轉譯執行緒遭到封鎖,則這兩個執行緒將會死結。
如需搭配多個執行緒使用 DXGI 的詳細資訊,請參閱 多執行緒和 DXGI。
DLLMain 的 DXGI 回應
由於 DllMain 函式無法保證載入和卸載 DLL 的順序,因此建議您應用程式的 DllMain 函式不會呼叫 Direct3D 或 DXGI 函式或方法,包括建立或釋放物件的函式或方法。 如果您的應用程式的 DllMain 函式呼叫特定元件,該元件可能會呼叫作業系統上不存在的另一個 DLL,這會導致作業系統損毀。 Direct3D 和 DXGI 可能會載入一組 DLL,通常是一組與電腦不同的驅動程式。 因此,即使您的應用程式在開發和測試電腦上未在 DllMain 函式呼叫 Direct3D 或 DXGI 函式或方法時當機,它可能會在另一部電腦上執行時損毀。
為了防止建立可能導致作業系統損毀的應用程式,DXGI 會在指定的情況下提供下列回應:
DXGI 1.1 變更
我們已在 DXGI 1.1 中新增下列功能。
同步的共用介面支援
Direct3D 10.1 和 Direct3D 11 的同步共用介面可在多個 Direct3D 裝置之間有效率地讀取和寫入介面共用, (Direct3D 10 與 Direct3D 11 裝置之間共用是可行的) 。 請參閱 IDXGIKeyedMutex::AcquireSync 和 IDXGIKeyedMutex::ReleaseSync。
高色彩支援
支援DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM格式。
IDXGIDevice1::SetMaximumFrameLatency和IDXGIDevice1::GetMaximumFrameLatency
IDXGIFactory1::EnumAdapters1 會列舉本機配接器 (s) ,而不附加任何監視器或輸出,以及附加輸出的配接器 () 。 第一個傳回的介面卡將會是桌面主要複本顯示所在的本機介面卡。
BGRA 格式支援
DXGI_FORMAT_B8G8R8A8_UNORM和DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,請參閱 IDXGISurface1::GetDC 和 IDXGISurface1::ReleaseDC。
DXGI 1.2 變更
我們已在 DXGI 1.2 中新增下列功能。
- 立體交換鏈結
- 翻轉模型交換鏈結
- 優化簡報 (捲動、已變更矩形和旋轉)
- 改善共用資源和同步處理
- 桌面重複
- 優化視訊記憶體的使用
- 每個圖元支援 16 位 (bpp) 格式 (DXGI_FORMAT_B5G6R5_UNORM、DXGI_FORMAT_B5G5R5A1_UNORM、DXGI_FORMAT_B4G4R4A4_UNORM)
- 偵錯 API
如需 DXGI 1.2 的詳細資訊,請參閱 DXGI 1.2 改善。