[toc]

# 前言

CPU 与 GPU 通信的时候需要进行同步,但最好的情况是不要进行同步。让 CPU 和 GPU 都会最大的发挥性能

# 命令队列和命令列表

每个 GPU 都至少维护着一个命令队列 ( command queue ,本质上是环形缓冲区)
借助 Direct3D API,CPU 可以利用命令列表 ( command list ) 将命令提交到这个队列中去。
同异步消息处理的方法,命令会异步进行处理,
这里就会产生几个问题,如命令队列被填满时,CPU 需要等待,但如果 CPU 迟迟无法传递命令进来,就会导致 GPU 等待。

# 创建命令队列

填写 D3D12_COMMAND_QUEUE_DESC 结构体来描述队列,然后通过 ID3D12Devce::CreateCommandQueue 方法创建队列 在 D3D 中,可以获取到每个类的 GUID, 通过 IID_PPV_ARGS(ppType) 宏进行判定

# 将命令列表添加到命令队列中

使用 ExecuteCommandLists 每个命令列表会在一起执行 (么?) 命令列表内的每条命令实际上是存储在与之关联的命令分配器。 创建命令分配器的接口如下:

1
2
3
4
5
HRESULT ID3D12Device::CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE type,
REFILD riid,
void **ppCommandAllocator
);

type: 指定与此命令分配器相关的命令列表类型,有两个类型,打包与 GPU 直接执行
riid: Allocator 的 COM ID
ppCommandAllocator: 输出指向所建命令分配器的指针 命令列表由以下接口创建:

参数解释

    1. nodeMask: 绑定硬件的 id
    1. type: 命令列表类型
    1. pCommandAllocator: 与所建立命令列表相关联的命令分配器。(类型必须一样)
    1. pInitialState: 指定命令列表的渲染流水线初始状态
    1. riid: COM ID
    1. ppCommandList: 输出指向所建命令列表的指针

同一个命令适配器同一时刻只能在一个命令列表上使用
但是同一个命令适配器可以绑定到多个命令列表

# CPU 与 GPU 间的同步

两个处理器并行工作时,会产生同步的问题。
如果 CPU 在一帧间对连 R 物体连续操作两次,发出两次渲染指令,就会造成错误。
为了保证 GPU 只能在渲染过老数据后再提交渲然新数据。可以通过 强制CPU等待 ,通过 Fence(围栏) 来实现这一点 (即锁)。

# 资源转换

我们通常会通过 GPU 对某个资源 R 按顺序进行先写后读这两个操作,如果在写操作还未完成前或者还没开始就对资源进行读,就会导致 资源冒险 。D3D 对每个资源设置了资源状态,需要写入资源的状态,需要读取资源的状态。GPU 会通过资源的状态防止 资源冒险 的发生。
添加状态通过 ResourceBarrier() 进行

# 命令与多线程

Direct3D 12 的设计目标是为用户提供一个高效的多线程环境,命令列表也是一种发挥 Direct3D 多线程优势的途径。
比如我们可以创建 4 个线程,分别渲染 25% 的物体。