Trouble with VAO's in linux

I have tried to modify this code in order to draw an annulus. I am quite confused why I am getting

OpenGL Error at displayCB()

I know that an answer is “just use glut” but I am trying to see what goes on under the hood, so to speak.
Am I calling Setup() at the wrong time?


//------------------------------------------------------------------------------
//
//   COMPILE WITH:
//       g++ -g -o glx_simple_new glx_simple_new.cxx -lGLU -lGL -lX11
 
//------------------------------------------------------------------------------
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>

#define VERTICES 0
#define INDICES 1
#define ANNULUS 0
#define TRIANGLE 1


// Begin globals.
// Vertex co-ordinate vectors for the annulus.
static float vertices1[] =  
{    
   30.0, 30.0, 0.0,
   10.0, 10.0, 0.0, 
   70.0, 30.0, 0.0,
   90.0, 10.0, 0.0,
   70.0, 70.0, 0.0,
   90.0, 90.0, 0.0,
   30.0, 70.0, 0.0,
   10.0, 90.0, 0.0
};

// Vertex color vectors for the annulus.
static float colors1[] =  
{
   0.0, 0.0, 0.0,
   1.0, 0.0, 0.0,
   0.0, 1.0, 0.0,
   0.0, 0.0, 1.0,
   1.0, 1.0, 0.0,
   1.0, 0.0, 1.0,
   0.0, 1.0, 1.0,
   1.0, 0.0, 0.0
};

// Vertex co-ordinate vectors for the triangle.
static float vertices2[] =  
{    
    40.0, 40.0, 0.0,
    60.0, 40.0, 0.0,
    60.0, 60.0, 0.0
};

// Vertex color vectors for the triangle.
static float colors2[] =  
{
    0.0, 1.0, 1.0,
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0
};

// Triangle strip vertex indices in order.
static unsigned int stripIndices[] = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1};

static unsigned int buffer[2]; // Array of buffer ids.

static unsigned int vao[2]; // Array of VAO ids.

struct MyWin
{
  Display  *display;
  Window    win;
  bool      displayed;
  int       width;
  int       height;
};
 
//----------------------------------------------------------------------------
 
const int   WIN_XPOS    = 256;
const int   WIN_YPOS    = 64;
const int   WIN_XRES    = 800;
const int   WIN_YRES    = 800;
const int   NUM_SAMPLES = 4;
 
//----------------------------------------------------------------------------
 
MyWin        Win;
 
//----------------------------------------------------------------------------
 
double elapsedMsec( const struct timeval &start, const struct timeval &stop )
{
  return ( ( stop.tv_sec  - start.tv_sec  ) * 1000.0 +
           ( stop.tv_usec - start.tv_usec ) / 1000.0 );
}
 
//----------------------------------------------------------------------------
 
double elapsedUsec( const struct timeval &start, const struct timeval &stop )
{
  return ( ( stop.tv_sec  - start.tv_sec  ) * 1000000.0 +
           ( stop.tv_usec - start.tv_usec ) );
}
 
//-----------------------------------------------------------------------------
 
/// check() - Check for GL errors, and report any queued
 
