4.1.4交換鏈和翻頁_4.1.12

4.1.4交換鏈和翻頁

爲了避免在動畫中閃爍,最好將整個動畫幀繪製到稱爲後緩衝區的離屏紋理中。一旦整個場景被繪製到給定動畫幀的後臺緩衝區,它將作爲一個完整的幀呈現給屏幕;通過這種方式,觀看者不會在畫框被觀看時觀看 - 觀看者只能看到完整的畫面。爲實現這一點,硬件維護兩個紋理緩衝區,一個稱爲前端緩衝區,另一個稱爲後端緩衝區。前端緩衝區存儲當前顯示在監視器上的圖像數據,而下一幀動畫正被繪製到後臺緩衝區。在幀被繪製到後臺緩衝區後,後臺緩衝區和前臺緩衝區的角色相反:後臺緩衝區成爲前臺緩衝區,前臺緩衝區成爲下一幀動畫的後臺緩衝區。交換後臺和前臺緩衝區的角色稱爲present.Presenting是一個高效的操作,因爲指向當前前臺緩衝區的指針和指向當前後臺緩衝區的指針只需要交換。圖4.1說明了這個過程。


圖4.1。 對於幀n,當前正在顯示緩衝區A,並且我們將下一幀渲染到緩衝區B,該緩衝區充當當前後端緩衝區。 一旦幀完成,指針交換,緩衝區B成爲前端緩衝區,緩衝區A成爲新的後端緩衝區。 然後,我們將下一幀n + 1渲染到緩衝區A.一旦幀完成,指針就交換,緩衝區A成爲前端緩衝區,緩衝區B再次成爲後端緩衝區。


前端和後端緩衝區形成交換鏈。 在Direct3D中,交換鏈由IDXGISwapChain接口表示。 該接口存儲正面和背面緩衝區紋理,並提供調整緩衝區大小(IDXGISwapChain :: ResizeBuffers)和顯示(IDXGISwapChain :: Present)的方法。

使用兩個緩衝區(正面和背面)稱爲雙緩衝。 可以使用兩個以上的緩衝區; 使用三個緩衝區稱爲三重緩衝區。 然而,兩個緩衝區通常就足夠了。


儘管後臺緩衝區是一個紋理(因此一個元素應該稱爲紋理元素),但我們經常將元素稱爲一個像素,因爲在後臺緩衝區的情況下,它會存儲顏色信息。 有時,即使不存儲顏色信息(例如,“法線貼圖的像素”),人們也會調用像素的紋理元素。


4.1.5深度緩衝
深度緩衝區是不包含圖像數據的紋理的示例,而是關於特定像素的深度信息。可能的深度值範圍從0.0到1.0,其中0.0表示觀看視錐體中可能對觀察者最接近的物體,1.0表示視錐體中觀察到的最遠的物體。深度緩衝區中的每個元素與後臺緩衝區中的每個像素之間存在一一對應關係(即,後臺緩衝區中的第i個元素對應於深度緩衝區中的第i個元素)。因此,如果後臺緩衝區的分辨率爲1280×1024,則會有1280×1024個深度條目。

圖4.2顯示了一個簡單的場景,其中一些對象部分遮蓋了它們後面的對象。爲了讓Direct3D確定一個對象的哪些像素位於另一個像素的前面,它使用了一種稱爲深度緩衝或z緩衝的技術。讓我們強調,通過深度緩衝,我們繪製對象的順序並不重要。


圖4.2。 一組彼此部分混淆的對象。

爲了處理深度問題,可能會建議按照最遠到最近的順序繪製場景中的對象。通過這種方式,近物體將被塗在遠物體上,並且應該呈現正確的結果。這是一個畫家如何繪製一個場景。但是,此方法有其自身的問題 - 按照從前到後的順序排列大型數據集並交叉幾何。此外,圖形硬件爲我們提供了免費的深度緩衝。

爲了說明深度緩衝如何工作,讓我們看一個例子。考慮圖4.3,它顯示了觀衆看到的音量和該音量的2D側視圖。從圖中可以看出,三個不同的像素競爭渲染到視圖窗口上的像素P上。 (當然,我們知道最接近的像素應該渲染到P,因爲它隱藏了背後的像素,但是計算機沒有。)首先,在任何渲染髮生之前,後臺緩衝區被清除爲默認顏色,深度緩衝區被清除爲默認值 - 通常爲1.0(像素可以具有的最遠深度值)。現在,假設對象按照圓柱體,球體和圓錐體的順序渲染。下表總結了像素P及其對應的深度值d如何在繪製對象時更新;其他像素會發生類似的過程。


