One of our programs which relies on shaders heavily is having issues,
and I have tracked it down to unexpected values in gl_NormalMatrix
within the fragment shader.

Using the attached program (patch against mesademos repo) I did
printf-esque debugging to get the values of gl_NormalMatrix.  Search
for 'fragShaderText' to see the shaders I'm using.  I get different
results on a Mesa 7.10.2 (Ubuntu 11.04) system with an Intel card
versus an nvidia-binary-blob system.  The nvidia-based system also
agrees with what I get using any card on a Mac and nvidia or ATI
cards on Windows (native drivers, not Mesa); we have no results for
Windows/Intel yet.

      nvidia                  intel
[ 1.0   0.0   0.0 ]    [ 1.0   0.0   0.0  ]
[ 0.0  -0.0   1.0 ]    [ 0.0   0.0  >0.0, <0.0001 ]
[ 0.0  -1.0  -0.0 ]    [ 1.0  15.0   0.0  ]

I used "-0.0" for a couple slots on the nvidia system; the value was
smaller than 0.0, but larger than 0-epsilon for some small epsilon,
similar to gl_NormalMatrix[1].z on intel but in the opposite direction.

I spot-checked gl_NormalMatrix[2].y with LIBGL_ALWAYS_SOFTWARE=1.  In
that case, Mesa agrees with the nvidia driver: the value is -1.0.  My
application also produces imagery identical (via a subjective eye test,
haven't tried image differencing the two) to the nvidia system when I
run it with LIBGL_ALWAYS_SOFTWARE=1.

On the intel system:

  GL_VENDOR: Tungsten Graphics, Inc
  GL_RENDERER: Mesa DRI Intel(R) Sandybridge Desktop GEM 20100330 DEVELOPMENT
  GL_VERSION: 2.1 Mesa 7.10.2

>From 'dmesg', I gather the GPU is an i915.

Is this a known issue?  Any workarounds available?  Anything else I
could do to help debug?

Thanks,

-tom

From c4b3d54e4d0ca991b8d76a4391d9c820fbb22747 Mon Sep 17 00:00:00 2001
From: Tom Fogal <tfo...@alumni.unh.edu>
Date: Thu, 6 Oct 2011 14:37:40 -0600
Subject: [PATCH] Add new test program to test gl_NormalMatrix issue.

Play with the 'if' condition in fragShaderText to identify what
any given gl_NormalMatrix entry is.
---
 src/demos/CMakeLists.txt |    1 +
 src/demos/normal.c       |  611 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 612 insertions(+), 0 deletions(-)
 create mode 100644 src/demos/normal.c

diff --git a/src/demos/CMakeLists.txt b/src/demos/CMakeLists.txt
index f1bcc03..b35fae6 100644
--- a/src/demos/CMakeLists.txt
+++ b/src/demos/CMakeLists.txt
@@ -51,6 +51,7 @@ set (targets
 	lodbias
 	morph3d
 	multiarb
+	normal
 	paltex
 	pixeltest
 	pointblast
diff --git a/src/demos/normal.c b/src/demos/normal.c
new file mode 100644
index 0000000..04ae5c5
--- /dev/null
+++ b/src/demos/normal.c
@@ -0,0 +1,611 @@
+/**
+ * Test gl_NormalMatrix.
+ * Tom Fogal
+ * 5 Oct 2011
+ *
+ * Based on Test OpenGL 2.0 vertex/fragment shaders.
+ * Brian Paul
+ * 1 November 2006
+ *
+ * Based on ARB version by:
+ * Michal Krol
+ * 20 February 2006
+ *
+ * Based on the original demo by:
+ * Brian Paul
+ * 17 April 2003
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glew.h>
+#include "glut_wrap.h"
+
+
+#define TEXTURE 0
+
+static GLint CoordAttrib = 0;
+
+static char *FragProgFile = NULL;
+static char *VertProgFile = NULL;
+
+static GLfloat diffuse[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
+static GLfloat specular[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
+static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 0.0f };
+static GLfloat delta = 1.0f;
+
+static GLuint fragShader;
+static GLuint vertShader;
+static GLuint program;
+
+static GLuint SphereList, RectList, CurList;
+static GLint win = 0;
+static GLboolean anim = GL_TRUE;
+static GLboolean wire = GL_FALSE;
+static GLboolean pixelLight = GL_TRUE;
+
+static GLint t0 = 0;
+static GLint frames = 0;
+
+static GLfloat xRot = 90.0f, yRot = 0.0f;
+
+
+static void
+normalize(GLfloat *dst, const GLfloat *src)
+{
+   GLfloat len = sqrt(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
+   dst[0] = src[0] / len;
+   dst[1] = src[1] / len;
+   dst[2] = src[2] / len;
+   dst[3] = src[3];
+}
+
+
+static void
+Redisplay(void)
+{
+   GLfloat vec[4];
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   /* update light position */
+   normalize(vec, lightPos);
+   glLightfv(GL_LIGHT0, GL_POSITION, vec);
+   
+   if (pixelLight) {
+      glUseProgram(program);
+      glDisable(GL_LIGHTING);
+   }
+   else {
+      glUseProgram(0);
+      glEnable(GL_LIGHTING);
+   }
+
+   glPushMatrix();
+   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
+   glRotatef(yRot, 0.0f, 1.0f, 0.0f);
+   /*
+   glutSolidSphere(2.0, 10, 5);
+   */
+   glCallList(CurList);
+   glPopMatrix();
+
+   glutSwapBuffers();
+   frames++;
+
+   if (anim) {
+      GLint t = glutGet(GLUT_ELAPSED_TIME);
+      if (t - t0 >= 5000) {
+         GLfloat seconds =(GLfloat)(t - t0) / 1000.0f;
+         GLfloat fps = frames / seconds;
+         printf("%d frames in %6.3f seconds = %6.3f FPS\n",
+                frames, seconds, fps);
+         fflush(stdout);
+         t0 = t;
+         frames = 0;
+      }
+   }
+}
+
+
+static void
+Idle(void)
+{
+   lightPos[0] += delta;
+   if (lightPos[0] > 25.0f || lightPos[0] < -25.0f)
+      delta = -delta;
+   glutPostRedisplay();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+   glViewport(0, 0, width, height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0f, 0.0f, -15.0f);
+}
+
+
+static void
+CleanUp(void)
+{
+   glDeleteShader(fragShader);
+   glDeleteShader(vertShader);
+   glDeleteProgram(program);
+   glutDestroyWindow(win);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+  (void) x;
+  (void) y;
+
+   switch(key) {
+   case ' ':
+   case 'a':
+      anim = !anim;
+      if (anim)
+         glutIdleFunc(Idle);
+      else
+         glutIdleFunc(NULL);
+      break;
+   case 'x':
+      lightPos[0] -= 1.0f;
+      break;
+   case 'X':
+      lightPos[0] += 1.0f;
+      break;
+   case 'w':
+      wire = !wire;
+      if (wire)
+         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+      else
+         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+      break;
+   case 'o':
+      if (CurList == SphereList)
+         CurList = RectList;
+      else
+         CurList = SphereList;
+      break;
+   case 'p':
+      pixelLight = !pixelLight;
+      if (pixelLight)
+         printf("Per-pixel lighting\n");
+      else
+         printf("Conventional lighting\n");
+      break;
+   case 27:
+      CleanUp();
+      exit(0);
+      break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+   const GLfloat step = 3.0f;
+
+  (void) x;
+  (void) y;
+
+   switch(key) {
+   case GLUT_KEY_UP:
+      xRot -= step;
+      break;
+   case GLUT_KEY_DOWN:
+      xRot += step;
+      break;
+   case GLUT_KEY_LEFT:
+      yRot -= step;
+      break;
+   case GLUT_KEY_RIGHT:
+      yRot += step;
+      break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+TestFunctions(void)
+{
+   printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
+
+   assert(glIsProgram(program));
+   assert(glIsShader(fragShader));
+   assert(glIsShader(vertShader));
+
+   /* attached shaders */
+   {
+      GLuint shaders[20];
+      GLsizei count;
+      int i;
+      glGetAttachedShaders(program, 20, &count, shaders);
+      for (i = 0; i < count; i++) {
+         printf("Attached: %u\n", shaders[i]);
+         assert(shaders[i] == fragShader ||
+                shaders[i] == vertShader);
+      }
+   }
+
+   {
+      GLchar log[1000];
+      GLsizei len;
+      glGetShaderInfoLog(vertShader, 1000, &len, log);
+      printf("Vert Shader Info Log: %s\n", log);
+      glGetShaderInfoLog(fragShader, 1000, &len, log);
+      printf("Frag Shader Info Log: %s\n", log);
+      glGetProgramInfoLog(program, 1000, &len, log);
+      printf("Program Info Log: %s\n", log);
+   }
+
+   /* active uniforms */
+   {
+      GLint n, max, i;
+      glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
+      glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max);
+      printf("Num uniforms: %d  Max name length: %d\n", n, max);
+      for (i = 0; i < n; i++) {
+         GLint size, len;
+         GLenum type;
+         char name[100];
+         glGetActiveUniform(program, i, 100, &len, &size, &type, name);
+         printf("  %d: %s nameLen=%d size=%d type=0x%x\n",
+                i, name, len, size, type);
+      }
+   }
+}
+
+
+#if TEXTURE
+static void
+MakeTexture(void)
+{
+#define SZ0 64
+#define SZ1 32
+   GLubyte image0[SZ0][SZ0][SZ0][4];
+   GLubyte image1[SZ1][SZ1][SZ1][4];
+   GLuint i, j, k;
+
+   /* level 0: two-tone gray checkboard */
+   for (i = 0; i < SZ0; i++) {
+      for (j = 0; j < SZ0; j++) {
+         for (k = 0; k < SZ0; k++) {
+            if ((i/8 + j/8 + k/8) & 1) {
+               image0[i][j][k][0] = 
+               image0[i][j][k][1] = 
+               image0[i][j][k][2] = 200;
+            }
+            else {
+               image0[i][j][k][0] = 
+               image0[i][j][k][1] = 
+               image0[i][j][k][2] = 100;
+            }
+            image0[i][j][k][3] = 255;
+         }
+      }
+   }
+
+   /* level 1: two-tone green checkboard */
+   for (i = 0; i < SZ1; i++) {
+      for (j = 0; j < SZ1; j++) {
+         for (k = 0; k < SZ1; k++) {
+            if ((i/8 + j/8 + k/8) & 1) {
+               image1[i][j][k][0] = 0;
+               image1[i][j][k][1] = 250;
+               image1[i][j][k][2] = 0;
+            }
+            else {
+               image1[i][j][k][0] = 0;
+               image1[i][j][k][1] = 200;
+               image1[i][j][k][2] = 0;
+            }
+            image1[i][j][k][3] = 255;
+         }
+      }
+   }
+
+   glActiveTexture(GL_TEXTURE2); /* unit 2 */
+   glBindTexture(GL_TEXTURE_2D, 42);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ0, SZ0, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image0);
+   glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, SZ1, SZ1, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image1);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+   glActiveTexture(GL_TEXTURE4); /* unit 4 */
+   glBindTexture(GL_TEXTURE_3D, 43);
+   glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, SZ0, SZ0, SZ0, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image0);
+   glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA, SZ1, SZ1, SZ1, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image1);
+   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
+   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+}
+#endif
+
+
+static void
+MakeSphere(void)
+{
+   GLUquadricObj *obj = gluNewQuadric();
+   SphereList = glGenLists(1);
+   gluQuadricTexture(obj, GL_TRUE);
+   glNewList(SphereList, GL_COMPILE);
+   gluSphere(obj, 2.0f, 10, 5);
+   glEndList();
+   gluDeleteQuadric(obj);
+}
+
+static void
+VertAttrib(GLint index, float x, float y)
+{
+#if 1
+   glVertexAttrib2f(index, x, y);
+#else
+   glTexCoord2f(x, y);
+#endif
+}
+
+static void
+MakeRect(void)
+{
+   RectList = glGenLists(1);
+   glNewList(RectList, GL_COMPILE);
+   glNormal3f(0, 0, 1);
+   glBegin(GL_POLYGON);
+   VertAttrib(CoordAttrib, 0, 0);   glVertex2f(-2, -2);
+   VertAttrib(CoordAttrib, 1, 0);   glVertex2f( 2, -2);
+   VertAttrib(CoordAttrib, 1, 1);   glVertex2f( 2,  2);
+   VertAttrib(CoordAttrib, 0, 1);   glVertex2f(-2,  2);
+   glEnd();    /* XXX omit this and crash! */
+   glEndList();
+}
+
+
+
+static void
+LoadAndCompileShader(GLuint shader, const char *text)
+{
+   GLint stat;
+
+   glShaderSource(shader, 1, (const GLchar **) &text, NULL);
+
+   glCompileShader(shader);
+
+   glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
+   if (!stat) {
+      GLchar log[1000];
+      GLsizei len;
+      glGetShaderInfoLog(shader, 1000, &len, log);
+      fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
+      exit(1);
+   }
+}
+
+
+/**
+ * Read a shader from a file.
+ */
+static void
+ReadShader(GLuint shader, const char *filename)
+{
+   const int max = 100*1000;
+   int n;
+   char *buffer = (char*) malloc(max);
+   FILE *f = fopen(filename, "r");
+   if (!f) {
+      fprintf(stderr, "fslight: Unable to open shader file %s\n", filename);
+      exit(1);
+   }
+
+   n = fread(buffer, 1, max, f);
+   printf("fslight: read %d bytes from shader file %s\n", n, filename);
+   if (n > 0) {
+      buffer[n] = 0;
+      LoadAndCompileShader(shader, buffer);
+   }
+
+   fclose(f);
+   free(buffer);
+}
+
+
+static void
+CheckLink(GLuint prog)
+{
+   GLint stat;
+   glGetProgramiv(prog, GL_LINK_STATUS, &stat);
+   if (!stat) {
+      GLchar log[1000];
+      GLsizei len;
+      glGetProgramInfoLog(prog, 1000, &len, log);
+      fprintf(stderr, "Linker error:\n%s\n", log);
+   }
+}
+
+
+static void
+Init(void)
+{
+   static const char *fragShaderText =
+      "void main(void) {\n"
+      "  if(-0.000001 <= gl_NormalMatrix[2].z && gl_NormalMatrix[2].z <= 0.0) {\n"
+      "    gl_FragColor = vec4(1.0, 0.0, 0.0, 0.05);\n"
+      "  } else if(0.0 <= gl_NormalMatrix[1].y && gl_NormalMatrix[1].y <= 0.5)"
+      "  {\n"
+      "    gl_FragColor = vec4(0.0, 1.0, 0.0, 0.05);\n"
+      "  } else {\n"
+      "    gl_FragColor = vec4(0.0, 0.0, 1.0, 0.05);\n"
+      "  }\n"
+      "}\n";
+/*      "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" */
+   static const char *vertShaderText =
+      "void main() {\n"
+      "  gl_Position = ftransform();\n"
+      "}\n";
+
+   if (!GLEW_VERSION_2_0) {
+      printf("This program requires OpenGL 2.x or higher\n");
+      exit(1);
+   }
+
+   GLfloat mview[16];
+   glGetFloatv(GL_MODELVIEW_MATRIX, mview);
+   printf("mview:\n"
+          "[%g  %g  %g  %g]\n"
+          "[%g  %g  %g  %g]\n"
+          "[%g  %g  %g  %g]\n"
+          "[%g  %g  %g  %g]\n",
+          mview[ 0], mview[ 1], mview[ 2], mview[ 3],
+          mview[ 4], mview[ 5], mview[ 6], mview[ 7],
+          mview[ 8], mview[ 9], mview[10], mview[11],
+          mview[12], mview[13], mview[14], mview[15]);
+
+   fragShader = glCreateShader(GL_FRAGMENT_SHADER);
+   if (FragProgFile)
+      ReadShader(fragShader, FragProgFile);
+   else
+      LoadAndCompileShader(fragShader, fragShaderText);
+
+
+   vertShader = glCreateShader(GL_VERTEX_SHADER);
+   if (VertProgFile)
+      ReadShader(vertShader, VertProgFile);
+   else
+      LoadAndCompileShader(vertShader, vertShaderText);
+
+   program = glCreateProgram();
+   glAttachShader(program, fragShader);
+   glAttachShader(program, vertShader);
+   glLinkProgram(program);
+   CheckLink(program);
+   glUseProgram(program);
+
+   if (CoordAttrib) {
+      int i;
+      glBindAttribLocation(program, CoordAttrib, "coord");
+      i = glGetAttribLocation(program, "coord");
+      assert(i >= 0);
+      if (i != CoordAttrib) {
+         printf("Hmmm, NVIDIA bug?\n");
+         CoordAttrib = i;
+      }
+      else {
+         printf("Mesa bind attrib: coord = %d\n", i);
+      }
+   }
+
+   /*assert(glGetError() == 0);*/
+
+   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_LIGHTING);
+   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
+   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
+   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);
+
+   MakeSphere();
+   MakeRect();
+
+   CurList = SphereList;
+
+#if TEXTURE
+   MakeTexture();
+#endif
+
+   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
+   printf("Press p to toggle between per-pixel and per-vertex lighting\n");
+
+   /* test glGetShaderSource() */
+   if (0) {
+      GLsizei len = strlen(fragShaderText) + 1;
+      GLsizei lenOut;
+      GLchar *src =(GLchar *) malloc(len * sizeof(GLchar));
+      glGetShaderSource(fragShader, 0, NULL, src);
+      glGetShaderSource(fragShader, len, &lenOut, src);
+      assert(len == lenOut + 1);
+      assert(strcmp(src, fragShaderText) == 0);
+      free(src);
+   }
+
+   assert(glIsProgram(program));
+   assert(glIsShader(fragShader));
+   assert(glIsShader(vertShader));
+
+   glColor3f(1, 0, 0);
+
+   /* for testing state vars */
+   {
+      static GLfloat fc[4] = { 1, 1, 0, 0 };
+      static GLfloat amb[4] = { 1, 0, 1, 0 };
+      glFogfv(GL_FOG_COLOR, fc);
+      glLightfv(GL_LIGHT1, GL_AMBIENT, amb);
+   }
+
+#if 0
+   TestFunctions();
+#else
+   (void) TestFunctions;
+#endif
+}
+
+
+static void
+ParseOptions(int argc, char *argv[])
+{
+   int i;
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-fs") == 0) {
+         FragProgFile = argv[++i];
+      }
+      else if (strcmp(argv[i], "-vs") == 0) {
+         VertProgFile = argv[++i];
+      }
+      else {
+         fprintf(stderr, "unknown option %s\n", argv[i]);
+         break;
+      }
+   }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   glutInitWindowSize(200, 200);
+   glutInit(&argc, argv);
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+   win = glutCreateWindow(argv[0]);
+   glewInit();
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutSpecialFunc(SpecialKey);
+   glutDisplayFunc(Redisplay);
+   if (anim)
+      glutIdleFunc(Idle);
+   ParseOptions(argc, argv);
+   Init();
+   glutMainLoop();
+   return 0;
+}
+
+
-- 
1.7.3.4

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to