driver bugs with glstate.light[i] uniforms in fp

This is reposted from NVIDIA developer forum because in five months no one answer. http://developer.nvidia.com/forums/index.php?showtopic=2141

A week ago I sent a this bug report to NVIDIA. Today I tried to duplicate a description of the problem at a developers forum, but he was unavailable.

Please do not reply to this message

Requester: Konstantin A. Sinitsyn
Bug ID: 461113
Date: 8/28/2008 5:06:39 AM
Company: nvdeveloper
Division: nvdeveloper
Severity: Critical
Synopsis: Programmer question: incorrect driver behavior, fragment program, lighting state variables

Description: problem appears when i render a small piece of data on a several draw calls and before each call i change some light parameters (glstate.light[n].* variables) that are used by my fragment program. It looks like value of light parameter sometimes are not updated.
Problem doesn’t occur when i rebind fragment program or disable/enable lighting or fragement program states.

There is a simple bug reproducing application - http://slil.ru/26539963 (also see attachment)

This problem occured earlier (on previos driver versions) but was hard to localize.

In order to reproduce problem edit this code section in test program

Tested on GF7/8 and all drivers of second half of 2008 year. Bug is represented.

Source code of test program listed below


#include <iostream>
#include <tchar.h>

#include <GL/glew.h>
#include <GL/glut.h>

GLuint g_FragmentProgramID;
bool g_bMousing = false;
int g_iStartX = 0, g_iStartY = 0;

float g_fSpinX = 0.0f, g_fSpinY = 0.0f;

#define BUG_CASE
//#define BUG_HACK 1
//#define BUG_HACK 2
//#define BUG_HACK 3

char g_szFragmentProgramText[] =
   "!!ARBfp1.0
"
#if defined(BUG_CASE)
   "PARAM c[1] = { state.light[0].ambient };
"
#else // BUG_CASE
   "PARAM c[1] = { state.material.front.emission };
"
#endif // BUG_CASE
   "MOV result.color, c[0];
"
   "END
";


//////////////////////////////////////////////////////////////////////
//  Initialize function
//////////////////////////////////////////////////////////////////////

void initialize()
{
   glGenProgramsARB(1, &g_FragmentProgramID);
   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragmentProgramID);

   glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, sizeof(g_szFragmentProgramText) - 1, g_szFragmentProgramText);
}


//////////////////////////////////////////////////////////////////////
//  Rendering callback function
//////////////////////////////////////////////////////////////////////

void display()
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glTranslatef(0.0f, 0.0f, -4.0f);
   glRotatef(-g_fSpinY, 1.0f, 0.0f, 0.0f);
   glRotatef(-g_fSpinX, 0.0f, 1.0f, 0.0f);

   glEnable(GL_FRAGMENT_PROGRAM_ARB);
   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragmentProgramID);

   const size_t ny = 8, nx = 8;
   for (size_t y = 0; y < ny; y++)
   {
      for (size_t x = 0; x < nx; x++)
      {
         GLfloat color[] = {1.0f, 1.0f, GLfloat((x ^ y) & 1), 1.0f};

#if defined(BUG_CASE)
         glLightfv(GL_LIGHT0, GL_AMBIENT, color);

   #if BUG_HACK == 1
         glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragmentProgramID);
   #elif BUG_HACK == 2
         glDisable(GL_FRAGMENT_PROGRAM_ARB);
         glEnable(GL_FRAGMENT_PROGRAM_ARB);
   #elif BUG_HACK == 3
         glDisable(GL_LIGHTING);
         glEnable(GL_LIGHTING);
   #endif // BUG_HACK

#else // BUG_CASE
         glMaterialfv(GL_FRONT, GL_EMISSION, color);
#endif // BUG_CASE

         float const 
            x0 = 2.0f * x / nx - 1.0f,
            y0 = 2.0f * y / ny - 1.0f,
            dx = (2.0f / nx) * 0.95f,
            dy = (2.0f / ny) * 0.95f;

         glBegin(GL_QUADS);
            glVertex2f(x0, y0);
            glVertex2f(x0 + dx, y0);
            glVertex2f(x0 + dx, y0 + dy);
            glVertex2f(x0, y0 + dy);
         glEnd();
      }
   }

   glDisable(GL_FRAGMENT_PROGRAM_ARB);

   glutSwapBuffers();
}


//////////////////////////////////////////////////////////////////////
//  Mouse callback functions
//////////////////////////////////////////////////////////////////////

void mouse( int button, int state, int x, int y )
{
   if (button == GLUT_LEFT_BUTTON)
   {
      if (state == GLUT_DOWN)
      {
         g_bMousing = true;
         g_iStartX = x;
         g_iStartY = y;
      }
      else if (state == GLUT_UP)
         g_bMousing = false;
   }
}

