Nvidia driver OpenGL3+ ruin mat4 calculated in Vetrex and used as out/in from/to vertex/fragment, bug confirmed

Nvidia forum bugreport link

Bug - using varying-like logic(out/in), and sending mat4 from Vertex to Fragment, this mat4 can be ruined if more mat4 logic used in Vertex function.

Bug confirmed - on Linux and Windows on Nvidia 7XX 9XX and 1XXX Series GPU, in OpenGL mode.
The bug does not work in Vulkan and DX11(using ANGLE).

Test:
This bug was found in Godot, and work in any minimal OpenGL3+ engine, this is not Godot bug.
Original Godot bugreport link.

Easy way to test:

  1. if you on Windows, then disable ANGLE first, launch chrome using
    chrome.exe --use-angle=gl
  2. open this link Web WebGL2 test link

Bug visual result:

Correct visual result:

Shader code of this bug:
Shader code for OpenGL3+, launch in any OpenGL3+ engine.
(this code is right quad on the screenshot, bug result green/white, correct is green/red)

main.vert

#version 300 es
in vec4 position;

out mat4 mtx;
out mat4 tmtx;

void translate(inout mat4 m, vec3 d){
    m[3][0] = d.x;
    m[3][1] = d.y;
    m[3][2] = d.z;

    m[3].xyz=d; //does not matter, both does not work
}

void main() {
    gl_Position = vec4(position.xyz,1.);
    
    mtx=mat4(vec4(1.),vec4(1.),vec4(1.),vec4(1.));
    tmtx=mat4(vec4(0.),vec4(0.),vec4(0.),vec4(0.));
    tmtx=mtx;

    vec3 a=vec3(1.,0.,0.);
    vec3 b=vec3(0.,1.,0.);

    //bug
    translate(tmtx,a);
    //tmtx[3].xyz=a; //fix

    mtx[3].xyz=b;
}

main.frag

#version 300 es
#ifdef GL_ES
precision highp float;
#endif
uniform vec2 u_resolution;

out vec4 glFragColor;

in mat4 mtx;
in mat4 tmtx;

void main() {
    vec2 uv = gl_FragCoord.xy/u_resolution.xy;
    vec3 col = vec3(0.);
    if(uv.x<0.5)col = mtx[3].xyz;
    else col = tmtx[3].xyz;
    glFragColor = vec4(col,1.);
}

For more shaders code look Godot bugreport page, there 5 shaders that display that mat4 completely ruined.

This bug ruin mat4, and this fix in example shader

    //bug
    translate(tmtx,a);
    //tmtx[3].xyz=a; //fix

this fix only this shader because its minimal, this fix does not work in other shaders with more mat4 logic, there everything broke way too much, I did not found a way to fix large shader logic unless moving everything from Vertex to Fragment shader.

This bug is interesting. And I think I may have a work around for you.

I was playing with the 3 versions of the vertex shader you suggested (the 2 “broken” versions of translate() and the 1 “fix” version which bypasses calling the translate() function entirely).

Tossing this against an older version of the NVIDIA GLSL compiler, I had it dump the generated NV assembly shader for all 3 versions. All output the same result for the mtx matrix:

1 1 1 0
1 1 1 1
1 1 1 0
1 1 1 1

However, they differ in the value output for the tmtx matrix:

"fix" version   other 2 versions
  1 1 1 1           1 1 1 1
  1 1 1 0           1 1 1 1
  1 1 1 0           1 1 1 1
  1 1 1 1           1 1 1 1

It would seem that this line in translate() is basically ignored:

   m[3].xyz = d; //does not matter, both does not work

However, I did find a workaround. In general, it seems that trying to write a subset of the components in that 3rd column of the matrix (in the translate() function) is ignored. However, writing all of them works:

   m[3] = vec4( d, m[3][3] );

I believe these should be equivalent, but alas, compiler bugs happen.

In other words, try this translate() function in your vertex shader instead:

void translate(inout mat4 m, vec3 d)
{
   m[3] = vec4( d, m[3][3] );
}

NOTE: I did not try this on the latest version of the NVIDIA GLSL compiler, as it’s a bit more trouble to snag the assembly there. But if this bug does exist in the latest NVIDIA drivers, it’s probably worth giving this workaround a shot.

1 Like

Thanks for comment, and great reply!

I did not try this on the latest version of the NVIDIA GLSL compiler

I have test this bug on latest drivers Linux/Windows bug works, I know only about 2019 year GLSL driver compiler update, I do not know if its new one or not.

And I think I may have a work around for you.

I have fix my big shaders already, thanks, there is way to avoid this bug for sure… but this is not okey, I think

I was playing with the 3 versions of the vertex shader you suggested (the 2 “broken” versions of translate() and the 1 “fix” version which bypasses calling the translate() function entirely).

as I understand you use Godot bug3.shader?

the biggest problem that at “some point” other out/in can be ruined like critical matrices WORLD_MATRIX that I had ruined in my large shader. I did not make an example for this, minimal code way too large.

as you can see in bug31.shader vs bug32.shader is only single line changed, this

mtx=WORLD_MATRIX; //comment this will ruin line 64 translate function

and when it hide in comment this line translate(tmtx,a); stop working

this makes “fixing this bug” a little bit complicated, I have to debug every single line of my large shader to make it work… not very cool.

bug still valid on latest Nvidia drivers (win and Linux)

and FabriceNeyret found a way to reproduce it in the fragment shader:

If you haven’t already, I would report this to NVIDIA. I’d suggest you post a bug report to their OpenGL Forum, with “Driver Bug:” in the Subject:

* OpenGL Forum (NVIDIA)

Never mind. I see now that you did:

If you still don’t get any response, you might augment this bug report by putting “Driver Bug:” in the subject and including the information described int the 2nd link below:

Once NVIDIA has been provided a simple repro demonstrating that there’s a bug in their drivers, they’re usually pretty quick to fix it.

I can use only their forums
everything else even under VPN does not work (Nvidia is U.S. corporation Im not U.S. citizen)
and they do react to my “most critical bugs and fix them” that reported using their forum

bringing attention to OpenGL my threads is way to get perma-banned there
if they want to react to this they will