DirectX 11 編程指南


微軟在2009年8月的DirectXSDK中發布了DirectX的正式版本。基於對DirectX的一貫興趣,我把DirectX Graphics的文檔邊看邊譯為中文。也算是一份學習筆記吧。

眾所周知,Direct3D是在Windows平台上開發實時3D應用的軟件開發接口。隨着Windows操作系統的升級,Direct3D的版本也隨着升級。WindowsXP對應Direct3D9的各個版本,Vista對應D3D10,10.1,Windows7則對應D3D11。所以在XP平台上是沒法做D3D10及以上的開發了。不過看起來因為Win7實際上是Vista的一個升級,所以微軟也准備在Vista上支持D3D11。

D3D11是D3D10的一個超集,即它包含了D3D10的所有功能,並在其渲染管線上添加了一些新的特性。根據官方的文檔,D3D11的新特性包括:

ComputerShader(計算着色器)

計算着色器能把GPU當成一種通用功能的並行處理器來使用。其實在D3D9時代就已經可以應用GPU來進行GP(General-Purpose)計算了,只不過那時候需要使用一些特殊的手段來處理(比如將數據包裝成“紋理”)。在D3D11中專門實現了這樣一個着色器階段來支持GP計算,應該使得開發這類應用更為方便一些了。(參考NVIDIA的CUDA 技術以及OpenCL標准)

雖然計算着色器也是通過D3DDevice進行訪問的,並能和其他的圖形着色器共享內存資源,但它並不直接連接到其他的着色器階段上面。這大概是因為ComputerShader並不直接與圖形渲染功能相關吧。

Dynamic Shader Linkage(動態着色器鏈接)

D3D11包含的SM5(Shader Model規范)支持面向對象語言的構建方式,並支持運行時的着色器鏈接。

多線程(Multithreading)

隨着CPU的多核化趨勢漸漸普及,D3DAPI對多線程的支持勢在必行。D3D11對多線程提供了這樣的功能支持:

  • 並發的對象創建 - 可以在多個線程中並發地進行對象(資源、着色器等)的創建。
  • 在多線程中創建命令列表 - 命令列表是一個記錄了圖形處理命令的序列。在D3D11中,可以在多個線程中創建命令列表,然后又主渲染線程來發送這個命令列表到渲染硬件。

Tessellation(細分)

細分技術使得能夠用不同的精度等級(LOD,Level of detail)來渲染一個模型。GPU可以根據所需的LOD來處理輸入的模型,以得到相應負責度的實際模型。這項技術可以大大減少內存帶寬對三角形數量的限制。這項技術通過兩個新的着色器階段來實現:Hull Shader(殼着色器)和Domain Shader(域着色器)。

除了上面的4項主要的特性外,D3D11還支持:

  • 通過在創建Device的時候指定特性等級(feature level),D3D11可以在低於等級的硬件(即不完全支持D3D11規格的硬件)上運行。
  • ShaderModel 5
  • 大內存支持 支持超過4GB的資源。
  • …(有待深入了解)

 

DirectX11 不但包含了新的Direct3D 11。 還引入了兩個新的圖形組件: Direct2D和DirectWrite。

Direct2D是一套硬件加速的、立即模式的2D圖形繪制接口。(是用來取代GDI,GDI+,DirectDraw嗎?) 它能高性能、高質量地繪制2D圖形、位圖以及文本。D2D能與D3D及GDI良好地互操作。

DirectWrite支持高質量的文本渲染,與分辨率無關的字體輪廓線繪制,全unicode文本支持及布局處理等等。

 

在D3D API 中, Device(設備)是一個核心的概念,Device是對一個圖形硬件的抽象,它負責創建和銷毀其他的對象,渲染圖元等功能。D3D11中,Device對象主要用來管理資源,而DeviceContext對象執行渲染操作。一個對象只能被創建它的Device使用。多個Device可以通過共享資源來共享數據,但這個共享的資源也只能在創建它的Device內使用。(意思就是說多個Device都可以訪問共享對象里面的數據,但處了創建Device之外,其他Device不能直接把這個資源連接到渲染管線上使用)

