OpenGL 编程指南 (11)
1、计算着色器,一种能够灵活运用GPU高速运算处理非图形任务的着色器,它能够使用大部分着色器的功能当然要出去非常专一性的如EmitVertex这样的方法。
2、计算着色器的调用有全局工作组的概念,全局工作组又包含局部工作组(本地工作组),局部工作组包含执行单元
3、局部工作组的大小在shader中由输入布局限定符声明,下面是一个4X4大小的局部工作组声明
#version 430 core
layout (local_size_x = 4, local_size_y = 4) in;
void main()
{
......
}
它的创建、编译、链接与其它shader相同,在使用的时候除了调用glUseProgram外还需要调用下面这个方法
void glDispatchCompute(GLuint num_group_x, GLuint num_group_y, GLuint num_group_z)//分别设置xyz维度上的工作组数量,值需要介于0与GL_MAX_COMPUTE_WORK_GROUP_SIZE之间,因此计算着色器中执行单元的总数是这个3维数组的大小乘以shader中定义的工作组大小
void glDsipatchComputeIndirect(GLintptr indirect)//三个参数将会绑定到GL_DISPATCH_INDIRECT_BUFFER上
glGenBuffers(1, dispatchbuffer);
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, dispatchbuffer);
static const struct
{
GLuint num_group_x;
GLuint num_group_y;
GLuint num_group_z;
} dispatchob = {4, 4, 1};
glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(dispatchob), &dispatchob, GL_STATIC_DRAW);
glDispatchComputeIndirect(0);
4、计算着色器的一大优势是它们能够互相通信,因此需要一些内建变量来支持这一特性
1)gl_WorkGroupSize 局部工作组大小向量,这样工作组大小可以被随意访问而不依赖于预处理,也能够以多维形式表示工作组大小
2)gl_NumWorkGroups 一个存储了glDispatchCompute参数的向量,能够提供全局工作组的大小
3)gl_LocalInvocationID 执行单元在局部工作组中的位置,它的范围uvec3(0)~gl_WorkGroupSize-uvec3(1)
4)gl_WorkGroupID 当前局部工作组在全局工作组中的位置,范围uvec3(0)~gl_NumWorkGroups-uvec3(1)
5)gl_GlobalInvocationID 当前执行单元在全局工作组中的位置,gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID
6)gl_LocalInvocationIndex 是gl_GlobalInvocationID的一种扁平化形式,是一维数据,gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + gl_LocalInvocationID.y * gl_WorkGroupSize.x * gl_WorkGroupSize.x
5、被关键字shared修饰的变量能够在局部工作组之间共享,它们被存储于共享空间中当做局部变量存储内存处理,访问性能较为优异。共享空间大小受限,通过GL_MAX_COMPUTE_SHARED_MEMORY_SIZE获取。
6、同步
1)barrier() 停止当前执行等待其它实例也执行到当前步骤后继续执行,所有实例在同一位置都需要执行barrier
2)memoryBarrier() 上一节说过
3)groupMemoryBarrier() 与memoryBarrier等价只是只能应用于局部工作组的请求