2

Both my fragment and vertex shaders contain the following two guys:

struct Light {
  mat4 view;
  mat4 proj;
  vec4 fragPos;
};

layout (std430, binding = 0) buffer Lights {
  Light lights[];
};

My problem is that that last field, fragPos, is computed by the vertex shader like this, but the fragment shader does not see the changes made by the vertex shader in fragPos (or any changes at all):

aLight.fragPos = bias * aLight.proj * aLight.view * vec4(vs_frag_pos, 1.0);

... where aLight is lights[i] in a loop. As you can imagine I'm computing the position of the vertex in the coordinate systems of each light present to be used in shadow mapping. Any idea what's wrong here? Am I doing a fundamentally wrong thing?

Here is how I initialize my storage:

struct LightData {
  glm::mat4 view;
  glm::mat4 proj;
  glm::vec4 fragPos;
};

glGenBuffers(1, &BBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, BBO);

glNamedBufferStorage(BBO, lights.size() * sizeof(LightData), NULL, GL_DYNAMIC_STORAGE_BIT);

// lights is a vector of a wrapper class for LightData.
for (unsigned int i = 0; i < lights.size(); i++) {
  glNamedBufferSubData(BBO, i * sizeof(LightData), sizeof(LightData), &(lights[i]->data));
}

It may be worth noting that if I move fragPos to a fixed-size array out variable in the vertex shader out fragPos[2], leave the results there and then add the fragment shader counterpart in fragPos[2] and use that for the rest of my stuff then things are OK. So what I want to know more about here is why my fragment shader does not see the numbers crunched down by the vertex shader.

Carlos Romero
  • 698
  • 8
  • 18

1 Answers1

2

I will not be very accurate, but I will try to explain you why your fragment shader does not see what your vertex shader write :

When your vertex shader write some informations inside your buffer, the value you write are not mandatory to be wrote inside video memory, but can be stored in a kind of cache. The same idea occur when your fragment shader will read your buffer, it may read value in a cache (that is not the same as the vertex shader).

To avoid this problem, you must do two things, first, you have to declare your buffer as coherent (inside the glsl) : layout(std430) coherent buffer ...

Once you have that, after your writes, you must issue a barrier (globally, it says : be careful, I write value inside the buffer, values that you will read may be invalid, please, take the new values I wrote).

How to do such a thing ? Using the function memoryBarrierBuffer after your writes. https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/memoryBarrierBuffer.xhtml

BTW : don't forget to divide by w after your projection.

Antoine Morrier
  • 3,930
  • 16
  • 37
  • Hey, thanks for your reply. That sounds like the kind of thing I'm missing. I'll make sure to try it later today. – Carlos Romero Aug 03 '17 at 12:59
  • hmm somehow i can't get it to work. I'm assuming the call to `memoryBarrierBuffer` should go in my vertex shader after I'm done writing, from what the red book tells me? – Carlos Romero Aug 03 '17 at 17:58
  • Normally yes like something that : buffer.value = x; memoryBarrierBuffer – Antoine Morrier Aug 03 '17 at 18:04
  • Also, think about your race conditions. It could be thousands vertices that are processed in the same time. So, it is possible that your values are overwrite and it explains why you do not get the good value ;) – Antoine Morrier Aug 03 '17 at 18:41
  • hmm I thought `memoryBarrierBuffer` would protect me against that. I'm also reading that this method works with `image` attributes. I'm trying to change `fragPos` to `image1D` and use `imageLoad` and `imageStore` to read/write into it. – Carlos Romero Aug 03 '17 at 20:11
  • For image you need use memoryBarrierImage. A barrier only say that your writes Will be visible by other thread. It, fortunately for performances, is not a mutex or something like that – Antoine Morrier Aug 03 '17 at 20:15