圖4.3。 視圖窗口對應於我們生成的3D場景的2D圖像(後臺緩衝區)。 我們看到可以將三個不同的像素投影到像素P.直覺告訴我們P1應該被寫入P,因爲它離觀察者更近並且阻擋另外兩個像素。 深度緩衝算法提供了用於在計算機上確定這一點的機械過程。 請注意,我們將顯示與正在查看的3D場景相關的深度值,但實際上,當存儲在深度緩衝區中時,它們會被標準化爲範圍[0.0,1.0]。


如你所見,當我們找到深度值較小的像素時,我們只更新深度緩衝區中的像素及其對應的深度值。 通過這種方式,在說完之後,最接近觀看者的像素將是渲染的像素。 (如果你仍然不確信,你可以嘗試切換繪圖順序並再次通過這個例子。)
總而言之,深度緩衝通過計算每個像素的深度值並執行深度測試而起作用。 深度測試比較競爭寫入到後緩衝區上的特定像素位置的像素的深度。 深度值最接近觀看者的像素獲勝,這是寫入後臺緩衝區的像素。 這是有道理的,因爲最接近觀看者的像素遮擋了它後面的像素。

深度緩衝區是一個紋理,所以它必須以特定的數據格式創建。 用於深度緩衝的格式如下所示:

1. DXGI_FORMAT_D32_FLOAT_S8X24_UINT:指定一個32位浮點深度緩衝區,其中8位(無符號整數)爲模板緩衝區保留,映射到[0,255]範圍,24位不用於填充。
2. DXGI_FORMAT_D32_FLOAT:指定一個32位浮點深度緩衝區。
3. DXGI_FORMAT_D24_UNORM_S8_UINT:指定映射到[0,1]範圍的無符號24位深度緩衝區,併爲映射到[0,255]範圍的模板緩衝區保留8位(無符號整數)。

4. DXGI_FORMAT_D16_UNORM:指定映射到[0,1]範圍的無符號16位深度緩衝區。

應用程序不需要有模板緩衝區,但如果有,模板緩衝區總是附加到深度緩衝區。 例如,32位格式
DXGI_FORMAT_D24_UNORM_S8_UINT

深度緩衝區使用24位,模板緩衝區使用8位。 爲此,深度緩衝區更好地稱爲深度/模板緩衝區。 使用模板緩衝區是一個更高級的主題,將在第11章中解釋。

4.1.6資源和描述符

在渲染過程中,GPU將向資源(例如,後臺緩衝區,深度/模板緩衝區)寫入數據,並從資源中讀取數據(例如描述表面外觀的紋理,存儲幾何圖形三維位置的緩衝區現場)。在我們發出繪圖命令之前,我們需要將資源綁定(或鏈接)到將在繪圖調用中引用的渲染管道。有些資源可能會因每次繪製調用而改變,因此如有必要,我們需要更新每次繪製調用的綁定。但是,GPU資源不會直接綁定。相反,資源是通過一個描述符對象來引用的,它可以被認爲是描述GPU資源的輕量級結構。本質上,它是一種間接的層面;給定一個資源描述符,GPU可以獲取實際的資源數據並知道關於它的必要信息。我們通過指定將在繪製調用中引用的描述符將資源綁定到渲染管道。

爲什麼要使用描述符進行這種額外級別的間接尋址?原因是GPU資源本質上是通用的內存塊。資源保持通用,因此可以在渲染管道的不同階段使用它們;一個常見的例子是使用紋理作爲渲染目標(即,Direct3D繪製到紋理中)並且稍後作爲着色器資源(即紋理將被採樣並用作着色器的輸入數據)。資源本身並不表示它是否被用作渲染目標,深度/模板緩衝區或着色器資源。另外,也許我們只想將資源數據的一個子區域綁定到渲染管道 - 在給定整個資源的情況下,我們該怎麼做?而且,資源可以用無類型的格式創建,所以GPU甚至不會知道資源的格式。

