2
votes

I have a fragment shader (GLSL 4.5), which is supposed to write non-transparent pixels to the framebuffer (by writing to the declared output variables) and transparent pixels into a shader storage buffer for later composition. To make that work I planned to write transparent pixels to the shader storage buffer and then call discard to prevent the write to the framebuffer.

Now I stumbled upon this section of the khronos.org's OpenGL Wiki (emphasis mine):

The discard command will also prevent any image store and atomic operations and Shader Storage Buffer Object writes (issued before the discard) from working.

I was very surprised to see this, because if you consider that different shader invocations are able to exchange information by writing and reading shader storage buffers, and therefor could have already behaved differently based on such a wirte before the discard statement is even reached.

I looked into the the GLSL 4.5 Specification, but I could not find anything, which supports the statement form the Wiki.

Also: If this is true, are maybe later writes to a shared storage buffer not discarded?

1
"then call discard to prevent the write to the framebuffer." You really shouldn't do that. Just use a write mask to turn off framebuffer writes.Nicol Bolas
"if you consider that different shader invocations are able to exchange information by writing and reading shader storage buffers, and therefor could have already behaved differently based on such a wirte before the discard statement is even reached" Actually, they can't. In a fragment shader, there is no way to synchronize such activity, to ensure that a read happens after a write within a rendering command. And therefore you will have invoked UB.Nicol Bolas
@NicolBolas: One shader invocation could make a call to atomicAdd to increase a global counter and after that call discard. This would be a side effect which is visible to other shader invocations. And if I'm not mistaken, this is not be UB.mic
"Just use a write mask to turn off framebuffer writes" : I looked at the linked wiki page, and I think write masks will not solve my problem, since the decision whether to write to the framebuffer or not is made by the fragment shader invocation (here based on the transparency). If I understand write masks correctly, they must be set before making a draw call, and will block all writes to a specific pixel.mic

1 Answers

3
votes

The specification is clear and unequivocally. See OpenGL Shading Language 4.60 Specification - 6.4. Jumps:

[...] This keyword causes the fragment to be discarded and no updates to any buffers will occur. Any prior writes to other buffers such as shader storage buffers are unaffected. [...]

Thus it is possible to write to a SSBO and after that discard writing to the framebuffer, because prior writes to SSBOs are unaffected.


See further 4.60 revision changes and discard with prior image load/store or SSBO operations #118

[...] while a shader is running, it is updating externally visible buffers and it would be unworkable to say those updates were somehow no longer present after a later discard [...]