101.ComputeShader三大参数语义

101.性能优化-GPU-着色器优化-ComputeShader-三大参数语义


101.1 知识点

三大参数语义指什么

参数三兄弟在这里主要指的是 Compute Shader 的内核入口函数中参数的三个系统语义:

  • SV_GroupID
  • SV_GroupThreadID
  • SV_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_GroupIDSV_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

×

喜欢就点赞,疼爱就打赏