從 Direct3D 11 移植到 Direct3D 12

本節提供從自訂 Direct3D 11 圖形引擎移植到 Direct3D 12 的一些指引。

裝置建立

Direct3D 11 和 Direct3D 12 共用類似的裝置建立模式。 現有的 Direct3D 12 驅動程式全都 D3D_FEATURE_LEVEL_11_0 或更好,因此您可以忽略較舊的功能層級和相關聯的限制。

也請記住,使用 Direct3D 12 時,您應該使用 DXGI 介面明確列舉裝置資訊。 在 Direct3D 11 中,您可以從 Direct3D 裝置 鏈結回 DXGI 裝置,而且 Direct3D 12 不支援此功能。

藉由提供從 IDXGIFactory4::EnumWarpAdapter取得的明確配接器,即可在 Direct3D 12 上建立 WARP 軟體裝置。 Direct3D 12 的 WARP 裝置僅適用于已啟用 圖形工具 選用功能的系統上。

注意

沒有相當於 D3D11CreateDeviceAndSwapChain。 即使使用 Direct3D 11,我們也不建議使用此函式,因為最好是在不同的步驟中建立裝置和交換鏈。

認可資源

在 Direct3D 11 中使用下列介面建立的物件,會轉譯為 Direct3D 12 中稱為「認可資源」的物件。 已認可的資源是一個資源,其具有虛擬位址空間和與其相關聯的實體頁面。 這是 Microsoft Windows Device Driver 2 (WDD2) 記憶體模型的概念,Direct3D 12 是以此模型為基礎。

Direct3D 11 資源:

在 Direct3D 12 中,這些全都以 ID3D12ResourceID3D12Device::CreateCommittedResource表示。

保留的資源

保留的資源是只配置虛擬位址空間的資源,在呼叫 ID3D12Device::CreateHeap之前,不會配置實體記憶體。 這基本上與 Direct3D 11 中的磚資源概念相同。

旗標 (D3D11_RESOURCE_MISC_FLAG) Direct3D 11 中用來設定磚資源,然後將它們對應至實體記憶體。

  • D3D11_RESOURCE_MISC_TILED
  • D3D11_RESOURCE_MISC_TILE_POOL

上傳資料

在 Direct3D 11 中,單一時間軸的外觀 (依序呼叫,例如使用 D3D11_SUBRESOURCE_DATA初始化的資料,然後呼叫 ID3D11DeviceCoNtext::UpdateSubresource,然後呼叫 ID3D11DeviceCoNtext::Map) 。 Direct3D 11 開發人員看不到建立資料的複本數目。

