PDA

View Full Version : Trouble with VAO's in linux



HMPARTICLE
09-06-2017, 04:31 PM
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\n", 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\n" );
break;

case 0:
switch ( sym )
{
case XK_Left :
printf( "You hit the Left Arrow key\n" );
break;

case XK_Right :
printf( "You hit the Right Arrow key\n" );
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!\n" );
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\n" );
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\n" );
exit(1);
}

printf( "Created GL context\n" );

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\n" );

int screen = DefaultScreen( display );
Window root_win = RootWindow( display, screen );

if ( !glXQueryExtension( display, 0, 0 ) )
printf( "X Server doesn't support GLX extension\n" );

// Pick an FBconfig and visual
GLXFBConfig fbconfig = chooseFBConfig( display, screen );
if ( !fbconfig )
{
printf( "Failed to get GLXFBConfig\n" );
exit(1);
}

XVisualInfo *visinfo = glXGetVisualFromFBConfig( display, fbconfig );
if ( !visinfo )
{
printf( "Failed to get XVisualInfo\n" );
exit(1);
}
printf( "X Visual ID = 0x%.2x\n", 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.\n" );

if ( ! glXIsDirect ( display, glXGetCurrentContext() ) )
printf( "Indirect GLX rendering context obtained\n" );

// Display the window
XMapWindow( display, win );

if ( ! glXMakeCurrent( display, win, context ) )
printf( "glXMakeCurrent failed.\n" );

check( "createWindow()" );

printf( "Window Size = %d x %d\n", WIN_XRES, WIN_YRES );
printf( "Window Samples = %d\n", 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\n" );
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\n" );
printf( "Press ESC to quit\n" );
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

mhagain
09-07-2017, 03:07 AM
And what hardware have you?

Dark Photon
09-07-2017, 06:45 AM
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()


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() (https://www.khronos.org/opengl/wiki/GlDebugMessageCallback). (more on that here (https://www.khronos.org/opengl/wiki/Debug_Output)). 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
... tags for readability.

Finally, for any future source code snippets you add to forum posts, please place them inside ... or
... 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.

yuehang.wu
09-12-2017, 07:45 AM
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.

mhagain
09-12-2017, 10:03 AM
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.

No.

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

yuehang.wu
09-13-2017, 04:49 AM
No.

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


// 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.