I want to improve my shadow mapping depth precision by getting the minimum and maximum depth value within my shadow map. When having both values I would convert the depth map to convolution shadow map basis functions and encode the values to 8bit each, which looses precision a lot, in case the depth span is high.

Right now I render the scenario depth values into a R32F texture. A second shader checks for each pixel, if it is the min / max depth within the shadowmap by using SSBO and AtomicMax / AtomicMin. Then the next shader converts the depth values with respect to the min/max depth into the basis functions of convolution shadow mapping.

Is there a way to get the minimum / maximum depth during the render pass of the scenario? If this is the case, I could skip the second shader.

During the geometry rendering within the fragment shader I can get the depth value and use the AtomicMin / AtomixMax function. But when doing so, there can be the case (it happens very often) that fragments will be executed, which are behind other faces. so the max distance will be wrong at the end, which decreases the shadow map precision.

I found the layout(early_fragment_tests) in; specification. But I am not sure if this will solve the problem. How does this specification work? Do you have other ideas?


1 Answer 1


There is no way in general to know whether a fragment you're currently shading will make it into the final image or not. You could be rendering 10,000 different meshes, and the last one could cover up the first one. Early fragment tests won't solve that issue.

Doing a post-pass over the image to find the min and max values is the right way to do it. There are, however, faster ways to accomplish this than atomic operations that try to reduce the whole image down to a single value in one step, as that will create a ton of contention.

It will be better to calculate the min/max of smaller areas of the image in parallel, then recursively take the min/max of those results. For example, do a pass where each threadgroup reads an 8×8 tile of the original image, calculates the min/max over those (can be done quickly using subgroup operations) and then stores that out to an 8× smaller RG32F texture. Then repeat that until you get down to 1×1, kind of like building mipmaps, but you can reduce by a factor of 8 or more in each pass.

See also: the AMD Single Pass Downsample library, which is a complex library but might be useful for ideas about this.

  • $\begingroup$ thanks for the answer. I understand the idea of subsampling the final image. But does is make a big impact in performance instead of the ssbo atomicMin atomicMax? The 2nd question I have is regarding the early fragment test... What does it do? $\endgroup$
    – Thomas
    Sep 4, 2022 at 21:51
  • 1
    $\begingroup$ The trouble with atomic operations is if every pixel in the image is trying to do their atomicMin/atomicMax on the same storage location at once, it'll be basically serialized due to contention on that one storage location. So it'll be really slow. The downsampling approach lets you do a lot more of the work in parallel, so it can be made much faster when tuned well. $\endgroup$ Sep 4, 2022 at 21:56
  • $\begingroup$ As for early fragment tests, you can read about it on the OpenGL Wiki. It's an optimization to cut down on unnecessary fragment shader invocations when the fragments can be determined to be invisible at the time they're rendered. $\endgroup$ Sep 4, 2022 at 22:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.