DX12学习笔记(龙书)(小点3:命令队列和命令列表)

DirectX12取消了立即渲染方式,完全采用“命令列表->命令队列"模型,使多个命令列表同时记录命令,借此充分发挥多核心处理器的性能。
每个GPU有至少1个命令队列(QUEUE),
CPU可以借助direct3d API把command LIST (命令列表)提交到命令队列(QUEUE)里区。命令列表里面有许多命令。
GPU管理的命令队列是先进先出QUEUE。

看到这一章才发现。原来一开始的

在ID3D112CommandQueue中使用的ExecuteCommandLists,
并不是执行这个List中的Command,
而是把命令列表里的命令添加到命令队列之中。
ID3D12CommandList* cmdsLists[] ={mCommandList.Get()};
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists),cmdsLists);
//其中第一个参数是第二个参数中命令列表的数量,第二个参数是命令列表数组中第一个元素的指针。

1. 如何创建队列*
ID3D12CommandQueue接口表示命令队列,
ID3D12CommandAllocxator接口代表命令分配器,(分配器是干啥的?用于把命令列表放到命令队列里?还是把命令放到命令列表里?)
ID3D12GraphicsCommandList接口表示命令列表。(埃!竟然不是Command开头……)
据此,我们通过以下代码分别展示这几种对象的创建流程。


ComPtr<ID3D12CommandQueue> mCommandQueue;
ComPtr<ID3D12CommandAllocator> mDirectCmdListAlloc;
Comptr<ID3D12GraphicsCommandList> mCommandList;
//这个接口封装了一系列图形渲染命令,它实际上继承于ID3D12CommandListJIEKOU .
ID3D12GraphicsCommandList接口有数种方法向命令列表添加命令。请记住它。

关于这个GraphicsCommandList:

比如,这里列举一下各种命令:设置视口、清除渲染、发起绘制
mCommandList->RSSetViewports(1,&mScreenViewport);
mCommandList->ClearRenderTargetView(mBackBufferView,Colors::LightSteelBlue,0,nullptr);
//啊啊啊,这个mBackBufferView,就是上次说的那个描述符了!大概,通过它对描述符对应的那款缓冲区进行清除。
mCommandList->DrawIndexedInstanded(36,1,0,0,0);
//发起绘制!!话说这个后面36,1,0,0,0表示什么呢,也要分一个小点进行探讨

mCommandList->Close();//分配后之后,一定要调用这个CLOSE将其关闭。

关于这个CommandAllocator分配器。它有什么用呢。我们注意到,在创建LIST的过程中,分配器的GET()返回值被传回到了创建函数中。说明一个LIST至少需要一个分配器。
原来,记录在命令列表内的命令,实际上是储存在与之关联的命令分配器(command allocator)上的。什么!命令不是储存在commandlist中的嘛……这这这,我至少知道的是,我们在要把命令传到GPU前时,我们是通过mCommandList.get()这种类似的方法获得List数组的。。。咦,我们有很多个Commandlist…

当通过ID3D12CommandQueue::ExecuteCommandLists方法执行命令列表的时候,命令队列就会引用分配器里的命令。而命令分配器则由ID3D12Device接口来创建。

其实是说,QUEUE->(调用)commandlist中的Allocator,来把CommandList分配到QUEUE里面。

id D3DApp::CreateCommandObject()
{
D3D12_COMMAND_QUEUE_DESC queueDesc ={};   这是一个用于描述queue情况的结构体
queueDesc.Type=D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags=D3D12_COMMAND_QUEUE_FLAG_NONE;
//创建QUEUE
ThrowIfFailed(md3dDevice->CreateCommandQueue(
&queueDesc,IID_PPV_ARGS(&mCommandQueue));
//创建分配器,第一个参数type表示DX12的两种命令列表类型,一般用这个。
//第二个参数是待创建的ID3D12CommandAllocator接口的COM ID
//第三个参数是输入指向所建命令分配器的指针。(用它来玩。)
ThrowIfFailed(md3dDevice->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(mDirectCmdListAlloc.GetAddressOf()))//创建LIST,参数1是GPU的数量。2是命令列的类型。3是相关联的分配器,类型需要相互匹配。4是指定命令列表的渲染流水线初始状态。5是COM ID 。6是输出指向所建命令列表的指针。
ThrowIfFailed(md3dDevice->CreateCommandList(
0,
D3D12_COMMAND_LIST_TYPE_DIRECT,
mDirectCmdListAlloc.Get(),
numptr,
IID_PPV_ARGS(mCommandList.GetAddressOf())

mCommandList>Close();//要关闭命令列表,方便我们对其
))
}

这个CreateCommandObject函数被封在了父类里。难怪没见它。父类初始化的时候会调用它。话说初始化的时候父类做了不少事。下一个点就讲这个父类。

命令列表和命令分配器的关系:

我们可以创建出多个关联于同一分配器的列表,但是不能同时用它们来记录命令。
因此,当其中一个命令列表在记录命令时,必须关闭同一命令分配器的其他命令列表。 当创建或重置命令列表时,它会具有一种打开的状态。

命令分配器其实是为了方便重新更新commandList时,内存仍然可以保存着。免得老是分配更新就很累了。所以在ExeComandList之后,调用一下allocator的reset.,就会使得所有list的reset被调用。
时大小归零但容量保存。

由于命令队列可能会引用命令分配器中的数据,所以在没有确定GPU执行完命令分配器中的所有命令之前千万不要重置命令分配器。

你可能感兴趣的:(DX12学习笔记(龙书)(小点3:命令队列和命令列表))