Opengl 计算着色器-gl_globalinovationid和local_size

Opengl 计算着色器-gl_globalinovationid和local_size,opengl,compute-shader,Opengl,Compute Shader,在尝试实现将影响灯光指定给簇的朴素计算着色器时,我遇到了一个意外的行为(对于像我这样的noob来说也是如此): 我使用glDispatchCompute(32,32,32)调用这个着色器;它应该为每次调用将一个[轻型计数器+8个索引]写入“索引”缓冲区。但在调试时,我发现我对该缓冲区的写入在调用之间重叠,即使我使用了唯一的clusterId。我通过指数[OutinexStart]的值超过8和视觉闪烁来检测它 根据文档,gl_GlobalInvocationID是gl_WorkGroupID*gl

在尝试实现将影响灯光指定给簇的朴素计算着色器时,我遇到了一个意外的行为(对于像我这样的noob来说也是如此):

我使用glDispatchCompute(32,32,32)调用这个着色器;它应该为每次调用将一个[轻型计数器+8个索引]写入“索引”缓冲区。但在调试时,我发现我对该缓冲区的写入在调用之间重叠,即使我使用了唯一的clusterId。我通过指数[OutinexStart]的值超过8和视觉闪烁来检测它

根据文档,gl_GlobalInvocationID是gl_WorkGroupID*gl_WorkGroupSize+gl_LocalInvocationID。但如果将所有本地大小设置为1,写入问题就会消失。为什么本地_大小会以这种方式影响此代码?我怎样才能在这里选择它的价值呢

#version 430
layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;

uniform int lightCount;

const unsigned int clusterSize = 32;
const unsigned int clusterSquared = clusterSize * clusterSize;

struct LightInfo {
    vec4 color;
    vec3 position;
    float radius;
};

layout(std430, binding = 0) buffer occupancyGrid {
    int exists[];
};

layout(std430, binding = 2) buffer lightInfos
{
  LightInfo lights [];
};

layout(std430, binding = 1) buffer outputList {
    int indices[];
};

void main(){
    unsigned int clusterId = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * clusterSize + gl_GlobalInvocationID.z * clusterSquared;

    if(exists[clusterId] == 0)
        return;

    //... not so relevant calculations

    unsigned int outIndexStart = clusterId * 9;
    unsigned int outOffset = 1;

    for(int i = 0; i < lightCount && outOffset < 9; i++){
        if(distance(lights[i].position, wordSpace.xyz) < lights[i].radius) {
            indices[outIndexStart + outOffset] = i;
            indices[outIndexStart]++;
            outOffset++;
        }
    }
}
#版本430
布局(本地大小x=4,本地大小y=4,本地大小z=4)在中;
均匀整数光计数;
常量unsigned int clusterSize=32;
常量unsigned int clusterSquared=clusterSize*clusterSize;
结构光信息{
vec4颜色;
vec3位置;
浮动半径;
};
布局(std430,绑定=0)缓冲区占用网格{
int存在[];
};
布局(std430,绑定=2)缓冲区灯光信息
{
LightInfo灯光[];
};
布局(std430,绑定=1)缓冲区输出列表{
整数指数[];
};
void main(){
unsigned int clusterId=gl_globalinsocationId.x+gl_globalinsocationId.y*clusterSize+globalinsocationId.z*clusterSquared;
如果(存在[clusterId]==0)
返回;
//…不太相关的计算
unsigned int outinexstart=clusterId*9;
无符号整数输出偏移量=1;
对于(int i=0;i
让我们看两个声明:

layout (local_size_x = 4, local_size_y = 4, local_size_z = 4) in;

他们说了不同的话。
local\u size
声明表示每个工作组将有4*4*4次调用,即64次。相比之下,您的
clusterSize
表示每个工作组只有32个调用

如果要解决此问题,请使用:

你甚至可以这样做:

const uvec3 linearizeInvocation = uvec3{1, clusterSize, clusterSize * clusterSize};

...

unsigned int clusterId = dot(gl_GlobalInvocationID, linearizeInvocation);

哦我的着色器可能让我的意图变得非常混乱。因为我不认为本地大小将组细分为更多的调用,而是认为其他一些事情是荒谬的。另一个观察结果是,如果我减少工作组的数量并增加工作组的大小,我的另一个计算着色器执行3d纹理下采样的速度会更快。但它没有共享的变量。是纹理缓存还是更复杂,我必须问另一个问题?
const unsigned int clusterSize = dot(gl_WorkGroupSize, uvec3(1, 1, 1));
const uvec3 linearizeInvocation = uvec3{1, clusterSize, clusterSize * clusterSize};

...

unsigned int clusterId = dot(gl_GlobalInvocationID, linearizeInvocation);