每個Device都由一個ID3D11Device接口來代表,可以通過D3D11CreateDevice或者D3D11CreateDeviceAndSwapChain函數來創建這個接口。每個Device都可以使用一個或多個DeviceContext,這主要是用來支持多線程操作。

D3D11CreateDevice函數的原型如下:

HRESULT D3D11CreateDevice(IDXGIAdapter*pAdapter,D3D_DRIVER_TYPEDriverType,HMODULESoftware,UINTFlags,CONST D3D_FEATURE_LEVEL*pFeatureLevels,UINTFeatureLevels,UINTSDKVersion,ID3D11Device **ppDevice,D3D_FEATURE_LEVEL*pFeatureLevel,ID3D11DeviceContext **ppImmediateContext);

參數解析:

IDXGIAdapter *pAdapter: 顯示適配器接口。表示要創建的Device與這個適配器硬件對應。一台電腦上可能安裝多個顯示適配器(即顯卡),可以使用IDXGIFactory::EnumAdapters函數來遍歷所有的適配器。傳入NULL的話就表示使用默認的適配器(你的電腦上至少應該有一個顯卡吧)。

D3D_DRIVER_TYPEDriverType:創建的Device的類型。可能的值有:

  • D3D_DRIVER_TYPE_UNKNOWN: 未知類型,創建設備時不能使用
  • D3D_DRIVER_TYPE_HARDWARE: 硬件設備,指使用硬件來實現D3D的功能。它使用硬件來加速D3D功能,並用軟件實現硬件不支持的部分,因此能提供最好的性能。這一種設備類型通常都用一個HAL(Hardware Abstraction Layer,硬件抽象層)來代表。
  • D3D_DRIVER_TYPE_REFERENCE: 參考設備,即使用軟件(CPU上運行)來實現D3D的所有功能。參考設備注重功能的准確性而不保證速度。因此主要用來做功能的測試、演示與調試等。參考設備由DirectXSDK提供(D3D11Ref.dll ?)。這個設備通常叫做REF Device或Reference rasterizer(光柵器)
  • D3D_DRIVER_TYPE_NULL: 空設備,即不提供D3D渲染功能的設備,它主要用來測試一些非測試的API的功能。它也是由DirectXSDK提供。
  • D3D_DRIVER_TYPE_SOFTWARE:  軟件渲染器,也是由軟件實現D3D的所有功能。這個渲染器必須由用戶自己實現,並通過一個DLL提供。
  • D3D_DRIVER_TYPE_WARP: Windows Advanced Resterization Platform。 一個高性能的軟件光柵器。提供特性集9.1到10.1的支持。

HMODULESoftware:軟件渲染器DLL,如果不用軟件渲染器的話,傳入NULL

UINTFlags:創建標記,這寫標記主要用來控制創建的Device中的層次,這些標記可以按位與操作。如果不特別指定的話,傳入0。  D3D11_CREATE_DEVICE_FLAG 的取值有:

  • D3D11_CREATE_DEVICE_SINGLETHREADED = 0x1,  設置Device為單線程使用。D3D11默認是支持多線程使用的,即在每個API的調用中都會進行鎖保護。如果確定不會在多線程環境中使用,則設置該標記,則不會進行鎖保護,這樣可以提高性能。
  • D3D11_CREATE_DEVICE_DEBUG = 0x2,  讓Device支持調試層
  • D3D11_CREATE_DEVICE_SWITCH_TO_REF = 0x4,  同時創建REF和HAL設備,這樣就可以在運行時進行切換,以支持調試功能。
  • D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8,  阻止創建多線程(這個需要深入了解)
  • D3D11_CREATE_DEVICE_BGRA_SUPPORT = 0x20, 在允許D2D與D3D互操作時設置

CONST D3D_FEATURE_LEVEL *pFeatureLevels, UINTFeatureLevels:指向一組特征集。創建函數會按順序嘗試這些特征集,並選擇第一個能支持的特征集。傳入NULL的話,則會依次嘗試從高到低(SM5->SM2)的所有特征集。  特征集的可選項有:

  • D3D_FEATURE_LEVEL_9_1 = 0x9100,   SM2
  • D3D_FEATURE_LEVEL_9_2 = 0x9200,   SM2
  • D3D_FEATURE_LEVEL_9_3 = 0x9300,    SM3
  • D3D_FEATURE_LEVEL_10_0 = 0xa000,    SM4
  • D3D_FEATURE_LEVEL_10_1 = 0xa100,    SM4
  • D3D_FEATURE_LEVEL_11_0 = 0xb000,    SM5

