UPL9-17-a——多个入口函数
UPL9-17-a——多个入口函数
本章代码关键字
1 | #pragma kernel // 通过 #pragma kernel 声明入口函数,可以有多个(请注意在 #pragma kernel 指令的同一行上不允许 "// text" 样式的注释) |
多个入口函数的含义
一个 Compute Shader 文件可以定义多个 Kernel(内核),即多个入口函数
每个 Kernel(内核)入口函数可以有独立的线程数量配置
我们在 CPU 端(C# 侧)需要为每个入口函数单独调用 Dispatch()
基本原理:我们每声明一个入口函数,都会被编译为一个独立的 内核(Kernel),相当于 GPU 上的一个可单独调用的计算程序
多个入口函数声明和使用方式
-
在 Compute Shader 中使用
#pragma kernel定义多个内核入口函数注意:
- 入口函数不能重名(在一个 Compute Shader 文件中)
- 入口函数可以共享该 Compute Shader 中声明的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 通过 #pragma kernel 声明入口函数,可以有多个
#pragma kernel CSMain
#pragma kernel CSMain2
// 所有入口函数共享的变量
RWTexture2D<float4> Result;
float f;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// 书写核心计算逻辑
Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}
[numthreads(8, 8, 1)]
void CSMain2 (uint3 id : SV_DispatchThreadID)
{
// 书写核心计算逻辑
} -
在 CPU(C# 侧)调用时,需要获取对应入口索引
通过多个
Dispatch() 函数进行调用,用索引进行区分,使用FindKernel()传入入口函数名即可获取索引注意:
Dispatch() 函数的调用类似异步,不会对 CPU 造成阻塞
只是提交执行指令给到 GPU,GPU 侧会按照Dispatch() 顺序,依次执行内核入口函数
即在一个 Dispatch() 内部,GPU 执行是并行的;多个 Dispatch() 调用之间,是串行的,需要按顺序执行1
2
3
4
5
6
7
8
9
10
11
12public ComputeShader computeShader; // 声明 computeShader 变量,可以通过 Inspector 窗口关联,也可以动态加载
void Start()
{
int index = computeShader.FindKernel("CSMain"); // 获取 computeShader 中名为 CSMain 的函数索引
int index2 = computeShader.FindKernel("CSMain2"); // 获取 computeShader 中名为 CSMain2 的函数索引
computeShader.SetFloat("f", 10.0f); // 传递相关参数
computeShader.Dispatch(index, 64, 64, 0); // 启动 CSMain 的计算
computeShader.Dispatch(index2, 64, 64, 0); // 启动 CSMain2 的计算,它会在 CSMain 计算完成后执行
// 使用GPU计算完成输出的数据渲染或者传回CPU
// 释放资源
}
多个入口函数对于我们的意义
-
分阶段执行
我们可以将部分计算逻辑分步执行,分阶段处理,我们可以利用多入口函数串行执行的这一特点。实现出类似流水线一样的分布执行,比如:
-
初始化阶段
在第一个内核入口函数中分配、填充初始数据
-
模拟阶段
在第二个内核入口函数中更新位置、速度等数据
-
渲染阶段
在第三个内核入口函数中把结果写入纹理
-
-
逻辑模块化
我们可以让不同的内核入口函数负责不同的功能,这样从设计上更加清晰易维护
-
不同任务可以使用不同线程组配置
不同内核入口函数的线程组配置可以不同
可以针对性的设置线程组配置 -
减少 ComputeShader 文件数量
在一个 ComputeShader 文件中可以包含多个内核入口函数
CPU(C# 侧)只需要加载一次 ComputeShader 文件,就可以执行多个内核入口函数 -
共享数据
多个内核入口函数由于在一个 ComputeShader 文件中,因此他们可以共享数据
总结:多入口函数相当于 GPU 并行计算的多阶段流水线,
它让我们可以把复杂 GPU 计算流程拆解成多个独立、可组合的模块,提高性能、可读性和可维护性
