CPU and GPU technologies make it possible to have complex system for Physics, 3D graphics, AI and all sorts of features that make games more entertaining. However building tools to provide real-time user interfaces to all these systems is a difficult task.

Read More...
 
Managing OpenGL error reports PDF Print E-mail
Written by Jay Taoko   
Friday, 19 December 2008 00:27

OpenGL generate all sorts of error reports and something goes wrong. Unfortunately, it is easy to miss them because OpenGL function calls do not return an error code. You have to call a special function "glGetError" to find out if an error has been generated or not. However, it is not enough to call glGetError only after the functions you suspect to generate and error. OpenGL errors are retains until glGetError is called. So if a function has generated long before you call glGetError, that first error will be reported even if your most recent OpenGL function call didn't generate and error.

  1. // error: rectangle texture do not accept GL_REPEAT as wrapping mode.
  2. glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_REPEAT);
  3. ...
  4. ...
  5. GLint id;
  6. // This function call is correct
  7. glGenFramebuffersEXT(1, &id);
  8. if(glGetError() == GL_NO_ERROR)
  9. {
  10. // error: we get here because we failed to call glGetError after glTexParameteri.
  11. ...
  12. }
  13.  

In the previous code sample, the call to glGenFramebuffersEXT does not cause an error. However, because glTexParameteri was called with an invalid value and we failed to call glGetError, we end up getting that error when we call glGetError right after we glTexParameteri. It can be very difficult to track down which OpenGL call caused the error. You have to test glGetError after every OpenGL function. And when you finally find the error you realize that it might be a good idea to leave all the glGetError calls you have added to your code just in case you need them again. And that is the right things to do.

But then you might wonder about performance. All these call to glGetError and add up very quickly and as your code become error free (OpenGL call errors that is), glGetError tends to do unnecessary work each time. You need glGetError only when there is something wrong.

So it is a good idea to call glGetError in debug mode and remove it when you release your program. And you can do that with C++ macros. Here they are:

  1. #define CHECKGL( GLcall ) \
  2. { \
  3. GLcall; \
  4. if(1) \
  5. CheckGLError( #GLcall, __FILE__, __LINE__ ); \
  6. }
  7.  
  8. #define CHECKGL_MSG( msg ) \
  9. { \
  10. if(1) \
  11. CheckGLError( #msg, __FILE__, __LINE__ ); \
  12. }
  13.  

Lets go over these macros. The first macro takes an OpenGL function call as parameter. The call is executed and right after, the function CheckGLError is called. More on CheckGLError later.

  1. CHECKGL( glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_WRAP) );

We don't have to call glGetError. This is taken care by CheckGLError.
Even when the OpenGL call returns a value like you can still encapsulate the call inside CHECKGL, provided you don't initialize the variable that receives the returned value inside the macro.

  1. void * ptr0;
  2. CHECKGL( ptr0 = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) );
  3. ...
  4. CHECKGL( void* ptr1 = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) );
  5. // Be careful here! ptr1 isn't defined anymore. ptr1 is out of scope.

The second macro is special. You can make an OpenGL call that is not encapsulated inside CheckGLError . But right after, you may use the macros CHECKGL_MSG and pass it the name of the previous OpenGL call. CHECKGL_MSG checks if and error as been triggered and reports the name of the OpenGL function that was passed as parameter.

  1. void *ptr0 = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
  2. CHECKGL_MSG( "glMapBufferARB" );

Now, onto CheckGLError! The purpose of this function is to call glGetError. If an error is detected, CheckGLError reports the name of the OpenGL call that created the error and the file and line number of the call.

  1. int CheckGLError(const char *GLcall, const char *file, int line)
  2. {
  3. GLenum glErr;
  4. int retCode = 0;
  5. while ( (glErr=glGetError()) != GL_NO_ERROR)
  6. {
  7. switch(glErr)
  8. {
  9. case GL_INVALID_ENUM:
  10. printf("GL_INVALID_ENUM error in File %s at line: %d", file, line);
  11. break;
  12. case GL_INVALID_VALUE:
  13. printf("GL_INVALID_VALUE error in File %s at line: %d", file, line);
  14. break;
  15. case GL_INVALID_OPERATION:
  16. printf("GL_INVALID_OPERATION error in File %s at line: %d", file, line);
  17. break;
  18. case GL_STACK_OVERFLOW:
  19. printf("GL_STACK_OVERFLOW error in File %s at line: %d", file, line);
  20. break;
  21. case GL_STACK_UNDERFLOW:
  22. printf("GL_STACK_UNDERFLOW error in File %s at line: %d", file, line);
  23. break;
  24. case GL_OUT_OF_MEMORY:
  25. printf("GL_OUT_OF_MEMORY error in File %s at line: %d", file, line);
  26. break;
  27. default:
  28. printf("UNKNOWN ERROR in File %s at line: %d", file, line);
  29. }
  30. }
  31. return retCode;
  32. }

You can adapt the macros and CheckGLError any way you like. But calling glGetError consistently after every OpenGL call is the only way to detect potential errors before it is too late. For your release build, you can simply have the macros do nothing and avoid a performance hit.

There are limitations though. You cannot call glGetError between glBegin and glEnd. Therefore, you can't use the macros between glBegin and glEnd. Here you are on your own; you have to make sure that everything you do between these calls correct. However, if you plan on moving to OpenGL 3.0, you are aware that glBegin, glEnd and many other functions that are called in between are being deprecated. You will have to use vertex buffer object and you will be able to use the macros to check for errors.

At first it can be tedious to go through your code and encapsulate your gl calls with the macros. But trust me, you won't regret it!

 
My new Radeon HD 4670 PDF Print E-mail
Written by Jay Taoko   
Tuesday, 09 December 2008 23:21

I have been working on a large OpenGL application for some time now. My development graphics card has always been an NVidia. But now I needed to get my application working on a Radeon card. So I invested in a Radeon HD 4670, and replaced my Nvidia 8800 GTX with it. After installing the driver for the card, came the moment of truth. I launch Visual C++ 2008, load my program and try to run it and... Boom! Compile errors (and later run-time errors with shaders).

Let's go through the errors.

  • "Shader profile is not recognized"

I have been using cgCreateProgram with profile CG_PROFILE_VP40 on my Geforce put that does not seems to work on my Radeon. Ok, I modified the code to get the best profile using cgGLGetLatestProfile(CG_GL_VERTEX). That seems to work so far...

  • #version must occur before any other statement in the program compilation. No code generated.

This one I understand. GLSL spec is clear about that (GLSL 1.30, section 3.3)

  • Separate Stencil

The ARB has defined GL_EXT_stencil_two_side extension, but ATI has GL_ATI_separate_stencil. This is just a matter of using the correct API according to the hardware.

That wasn't so bad! Now the code compiles and the program should render something like this:

Rendering on Geforce 8800 GTX.

But instead this is what I get on my Radeon 4670:

Rendering on Radeon HD 4670.

Not quite there yet. I am pretty sure of my OpenGL code logic but I tested nonetheless to be sure that I wasn't missing anything. It took me a few days and some posting on opengl forums to finally conclude that I had to deactivate the loading of texture through pixel buffer object in OpenGL with my Radeon. This seems to be a driver bug with the Radeon. Too bad! But apart from this issue, my Radeon rendered my program graphics really well.

 
<< Start < Prev 1 2 3 Next > End >>

Page 3 of 3