UINTSDKVersion: SDK版本,傳入D3D11_SDK_VERSION,這是由SDK設置的一個常數

ID3D11Device **ppDevice,D3D_FEATURE_LEVEL *pFeatureLevel,ID3D11DeviceContext**ppImmediateContext  三個返回值,返回創建的Device,立即DeviceContext及當前的特征集。

Device Context 包含了Device的環境或設置。更精確地說,DeviceContext用來設置渲染狀態,產生渲染命令,並使用資源。D3D11實現了兩種Context,一種是立即渲染(immediate rendering),一種是延遲渲染(deferred rendering)。它們都由ID3D11DeviceContext接口代表。每個線程只能有一個Context,一般主線程擁有立即Context,用於渲染,其他工作線程擁有延遲Context。

一個Device有且只有一個立即Context,它用來直接繪制到硬件,它能夠從GPU獲取數據,也可以用來立即執行(或回放)一個命令列表。立即Context可以在創建Device時獲取,也可以通過ID3D11Device::GetImmediateContext()接口獲取。

延遲Context將GPU命令記錄到命令列表之中。它主要用來在主線程之外記錄渲染命令。創建延遲Context時將不會繼承任何的立即Context的狀態。延遲Context通過ID3D11Device::CreateDeferredContext()接口創建。

ID3D11Device接口函數都是線程安全的,但ID3D11DeviceContext接口不是線程安全的,即必須只能在一個線程內進行調用。這區別於ID3D10Device接口。

 

 

D3D11 運行時是按照層次構建的,核心層提供了最基本的功能,外圍層則提供了一些可選功能及輔助程序員進行開發的功能。通常來講,外圍層添加新的功能,但不改變里層的已有行為。在創建設備時核心層是必須的,外圍層可以使用D3D11_CREATE_DEVICE_FLAG標記進行配置。

Core Layer: 核心層默認就被創建。它提供了圖形設備驅動和API之間的簡單映射。它只提供最關鍵性的校驗,以盡量減少開銷,提供最佳的性能。

Debug Layer: 調試層提供了更多的一致性檢查,並提供更多新返回信息。這會導致一定的性能損失,並且需要額外的DLL來支持(D3D11SDKLayers.dll)

所以,在發布版本中只保留Core Layer,而在開發過程中可以使用Debug Layer。

 

 

 

資源為渲染管線提供數據。它可以是從外部載入的,也可以在運行時動態生成。典型的資源包括紋理數據、頂點數據(幾何數據)和着色器數據。資源可以是強類型的或無類型的。也可以指定資源的讀寫屬性。資源可以被CPU或/和GPU訪問。每個渲染管線狀態至多可以有128個活動的資源。

有兩種方式指定資源的內存布局(即格式),一種是在創建資源時,另一種是在將資源綁定到管線上時。前一種稱為有類型的資源,后一種稱為無類型資源。無類型資源可以通過資源視圖來指導類型並綁定到渲染管線上,一個資源可以同時擁有多個視圖,並同時綁定到多個渲染管線階段上。

資源主要分為紋理和緩存兩大類。

D3D11資源系統的類圖如下:

D3D11Resouces

渲染管線狀態根據一個視圖來解析資源數據。一個視圖就像一種轉換,將數據解析成適合某種用途的格式。

四種視圖:

子資源(Subresource) 是一個資源的一部分。一個Buffer資源只有一個子資源,而紋理資源根據維、Mipmap及array的不同,會有多種情況。紋理的每一個Mipmap等級,array中的每個元素都單獨構成一個子資源。

Buffer是用來存放描述幾何體的數據,幾何體索引數據以及着色器數據。buffer資源必須是有類型的,一個buffer是由一個個元素組成的,每個元素由一到4個組件組成。

