[toc] First. GPU 并行架构的优势在什么时候才会体现出来?

  1. 拥有大量执行相同操作的数据时

# 线程与线程组

在 GPU 编程的过程中,根据程序具体的执行需求,可将线程划分为线程组构成的网格。 一个线程组运行于一个多处理器之上,但为了获取更好的性能,通常会令多个处理器至少拥有两个线程组 (类似于操作系统的线程)。
每个线程组内都有一块共享内存,供组内的线程访问。但是,线程并不能访问其他组中的共享内存。 一个线程组有 n 个线程。硬件实际上会将这些线程分为多个 warp,每个 warp 中有 32 个线程,而且多处理器会以 SIMD32 的方式来处理 warp,所以,处于性能的原因,通常我们总是将线程组的大小设置为 warp 尺寸的整数倍

# 启动线程组

在 Direct3D 中,可以通过下列方法来启动线程组

1
2
3
4
5
6
7
void ID3D12GraphicsCommandList::Dispatch(
UINT ThreadGroupCountX,
UINT ThreadGroupCountY,
UINT ThreadGroupCountZ,
)

cmdList->Dispatch(3,2,1);

上面代码中最后一句是派发一个总数为 3*2=6 的线程组网格

# 一个简单的 Compute Shader

将两个纹理进行简单累加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cbuffer cbSettings{
//计算着色器能访问的常量缓冲区数据
};

//数据源与着色器的输出
Texture2D gInputA;
Texture2D gInputB;
RWTexture2D<float4> gOutput;

//线程组中的线程数。组中的线程可以被设置为1D、2D或3D的网格布局
[numthreads(16,16,1)]
void CS(int3 dispatchThreadID : SV_DispatchThreadID) //线程ID
{
gOutput[dispatchThreadID.xy] =
gOutputA[dispatchThreadID.xy] + gOutputB[dispatchThreadID.xy];
}

一个计算着色器主要由下列要素构成:

  1. 通过常量缓冲区访问的全局变量
  2. 输入与输出资源
  3. [numthreads (X,Y,Z)] 属性,指定 3D 线程网格中的线程数量
  4. 每个线程都要执行的着色器指令
  5. 线程 ID 系统值参数

建议 X_Y_Z 是 32 的整数倍 (通常 Z=1 即可)