101.性能优化-GPU-着色器优化-ComputeShader-三大参数语义
101.1 知识点
三大参数语义指什么
参数三兄弟在这里主要指的是 Compute Shader 的内核入口函数中参数的三个系统语义:
SV_GroupIDSV_GroupThreadIDSV_DispatchThreadID
语义 是 CG/HLSL 中的一种”数据标签”,用来告诉 GPU 某个变量在渲染管线或计算管线中代表什么意义。语义是 Shader 输入、输出变量的角色标签,它告诉 GPU 这个变量从哪里来、要传到哪里去、它在管线中扮演什么角色。
对于 Compute Shader 内核入口函数中主要使用的这三个语义,它们主要是告诉 GPU 这个变量从哪里来,其中需要存储什么样的数据,GPU 就会通过该变量传入对应的数据。
// 线程组配置:指定每个线程组包含的线程数量
// [numthreads(X, Y, Z)] 定义一个线程组包含 X*Y*Z 个线程
// 常见配置如 8x8x1=64 个线程,适合处理二维图像数据
[numthreads(8,8,1)]
void CSMain(uint3 id : SV_DispatchThreadID, // 全局线程 ID(在整个 Dispatch 调用中唯一)
uint3 id2 : SV_GroupID, // 线程组 ID(标识当前线程组的位置)
uint3 id3 : SV_GroupThreadID) // 线程组内线程 ID(在线程组内唯一)
{
// 类型转换示例:将 4x4 矩阵转换为 2x2 矩阵(截取左上角 2x2 部分)
f22 = (float2x2)f44;
// 核心计算逻辑:根据线程 ID 生成棋盘格图案
// R 通道:id.x 和 id.y 的按位与结果
// G 通道:id.x 的低 4 位映射到 [0,1] 范围
// B 通道:id.y 的低 4 位映射到 [0,1] 范围
// A 通道:固定为 0.0(完全透明)
Result[id.xy] = float4(id.x & id.y, (id.x & 15) / 15.0, (id.y & 15) / 15.0, 0.0);
}
三大参数语义的区别
入口函数传入的数据类型都是 uint3,但是可以有不同的含义:
| 语义 | 含义 | 说明 | 假设示例 |
|---|---|---|---|
SV_GroupID |
线程组 ID | 当前线程组在整个 Dispatch 中的索引,当前是第几组。可以理解为:第几个方块区域 | (1, 2, 0) |
SV_GroupThreadID |
组内线程 ID | 当前线程在组内的局部索引,当前线程是组内第几个。可以理解为:方块里的第几个格子 | (4, 6, 0) |
SV_DispatchThreadID |
调度线程 ID | 每个线程的全局索引(系统自动传入),比如第 N 个像素、第 N 个粒子。可以理解为:唯一线程编号 | (1×8+4, 2×8+6, 0×1+0) = (12, 22, 0) |
图解三大语义的关系
假设 [numthreads(8, 8, 1)],Dispatch(3, 3, 1):
第一层:Dispatch 产生的线程组网格(每格是一个线程组)
Dispatch(3, 3, 1) 线程组网格
┌────────────┬────────────┬────────────┐
│ Group │ Group │ Group │
│ (0,0,0) │ (1,0,0) │ (2,0,0) │
├────────────┼────────────┼────────────┤
│ Group │ Group │ Group │
│ (0,1,0) │ (1,1,0) │ (2,1,0) │
├────────────┼────────────┼────────────┤
│ Group │ Group │ Group │
│ (0,2,0) │ (1,2,0) ◄──│ (2,2,0) │
└────────────┴────────────┴────────────┘
│
SV_GroupID = (1, 2, 0)
"我是第 1 列、第 2 行的那个线程组"
第二层:展开 Group(1,2,0) 内部的线程(8×8 网格)
Group(1,2,0) 内部 [numthreads(8,8,1)]
x→ 0 1 2 3 4 5 6 7
y↓ ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
0 │(0,0)│(1,0)│(2,0)│(3,0)│(4,0)│(5,0)│(6,0)│(7,0)│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
1 │(0,1)│(1,1)│(2,1)│(3,1)│(4,1)│(5,1)│(6,1)│(7,1)│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
… │ … │ … │ … │ … │ … │ … │ … │ … │
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
6 │(0,6)│(1,6)│(2,6)│(3,6)│(4,6)│(5,6)│(6,6)│(7,6)│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤
7 │(0,7)│(1,7)│(2,7)│(3,7)│(4,7)│(5,7)│(6,7)│(7,7)│
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
↑
SV_GroupThreadID = (4, 6, 0)
"我是这个组里第 4 列、第 6 行的线程"
第三层:计算全局 ID
SV_DispatchThreadID = SV_GroupID × numthreads + SV_GroupThreadID
= (1, 2, 0) × (8, 8, 1) + (4, 6, 0)
= (8, 16, 0) + (4, 6, 0)
= (12, 22, 0)
"我是全局第 12 列、第 22 行的线程 → 对应图像的第 (12,22) 个像素"
三大参数语义的意义
最常用: SV_DispatchThreadID,它可以帮助我们直接映射到图像像素或数组元素的下标,可以让我们直接处理目标数据。
常用: SV_GroupID 和 SV_GroupThreadID,我们可以利用它们来共享一些内存,或者分块处理大数据。
101.2 知识点代码
Lesson101_性能优化_GPU_着色器优化_ComputeShader_三大参数语义.cs
public class Lesson101_性能优化_GPU_着色器优化_ComputeShader_三大参数语义
{
#region 知识点一 三大参数语义指什么
// 参数三兄弟在这里主要指的是
// Compute Shader 的内核入口函数中参数的三个系统语义
// SV_GroupID
// SV_GroupThreadID
// SV_DispatchThreadID
// 语义:
// 是 CG/HLSL 中的一种"数据标签"
// 用来告诉 GPU 某个变量在渲染管线或计算管线中代表什么意义
// 语义是 Shader 输入、输出变量的角色标签
// 它告诉 GPU,这个变量从哪里来、要传到哪里去、它在管线中扮演什么角色
// 对于 Compute Shader 内核入口函数中主要使用的这三个语义
// 它们主要是告诉 GPU,这个变量从哪里来,其中需要存储什么样的数据
// GPU 就会通过该变量传入对应的数据
#endregion
#region 知识点二 三大参数语义的区别
// 入口函数传入的数据类型都是 uint3 但是可以有不同的含义
// SV_GroupID
// 线程组 ID 当前线程组在整个 Dispatch 中的索引 当前是第几组 假设(1,2,0)
// 可以理解为:第几个方块区域
// SV_GroupThreadID
// 组内线程 ID 当前线程在组内的局部索引 当前线程是组内第几个 假设(4,6,0)
// 可以理解为:方块里的第几个格子
// SV_DispatchThreadID
// 调度线程 ID 每个线程的全局索引(系统自动传入)比如第 N 个像素、第 N 个粒子
// (1*8 + 4, 2*8 + 6, 0*1 + 0) = (12,22,0)
// 可以理解为:唯一线程编号
#endregion
#region 知识点三 三大参数语义的意义
// 最常用
// SV_DispatchThreadID
// 它可以帮助我们直接映射到图像像素或数组元素的下标
// 可以让我们直接处理目标数据
// 常用
// SV_GroupID 和 SV_GroupThreadID
// 我们可以利用它们来共享一些内存
// 或者分块处理大数据
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com