admin管理员组

文章数量:1291027

Before you read further, I found the answer to this problem. While this is rather basic and has nothing to do with the shader logic itself, I think it's a common pitfall and I will add the solution in the question for future readers that may run into a similar problem:

What was the cause of the problem and solution

I fot to pad the counter's buffer's memory. The counter is only 4 bytes but the minimum requirement alignment for my GPU is 16. As soon as I set the size of the buffer to 16, it worked fine.

Initial Question

I am implementing an object selection solution in Vulkan where I write the object ID using a dynamic UBO to a buffer in the fragment shader. In fact, there are two buffers: one that acts as a counter to track how many objects were in the selection region (defined by the mouse position and the width/height of the rectangle), and another buffer where I write the object IDs.

#version 450

layout(binding = 0) uniform UBO {
    ...
} ubo;

layout(binding = 1) uniform DynamicUBO {
    ...
    uvec4 data;
    ...
} dynamicUBO;

// Storage buffer to store selected Object IDs
layout(std430, binding = 2) buffer OutputBuffer {
    uint objectIDs[];
};

// Atomic counter buffer to track buffer index
layout(binding = 3) buffer Counter {
    uint counter;
};

layout(push_constant) uniform PushConstants {
    ivec2 mousePos; // Mouse position (x, y) for now...
} pc;

void main() {
    ivec2 fragCoord = ivec2(gl_FragCoord.xy);
    if (fragCoord.x == pc.mousePos.x && fragCoord.y == pc.mousePos.y) {
        uint objID = dynamicUBO.data.x;

        if (objID != 0) {
            uint index = atomicAdd(counter, 1);
            objectIDs[index] = objID;
        }
    }
    
    outColor = ...;
}

Here is a result I get from this:

Selected Objects: 2
 - Object ID: 268
 - Object ID: 0

As you can see, I still get some entries with Object ID: 0 (sometimes more than one). I thought that maybe the fragment shader was being called for some fragments where there was no geometry (there are likely plenty of reasons I might not be aware of that are causing this to happen), so I added this check:

if (objID != 0) {
    // only write if object ID != 0
    ...
}

However, I still occasionally see - Object ID: 0. (Edit) What happens is that 0s are the default values from the buffer. It seems that the shader is not effectively writing 0 to objectIDs[index]. What’s odd is that it increments the counter incorrectly (or somehow the counter is being incremented and updated independently from objectIDs[index]).

I have added the layout(early_fragment_tests) in; option. This has significantly reduced the number of zeros being written to the buffer, I still see them occasionally.

My big question though is: why does the counter value doesn't reflect the number of values being effectively written to the ObjectIDs buffer?

本文标签: Writing an ObjectID to a buffer with VulkanGLSL for object pickStack Overflow