Bug report: Setting a uniform uint64_t with named function interferes with program state

After searching for a bizarre bug in our application for two days, I could finally isolate what I assume has to be a driver bug. If a named function (glProgramUniform1ui64NV, glProgramUniform1ui64vNV( , , 1, ), glProgramUniform1ui64vARB( , , 1, )) is used to set a 64 bit uniform of a program with another program currently in use, the 64 bit value is apparently set for both programs at the uniform location of the first one.

To check this, I used two programs:

#version 450
...
layout(bindless_image, r32i) uniform restrict writeonly iimage1D debugImage;

uniform bool a0;
uniform uint64_t a1;
uniform int a2 = 1337;

void main()
{
    ... // dummy use of a0 and a1 so they are not optimized away

    imageStore(debugImage, 0, ivec4(a2));
}

and

#version 450
...
layout(bindless_image, r32i) uniform restrict writeonly iimage1D debugImage;

uniform uint64_t b0;
uniform int b1 = 1337;

void main()
{
    ... // dummy use of b0 so it is not optimized away

    imageStore(debugImage, 0, ivec4(b1));
}

So the only difference is the missing bool variable in the second shader. Both times, I simply write the value of the int variable to an image of which content I read afterwards.

From the host side, the setup is:

GLuint programA = ...
GLint progALoc0 = glGetUniformLocation(programA, "a0"); // 1
GLint progALoc1 = glGetUniformLocation(programA, "a1"); // 2
GLint progALoc2 = glGetUniformLocation(programA, "a2"); // 3

GLuint programB = ...
GLint progBLoc0 = glGetUniformLocation(programB, "b0"); // 1
GLint progBLoc1 = glGetUniformLocation(programB, "b1"); // 2

glUseProgram(programB);

At this point, programB is active, as verified with glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram).

If I now do

for (int i = 0; i < 3; i++)
{
    glProgramUniform1ui64NV(programA, progALoc1, 666ul);
    glProgramUniform1ui64NV(programB, progBLoc0, 0ul);

    glDrawElementsInstanced(...);

    int debugData;
    glGetTextureImage(..., &debugData);

    std::cout << "b1 [" << i << "]: " << debugData << "\n";
}

the output is

b1 [0]: 1337
b1 [1]: 666
b1 [2]: 666

So the value of a1 of programA at location 2 has also been set to variable b1 of programB at location 2. This happens every frame, i.e. if programB is bound anew, the value of b1 is 1337 again in the first iteration.

However, the value 666 that I have set for programA, does only appear inside programB during execution. If I query the value of b1 manually using glGetUniformiv(programB, progBLoc1, &v), the value is always 1337.

If, however, I explicitly bind programB once more after setting the uniform of programA,

for (int i = 0; i < 3; i++)
{
    glProgramUniform1ui64NV(programA, progALoc1, 666ul);

    [b]GLint activeProgram;
    glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
    glUseProgram(activeProgram);[/b]

    glProgramUniform1ui64NV(programB, progBLoc0, 0ul);

    glDrawElementsInstanced(...);

    int debugData;
    glGetTextureImage(..., &debugData);

    std::cout << "b1 [" << i << "]: " << debugData << "\n";
}

the output is

b1 [0]: 1337
b1 [1]: 1337
b1 [2]: 1337

To me, it appears nonsensical to bind the current program again, but it “fixes” the problem. My explanation would be that using glProgramUniform1ui64NV for any other than the current program breaks something that leads to the assignment of values to the same locations in the wrong programs. This must be a bug as the named uniform setters should be independent from the current program. I cannot explain at all why the uniform in the shader (as output to the debug image) has a different value than when I query the value of that uniform from host side.

My system: Windows 8.1 64 bit, GeForce GTX 1080, driver version 382.33.

mOfl,

Thanks for reporting the problem. We have filed an internal bug to track this issue. At the same time I would recommend to try the latest Nvidia driver. 382.33 is quite old.

mOfl,

Can you share the missing part of the code, I would have a look.