Direct3D 12 尝鲜: 基本呈现
(轉載請注明出處)
請叫我挖坑狂魔_(:3」∠)_
微軟前幾天發布了Win10的開發工具,希望使用的童鞋可以加入windows insider計劃 進行下載.
下面是我的環境:
- Windows 10 Technical Preview Build 10041
- Visual Studio 2015 CTP 6
- Visual Studio Tools for Windows 10
當然,使用的是虛擬機.
D3D12文檔可以在官方文檔里面進行查看,里面有編程向導與API文檔. 不過, 這個文檔也是初步的, 可能鏈接會失效.
初始化:
初始化COM組件和創建窗口就不再累述,直接殺入主題:
和D3D11類似, 使用D3D12CreateDevice創建D3D12設備,目前,函數聲明如下:
第一個是顯卡適配器, 可以枚舉, 可以為nullptr,
第二個是驅動類型, 我這里是虛擬機, 所以選擇WARP
第三個是創建flag(沒有RGBA支持,也就是說不能鏈接D2D?)
第四個是特性等級, 現在還沒有12的等級,所以選擇11.1
第五個是SDK版本, 使用宏D3D12_SDK_VERSION即可
第五個第六個也就很熟悉了, 假如只是用MSC編譯, 可以使用宏
IID_PPV_ARGS,不過對于GCC等編譯器還是手寫吧:
不知道是不是bug還是沒有實現還是什么原因,不能像D3D11那樣利用d3d設備獲取dxgi設備, 再balabala創建交換鏈。 所以這里利用CreateDXGIFactory2創建Dxgi工廠
hr = ::CreateDXGIFactory2(0,IID_IDXGIFactory2, reinterpret_cast<void**>(&m_pDxgiFactory));再使用IDXGIFactory2::CreateSwapChainForHwnd為窗口創建交換鏈, 需要注意的是第一個參數,用過D3D11的童鞋可能習慣性地傳個D3D12設備指針,不過這是錯誤的,調用可能沒問題, 但是呈現時會出錯,第一個參數應該傳一個ID3D12CommandQueue指針,所以我們還應該創建一個D3D12的命令隊列, 官方給的向導里面可以獲取一個默認的隊列,但是發現現在這個接口被移除了,只能直接創建了:
// 創建命令隊列if (SUCCEEDED(hr)) {D3D12_COMMAND_QUEUE_DESC desc = {D3D12_COMMAND_LIST_TYPE_DIRECT,0,D3D12_COMMAND_QUEUE_NONE,0};hr = m_pd3dDevice->CreateCommandQueue(&desc,IID_ID3D12CommandQueue,reinterpret_cast<void**>(&m_pCmdQueue));}// 創建交換鏈if (SUCCEEDED(hr)) {RECT rect = { 0 }; ::GetClientRect(m_hwnd, &rect);// 交換鏈信息DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };m_uBufferWidth = swapChainDesc.Width = rect.right - rect.left;m_uBufferHeight = swapChainDesc.Height = rect.bottom - rect.top;swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;swapChainDesc.Stereo = FALSE;swapChainDesc.SampleDesc.Count = 1;swapChainDesc.SampleDesc.Quality = 0;swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;swapChainDesc.BufferCount = 2;swapChainDesc.Scaling = DXGI_SCALING_STRETCH;swapChainDesc.Flags = 0;// 一般桌面應用程序swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;// 利用窗口句柄創建交換鏈hr = m_pDxgiFactory->CreateSwapChainForHwnd(m_pCmdQueue,m_hwnd,&swapChainDesc,nullptr,nullptr,&m_pSwapChain);}D3D12中中顯然的就是命令列表ID3D12CommandList, 其中一個實現是ID3D12GraphicsCommandList , 和Direct2D中的命令列表類似,不過可以重置.
這個圖像命令列表的特點就是用來記錄DrawCall, 完了就關閉, 然后高效重現.
為了創建圖像命令列表, 我們需要創建一個命令分配器, 因為可以指定分配器的類型, 不然可以向D2D那樣由設備上下文直接創建命令列表, 使用ID3D12Device::CreateCommandQueue:
// 創建命令隊列if (SUCCEEDED(hr)) {D3D12_COMMAND_QUEUE_DESC desc = {D3D12_COMMAND_LIST_TYPE_DIRECT,0,D3D12_COMMAND_QUEUE_NONE,0};hr = m_pd3dDevice->CreateCommandQueue(&desc,IID_ID3D12CommandQueue,reinterpret_cast<void**>(&m_pCmdQueue));}這樣創建一個D3D12_COMMAND_LIST_TYPE_DIRECT類型的分配器,這個是可以創建GPU可執行的命令列表.
現在終于可以創建一個圖像命令列表ID3D12Device::CreateCommandList了:
// 創建圖像命令列表if (SUCCEEDED(hr)) {hr = m_pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,m_pCmdAllocator,nullptr,IID_ID3D12GraphicsCommandList,reinterpret_cast<void**>(&m_pGfxCmdList));}這個圖像命令列表就和D3D11的設備上下文一樣可以執(ji)行(lu)具體渲染命令:
D3D11中, 我們可以從交換鏈中獲取一個2D紋理, 但是D3D12中就沒有2D紋理, 取代的是可以代表資源的ID3D12Resource接口, 直接獲取就行了:
// 獲取緩沖區if (SUCCEEDED(hr)) {hr = m_pSwapChain->GetBuffer(0, IID_ID3D12Resource,reinterpret_cast<void**>(&m_pTargetBuffer));}同樣地, D3D11中, 可以使用設備創建RTV
(ID3D11Device::CreateRenderTargetView),
在D3D12中, 所有的資源都被綁定到”descriptor”標識符上面,還有descriptor tables, descriptor heaps, root signature什么的,詳見資源綁定. 這里主要是descriptor 和 descriptor heap,主要區別, 前者是單個后者是連續.
因為(目前)沒有ID3D12Device::CreateDescriptor, 所以使用ID3D12Device::CreateDescriptorHeap代替, 創建一個就好了, 以后有相同資源需要綁定, 可以創建一個descriptor heap一起使用.
D3D11類似, 創建RTV, 不過沒有專用的接口了, 用這個描述符就好了, 從這里和上面可以看出, D3D12沒有了一大堆接口, 泛化了.
D3D11 中, 清屏很簡單:
D3D12中:
可以看出多了幾步, 其實就多了兩步: 設置資源Barrier過去, 設置Barrier回來. (因為D3D12對多線程渲染做了很多?) 資源Barrier就是為了處理資源的多個訪問.
對于命令列表, 如果不再使用可以重置.
這部分代碼就不放上來了, 可以看所附帶的實例代碼: 下載地址
下面就是成果圖
已知問題
從輸出窗口可以看出錯誤:
這個錯誤有機會再說吧_(:3」∠)_
代碼下載地址在上面, 不要漏掉了
總結
以上是生活随笔為你收集整理的Direct3D 12 尝鲜: 基本呈现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 更改tkinter的OptionMenu
- 下一篇: 微服务多网卡部署(eureka显示IP不