日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Direct3D 12 尝鲜: 基本呈现

發布時間:2023/12/14 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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設備,目前,函數聲明如下:

HRESULT WINAPI D3D12CreateDevice(IDXGIAdapter* pAdapter,D3D_DRIVER_TYPE DriverType,D3D12_CREATE_DEVICE_FLAG Flags,D3D_FEATURE_LEVEL MinimumFeatureLevel,UINT SDKVersion,REFIID riid,void** ppDevice );

第一個是顯卡適配器, 可以枚舉, 可以為nullptr,
第二個是驅動類型, 我這里是虛擬機, 所以選擇WARP
第三個是創建flag(沒有RGBA支持,也就是說不能鏈接D2D?)
第四個是特性等級, 現在還沒有12的等級,所以選擇11.1
第五個是SDK版本, 使用宏D3D12_SDK_VERSION即可
第五個第六個也就很熟悉了, 假如只是用MSC編譯, 可以使用宏
IID_PPV_ARGS,不過對于GCC等編譯器還是手寫吧:

D3D12_CREATE_DEVICE_FLAG flags = D3D12_CREATE_DEVICE_NONE; #ifdef _DEBUGflags |= D3D12_CREATE_DEVICE_DEBUG; #endifhr = ::D3D12CreateDevice(nullptr,D3D_DRIVER_TYPE_WARP,flags,D3D_FEATURE_LEVEL_11_1,D3D12_SDK_VERSION,IID_ID3D12Device,reinterpret_cast<void**>(&m_pd3dDevice));

不知道是不是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一起使用.

// 創建RTV描述符if (SUCCEEDED(hr)) {D3D12_DESCRIPTOR_HEAP_DESC desc = {D3D12_RTV_DESCRIPTOR_HEAP,1,D3D12_DESCRIPTOR_HEAP_NONE,0};hr = m_pd3dDevice->CreateDescriptorHeap(&desc, IID_ID3D12DescriptorHeap,reinterpret_cast<void**>(&m_pRTVDescriptor));}// 創建RTVif (SUCCEEDED(hr)) {m_pd3dDevice->CreateRenderTargetView(m_pTargetBuffer,nullptr,m_pRTVDescriptor->GetCPUDescriptorHandleForHeapStart());}

D3D11類似, 創建RTV, 不過沒有專用的接口了, 用這個描述符就好了, 從這里和上面可以看出, D3D12沒有了一大堆接口, 泛化了.


D3D11 中, 清屏很簡單:

  • 為當前設備上下文在OM階段設置RTV
  • 清理RTV
  • D3D12中:

  • 為某圖像命令列表在RS階段設置RTV
  • 為該命令列表對于資源(呈現緩存)設置Barrier表明從”用于呈現”變為”用于渲染對象”
  • 清除RTV
  • 設置Barrier, 變回來
  • 關閉本命令列表
  • 加入命令隊列并執行
  • 可以看出多了幾步, 其實就多了兩步: 設置資源Barrier過去, 設置Barrier回來. (因為D3D12對多線程渲染做了很多?) 資源Barrier就是為了處理資源的多個訪問.

    對于命令列表, 如果不再使用可以重置.
    這部分代碼就不放上來了, 可以看所附帶的實例代碼: 下載地址


    下面就是成果圖


    已知問題

    從輸出窗口可以看出錯誤:

    這個錯誤有機會再說吧_(:3」∠)_


    代碼下載地址在上面, 不要漏掉了

    總結

    以上是生活随笔為你收集整理的Direct3D 12 尝鲜: 基本呈现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。