在 Direct3D 12 中有兩個時程表,GPU 時間軸 (透過呼叫 CopyTextureRegion來設定,以及從可對應記憶體) 的 CopyBufferRegion ,以及呼叫 Map) 所決定的 CPU 時間軸 (。 協助程式函式會在 d3dx12.h 檔案中提供 (,) 稱為使用共用時程表 的 Updatesubresources 。 此協助程式函式有數種變化,一個使用 ID3D12Device::GetCopyableFootprints、另一個使用堆積配置機制,另一個使用堆疊配置機制。 這些協助程式函式會透過記憶體的中繼預備區域,將資源複製到 GPU 和 CPU。

GPU 和 CPU 通常會有自己的資源複本,並系結至自己的時程表。 共用時程表方法同樣會維護兩個複本。

著色器和著色器物件

在 Direct3D 11 中,有許多著色器和狀態物件建立,並使用 ID3D11Device 建立方法和 ID3D11DeviceCoNtext set 方法設定這些物件的狀態。 這些方法通常會進行大量的呼叫,然後由驅動程式在繪製時間合併,以設定正確的管線狀態。

在 Direct3D 12 中,此管線狀態的設定已結合成單一物件, (計算引擎的 CreateComputePipelineState ,而圖形引擎的 CreateGraphicsPipelineState) ,然後附加至命令清單,再呼叫 SetPipelineState

這些呼叫會取代 Direct3D 11 中設定著色器、輸入配置、混合狀態、點陣化狀態、深度樣板狀態等所有個別呼叫

  • 裝置 11 方法: CreateInputLayoutCreateXShaderCreateDepthStencilStateCreateRasterizerState
  • 裝置內容 11 方法: IASetInputLayoutxxSetShaderOMSetBlendStateOMSetDepthStencilState 、 和 RSSetState

雖然 Direct3D 12 可以支援較舊的編譯著色器 Blob,但應該使用著色器模型 5.1 與 FXC/D3DCompile API,或使用 DXIL DXC 編譯器使用著色器模型 6 來建置著色器。 您應該使用 CheckFeatureSupportD3D12_FEATURE_SHADER_MODEL來驗證著色器模型 6 支援。

將工作提交至 GPU

在 Direct3D 11 中,對於實際提交工作的方式沒有控制權,它主要是由驅動程式處理,不過某些控制項是透過 ID3D11DeviceCoNtext::FlushIDXGISwapChain1::P resent1 呼叫來啟用。

在 Direct3D 12 工作提交中,應用程式非常明確且受到控制。 提交工作的主要建構是 ID3D12GraphicsCommandList,用來記錄所有應用程式命令 (,在概念上與 ID3D11 延後的內容) 相當類似。 命令清單的備份存放區是由 ID3D12CommandAllocator所提供,可讓應用程式實際公開 Direct3D 12 驅動程式用來儲存命令清單的記憶體使用率。

最後 ,ID3D12CommandQueue 是第一個先出佇列,可儲存命令清單的正確順序以提交至 GPU。 只有當一個命令清單在 GPU 上完成執行時,驅動程式才會提交來自佇列的下一個命令清單。

在 Direct3D 11 中,沒有明確的命令佇列概念。 在 Direct3D 12 的常見設定中,目前框架目前開啟 的D3D12_COMMAND_LIST_TYPE_DIRECT 命令清單可以視為類似 Direct3D 11 立即內容。 這提供許多相同的函式。

D3D11DeviceCoNtext ID3D12GraphicsCommand List
ClearDepthStencilView ClearDepthStencilView
ClearRenderTargetView ClearRenderTargetView
ClearUnorderedAccess* ClearUnorderedAccess*
Draw、DrawInstanced DrawInstanced
DrawIndexed、DrawIndexedInstanced DrawIndexedInstanced
分派 分派
IASetInputLayout、xxSetShader 等等。 SetPipelineState
OMSetBlendState OMSetBlendFactor
OMSetDepthStencilState OMSetStencilRef
OMSetRenderTargets OMSetRenderTargets
RSSetViewports RSSetViewports
RSSetScissorRects RSSetScissorRects
IASetPrimitiveTopology IASetPrimitiveTopology
IASetVertexBuffers IASetVertexBuffers
IASetIndexBuffer IASetIndexBuffer
ResolveSubresource ResolveSubresource
CopySubresourceRegion CopyBufferRegion
UpdateSubresource CopyTextureRegion
CopyResource CopyResource

注意

使用 D3D12_COMMAND_LIST_TYPE_BUNDLE 建立的命令清單類似于延遲的內容。 Direct3D 12 也支援透過D3D12_COMMAND_LIST_TYPE_COPYD3D12_COMMAND_LIST_TYPE_COMPUTE命令清單類型同時存取即時內容的某些功能。

CPU/GPU 同步處理

在 Direct3D 11 CPU/GPU 同步處理中,大部分是自動的,而且不需要應用程式維護實體記憶體的狀態。

在 Direct3D 12 中,應用程式必須明確管理兩個時間軸 (CPU 和 GPU) 。 這需要由應用程式維護資訊、GPU 所需的資源,以及多久時間。 這也表示應用程式負責確保資源的內容 (認可的資源、堆積、命令配置器,例如,在 GPU 完成使用這些資源之前,) 不會變更。

同步時間軸的主要物件是 ID3D12Fence 物件。 柵欄的作業相當簡單,可讓 GPU 在工作完成時發出訊號。 GPU 和 CPU 可以同時發出訊號,而且可以等候柵欄。

一般而言,當提交命令清單以供執行時,GPU 會在完成時傳輸柵欄訊號, (完成時傳送資料) ,讓 CPU 能夠重複使用或終結資源。

在 Direct3D 11 中, ID3D11DeviceCoNtext::Map 旗標D3D11_MAP_WRITE_DISCARD基本上會將每個資源視為無止盡的記憶體供應,應用程式可以寫入 (稱為「重新命名」) 的進程。 再次在 Direct3D 12 中,程式是明確的:需要配置額外的記憶體,而且應該使用柵欄來同步處理作業。 信號緩衝區 (包含大型緩衝區) 可能是很好的技巧,請參閱 柵欄式資源管理中的環形緩衝區案例。

使用環形緩衝區

資源系結

Direct3D 11 中的檢視 (著色器資源檢視、轉譯目標檢視等) ,在 Direct3D 12 中已大幅取代為描述元的概念。 建立方法仍存在於 Direct3D 12 (中,例如 CreateShaderResourceViewCreateRenderTargetView) ,在建立描述元堆積之後呼叫,以將資料寫入堆積。 Direct3D 12 中的系結現在由根簽章中所述的描述項控制碼處理,並使用 SetGraphicsRootDescriptorTableSetComputeRootDescriptorTable 方法提交。

根簽章詳述根簽章位置編號和描述中繼資料表之間的對應,其中描述中繼資料表可以包含頂點著色器、圖元著色器和其他著色器的參考,例如常數緩衝區、著色器資源檢視和取樣器。 此彈性會中斷 HLSL 暫存器空間與 Direct3D 12 中 API 系結空間的連線,與 Direct3D 11 不同,這些對應之間有一對一的對應。

此系統的其中一個含意是應用程式負責重新命名描述中繼資料表,讓開發人員瞭解變更每一繪製呼叫之單一描述元的效能成本。

Direct3D 12 的新功能是應用程式可以控制哪些描述項會在哪些著色器階段之間共用。 在 Direct3D 11 資源中,例如 UAV 會在所有著色器階段之間共用。 藉由啟用特定著色器階段停用描述項,已停用之描述元所使用的暫存器可供特定著色器階段啟用的描述項使用。

下表顯示範例根簽章。

根參數位置 描述項資料表專案
0 VS 描述元範圍 b0-b13
1 VS 描述元範圍 t0-t127
2 VS 描述元範圍 s0-s16
3 PS 描述元範圍 b0-b13
...
14 DS 描述元範圍 s0-16
15 共用描述項範圍 u0-u63

 

資源狀態

應用程式不會維護 Direct3D 11 資源狀態,而是由驅動程式維護。

在 Direct3D 12 中,維護資源狀態會成為應用程式的責任,若要在命令清單的錄製中啟用完整平行處理原則:應用程式必須處理命令清單的錄製時程表, (可以平行) 完成,以及必須循序的執行時程表。

ResourceBarrier方法會處理資源狀態轉換。 主要是應用程式必須在資源使用量變更時通知驅動程式。 例如,如果資源用來做為轉譯目標,然後在下一次繪製呼叫時用來做為頂點著色器的輸入,則可能需要在 GPU 作業中短暫停止,才能處理頂點著色器之前完成轉譯目標作業。

此系統可在圖形管線的 GPU 停止) (細微同步處理,以及快取排清,以及某些記憶體配置變更 (例如轉譯目標檢視到深度樣板檢視解壓縮) 。

這稱為轉換屏障。 Direct3D 11 中還有其他種類的屏障, ID3D11DeviceCoNtext2::TiledResourceBarrier 已啟用兩個不同的並排資源使用相同的實體記憶體。 在 Direct3D 12 中,這稱為「別名屏障」。 別名屏障可用於 Direct3D 12 中並排和放置的資源。 此外,還有 UAV 屏障。 在 Direct3D 11 中,所有 UAV 分派和繪製作業都必須序列化,即使這些作業可以管線處理或平行運作也一樣。 針對 Direct3D 12,新增 UAV 屏障會移除這項限制。 UAV 屏障可確保 UAV 作業是循序的,因此,如果第二個作業需要第一個完成,則會強制第二個作業等待加入屏障。 UAV 的預設作業只是作業會儘快繼續進行。

如果工作負載可以平行處理,則明顯會有效能提升。

交換鏈結

DXGI 交換鏈結是 Direct3D 11 和 12 中交換鏈結的基礎。 Direct3D 11 有一些微差異,交換鏈結的三種類型為 SEQUENTIAL、DISCARD 和 FLIP_SEQUENTIAL。 針對 Direct3D 12,只有兩種類型:FLIP_SEQUENTIAL 和 FLIP_DISCARD。 如上所述,您應該透過 IDXGIFactory4或更新版本明確建立交換鏈,並針對任何配接器列舉使用相同的介面。

在 Direct3D 11 中,有自動反緩衝器旋轉:後端緩衝區 0 只需要一個轉譯目標檢視。 在 Direct3D 12 緩衝區旋轉是明確的,每個背景緩衝區都必須有轉譯目標檢視。 使用 IDXGISwapChain3::GetCurrentBackBufferIndex 方法來選取要轉譯的 IDXGISwapChain3::GetCurrentBackBufferIndex 方法。 同樣地,這個額外的彈性可提高平行處理。

注意

雖然有許多方式可以設定您的應用程式,但應用程式通常每個交換鏈結緩衝區都有一個 ID3D12CommandAllocator 。 這可讓應用程式繼續為下一個畫面建置一組命令,同時 GPU 轉譯上一個畫面。

固定函式轉譯

在 Direct3D 11 中,有一些方法可簡化各種較高層級的作業,例如 GenerateMips (建立完整的 mip 鏈結) 和 DrawAuto (使用串流輸出作為著色器輸入,而不需進一步輸入應用程式) 。 Direct3D 12 中無法使用這些方法,應用程式必須藉由建立著色器來執行這些作業來處理這些作業。

奇數和結束

下表顯示 Direct3D 11 與 12 之間類似但不同之處的一些功能。

Direct3D 11 Direct3D 12
ID3D11Query ID3D12QueryHeap 可讓查詢群組在一起,以降低成本。
ID3D11Predicate 現在,在完全透明緩衝區中擁有資料,即可啟用預先分割。 Direct3D 11 ID3D11Predicate 物件會由 ID3D12Resource::Map取代,該物件必須遵循 ResolveQueryData 的呼叫,並使用柵欄來等候資料就緒。 請參閱 預先分割
UAV/SO 隱藏計數器 應用程式負責配置和管理 SO/UAV 計數器。 請參閱 資料流程輸出計數器UAV 計數器
資源動態 MinLOD (詳細資料) 的迷你層級 這已移至 SRV 描述元靜態 MinLOD。
Draw*Indirect/DispatchIndirect 繪圖間接方法全都會合並到一個 ExecuteIndirect 方法中。
DepthStencil 格式交錯 DepthStencil 格式是平面格式。 例如,深度為 24 位的格式,8 位樣板會以 24/8/24/8 格式儲存...Direct3D 11 中的 etc,但如 24/24/24...後面接著 8/8/8...在 Direct3D 12 中。 請注意,每個平面都是 D3D12 中自己的子資源, (參考 Subresources) 。
ResizeTilePool 保留的資源可以對應至多個堆積。 當磚集區在 D3D11 中成長時,可以改為在 D3D12 中配置額外的堆積。

 

DirectX 進階學習影片教學課程:DirectX 11 至 DirectX 12 移植指南

瞭解 Direct3D 12

使用 Direct3D 11、Direct3D 10 和 Direct2D