1

While reading Physically Based Rendering in Filament I found a few interesting paragraphs in section 4.4.1 about optimizing the implementation of a GGX NDF approximation for half precision floats. I understood that the calculation of 1 - dot(n, h) * dot(n,h) can cause so called catastrophic cancellation and why using the cross product solves the problem, however I didn't get how is any of this related to half precision floats.

It seems that GLSL does not have any half specifier, unlike HLSL (which simply maps it to float since D3D10 most likely because modern desktop hardware doesn't support it anyway; though it seems that with the newest hardware its back again). The thing with Filament is that it is primarly developed for mobile platforms like Android, where half precision floats are supported in hardware.

I understand that using half precision floats is important for performance on both mobile and the most modern desktop targets. As such I would like to understand how is the following code optimized for half precision floats as I can see no half specifier or similar, but merely some constant and a macro:

#define MEDIUMP_FLT_MAX    65504.0
#define saturateMediump(x) min(x, MEDIUMP_FLT_MAX)

float D_GGX(float roughness, float NoH, const vec3 n, const vec3 h) {
    vec3 NxH = cross(n, h);
    float a = NoH * roughness;
    float k = roughness / (dot(NxH, NxH) + a * a);
    float d = k * k * (1.0 / PI);
    return saturateMediump(d);
}

For completeness, here is the unoptimized code:

float D_GGX(float NoH, float roughness) {
    float a = NoH * roughness;
    float k = roughness / (1.0 - NoH * NoH + a * a);
    return k * k * (1.0 / PI);
}
janekb04
  • 4,304
  • 2
  • 20
  • 51

1 Answers1

2

While GLSL does not have a half type, it does have precision qualifiers whose effects are exclusive-to and dependent-on mobile platforms. I'm assuming that the (complete) optimized shader code from your example contains a default qualifier setting floats to mediump like so: precision mediump float; Note though that the actual precision remains unspecified, a mediump float might have 16 bits on one platform while it has 24 bits on another.

Here's the catch though: As stated in the linked article and the GLSL specification precision qualifiers are only supported for portability and ought to have no effect on desktop platforms. That means that even desktop GPUs with float16 support would break with the specification if they honored the precision qualifier. On desktop platforms you'll have to enable and use the appropriate extension(e.g. GL_AMD_gpu_shader_half_float) and its specific syntax(e.g. types) to utilize the float16 capabilities.

LJᛃ
  • 7,655
  • 2
  • 24
  • 35