這是描述符出現的地方。除了標識資源數據外,描述符還描述了GPU的資源:它們告訴Direct3D資源將如何使用(即,您將綁定到哪個管道的哪個階段),如果適用,我們可以指定我們想要在描述符中綁定的資源的子區域,並且如果在創建時將資源格式指定爲無類型,那麼現在我們必須在創建描述符時指定類型。

視圖是描述符的同義詞。 術語“視圖”在以前的Direct3D版本中使用,它仍然用於Direct3D 12 API的某些部分。 我們在本書中互換使用; 例如,常量緩衝區視圖和常量緩衝區描述符意味着同樣的事情。
描述符有一個類型,類型意味着資源將如何使用。 我們在本書中使用的描述符類型有:
1. CBV / SRV / UAV描述符描述常量緩衝區,着色器資源和無序訪問視圖資源。
2.採樣器描述符描述採樣器資源(用於紋理化)。
3. RTV描述符描述渲染目標資源。
4. DSV描述符描述深度/模板資源。

描述符堆是描述符的數組; 它是您的應用程序使用的特定類型的所有描述符的內存支持。 對於每種類型的描述符,您都需要一個單獨的描述符堆。 您也可以創建多個相同描述符類型的堆。

我們可以有多個描述符引用相同的資源。例如,我們可以有多個描述符引用資源的不同子區域。另外,如前所述,資源可以綁定到渲染管線的不同階段。對於每個階段,我們需要一個單獨的描述符。對於使用紋理作爲渲染目標和着色器資源的示例,我們需要創建兩個描述符:一個RTV類型描述符和一個SRV類型描述符。同樣,如果您使用無類型格式創建資源,則可以將紋理的元素視爲浮點值或整數,例如;這需要兩個描述符,其中一個描述符指定浮點格式,另一個描述符指定整數格式。
描述符應該在初始化時創建。這是因爲有一些類型檢查和驗證發生,最好在初始化時而不是運行時執行。

2009年8月的SDK文檔說:“創建完全類型的資源會將資源限制爲其創建的格式。 “因此,如果您真的需要它們提供的靈活性(能夠以多種視圖以多種方式重新解釋數據),您應該只創建一個無類型資源;”否則,請創建一個完整類型的資源。

4.1.7多重抽樣理論

由於顯示器上的像素不是無限小,因此在計算機顯示器上無法完美呈現任意線條。 圖4.4說明了一個“階梯”(混疊)效應,當通過像素矩陣逼近一條線時會出現這種效應。 三角形的邊緣會出現類似的鋸齒效應。


圖4.4。 在頂部,我們觀察到混疊(當嘗試用像素矩陣表示一條線時的階梯效果)。在底部,我們看到一條反鋸齒線,該線通過採樣並使用其相鄰像素來生成像素的最終顏色; 這會產生更平滑的圖像並淡化樓梯效果。

通過增加顯示器分辨率來縮小像素大小可以顯着減輕問題,而樓梯效應在很大程度上不會被注意到。

當增加顯示器分辨率是不可能或不夠的時候,我們可以應用抗鋸齒技術。一種稱爲超採樣的技術通過使後緩衝區和深度緩衝區大於屏幕分辨率4倍來工作。然後以更高的分辨率將3D場景渲染到後臺緩衝區。然後,當需要向屏幕顯示後臺緩衝區時,後臺緩衝區將被解析(或縮減採樣),以便將4個像素塊的顏色平均到一起以獲得平均的像素顏色。實際上,超採樣通過增加軟件中的分辨率來工作。

超採樣是昂貴的,因爲它將像素處理和存儲量增加了四倍。 Direct3D支持一種折衷的抗混疊技術,稱爲多重採樣,它在子像素之間共享一些計算信息,使其比超級採樣更便宜。假設我們使用4倍多重採樣(每個像素4個子像素),多重採樣還使用比屏幕分辨率大4倍的後臺緩衝區和深度緩衝區;然而,不是計算每個子像素的圖像顏色,而是在像素中心每像素只計算一次圖像顏色,然後根據可見性(深度/模板測試評估每個子像素)和覆蓋範圍與子像素共享該顏色信息(子像素中心位於多邊形的內部還是外部?)。圖4.5顯示了一個例子。


