PDA

View Full Version : Write to gl_FragDepth with early_fragment_tests



nosense
08-09-2012, 12:17 PM
Hi.

I've been conducting some experiments in OpenGL 4.2, and I got stuck in some non-clearly-defined-OpenGL specification (or so I think).
I know that what I want is a little non-usual, but believe me, it is for a good reason: speed up the rendering.

So, I want to perform the early fragment tests (depth and stencil) and, for the fragments that pass the tests, update the depth value.
I started by forcing the early tests with "layout(early_fragment_tests) in" which worked very well.
But when I tried to write to the depth buffer "gl_FragDepth = variableA" it did nothing.

I understand that such action may leave fragments with depth values that do not obey to the previous depth-tests, but this in fact expected by my algorithm.
I see no reason for this not to work.
Well, I can only suspect the following: maybe the depth values (from the depth buffer) are cached, and therefore, the gl_FragDepth writes are discarded? For optimization purposes, due to the usage of early fragment tests?


Thanks in advance,

Alfonse Reinheart
08-09-2012, 12:50 PM
That's just how the spec is defined. Section 3.8 says:


If early fragment tests are enabled, any depth value computed by the fragment shader has no effect. Additionally, the depth buffer, stencil buffer, and occlusion query sample counts may be updated even for fragments or samples that would be discarded after fragment shader execution due to per-fragment operations such as alpha-to-coverage tests.

In short, early tests are not a way to cheat. If the depth test passes, then the depth buffer will be updated to the value that was tested against, regardless of where that test happened.

nosense
08-09-2012, 01:33 PM
Nevertheless, if this was possible it would be a great aquisition ;)

Thanks

malexander
08-09-2012, 01:48 PM
You may be able to use the conservative depth extension (http://www.opengl.org/registry/specs/ARB/conservative_depth.txt).


For example, if you were rendering with Zfunc = less and your fragment shader was only ever increasing the depth value, the driver could do an early depth test as you're saying you'll never decrease Z. Thus (Zframebuffer < Zoriginal) will be always have the same value as (Zframebuffer < Zfragment), since (Zoriginal <= Zfragment). However, if you're altering Z in a way that it may be greater or less that the Z value computed by the vertex/tess/geo shader, or decreasing with Zfunc=less/increasing with Zfunc=greater, then this won't help.

nosense
08-09-2012, 05:08 PM
Thanks malexander, but that won't do the trick. =\

Another way to explain my problem is:
I want to perform a depth test before fragment shader execution, and after that, change the depth value based on some calculations.
Basically, I want to disable some fragments as they iterate through the primitives, i.e., during a single draw call. But I want to completley avoid fragment shader execution on the disabled ones (using early_fragment_tests), because my fragment shader may be pretty slow.

Unfortunatly, it seems that this is not possible.

Alfonse Reinheart
08-09-2012, 07:13 PM
It's very possible; just not with early depth tests.

Remember: fragment shaders don't execute one after another; they execute in groups that all execute instructions in lockstep. So even if you discard one fragment shader invocation, if its neighbor needs to run, it will still have to execute. Obviously all actual effects are discarded.

Because of that, if you `discard` early on in your fragment shader, and this discard triggers on all of the shaders in the group, then the group will be discarded (in all likelihood). So you'll save the time it takes to execute the shader. But if not all of them would have been discarded, you wouldn't save anything from your depth test.

In short: there is little advantage to making depth tests remove fragments you don't like instead of just doing it in the shader. The only significant advantage you might get is z-culling hardware that discards entire fragment groups based on their Z values.