Floating point z-buffers and why I'm not adding them to Supermodel (yet)

Technical discussion for those interested in Supermodel development and Model 3 reverse engineering. Prospective contributors welcome. Not for end-user support.
Forum rules
Keep it classy!
  • No ROM requests or links.
  • Do not ask to be a play tester.
  • Do not ask about release dates.
  • No drama!
Post Reply
gm_matthew
Posts: 15
Joined: Wed Nov 08, 2023 2:10 am

Floating point z-buffers and why I'm not adding them to Supermodel (yet)

Post by gm_matthew »

One of the questions regarding the Model 3 is how it figures out which values it should use for the near/far clipping planes, and the simple answer is that it doesn't. The Model 3 uses a 22-bit floating-point reversed z-buffer - 6 bits exponent, 16 bits mantissa - which offers high precision over an extremely vast range; we're talking 2^63, or 9.2 quintillion. Because the range is so vast, the Model 3 doesn't need to implement near/far clipping planes at all. This article helps explain why floating-point z-buffers are so useful.

Having discovered this I looked into the possibility of implementing a floating-point reversed z-buffer within Supermodel, as it would mean Ian's ingenious but complex approach to dynamically calculating near/far clipping values would no longer be needed. Sure enough I found that support for 32-bit floating-point z-buffers have been required since OpenGL 3.0, and Supermodel currently requires OpenGL 4.1+. So all good to go, right? Alas, sadly not.

The idea behind reversing the z-buffer is that most of the depth values are bunched close to 0.0 where floating-point values have a LOT more precision. But OpenGL, rather than using a z-buffer range from 0.0 to 1.0, instead uses a range from -1.0 to 1.0. This means reversing the z-buffer doesn't work as the values are now bunched towards -1.0, which doesn't offer any precision improvement and means floating-point z-buffers are effectively useless. It wasn't until OpenGL 4.5, six years after 32-bit floating-point z-buffers were introduced, that the ability to set the z-buffer range from 0.0 to 1.0 was finally added with the glClipControl() function. Unfortunately, Apple stopped updating OpenGL support for macOS after version 4.1, which means that implementing a floating-point reversed z-buffer within Supermodel would mean breaking all support for macOS. Also glClipControl() is not supported in OpenGL ES, which means that we would not be able to port Supermodel to Android.

The only other way to effectively implement a floating-point reversed z-buffer without using glClipControl() is to write the depth values within the fragment shader. As it turns out we already do this for the quad renderer, but not for the triangle renderer which exists mostly to provide better performance on GPUs not powerful enough to run the quad renderer smoothly; modifying the fragment shader to write depth values would hurt performance due to not being able to perform early z-testing, not to mention the additional calculations that would be required.

Because the Khronos Group took six years to add the glClipControl() function, and because Apple refuses to support OpenGL past version 4.1, and because we don't want to abandon support for macOS, I can't integrate my floating-point reversed z-buffer into Supermodel. It's really annoying because it works so well on my personal build; even with the near clipping plane value set infinitesimally small (e.g. 1.0e-16) there is no visible z-fighting.

If Apple one day decides to drop support for OpenGL altogether, I might say "screw it" and integrate the floating-point z-buffer anyway ;)
model123
Posts: 2
Joined: Wed Nov 08, 2023 9:59 am

Re: Floating point z-buffers and why I'm not adding them to Supermodel (yet)

Post by model123 »

I'm not a programmer, so I might be wrong.

OpenGL 4.1 z-buffers will stop development unless there are major errors or bugs
Is it possible to create an option to use OpenGL 4.5's glClipControl() (for example -new-zbuffers) and proceed with development?

I have one more question
Does using glClipControl() also improve performance for quad rendering?

Use Google Translate
gm_matthew
Posts: 15
Joined: Wed Nov 08, 2023 2:10 am

Re: Floating point z-buffers and why I'm not adding them to Supermodel (yet)

Post by gm_matthew »

It wouldn't improve performance on the GPU side, but it would mean that the code used to calculate the near/far clipping planes wouldn't need to be run. The way it works is that it manually transforms every model that intersects with the left, right, top and bottom clipping planes and checks every polygon to determine the minimum and maximum z-values; cutting this out might speed up the render thread slightly on the CPU side.

On a system that doesn't support OpenGL 4.5 the function glClipControl() wouldn't point to anything, and would crash if we tried to run it. But maybe... maybe we could check if it points to nothing and fall back to more conservative near/far clipping planes if it does...
Ian
Posts: 26
Joined: Wed Nov 08, 2023 10:26 am

Re: Floating point z-buffers and why I'm not adding them to Supermodel (yet)

Post by Ian »

The only other way to effectively implement a floating-point reversed z-buffer without using glClipControl() is to write the depth values within the fragment shader. As it turns out we already do this for the quad renderer, but not for the triangle renderer which exists mostly to provide better performance on GPUs not powerful enough to run the quad renderer smoothly;
It might be possible to do this for the triangle renderer too in a way which isn't too expensive.

I looked up extensions yesterday. So beyond a core version opengl can support any number of extensions, but unfortunately apple doesn't support the extensions we require. Also surprising how few extensions they actually do support.

But yes it's a frustrating situation. It's crazy that floating point depth buffers are almost useless in opengl (worse than just integer formats) due to the way floating point precision works without reverse Z / clip control.
I have one more question
Does using glClipControl() also improve performance for quad rendering?
Maybe a tiny bit. The code software clips any the polys in any nodes that traverse the view frustum, so that path is slightly more expensive on the CPU but it's honestly not too bad.
Post Reply