Buffer可以用來存放頂點數據,法線數據,紋理坐標,索引,以及設備狀態等。 Buffer分為3種:

VertexBuffer(頂點緩存) 存放每個頂點的數據

IndexBuffer(索引緩存) 存放頂點索引數據

ConstantBuffer(常數緩存) 存放着色器常量數據,也可以存放Stream-output的輸出。從概念上講,它就像一個單組件元素的數組。常數緩存只能使用D3D11_BIND_CONSTANT_BUFFER綁定。常數緩存的大小必須是16bytes的整數倍,而且必須小於或等於D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT

Buffer使用ID3D11Device::CreateBuffer接口進行創建

HRESULT CreateBuffer(const D3D11_BUFFER_DESC *pDesc,const D3D11_SUBRESOURCE_DATA*pInitialData,ID3D11Buffer **ppBuffer);

參數解析如下:

const D3D11_BUFFER_DESC *pDesc: buffer描述結構

  • UINT ByteWidth; Buffer的總大小,以byte記。
  • D3D11_USAGE Usage;  Buffer的用途,即讀寫屬性。這主要根據對buffer的訪問/更新頻率來確定。
  • UINT BindFlags;  指定Buffer如何綁定到渲染管線上。這個值是可以是D3D11_BIND_FLAG 的值的“或”,但通常只選擇一種綁定方式。
  • UINT CPUAccessFlags;  Buffer的CPU訪問權限,0表示CPU無法讀寫
  • UINT MiscFlags; 其他輔助功能選項。
  • UINT StructureByteStride;  當作為有結構的Buffer時,結構的大小

 

 

DXGI(DirectX Graphics Infrastructure,DirectX 圖形基礎架構) 提供了對圖形硬件進行底層管理的功能。這些功能不涉及顯卡的高級特性(比如不需要區別D3D9級別顯卡和D3D11級別顯卡),因此是與D3D的圖形功能是分開的。 DXGI是提供了一個底層的通用框架來支持未來的硬件。DXGI最初是在D3D10中引入的。現在它支持D3D11。即DXGI和D3D可以分開進行進化,而且DXGI的進化應該比D3D慢。

DXGI的主要功能有:枚舉顯示硬件設備,將渲染好的幀呈現到輸出設備,調整Gamma,以及全屏模式的切換等。DXGI的目的是溝通核心模式驅動和系統硬件。一個應用程序可以直接調用DXGI接口,也可以通過D3D接口間接使用DXGI的功能。

DXGI類結構圖如下:

 

枚舉顯示適配器(Adapter)

適配器是對顯示硬件或軟件的抽象,它可以是一個顯卡,也可以是一個軟件渲染器。一台計算機可以有多個適配器。一個適配器可以有一個或多個輸出終端(Monitor)。每個輸出終端用一個IDXGIOutput接口來代表,適配器用IDXGIAdapter來代表。IDXGIFactory用來枚舉Adapter

呈現(Presentation)

D3D的功能是渲染到幀緩存,然后DXGI將幀呈現到輸出終端上。為了得到最好的性能和效果,至少需要兩個緩存,一個用於D3D的繪制,一個用於DXGI的呈現。也可能有不止兩個的幀。這樣一組幀緩存就組成一個交換鏈(Swap Chain)SwapChain用IDXGISwapChain接口來表示。SwapChain有一個前緩存,一到多個后緩存。為了得到最好的效率SwapChain總是創建在顯示子系統(這個顯示子系統就是一個適配器)中,這個系統包括GPU,DAC(Digital to Analog Converter,數模轉換器)以及內存。這個子系統通常是一個顯卡,但也可能在主板上實現。SwapChain分配在顯示子系統的內存中以提高呈現的速度。顯示子系統負責把SwapChain 前緩存的數據呈現到輸出終端上。SwapChain可以被設置使用全屏或窗口模式繪制,這樣就不需要知道顯示終端是全屏幕還是一個窗口。全屏模式的SwapChain能切換顯示器的分辨率以優化性能。

創建SwapChain

SwapChain包含一組Buffer,它們都有相同的尺寸和格式。SwapChain由IDXGIFactory::CreateSwapChain 函數創建。

