Direct3D 12 尝鲜: 基本呈现

(转载请注明出处)

请叫我挖坑狂魔_(:3」∠)_

微软前几天发布了Win10的开发工具,希望使用的童鞋可以加入windows insider计划 进行下载.

下面是我的环境:

当然,使用的是虚拟机.

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),

那么威尼斯就是一艘轻盈和流动的舟船,

Direct3D 12 尝鲜: 基本呈现

相关文章:

你感兴趣的文章:

标签云: