Early fragment test not working

I cannot seem to get early fragment depth test to work as my fragment shader is still writing data into my storage buffer where the sample is suppose to be hidden. I have specified “layout(early_fragment_tests) in;” in my fragment shader as how it was done previously in OpenGL. The Vulkan spec mentions enabling the EarlyFragmentTests OpExecutionMode which I assume that’s what the layout qualifier is suppose to do. There are no validation, SPIR-V or rendering errors. Has anyone else run into this problem?

I am using Vulkan

My fragment shader:

#version 450
#extension GL_ARB_separate_shader_objects : enable

layout(early_fragment_tests) in;

layout(location = 0) in vec3 fragPosition;
layout(location = 1) in vec3 fragNormal;
layout(location = 2) in vec2 fragTexCoord;
layout(location = 3) flat in uint fragId;

layout(location = 0) out vec4 outColor;

layout(binding = 1) uniform sampler2D texSampler;

struct SampleWriteback
	vec2 texcoord;
    float dist;
    uint id;

layout(std140, binding = 2) buffer StorageBufferObjects {
    SampleWriteback outSample[];

void main()
    vec4 finalColor = texture(texSampler, fragTexCoord);

    outSample[fragId].texcoord = fragTexCoord;
    outSample[fragId].dist = fragPosition.z;
    outSample[fragId].id = fragId;

    outColor = finalColor;

What are you using to get a SPIR-V? Try to force it to give human readable form, and verify the presence of the early fragment test Execution mode.

How exactly do you recognize it is not working? What’s a fragId?

By any chance did you forget to enable depth testing in the pipeline?

Hi Krooze thanks for the reply. I use glslangValidator.exe to translate GLSL to SPIRV. I do see the line “ExecutionMode 4 EarlyFragmentTests” in the human readable SIPRV.

Early depth test doesn’t seem to work as I place a mesh right in front of the camera blocking all the background meshes yet their hidden fragments are still processed. fragId is just my textureId used to index the storagebuffer, passed from vertex attribute into the vertex shader then into the fragment shader. I am clearing outSample’s id (at index fragId) to -1 in the vertex shader and I am just counting the number of non -1 values in the id buffer array after the frame is rendered.

I am sure depth testing is enabled in the pipeline:

VkPipelineDepthStencilStateCreateInfo depthStencil = {};
	depthStencil.depthTestEnable = VK_TRUE;
	depthStencil.depthWriteEnable = VK_TRUE;
	depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
	depthStencil.depthBoundsTestEnable = VK_FALSE;
	depthStencil.stencilTestEnable = VK_FALSE;

Another issue I ran into is when I copy my storage buffer data (located in device and host visible memory) into my vector in the update loop like:

memcpy(listSamples.data(), ssbObjectsAllocInfo.pMappedData, ssbObjectsAllocInfo.size);

my application tend to break arbitrarily at some line within the update loop. Is it a conflict caused by reading/writing the storage buffer by CPU and GPU at the same time and if so how can I fix it?