2

I am trying to do culling on a compute shader. My problem is that my atomic counter does not seem to get written to by the shader, or it does but then gets nullified?

Renderdoc says it has no data but there are values in InstancesOut (see picture at bottom)

This is my compute shader:

#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable

struct Indirect
{
    uint indexCount;
    uint instanceCount;
    uint firstIndex;
    uint vertexOffset;
    uint firstInstance;
};
struct Instance
{
    vec4 position;
};

layout (binding = 0, std430) buffer IndirectDraws
{
    Indirect indirects[];
};

layout (binding = 1) uniform UBO 
{
    vec4 frustum[6];
} ubo;

layout (binding = 2, std140) readonly buffer Instances
{
    Instance instances[];
};

layout (binding = 3, std140) writeonly buffer InstancesOut
{
    Instance instancesOut[];
};
layout (binding = 4) buffer Counter
{
    uint counter;
};

bool checkFrustrum(vec4 position, float radius)
{
    for(uint i = 0; i < 6; i++)
        if(dot(position, ubo.frustum[i]) + radius < 0.0)
            return false;
    return true;
}
layout (local_size_x = 1) in;
void main()
{
    uint i = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * gl_NumWorkGroups.x * gl_WorkGroupSize.x;

    uint instanceCount = 0;
    if(i == 0)
        atomicExchange(counter, 0);


    for(uint x = 0; x < indirects[i].instanceCount; x++)
    {
        vec4 position = instances[indirects[i].firstInstance + x].position;
        //if(checkFrustrum(position, 1.0))
        //{
            instancesOut[atomicAdd(counter, 1)].position = position;
            instanceCount++; 
        //}
    }
    //indirects[i].instanceCount = instanceCount;
    indirects[i].instanceCount = i; // testing
}

Picture of buffers in RenderDoc

Thanks for your help!

3
  • Have you tried putting a barrier after the atomicExchange. I'm worried that other invocations of the shader proceed before the counter is initialized properly. Commented Jun 5, 2018 at 23:50
  • I tried with a barrier now but get the same result :( Commented Jun 6, 2018 at 1:06
  • barrier(); only synchronizes within a workgroup, as his workgroup is size 1, it will do nothing (local_size_x = 1). Commented Jul 25, 2018 at 19:27

1 Answer 1

0

There's so much that it seems you're misunderstanding about how synchronization and workgroups work.

Within a compute shader, atomics will allow you to synchronize across workgroups. However, there's no guarantee for the order that workgroups execute, so atomicExchange(counter, 0); is not gauranteed to happen before the other workgroups execute. Error #1?

A workgroup size of 1 is a tremendous waste of resources, particularly if you're going through the expense of synchronizing across workgroups. Synchronization within a workgroup will always be fastest, and it allows you to actually use your gpu resources (most GPUs are organized into modules containing SIMD processors that can only handle execution on one workGroup at a time. If you're only using size 1 workgroups, 31/32 or 63/64 of those processors sit idle. {caveat, most of those same processors can hold multiple workgroups in memory simultaneously, but execution only happens on one at any given moment}). Further, within a workgroup you can synchronize execution with barriers, ensuring order of operations. Error #2?

atomicCounterIncrement is probably a better instruction if you're only ever adding one.

In your particular application, why is the answer for instancesOut wrong? it actually seems right to me, every input ended up in the output, without a guaranteed order (because you're not guaranteed that workgroups execute in a particular order, i.e. that's how parallel execution works). If you wanted them in order, calculate it from the invocation IDs?

As for why renderDoc doesn't show you a value in counter, i don't know, it should have a value if it's mapped correctly.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.