圖4.5。 我們考慮一個穿過多邊形邊緣的像素。 (a)像素中心評估的綠色存儲在多邊形覆蓋的三個可見子像素中。 第四象限中的子像素未被多邊形覆蓋,因此不會用綠色更新 - 它只是保持先前繪製的幾何圖形或“清除”操作計算的以前的顏色。 (b)爲了計算分辨的像素顏色,我們對四個子像素(三個綠色像素和一個白色像素)進行平均,以獲得沿着多邊形邊緣的淺綠色。 這可以通過稀釋沿多邊形邊緣的階梯效果,獲得更平滑的圖像。

觀察超採樣和多采樣之間的關鍵區別。 使用超級取樣,圖像顏色是按每個子像素計算的,因此每個子像素可能具有不同的顏色。 使用多重採樣(圖4.5)時,圖像顏色每個像素計算一次,該顏色被複制到多邊形覆蓋的所有可見子像素中。 由於計算圖像顏色是圖形管線中最昂貴的步驟之一,因此超採樣對超採樣的節省顯着。 另一方面,超級取樣更準確。

在圖4.5中,我們展示了一個細分爲四個均勻網格模式的子像素的像素。 由於Direct3D沒有定義子像素的位置,因此所使用的實際模式(子像素所在的位置)可能因硬件供應商而異。某些模式在某些情況下比其他模式效果更好。

4.1.8 Direct3D中的多重採樣

在下一節中,我們將被要求填寫一個DXGI_SAMPLE_DESC結構。 這個結構有兩個成員,定義如下:

typedef struct DXGI_SAMPLE_DESC
{
UINT Count;
UINT Quality;

} DXGI_SAMPLE_DESC;

Count成員指定每像素採樣的數量,Quality成員用於指定所需的質量級別(硬件製造商的“質量級別”可能會有所不同)。 更高的樣本數量或更高的質量會導致更高的渲染成本,因此必須在質量和速度之間進行權衡。 質量等級的範圍取決於每個像素的紋理格式和採樣數量。

我們可以使用ID3D12Device :: CheckFeatureSupport方法來查詢給定紋理格式和樣本數量的質量級別數量,如下所示:

typedef struct
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS {
DXGI_FORMAT Format;
UINT SampleCount;
D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG Flags;
UINT NumQualityLevels;
} D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS
msQualityLevels;
msQualityLevels.Format = mBackBufferFormat;
msQualityLevels.SampleCount = 4;
msQualityLevels.Flags =
D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
msQualityLevels.NumQualityLevels = 0;
ThrowIfFailed(md3dDevice->CheckFeatureSupport(
D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&msQualityLevels,

sizeof(msQualityLevels)));

請注意,第二個參數既是輸入參數,也是輸出參數。 對於輸入,我們必須指定紋理格式,樣本數量和我們想要查詢多重採樣支持的標誌。 該功能將填寫質量水平作爲輸出。 紋理格式和樣本數量組合的有效質量級別從零到NumQualityLevels-1。

每個像素可以採樣的最大采樣數由以下定義:

#define D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT ( 32 )

但是,爲了保持多采樣的性能和內存成本合理,採樣數爲4或8是很常見的。 如果您不希望使用多重採樣,請將採樣計數設置爲1,質量級別設置爲0.所有支持Direct3D 11的設備都支持所有渲染目標格式的4倍多重採樣。

DXGI_SAMPLE_DESC結構需要爲交換鏈緩衝區和深度緩衝區填寫。 後臺緩衝區和深度緩衝區必須使用相同的多重採樣設置創建。

4.1.9功能級別

Direct3D 11引入了功能級別的概念(用D3D_FEATURE_LEVEL枚舉類型代碼表示),它大致對應於從版本9到版本11的各種Direct3D版本:

enum D3D_FEATURE_LEVEL
{
D3D_FEATURE_LEVEL_9_1 = 0x9100,
D3D_FEATURE_LEVEL_9_2 = 0x9200,
D3D_FEATURE_LEVEL_9_3 = 0x9300,
D3D_FEATURE_LEVEL_10_0 = 0xa000,
D3D_FEATURE_LEVEL_10_1 = 0xa100,
D3D_FEATURE_LEVEL_11_0 = 0xb000,
D3D_FEATURE_LEVEL_11_1 = 0xb100

}D3D_FEATURE_LEVEL;