void motion( int x, int y )
{
   if (g_bMousing)
   {
      g_fSpinX -= (x - g_iStartX);
      g_fSpinY -= (y - g_iStartY);

      g_iStartX = x;
      g_iStartY = y;
   }
}


//////////////////////////////////////////////////////////////////////
//  Window callback function
//////////////////////////////////////////////////////////////////////

void reshape( int w, int h )
{
   if (h == 0) h = 1;

   glViewport(0, 0, w, h);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0);

   //glMatrixMode(GL_MODELVIEW);
   //glLoadIdentity();
}


//////////////////////////////////////////////////////////////////////
//  Idle callback functions
//////////////////////////////////////////////////////////////////////

void idle()
{
   glutPostRedisplay();
}


//////////////////////////////////////////////////////////////////////
//  Main entry function
//////////////////////////////////////////////////////////////////////

int _tmain(int argc, _TCHAR* argv[])
{
   glutInit(&argc, argv);
   glutInitWindowSize(512, 512);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
   glutCreateWindow("driver_test");

   glewInit();
   initialize();

   glutDisplayFunc(display);
   glutMouseFunc(mouse);
   glutMotionFunc(motion);
   glutReshapeFunc(reshape);
   glutIdleFunc(idle);

   glutMainLoop();

   return 0;
}

On right picture with defined BUG_CASE, on left BUG_HACK is additionally defined to 1,2 or 3

Another bug has been localized today. This bug occurs with GF7 only on lasted NVIDIA drivers (181.20).

We have a fragment program (fp40) that have a recursive if blocks like this:


!!ARBfp1.0
OPTION NV_fragment_program2;
OPTION ARB_fog_exp2;
PARAM c[3] = { program.local[0], {1,0,0}, {1,1,1} };

SHORT TEMP H0;
SHORT TEMP HC;
SHORT OUTPUT oCol = result.color;

//MOVHC HC.x, c[1].x;
//IF    GT.x;
MOVH  H0.xyz, c[1];

MOVHC HC.x, c[0].x;
IF GT.x;
  MOVHC HC.x, c[0].x;
  IF GT.x;
    MOVHC HC.x, c[0].x;
    IF GT.x;
      MOVHC HC.x, c[0].x;
      IF GT.x;
        MOVHC HC.x, c[0].x;
        IF GT.x;
          MOVHC HC.x, c[0].x;
          IF GT.x;
            MOVHC HC.x, c[0].x;
            IF GT.x;
              MOVH H0.xyz, c[2];
            ENDIF;
          ENDIF;
        ENDIF;
      ENDIF;
    ENDIF;
  ENDIF;
ENDIF;

//ENDIF;

MOV oCol.xyz, H0;

END

This program works very simple. If we set argument to negative value program must return red color and otherwise if we set to argument positive value then all conditions will be passed and program return white color.


out red_color
if arg0 > 0
  if arg0 > 0
  ...
    if arg0 > 0
      out white_color
    endif
  ...
  endif
endif

Finally what bug I mean… If I draw several quads with enabled black fog by this program and for some quads argument is positive and for others is negative. I see something like this:

With colors all is ok. But fog not applied to red quads!!!

If I uncomment first ‘if’ that always ‘true’ resulting image is absolutely correct, but it’s not right :frowning:

Full source of test:


#include <iostream>
#include <tchar.h>

#include <GL/glew.h>
#include <GL/glut.h>

GLuint g_FragmentProgramID;
bool g_bMousing = false;
int g_iStartX = 0, g_iStartY = 0;

float g_fSpinX = 0.0f, g_fSpinY = 0.0f;

char g_szFragmentProgramText[] =
"!!ARBfp1.0
"
"OPTION NV_fragment_program2;
"
"OPTION ARB_fog_exp2;
"
"PARAM c[3] = { program.local[0], {1,0,0}, {1,1,1} };
"

"SHORT TEMP H0;
"
"SHORT TEMP HC;
"
"SHORT OUTPUT oCol = result.color;
"

//"MOVHC HC.x, c[1].x;
"
//"IF    GT.x;
"
"MOVH  H0.xyz, c[1];
"

"MOVHC HC.x, c[0].x;
" 
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"
"MOVHC HC.x, c[0].x;
"
"IF    GT.x;
"

"MOVH  H0.xyz, c[2];
"

"ENDIF;
"
"ENDIF;
"
"ENDIF;
"
"ENDIF;
"
"ENDIF;
"
"ENDIF;
"
"ENDIF;
"

//"ENDIF;
"

"MOV oCol.xyz, H0;
"

"END
";


//////////////////////////////////////////////////////////////////////
//  Initialize function
//////////////////////////////////////////////////////////////////////

void initialize()
{
   glGenProgramsARB(1, &g_FragmentProgramID);
   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragmentProgramID);

   glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, sizeof(g_szFragmentProgramText) - 1, g_szFragmentProgramText);
}


//////////////////////////////////////////////////////////////////////
//  Rendering callback function
//////////////////////////////////////////////////////////////////////

void display()
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glTranslatef(0.0f, 0.0f, -2.0f);
   glRotatef(-g_fSpinY, 1.0f, 0.0f, 0.0f);
   glRotatef(-g_fSpinX, 0.0f, 1.0f, 0.0f);

   glFogi(GL_FOG_MODE, GL_EXP2);
   glFogf(GL_FOG_DENSITY, 0.55f);

   glEnable(GL_FRAGMENT_PROGRAM_ARB);
   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, g_FragmentProgramID);

   static const size_t ny = 4, nx = 4;

   for (size_t y = 0; y < ny; y++)
   {
      for (size_t x = 0; x < nx; x++)
      {
         const GLfloat test_value = (x == y) ? -0.1f : 0.1f;
         glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, test_value, 0.0f, 0.0f, 0.0f);

         float const 
            x0 = 2.0f * x / nx - 1.0f,
            y0 = 2.0f * y / ny - 1.0f,
            dx = (2.0f / nx) * 0.95f,
            dy = (2.0f / ny) * 0.95f;

         glBegin(GL_QUADS);
            glVertex2f(x0, y0);
            glVertex2f(x0 + dx, y0);
            glVertex2f(x0 + dx, y0 + dy);
            glVertex2f(x0, y0 + dy);
         glEnd();
      }
   }

   glDisable(GL_FRAGMENT_PROGRAM_ARB);

   glutSwapBuffers();
}


//////////////////////////////////////////////////////////////////////
//  Mouse callback functions
//////////////////////////////////////////////////////////////////////

void mouse( int button, int state, int x, int y )
{
   if (button == GLUT_LEFT_BUTTON)
   {
      if (state == GLUT_DOWN)
      {
         g_bMousing = true;
         g_iStartX = x;
         g_iStartY = y;
      }
      else if (state == GLUT_UP)
         g_bMousing = false;
   }
}

void motion( int x, int y )
{
   if (g_bMousing)
   {
      g_fSpinX -= (x - g_iStartX);
      g_fSpinY -= (y - g_iStartY);

      g_iStartX = x;
      g_iStartY = y;
   }
}


//////////////////////////////////////////////////////////////////////
//  Window callback function
//////////////////////////////////////////////////////////////////////

void reshape( int w, int h )
{
   if (h == 0) h = 1;

   glViewport(0, 0, w, h);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0);

   //glMatrixMode(GL_MODELVIEW);
   //glLoadIdentity();
}


//////////////////////////////////////////////////////////////////////
//  Idle callback functions
//////////////////////////////////////////////////////////////////////

void idle()
{
   glutPostRedisplay();
}


//////////////////////////////////////////////////////////////////////
//  Main entry function
//////////////////////////////////////////////////////////////////////

int _tmain(int argc, _TCHAR* argv[])
{
   glutInit(&argc, argv);
   glutInitWindowSize(512, 512);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);
   glutCreateWindow("driver_test");

   glewInit();
   initialize();

   glutDisplayFunc(display);
   glutMouseFunc(mouse);
   glutMotionFunc(motion);
   glutReshapeFunc(reshape);
   glutIdleFunc(idle);

   glutMainLoop();

   return 0;
}

yes Ive noticed this years ago on the nv3x though with glsl (though seems to working now though)

http://www.opengl.org/discussion_boards/…true#Post224099

perhaps dont rely on fixed function stuff like
glstate.light[n] etc

I can confirm this bug really takes place on my 7950 at work.
But when i tried to run it at home on 8800, I saw really weird behaviour - quads which might be white were magenta!

I decided to make some more investigations on that and I found out that for 8800 fog applies always, but sometimes output color is got corrupted somehow. And this corruption takes place only for SHORT color output, if I make full precision color output, everything works fine.

So your test uncovered one more nVidia driver problem :slight_smile:

Jackis
I’ve run my test application on GF8, and it’s all right with fog, but driver have some problems with only one IF block. I simplified the fragment program and found that a simple program with a conditional fill of certain color does not work correctly.

There is a fragment program:


!!ARBfp1.0
OPTION NV_fragment_program2;
PARAM c[3] = { program.local[0], {1, 1, 1}, {1, 0, 0} };
TEMP HC;
SHORT OUTPUT oCol = result.color;
MOVH oCol.xyz, c[1];
MOVHC HC.x, c[0].x;
IF GT.x;
MOVH oCol.xyz, c[2];
ENDIF;
END

The test program works so that one the diagonal squares value of parameter is negative (condition fails), and they should be white but they are magenta (like on picture below).

But if you change the line:

SHORT OUTPUT oCol = result.color;

to:

OUTPUT oCol = result.color;

result is correct.