void check( const char hdr[] = "" )
{
  int err;
 
  while ( ( err = glGetError() ) != GL_NO_ERROR )
    fprintf( stderr, "OpenGL Error at %s: %s
", hdr, gluErrorString(err) );
}
 
//----------------------------------------------------------------------------
 

 
//----------------------------------------------------------------------------
 
void keyboardCB( KeySym sym, unsigned char key, int x, int y,
                 bool &setting_change )
{
  switch ( tolower( key ) )
  {
    case 27:
      // ESCape - We're done!
      exit (0);
      break;
 
    case 'k':
      printf( "You hit the 'k' key
" );
      break;
 
    case 0:
      switch ( sym )
      {
        case XK_Left  : 
          printf( "You hit the Left Arrow key
" );
          break;
 
        case XK_Right :
          printf( "You hit the Right Arrow key
" );
          break;
      }
      break;
  }
}
 
//----------------------------------------------------------------------------
 
void reshapeCB( int width, int height )
{
  Win.width = width;
  Win.height = height;
}
 
//----------------------------------------------------------------------------
 
/** chooseFBConfig() - Try to find a framebuffer config that matches
 *    the specified pixel requirements.
 */
 
GLXFBConfig chooseFBConfig( Display *display, int screen )
{
  // Default template
  static const int Visual_attribs[] =
    {
      GLX_X_RENDERABLE    , True,
      GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
      GLX_RENDER_TYPE     , GLX_RGBA_BIT,
      GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,
      GLX_RED_SIZE        , 8,
      GLX_GREEN_SIZE      , 8,
      GLX_BLUE_SIZE       , 8,
      GLX_ALPHA_SIZE      , 8,
      GLX_DEPTH_SIZE      , 24,
      GLX_STENCIL_SIZE    , 8,
      GLX_DOUBLEBUFFER    , True,
      GLX_SAMPLE_BUFFERS  , 1,
      GLX_SAMPLES         , 4,
      None
    };
 
  int attribs [ 100 ] ;
  memcpy( attribs, Visual_attribs, sizeof( Visual_attribs ) );
 
  // DELETED
 
  GLXFBConfig ret = 0;
 
  int fbcount;
  GLXFBConfig *fbc = glXChooseFBConfig( display, screen,
                                        attribs, &fbcount );
  if ( fbc )
  {
    if ( fbcount >= 1 )
      ret = fbc[0];
 
    XFree( fbc );
  }
 
  return ret;
}
 
//----------------------------------------------------------------------------
 
GLXContext createContext( Display *display, int screen,
                          GLXFBConfig fbconfig, XVisualInfo *visinfo, 
                          Window window )
{
#define GLX_CONTEXT_MAJOR_VERSION_ARB       0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB       0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
 
  // Verify GL driver supports glXCreateContextAttribsARB()
  //   Create an old-style GLX context first, to get the correct function ptr.
  glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
 
  GLXContext ctx_old = glXCreateContext( display, visinfo, 0, True );
  if ( !ctx_old ) 
  {
    printf( "Could not even allocate an old-style GL context!
" );
    exit(1);
  }
 
  glXMakeCurrent ( display, window, ctx_old ) ;
 
  // Verify that GLX implementation supports the new context create call
  if ( strstr( glXQueryExtensionsString( display, screen ), 
               "GLX_ARB_create_context" ) != 0 )
    glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
      glXGetProcAddress( (const GLubyte *) "glXCreateContextAttribsARB" );
 
  if ( !glXCreateContextAttribsARB )
  {
    printf( "Can't create new-style GL context
" );
    exit(1);
  }
 
  // Got the pointer.  Nuke old context.
  glXMakeCurrent( display, None, 0 );
  glXDestroyContext( display, ctx_old );
 
  // Try to allocate a GL 4.2 COMPATIBILITY context
  static int Context_attribs[] =
  {
    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
    GLX_CONTEXT_MINOR_VERSION_ARB, 1,
    GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
    //GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
    //GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
    //GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_DEBUG_BIT_ARB,
    None
  };
 
  GLXContext context = glXCreateContextAttribsARB( display, fbconfig, 0, 
                                                   True, Context_attribs );
 
  // Forcably wait on any resulting X errors
  XSync( display, False );
 
  if ( !context )
  {
    printf( "Failed to allocate a GL 4.2 context
" );
    exit(1);
  }
 
  printf( "Created GL context
" );
 
  return context;
}
 
//----------------------------------------------------------------------------
 
void createWindow()
{
  // Init X and GLX
  Win.displayed = false;
  Display *display = Win.display = XOpenDisplay( ":0.0" );
  if ( !display )
    printf( "Cannot open X display
" );
 
  int    screen   = DefaultScreen( display );
  Window root_win = RootWindow( display, screen );
 
  if ( !glXQueryExtension( display, 0, 0 ) )
    printf( "X Server doesn't support GLX extension
" );
 
  // Pick an FBconfig and visual
  GLXFBConfig fbconfig = chooseFBConfig( display, screen );
  if ( !fbconfig )
  {
    printf( "Failed to get GLXFBConfig
" );
    exit(1);
  }
 
  XVisualInfo *visinfo = glXGetVisualFromFBConfig( display, fbconfig );
  if ( !visinfo )
  {
    printf( "Failed to get XVisualInfo
" );
    exit(1);
  }
  printf( "X Visual ID = 0x%.2x
", int( visinfo->visualid ) );
 
  // Create the X window
  XSetWindowAttributes winAttr ;
 
  winAttr.event_mask = StructureNotifyMask | KeyPressMask ;
  winAttr.background_pixmap = None ;
  winAttr.background_pixel  = 0    ;
  winAttr.border_pixel      = 0    ;
 
  winAttr.colormap = XCreateColormap( display, root_win,
                                      visinfo->visual, AllocNone );
 
  unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
 
  Window win = Win.win = XCreateWindow ( display, root_win, 
                                         WIN_XPOS, WIN_YPOS, 
                                         WIN_XRES, WIN_YRES, 0, 
                                         visinfo->depth, InputOutput, 
                                         visinfo->visual, mask, &winAttr ) ;
 
  XStoreName( Win.display, win, "My GLX Window");
 
  // Create an OpenGL context and attach it to our X window
  GLXContext context = createContext( display, screen, fbconfig, visinfo, win );
 
  if ( ! glXMakeCurrent( display, win, context ) )
    printf( "glXMakeCurrent failed.
" );
 
  if ( ! glXIsDirect ( display, glXGetCurrentContext() ) )
    printf( "Indirect GLX rendering context obtained
" );
 
  // Display the window
  XMapWindow( display, win );
 
  if ( ! glXMakeCurrent( display, win, context ) )
    printf( "glXMakeCurrent failed.
" );
 
  check( "createWindow()" );
 
  printf( "Window Size    = %d x %d
", WIN_XRES, WIN_YRES );
  printf( "Window Samples = %d
", NUM_SAMPLES );
}
 
//----------------------------------------------------------------------------
 
void processXEvents( Atom wm_protocols, Atom wm_delete_window )
{
  bool setting_change = false;
 
  while ( XEventsQueued( Win.display, QueuedAfterFlush ) )
  {
    XEvent    event;
 
    XNextEvent( Win.display, &event );
 
    if( event.xany.window != Win.win )
      continue;
 
    switch ( event.type )
    {
      case MapNotify:
        {
          Win.displayed = true;
          break;
        }
      case ConfigureNotify:
        {
          XConfigureEvent &cevent = event.xconfigure;
          reshapeCB( cevent.width, cevent.height );
          break;
        }
      case KeyPress:
        {
          char      chr;
          KeySym    symbol;
          XComposeStatus status;
 
          XLookupString( &event.xkey, &chr, 1, &symbol, &status );
 
          keyboardCB( symbol, chr, event.xkey.x, event.xkey.y,
                      setting_change );
          break;
        }
      case ClientMessage:
        {
          if ( event.xclient.message_type      == wm_protocols &&
               Atom( event.xclient.data.l[0] ) == wm_delete_window )
          {
            //printf( "Received WM_DELETE_WINDOW
" );
            exit(0);
          }
          break;
        }
    }
  }
}
 
//----------------------------------------------------------------------------
 

 
//----------------------------------------------------------------------------


void setup()
{
   glGenVertexArrays(2, vao); // Generate VAO ids.

   // BEGIN bind VAO id vao[ANNULUS] to the set of vertex array calls following.
   glBindVertexArray(vao[ANNULUS]); 

   glGenBuffers(2, buffer); // Generate buffer ids.

   // Enable two vertex arrays: co-ordinates and color.
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);

   // Bind vertex buffer and reserve space.
   glBindBuffer(GL_ARRAY_BUFFER, buffer[VERTICES]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1) + sizeof(colors1), NULL, GL_STATIC_DRAW);
   
   // Copy vertex coordinates data into first half of vertex buffer.
   glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices1), vertices1);
   
   // Copy vertex color data into second half of vertex buffer.
   glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices1), sizeof(colors1), colors1);

   // Bind and fill indices buffer.
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[INDICES]);
   glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(stripIndices), stripIndices, GL_STATIC_DRAW);

   // Specify vertex and color pointers to the start of the respective data.
   glVertexPointer(3, GL_FLOAT, 0, 0);
   glColorPointer(3, GL_FLOAT, 0, (GLvoid*)(sizeof(vertices1)));
   // END bind VAO id vao[ANNULUS].

   // BEGIN bind VAO id vao[TRIANGLE] to the set of vertex array calls following.
   glBindVertexArray(vao[TRIANGLE]);

   glGenBuffers(1, buffer); // Generate buffer ids.

   // Enable two vertex arrays: co-ordinates and color.
   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_COLOR_ARRAY);

   // Bind vertex buffer and reserve space.
   glBindBuffer(GL_ARRAY_BUFFER, buffer[VERTICES]);
   glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2) + sizeof(colors2), NULL, GL_STATIC_DRAW);
   
   // Copy vertex coordinates data into first half of vertex buffer.
   glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices2), vertices2);
   
   // Copy vertex color data into second half of vertex buffer.
   glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices2), sizeof(colors2), colors2);

   // Specify vertex and color pointers to the start of the respective data.
   glVertexPointer(3, GL_FLOAT, 0, 0);
   glColorPointer(3, GL_FLOAT, 0, (GLvoid*)(sizeof(vertices2)));
   // END bind VAO id vao[TRIANGLE].
}

void displayCB()
{

  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   // Draw annulus.
   glBindVertexArray(vao[ANNULUS]);
   glDrawElements(GL_TRIANGLE_STRIP, 10, GL_UNSIGNED_INT, 0);

   // Draw triangle.
   glBindVertexArray(vao[TRIANGLE]);
   glDrawArrays(GL_TRIANGLES, 0, 3);

  glXSwapBuffers( Win.display, Win.win );
 
  check( "displayCB()" );
}


void mainLoop()
{
  // Register to receive window close events (the "X" window manager button)
  Atom wm_protocols     = XInternAtom( Win.display, "WM_PROTOCOLS"    , False);
  Atom wm_delete_window = XInternAtom( Win.display, "WM_DELETE_WINDOW", False);
  XSetWMProtocols( Win.display, Win.win, &wm_delete_window, True );
 
  while (1) 
  {
    // Redraw window (after it's mapped)
    if ( Win.displayed )
      displayCB();
 
    // Update frame rate
    static timeval last_xcheck   = {0,0};
    struct timeval now;
    gettimeofday( &now, 0 );
 
    // Check X events every 1/10 second
    if ( elapsedMsec( last_xcheck, now ) > 100 )
    {
      processXEvents( wm_protocols, wm_delete_window );
      last_xcheck = now;
    }
  }
}
int main( int argc, char *argv[] )
{

  // Init globals
  Win.width = WIN_XRES, Win.height = WIN_YRES;

  // Create context and window
  createWindow();

  // Init OpenGL
  glViewport  ( 0, 0, Win.width, Win.height ); 
  glColorMask ( 1,1,1,1 );
  glClearColor( 0.1,0.3,0.5,1 );
  glClear     ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  // Go
  printf( "Valid keys: Left, Right, k, ESC
" );
  printf( "Press ESC to quit
" );
  setup();
  mainLoop();
 
  return 0;
}

Even something as simple as a modern version of the below. I know I can not use (do not want to use) the fixed pipeline

https://www.khronos.org/opengl/wiki/Programming_OpenGL_in_Linux:_GLX_and_Xlib

And what hardware have you?

[QUOTE=HMPARTICLE;1288407]I have tried to modify this code in order to draw an annulus. I am quite confused why I am getting

OpenGL Error at displayCB()
[/QUOTE]

Did the original version you pulled out of the forums work properly without error?

If so, you know the problem lies with the changes you made. That helps narrow it down. Try commenting your changes out. Does the problem go away?

You can narrow down which GL call is triggering the error by adding more calls to check() in between GL calls in the displayCB() function. If you call it before a GL call and after a GL call, and you only see it flagging a GL error after the call, you’ll know it’s that call that caused the error. Then look up the man page for the function and see what conditions cause it to throw that specific GL error.

Later, you can learn how to create a DEBUG context and register a glDebugMessageCallback(). (more on that here). With this, OpenGL will call “you” when it detects that you’ve committed a GL error. This makes it much easier/faster to nail down which of your calls caused an error. But I wouldn’t delve into this right now. Just bookmark it for later.

Am I calling Setup() at the wrong time?

No. You’ve got an active GL context then, so you’re good.

Also, to mhagain’s question, let’s see the output of the “glxinfo” command. Please place this output inside [noparse]

...

[/noparse] tags for readability.

Finally, for any future source code snippets you add to forum posts, please place them inside [noparse]

...

or

...

[/noparse] tags (note that you can use “glsl” instead of “cpp” for GLSL shader code). This makes your posts “much” more readable and so increases the likelihood that you’ll get a response.

Hi HMPARTICLE,

I paste your code and run it under my machine and it gets this error

X Visual ID = 0xcd
Created GL context
Window Size    = 800 x 800
Window Samples = 4
Valid keys: Left, Right, k, ESC
Press ESC to quit
Mesa: User error: GL_INVALID_OPERATION in unsupported function called (unsupported extension or deprecated function?)
OpenGL Error at displayCB(): invalid operation

Looks like “glEnableClientState” is deprecated in your OpenGL version because this API is initialized as NOP. In other word, your program sets up no primitives except a fullscreen clean operation.
I suggest you’d better try a modern way like “glVertexAttribPointer” to set up the attributes.

[QUOTE=yuehang.wu;1288494]Looks like “glEnableClientState” is deprecated in your OpenGL version because this API is initialized as NOP. In other word, your program sets up no primitives except a fullscreen clean operation.
I suggest you’d better try a modern way like “glVertexAttribPointer” to set up the attributes.[/QUOTE]

No.

The OP is explicitly creating a compatibility context, and VAOs are specified to work with legacy vertex attribs under compatibility contexts.

[QUOTE=mhagain;1288500]No.

The OP is explicitly creating a compatibility context, and VAOs are specified to work with legacy vertex attribs under compatibility contexts.[/QUOTE]

  // Try to allocate a GL 4.2 COMPATIBILITY context
  static int Context_attribs[] =
  {
    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
    GLX_CONTEXT_MINOR_VERSION_ARB, 1,
    GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
    //GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
    //GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
    //GLX_CONTEXT_FLAGS_ARB       , GLX_CONTEXT_DEBUG_BIT_ARB,
    None
  };

From his codes, the 3.1 is what he wants to create for. The Mesa does see the 3.1 version as “API_OPENGL_CORE” instead of “API_OPENGL_COMPAT”, then glEnableClientStatus is initialized as NOP.

Please refer to this line in context create from “mesa/drivers/dri/common/dri_utils.c”

/* Mesa does not support the GL_ARB_compatibilty extension or the
     * compatibility profile.  This means that we treat a API_OPENGL_COMPAT 3.1 as
     * API_OPENGL_CORE and reject API_OPENGL_COMPAT 3.2+.
     */
    if (mesa_api == API_OPENGL_COMPAT && major_version == 3 && minor_version == 1)
       mesa_api = API_OPENGL_CORE;

The above assumption is based on you’re running open source driver.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.