从一个三角形开始看DX 12,DX11对比-1
上篇帖子讲述了DX12一个有意思的功能: AFR多显示适配器的工作原理。从本帖开始,将从绘制一个三角形开始慢速介绍DX12的每一个特点并且和DX11对比。本帖属于入门贴但是跳过DX12大概述*(因为网上都说了)。这个帖子讲述的内容会很少但是以后会追加内容度。 DX12的相关结构定义和设备初始化DX11的相关结构定义和设备初始化
DX11:D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
不必纠结代码,D3D11的CreateDevice创建起一个特点就是要传递一个要初始化的ID3D11DeviceContext指针对象。ID3D11DeviceContext在D3D11里面的很多功能开发操作都会用到,而且ID3D11DeviceContext里面的功能是依赖于显卡驱动的。
而且D3D11的每个相关状态的切换都要单独控制。
DX12: ComPtr<IDXGIAdapter1> hardwareAdapter;
GetHardwareAdapter(factory.Get(), &hardwareAdapter);
ThrowIfFailed(D3D12CreateDevice(
hardwareAdapter.Get(),
D3D_FEATURE_LEVEL_12_1,
IID_PPV_ARGS(&m_device)
));
}
// Describe and create the command queue.
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ThrowIfFailed(m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue)));
// Describe and create the swap chain.
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = FrameCount;
swapChainDesc.BufferDesc.Width = m_width;
swapChainDesc.BufferDesc.Height = m_height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.OutputWindow = Win32Application::GetHwnd();
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
ComPtr<IDXGISwapChain> swapChain;
ThrowIfFailed(factory->CreateSwapChain(
m_commandQueue.Get(), // Swap chain needs the queue so that it can force a flush on it.
&swapChainDesc,
&swapChain
));
ThrowIfFailed(swapChain.As(&m_swapChain));
// This sample does not support fullscreen transitions.
ThrowIfFailed(factory->MakeWindowAssociation(Win32Application::GetHwnd(), DXGI_MWA_NO_ALT_ENTER));
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
// Create descriptor heaps.
{
// Describe and create a render target view (RTV) descriptor heap.
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = FrameCount;
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
// Create frame resources.
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
// Create a RTV for each frame.
for (UINT n = 0; n < FrameCount; n++)
{
ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets)));
m_device->CreateRenderTargetView(m_renderTargets.Get(), nullptr, rtvHandle);
rtvHandle.Offset(1, m_rtvDescriptorSize);
}
}
CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)));
DX12的设备创建只需要你拿到硬件显示适配器并且指定D3D_FEATURE_LEVEL就可以了。
而原先DX11里D3D11DeviceContext交由具体开发人员自己来完成。
DX12相关状态的切换
首先需要开发人员CreateGraphicsPipelineState(
_In_const D3D12_GRAPHICS_PIPELINE_STATE_DESC *pDesc,
REFIID riid,
_COM_Outptr_void **ppPipelineState) 创建一个统一的图形流水线的状态。
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
psoDesc.pRootSignature = m_rootSignature.Get();
psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats = DXGI_FORMAT_R8G8B8A8_UNORM;
psoDesc.SampleDesc.Count = 1;
ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)));
DX12在相关渲染状态更新时,只在必要的时候去更新整个的图形流水线状态,不会像DX11那样频繁的切换每个单独的类型状态。
今天先介绍DX12和DX11两个明显不同的地方,后续帖子将讲述DX12,DX11绘制三角形的全过程。
今天讲述的内容比较少也可以说很少,因为DX12本身相比DX11对于程序人员都很难理解,若想学习好DX12,还必须了解硬件相关的。因为发的都是技术贴,要大家慢慢吸收。
今后一系列帖子只讨论技术,不讨论PC显卡好坏。因为由于我个人工作,爱好的原因我配置台式机,基本每配置一次至少两台机器,都是高端机,N卡旗舰一台,A卡期间一台,有代表性的每一代我都不会放过,如果赶上我自己研究新技术需要测试,那机器不会就两台,显卡数量就要看需要了。
我个人并不关心两厂显卡谁家强。因为反正我一样有俩,在上我业余时间PC只玩三大厂游戏。
PS:微星主板内存通道坏了一次,还好在售后期就换了一个 谢谢楼主的技术贴,做个记号 创建渲染前一来就是上指针,没问题?
fastone 发表于 2016-2-28 09:04
创建渲染前一来就是上指针,没问题?
传进去之后会被赋值
科普性好强,赞一个
建议以后中文解说部分标红,不然看起来有点点累 楼主讲讲原理就好吧,编程就记得一个hollo world{:1_509:} 这类帖子很少有人懂的
所以要顶一顶! 马克吐槽 发表于 2016-2-29 12:32
楼主讲讲原理就好吧,编程就记得一个hollo world
DX12那个原理的话,网上一堆,如果是写hallo worldDX12上面一堆东西依然要讲,因为实际纯DX12开发驱动部分基本是让程序员自己去写,同时包括DX11 要了解也需要先了解开头的驱动加载,不然写hallo world也没用,所以SCE的工程师才这样写这个文章的 fastone 发表于 2016-2-29 19:27
DX12那个原理的话,网上一堆,如果是写hallo worldDX12上面一堆东西依然要讲,因为实际纯DX12开发驱动 ...
谢谢,懂得。还有点建议。比如可以教教大家怎么玩这些编程,大学工科毕业的都会有这方面基础吧,就是需要点提示。比如用什么运行环境,代码也分享一下别用截图,这样我在自己电脑里也能玩玩{:1_456:}
{:1_464:}大概能看懂代码,不过还是建议排个版说详细点 c++的,dx12应该只能在win10下编译吧,毕竟win7是不支持dx12的。
代码截图看起来不方便,直接贴代码又没语法高亮。 拜读,技术贴,纯支持了! 技术贴 mark一下{:1_474:}
页:
[1]