功能級別定義了一組嚴格的功能(有關每個功能級別支持的特定功能,請參閱SDK文檔)。例如,支持功能級別11的GPU必須支持整個Direct3D 11功能集,只有少數例外(有些事情像多重採樣計數仍需要查詢,因爲它們允許在不同的Direct3D 11硬件之間變化)。功能集使開發變得更加簡單 - 一旦您知道了支持的功能集,就可以瞭解您可以使用的Direct3D功能。

 如果用戶的硬件不支持某個功能級別,則應用程序可能會回退到較舊的功能級別。例如,爲了支持更廣泛的受衆,應用程序可能支持Direct3D 11,10和9.3級硬件。應用程序會檢查從最新到最舊的功能級別支持:也就是說,應用程序首先會檢查是否支持Direct3D 11,第二個Direct3D 10,最後是Direct3D 9.3。在本書中,我們總是需要支持功能級別D3D_FEATURE_LEVEL_11_0。但是,真實世界的應用程序確實需要擔心支持舊硬件以最大限度地提高受衆。

4.1.10 DirectX圖形基礎結構
DirectX圖形基礎結構(DXGI)是與Direct3D一起使用的API。 DXGI的基本思想是,一些與圖形相關的任務對於多個圖形API是通用的。例如,2D渲染API需要交換鏈和頁面翻轉以獲得與3D渲染API一樣多的平滑動畫;因此交換鏈接口IDXGISwapChain(§4.1.4)實際上是DXGI API的一部分。 DXGI處理其他常見的圖形功能,如全屏模式轉換,枚舉圖形系統信息,如顯示適配器,監視器和支持的顯示模式(分辨率,刷新率等)。它還定義了各種支持的表面格式(DXGI_FORMAT)。

我們簡要介紹一下在我們的Direct3D初始化過程中將使用的一些DXGI概念和接口。其中一個關鍵的DXGI接口是IDXGIFactory接口,主要用於創建IDXGISwapChain接口和枚舉顯示適配器。顯示適配器實現圖形功能。通常,顯示適配器是硬件的物理部分(例如,圖形卡);但是,系統也可以具有模擬硬件圖形功能的軟件顯示適配器。系統可以有幾個適配器(例如,如果它有幾個圖形卡)。適配器由IDXGIAdapter接口表示。我們可以使用以下代碼枚舉系統上的所有適配器:

void D3DApp::LogAdapters()
{
UINT i = 0;
IDXGIAdapter* adapter = nullptr;
std::vector<IDXGIAdapter*> adapterList;
while(mdxgiFactory->EnumAdapters(i, &adapter) !=
DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
std::wstring text = L”***Adapter: “;
text += desc.Description;
text += L”\n”;
OutputDebugString(text.c_str());
adapterList.push_back(adapter);
++i;
}
for(size_t i = 0; i < adapterList.size(); ++i)
{
LogAdapterOutputs(adapterList[i]);
ReleaseCom(adapterList[i]);
}

}

該方法的輸出示例如下:

***Adapter: NVIDIA GeForce GTX 760

***Adapter: Microsoft Basic Render Driver

“Microsoft Basic Render Driver”是Windows 8及更高版本附帶的軟件適配器。

一個系統可以有多個監視器。 監視器是顯示輸出的一個例子。 輸出由IDXGIOutput接口表示。 每個適配器都與一系列輸出相關聯。 例如,考慮一個帶有兩個圖形卡和三個顯示器的系統,其中兩個顯示器連接到一個圖形卡,第三個顯示器連接到另一個圖形卡。 在這種情況下,一個適配器具有兩個與其關聯的輸出,另一個適配器具有與其關聯的一個輸出。 我們可以使用以下代碼枚舉與適配器關聯的所有輸出:

void D3DApp::LogAdapterOutputs(IDXGIAdapter* adapter)
{
UINT i = 0;
IDXGIOutput* output = nullptr;
while(adapter->EnumOutputs(i, &output) !=
DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
std::wstring text = L”***Output: “;
text += desc.DeviceName;
text += L”\n”;
OutputDebugString(text.c_str());
LogOutputDisplayModes(output,
DXGI_FORMAT_B8G8R8A8_UNORM);
ReleaseCom(output);
++i;
}

}

請注意,根據文檔,“Microsoft Basic Render Driver”沒有顯示輸出。

每臺顯示器都有一套它支持的顯示模式。 顯示模式是指DXGI_MODE_DESC中的以下數據:

typedef struct DXGI_MODE_DESC
{
UINT Width; // Resolution width
UINT Height; // Resolution height
DXGI_RATIONAL RefreshRate;
DXGI_FORMAT Format; // Display format
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
//Progressive vs. interlaced
DXGI_MODE_SCALING Scaling; // How the image is
stretched
// over the monitor.
} DXGI_MODE_DESC;
typedef struct DXGI_RATIONAL
{
UINT Numerator;
UINT Denominator;
} DXGI_RATIONAL;
typedef enum DXGI_MODE_SCANLINE_ORDER
{
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED = 0,
DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE = 1,
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST = 2,
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST = 3
} DXGI_MODE_SCANLINE_ORDER;
typedef enum DXGI_MODE_SCALING
{
DXGI_MODE_SCALING_UNSPECIFIED = 0,
DXGI_MODE_SCALING_CENTERED = 1,
DXGI_MODE_SCALING_STRETCHED = 2

} DXGI_MODE_SCALING;

修復顯示模式格式,我們可以使用以下代碼獲得輸出支持的所有支持的顯示模式列表:

void D3DApp::LogOutputDisplayModes(IDXGIOutput*
output, DXGI_FORMAT format)
{
UINT count = 0;
UINT flags = 0;
// Call with nullptr to get list count.
output->GetDisplayModeList(format, flags, &count,
nullptr);
std::vector<DXGI_MODE_DESC> modeList(count);
output->GetDisplayModeList(format, flags, &count,
&modeList[0]);
for(auto& x : modeList)
{
UINT n = x.RefreshRate.Numerator;
UINT d = x.RefreshRate.Denominator;
std::wstring text =
L”Width = ” + std::to_wstring(x.Width) + L” ” +
L”Height = ” + std::to_wstring(x.Height) + L” ”
+
L”Refresh = ” + std::to_wstring(n) + L”/” +
std::to_wstring(d) +
L”\n”;
::OutputDebugString(text.c_str());
}

}

此代碼的一些輸出示例如下所示:

***Output: \.\DISPLAY2
… Width =1920 Height =1080 Refresh =59950/1000

Width = 1920 Height = 1200 Refresh = 59950/1000

枚舉顯示模式在進入全屏模式時尤其重要。 爲了獲得最佳的全屏性能,指定的顯示模式(包括刷新率)必須與顯示器支持的顯示模式完全匹配。

指定枚舉顯示模式保證了這一點。 有關DXGI的更多參考資料,我們建議您閱讀以下文章“DXGI概述”,“DirectX圖形基礎架構:最佳實踐”和“DXGI 1.4改進”

DXGI Overview:http://msdn.microsoft.com/enus/ library/windows/desktop/bb205075(v=vs.85).aspx
DirectX Graphics Infrastructure: Best Practices: http://msdn.microsoft.com/enus/
library/windows/desktop/ee417025(v=vs.85).aspx

DXGI 1.4 Improvements:https://msdn.microsoft.com/enus/ library/windows/desktop/mt427784%28v=vs.85%29.aspx

4.1.11檢查功能支持

我們已經使用ID3D12Device :: CheckFeatureSupport方法來檢查當前圖形驅動程序的多重採樣支持。 但是,這只是我們可以使用此功能檢查的一項功能支持。 這種方法的原型如下:

HRESULT ID3D12Device::CheckFeatureSupport(
D3D12_FEATURE Feature,
void *pFeatureSupportData,

UINT FeatureSupportDataSize);

1.特徵:D3D12_FEATURE枚舉類型的成員,標識我們要檢查支持的特徵的類型:
1. D3D12_FEATURE_D3D12_OPTIONS:檢查是否支持各種Direct3D 12功能。
2. D3D12_FEATURE_ARCHITECTURE:檢查對硬件體系結構功能的支持。
3. D3D12_FEATURE_FEATURE_LEVELS:檢查功能級別支持。
4. D3D12_FEATURE_FORMAT_SUPPORT:檢查給定紋理格式的功能支持(例如,格式是否可用作渲染目標,該格式是否可用於混合)。

5. D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS:檢查多重採樣功能支持。