HRESULT CreateSwapChain(IUnknown *pDevice,DXGI_SWAP_CHAIN_DESC*pDesc,IDXGISwapChain **ppSwapChain);

參數解析如下:

IUnknown *pDevice: D3D Device,SwapChain在創建時就必須綁定到Device。這個Device將繪制到SwapChain的Buffer中。

DXGI_SWAP_CHAIN_DESC *pDesc: SwapChain描述結構。字段有:

  • DXGI_MODE_DESC BufferDesc;  設置顯示模式,比如分辨率,刷新率,緩存格式,掃描線模式,縮放模式。默認選項都是0,所以只需要改變你想改變的值。
  • DXGI_SAMPLE_DESC SampleDesc;  設置多重采樣(multi-sampling)參數包括每像素的采樣數量及圖形質量等級。默認不進行多重采樣,則兩個數值分別為1和0
  • DXGI_USAGE BufferUsage; 設置表面的用法及CPU的訪問選項。后緩存可以作為着色器的輸入或者渲染目標。
  • UINT BufferCount; 緩存的數量,包括前緩存,
  • HWND OutputWindow; 顯示窗口,不能為空
  • BOOL Windowed; 是否窗口模式
  • DXGI_SWAP_EFFECT SwapEffect;  設置當表面呈現之后對緩存的處理方式。可選方式為:DXGI_SWAP_EFFECT_DISCARD = 0, 丟棄緩存,即緩存內容將不再被使用。應用程序只能操作索引為0的緩存。 DXGI_SWAP_EFFECT_SEQUENTIAL = 1, 緩存將不會被丟棄,按順序使用緩存鏈中的緩存,不能在多重采樣時使用。
  • UINT Flags; 其他可選項。DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1, 關閉圖像自動旋轉DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2, 允許切換顯示模式。DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4, 允許使用GDI來訪問緩存。

 

 

D3D11 的圖形渲染管線是在D3D10 的基礎上進行擴展而得到的。D3D10的功能都得到了保留,並添加了一些新的特性。

d3d11Pipeline

兩個主要的新特性就是ComputerShader和Tessellation技術。注意ComputerShader並不是對圖形渲染的功能的擴展,所以沒有在渲染管線上體現出來。

 

 

DirectX Effect(特效?)是一組管線狀態的集合。如何組織管線狀態,也就決定了會得到什么樣的渲染結果,所以Effect這個名字是名副其實的。Effect中的表達式是用HLSL語言寫成的,再加上一些Effect特定的語法。經過編譯以后,EffectAPI就可以加載Effect並控制渲染硬件進行渲染。Effect不止可以控制可編程階段的着色器,也可以控制不可編程階段的設置。

Effect可以管理的狀態包括:着色器狀態(shader state),在着色器中使用的紋理及采樣狀態(Texture and Sampler state),非可編程管線階段狀態。effect代碼是純文本形式的,通常以fx為擴展名。

一個Effect文件中可以包含多個渲染效果,每個渲染效果是一組完整的狀態集合,這組集合稱為一個Technique。通常的做法是把適合不同硬件平台的效果放到不同的Technique中。一組Technique可以組織到一個group中(使用fxgroup)。通常可以這樣組織:一個Effect文件包含多個Group,每個Group表示一種材質(即渲染效果),每個Group包含多個Technique,用來對應不同的硬件等級(配置),每個Technique都可以由一到多個pass組成。

Effect系統API是作為D3DX庫的一部分提供的,即它不是D3D核心API。它只是作為一個輔助工具提供,在實際開發中完全可以不用Effect來組織你的Material。

Effect系統API的意義都很直接,與Effect文件的內容也幾乎是一一對應的,只是為應用程序提供了一個接口使用Effect文件以及與Effect交換數據。

奇怪的是,D3D11的經典Sample Basic HLSL 也沒有使用ID3DX11Effect接口。Effect看起來很強大,但實際上還是不夠靈活啊。

 

 

D3D11支持在多線程中進行對象的創建和渲染。多線程的主要目的是調高性能。

D3D11的多線程支持分為兩個部分:

1 多線程式的對象創建

2 立即渲染與延遲渲染

 

 

 

 

 

 

 

 

 

再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM