Bug 7984 - Display lists cause GL_INVALID_OPERATION when glGetError() called if GL_COMPILE_AND_EXECUTE used with large lists
Summary: Display lists cause GL_INVALID_OPERATION when glGetError() called if GL_COMPI...
Status: RESOLVED FIXED
Alias: None
Product: Mesa
Classification: Unclassified
Component: Mesa core (show other bugs)
Version: 6.4
Hardware: x86 (IA32) Linux (All)
: high normal
Assignee: mesa-dev
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-08-24 09:29 UTC by Robert Ancell
Modified: 2006-08-28 08:01 UTC (History)
0 users

See Also:
i915 platform:
i915 features:


Attachments

Description Robert Ancell 2006-08-24 09:29:52 UTC
Ok this one is really obscure...

If you use Mesa to build a display list using GL_COMPILE_AND_EXECUTE and call
glGetError() inside the list then glGetError() returns GL_INVALID_OPERATION
after calling glEndList(). Also the list needs to contain a large number of
commands.

This was discovered using the Python OpenGL bindings - they call glGetError()
frequently and generate an exception if an error has occured.

I'm really not sure what is going but here are some hints I have been picking up:

o  The bug seems to be based on the number of commands in the display list, i.e.
if you replace the triangles with GL_QUADS then only approx. 1000 * 3 / 4 = 750
iterations are required.

o By using less vertices the bug still occurs if the display list is built
multiple times - it appears it occurs when the total number of commands hits a
threshold of approx. 3000.

Architecture: Intel Pentium 4 (at least two types), AMD XP2000+
OS: Ubuntu 6.06
Repeatable: Always
Occurs in versions: 6.4.1 (from Ubuntu 6.06) and 6.4.2 (from Mesa sf.net page).
Does not occur in ATI fglrx Linux drivers.

Here is a basic example that generates the error:
glNewList(4, GL_COMPILE_AND_EXECUTE); // Must be GL_COMPILE_AND_EXECUTE
glBegin(GL_TRIANGLES);
for(i = 0; i < 1000; i++) // Must be 1000 triangles in one frame to occur
{
   glVertex3f(-0.8, -0.8, 1.0);
   glVertex3f(0.8, -0.8, 1.0);
   glVertex3f(0.0, 0.8, 1.0);
}
glGetError();
glEnd();
glEndList();
printf("Error=%i\n", glGetError()); // Prints "Error = 1282"
Comment 1 Robert Ancell 2006-08-24 09:33:24 UTC
Here is a full Glut program that causes the bug for me:
#include <stdlib.h>
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glut.h>

// Compile with: gcc -g -Wall -lGL -lglut broken.c -o broken

static void renderScene(void)
{
   glClear(GL_COLOR_BUFFER_BIT);

   glNewList(4, GL_COMPILE_AND_EXECUTE); // Must be GL_COMPILE_AND_EXECUTE
   glBegin(GL_TRIANGLES);
   for(i = 0; i < 1000; i++) // Must be large to occur in one frame
   {
      glVertex3f(-0.8, -0.8, 1.0);
      glVertex3f(0.8, -0.8, 1.0);
      glVertex3f(0.0, 0.8, 1.0);
   }
   glGetError(); // Removing this removes the bug
   glEnd();
   glEndList();
   printf("OpenGL error = %i\n", glGetError());

   glFlush();
}

int main(int argc, char **argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
   glutInitWindowPosition(100,100);
   glutInitWindowSize(320,320);
   glutCreateWindow("Mesa bug?");
   glutDisplayFunc(renderScene);
   glutMainLoop();

   return 1;
}
Comment 2 Brian Paul 2006-08-24 09:38:27 UTC
It's illegal to call glGetError() between glBegin/glEnd, even if you're
compiling a display list.

'man glGetError' and see ERRORS section near end.
Comment 3 Robert Ancell 2006-08-25 02:00:00 UTC
Good point, however:

The behaviour is not consistent. If you set the loop to 1 then the
GL_INVALID_OPERATION is not generated.

I made a mistake in the example; if you change it to:

static void renderScene(void)
{
   int i;

   glClear(GL_COLOR_BUFFER_BIT);

   glNewList(4, GL_COMPILE_AND_EXECUTE); // Must be GL_COMPILE_AND_EXECUTE
   glBegin(GL_TRIANGLES);
   for(i = 0; i < 1000; i++) // Must be large to occur in one frame
   {
      glVertex3f(-0.8, -0.8, 1.0);
      glVertex3f(0.8, -0.8, 1.0);
      glVertex3f(0.0, 0.8, 1.0);
   }
   glEnd();
   glGetError(); // Removing this removes the bug
   glEndList();
   printf("OpenGL error = %i\n", glGetError());

   glFlush();
}

The error should not be generated but it does. This is what causes the Python
bindings to fail as glGetError() is called before all calls to glEndList(). The
OpenGL man pages and spec seem to indicate this should be valid behaviour.

I have run both these examples using MESA_DEBUG=1 and it matches the behaviour I
am getting from glGetError(). i.e. displays "Mesa: User error:
GL_INVALID_OPERATION in begin/end" if there is a glGetError() called inside a
glNewList/glEndList AND the loop is 1000 or more (independant of if the
glGetError() is in/outside the glBegin/glEnd pair).
Comment 4 Brian Paul 2006-08-25 08:44:43 UTC
OK, I found the problem and checked in the fix.
Comment 5 Robert Ancell 2006-08-26 05:28:02 UTC
Thanks, could you point at the files changed?
Comment 6 Brian Paul 2006-08-28 08:01:50 UTC
Mesa/src/mesa/tnl/t_save_api.c


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.