2. pFeatureSupportData:指向數據結構以檢索功能支持信息的指針。 您使用的結構類型取決於您爲Feature參數指定的內容:
1.如果您指定了D3D12_FEATURE_D3D12_OPTIONS,則傳遞一個實例
的D3D12_FEATURE_DATA_D3D12_OPTIONS。
2.如果指定了D3D12_FEATURE_ARCHITECTURE,則傳遞D3D12_FEATURE_DATA_ARCHITECTURE的一個實例。
3.如果指定了D3D12_FEATURE_FEATURE_LEVELS,則傳遞D3D12_FEATURE_DATA_FEATURE_LEVELS的一個實例。
4.如果指定了D3D12_FEATURE_FORMAT_SUPPORT,則傳遞D3D12_FEATURE_DATA_FORMAT_SUPPORT的實例。

5.如果您指定了D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,則傳遞D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS的一個實例。

3. FeatureSupportDataSize:傳遞給pFeatureSupportData參數的數據結構的大小。

ID3D12Device :: CheckFeatureSupport函數檢查對許多功能的支持,其中很多功能我們不需要檢查本書並且是高級的; 有關每個功能結構的數據成員的詳細信息,請參閱SDK文檔。 但是,作爲示例,我們在下面顯示如何檢查支持的功能級別(§4.1.9):

typedef struct D3D12_FEATURE_DATA_FEATURE_LEVELS {
UINT NumFeatureLevels;
const D3D_FEATURE_LEVEL *pFeatureLevelsRequested;
D3D_FEATURE_LEVEL MaxSupportedFeatureLevel;
} D3D12_FEATURE_DATA_FEATURE_LEVELS;
D3D_FEATURE_LEVEL featureLevels[3] =
{
D3D_FEATURE_LEVEL_11_0, // First check D3D 11
support
D3D_FEATURE_LEVEL_10_0, // Next, check D3D 10
support
D3D_FEATURE_LEVEL_9_3 // Finally, check D3D 9.3
support
};
D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevelsInfo;
featureLevelsInfo.NumFeatureLevels = 3;
featureLevelsInfo.pFeatureLevelsRequested =
featureLevels;
md3dDevice->CheckFeatureSupport(
D3D12_FEATURE_FEATURE_LEVELS,
&featureLevelsInfo,

sizeof(featureLevelsInfo));

請注意,第二個參數既是輸入參數,也是輸出參數。 對於輸入,我們指定要素級數組中的元素數(NumFeatureLevels),以及指向特徵級數組(pFeatureLevelsRequested)的指針,其中包含我們要檢查硬件支持的特徵級別列表。 該函數通過MaxSupportedFeatureLevel字段輸出最大支持的功能級別。

4.1.12居留
一個複雜的遊戲將使用很多資源,如紋理和3D網格,但GPU中通常不需要這些資源中的大部分。例如,如果我們想象一個擁有大洞穴的室外森林的遊戲,那麼在玩家進入洞穴之前不需要洞穴資源,當玩家進入洞穴時,不再需要森林資源。
在Direct3D 12中,應用程序通過從GPU內存中驅逐資源並根據需要再次將它們駐留在GPU上來管理資源駐留(本質上,無論資源是否位於GPU內存中)。 基本思想是儘量減少應用程序使用的GPU內存量,因爲可能不足以存儲整個遊戲的所有資源,或者用戶運行其他需要GPU內存的應用程序。 作爲一個性能說明,應用程序應該避免在短時間內將相同的資源進出GPU內存的情況,因爲這會帶來開銷。 理想情況下,如果你要驅逐一個資源,那麼這個資源不應該需要一段時間。 遊戲級別/區域變化是改變資源駐留時間的好例子。

默認情況下,當一個資源被創建時,它被設置爲駐留,並在被銷燬時被驅逐。但是,應用程序可以使用以下方法手動控制駐留:

HRESULT ID3D12Device::MakeResident(
UINT NumObjects,
ID3D12Pageable *const *ppObjects);
HRESULT ID3D12Device::Evict(
UINT NumObjects,
ID3D12Pageable *const *ppObjects);

對於這兩種方法,第二個參數都是ID3D12Pageable資源的數組,第一個參數是數組中的資源數。

在本書中,爲了簡單起見,由於我們的演示與遊戲相比較小,我們不管理居住。 有關更多信息,請參閱駐留文檔:

https://msdn.microsoft.com/enus/ library/windows/desktop/mt186622%28v=vs.85%29.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章