Compiler Behavior Notes
From shaderLABS
More actions
All GPU drivers have quirks that violate the GLSL specification or interpret it differently. They can lead to crashes, compilation errors and visual glitches. This non-exhaustive list aims to document as many of them as possible.
Windows
Nvidia
- Includes before the
#version
argument are not supported.- The GLSL spec says that
#version
must be the first non-whitespace line in your code.
- The GLSL spec says that
- Equal conditions using floats may not work as intended.
- e.g.
if (a == 1.0)
- Comparing floats this way is considered bad practice since there's multiple ways to represent a lot of numbers, meaning that they might have different values. A more reliable way is to either convert them to
int
s first or do something likeif(abs(a - 1.0) < 0.0001)
- e.g.
- Constant arguments of functions get compiled as actual constants and can be used in constant expressions.
- e.g.
void blah(const int a, const float b)
- e.g.
mix()
is not supported in constant expressions on GeForce 500 and older.- Can be manually implemented like this:
#define cmix(x, y, a) (y * a + x * (1.0 - a))
- Can be manually implemented like this:
- GL Extensions have to be explicitly enabled (e.g.
GL_ARB_shader_texture_lod
). - GL Extension
#extension GL_EXT_gpu_shader4 : enable
is required for specific operations, even on GL300 and newer when using function calls with the2D
or3D
suffix (e.g.texelFetch2D()
). - NaNs may occur when not clamping the framebuffer used for the main scene color, especially on blacks.
- Doing a clamp with a minimum of
1.0 / k
on said buffer fixes the issue, with k being the maximum amount of discreet values supported by the current buffer precision (e.g.255.0
on 8 bit and65535.0
on 16 bit).
- Doing a clamp with a minimum of
- Normalizing a zero vector results in NaNs.
- Implicit casts from
int
/uint
to float may fail to compile. - Variables marked as
const
that aren't constant expressions are allowed treated as immutable, even prior to GLSL 4.2 where this is illegal according to the spec.
AMD
- Constants using some of the built-in functions are not supported.
- e.g.
const float f = const_func();
- They can be manually implemented as macro, just like non-built-in functions:
- e.g.
#define add(x, y) (x + y)
instead offloat add(float x, float y) { return x + y; }
- e.g.
- The same might apply to constants made of other constants.
- e.g.
- Sampling textures outside of
void main()
causes sampling of a wrong texture.- Sampling inside a function works fine, as long as it doesn't get used outside of
void main()
or other functions.
- Sampling inside a function works fine, as long as it doesn't get used outside of
- Reserved words:
buffer
,input
andhalf
input
is reserved for future use as part of specification.half
is reserved as part of specification.
- Using
gl_MultiTexcoord
on GLSL 1.3+ without the compatibility profile is allowed.gl_MultiTexCoord
was deprecated in GLSL 1.3 and removed from the core profile in 1.4, so it shouldn't be possible to use in a core profile of 1.4 or later.
- Some GL Extensions will be enabled automatically when used without explicitly being enabled (e.g.
GL_ARB_shader_texture_lod
). - The usage of geometry shaders on terrain requires external triangulation for quad-geometry.
- Using shadow mipmaps with a shadow map resolution that is not a power of two can cause a crash on loading.
- Function type casting from float to a vector type is apparently supported.
- Variables marked as
const
that aren't constant expressions are not allowed, even in GLSL 4.2+ where this is legal according to the spec (the variables should be treated as immutable).
Intel
- Reserved word:
half
half
is reserved as part of specification.
- Only up to seven framebuffer attachments are supported.
- The specification only guarantees seven but allows more.
- GLSL 3.0+ guarantees eight framebuffer attachments.
- Recursive macros are not allowed (e.g.
#define smoothstep(x, low, high) smoothstep(low, high, x)
). - Extensions have to be declared directly after the
#version
directive. - Constants using built-in functions may fail to compile.
- e.g.
const float f = const_func();
- They can be manually implemented as macro.
- e.g.
#define add(x, y) (x+y)
instead offloat add(float x, float y) {return x + y;}
- e.g.
- e.g.
- Constants using
struct
inputs are not supported.
macOS
- Empty external declarations (just a single
;
at the global level) are not allowed. This includes semicolons after function definitions likevoid main() { ... };
where the semicolon is technically separate from the function definition and constitutes its own (empty) external declaration.
Apple Silicon (M1 or Newer)
- Calling a function in the global scope (outside of other functions) crashes the whole application.
- Instead, move the initialization to the top of the
main
function and only keep the declaration in its original location.
- Instead, move the initialization to the top of the
- Arrays of arrays (eg.
vec2[8][4]
) crash the whole application as well.
Linux
Mesa (AMD, Open Source)
- Only GLSL 1.1, 1.2, 1.3, 1.0 ES, 3.0 ES, 3.1 ES and 3.2 ES are supported (possibly only affects APUs).
- On Polaris/Vega based cards, GLSL 4.3 compatibility is available.
EXT_gpu_shader_4
is not supported.- Certain features can be achieved with different extensions.
- If an image has LODs enabled but gets overwritten in the next pass, the LODs from the previous pass are still bound.
- This can lead to wrong information being read unless the LOD to be read from is explicitly declared (
textureLod()
).
- This can lead to wrong information being read unless the LOD to be read from is explicitly declared (
Nouveau (Nvidia, Open Source)
- Not compatible.
Nvidia (proprietary)
- Same as on Windows.
AMD (proprietary)
- Same as on Windows.