Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1357060
  • 博文数量: 281
  • 博客积分: 8800
  • 博客等级: 中将
  • 技术积分: 3346
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-17 22:31
文章分类

全部博文(281)

文章存档

2013年(1)

2012年(18)

2011年(16)

2010年(44)

2009年(86)

2008年(41)

2007年(10)

2006年(65)

我的朋友

分类: LINUX

2012-03-31 15:47:22

OpenGL vsync Notes

Vsync prevents your program's frame rate from exceeding the refresh rate your graphics hardware is set at, Thus if your graphics card only sends 60 frames to your monitor every second, your program will not render more frames than 60.

As I understand it, Vsync works by forcing OpenGL to wait for the video hardware to set a flag which indicates that it has drawn a frame, before it can swap the image in the back buffer (where it is drawn) to the front buffer (where the image displayed on the monitor is read from).

Reasons for using Vsync:

  • Using Vsync helps to prevent a visual artifact called 'tearing', where an incompletely drawn image is displayed on the monitor, the incomplete portion consists of the data from the last frame.
  • When Vsync is enabled less cpu capacity is used, as without vsync enabled the program will draw as many frames as it can, often using more resources than necessary.
  • Some games run noticeably smoother with vsync enabled.

Enabling Vsync in OpenGL Windows

On windows enabling vsync is straight forward.
Just calling "wglSwapIntervalEXT(1)" has always worked for me.

Linux

For some reason I always seem to run into trouble enabling vsync for Linux code.

nVidia and ATI/AMD drivers support the GLX_SGI_swap_control extension which provides the glXSwapIntervalSGI() function.

Strangely the MESA drivers have their own function to control Vsync, and glXSwapIntervalSGI will not work on systems using MESA drivers.

glXSwapIntervalSGI(1); works perfectly with my nVidia graphics card (and nVidia drivers), but my laptop has an Intel graphics card and although glXSwapIntervalSGI compiles and runs, it doesn't do anything.


So I need a way to choose the glXSwapIntervalMESA when its needed and glXSwapIntervalSGI otherwise. My theory is that glXSwapIntervalMESA will only be available on MESA implementations.

I use GLee () to handle OpenGL extensions, unfortunatly it does not seem to define glXSwapIntervalMESA.
As when I try to compile with glXSwapIntervalMESA I get:
undefined reference to `glXSwapIntervalMESA'

It seems that glXSwapIntervalMESA is related to the extension string GLX_MESA_SWAP_CONTROL
printf("extensions: %s \n", glGetString(GL_EXTENSIONS));
does not contain GLX_MESA_SWAP_CONTROL,

but
printf("glXQueryExtensionsString: %s \n", glXQueryExtensionsString(dpy, screen));
does.

A valid rendering context must be available before glXQueryExtensionsString will work.

glXGetProcAddress returns a function pointer to the extension which you pass it.

I was getting confused as:
glXGetProcAddress((const GLubyte*) "GLX_MESA_SWAP_CONTROL");
returns null.

But it should have been:
glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");
Which returns the expected not null pointer.

I declare a function pointer:
void (*swapInterval)(int);
This was a guess as I know glXSwapIntervalSGI takes an integer as an argument.

The function pointer is set by this line of code:
swapInterval = (void (*)(int)) glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");

Call:
swapInterval(1);
Finally frame rate is limited to 60!!!

I originally used strstr to parse the list of glx extensions, until I came across the page at:

Which argues that strstr is not always reliable because it could return false positives, for example when searching for "GL_EXT_texture" extension, if "GL_EXT_texture3D" is available the strstr method will return true, even if "GL_EXT_texture" can not be found.

This function is slightly modified from the above mentioned webpage:

  1. bool checkGLXExtension(const char* extName)
  2. {
  3.   /*
  4.     Search for extName in the extensions string.  Use of strstr()
  5.     is not sufficient because extension names can be prefixes of
  6.     other extension names.  Could use strtok() but the constant
  7.     string returned by glGetString can be in read-only memory.
  8.   */
  9.   char* list = (char*) glXQueryExtensionsString(dpy, screen);
  10.   char* end;
  11.   int extNameLen;
  12.  
  13.   extNameLen = strlen(extName);
  14.   end = list + strlen(list);
  15.  
  16.   while (list < end)
  17.   {
  18.     int n = strcspn(list, " ");
  19.    
  20.     if ((extNameLen == n) && (strncmp(extName, list, n) == 0))
  21.       return true;
  22.    
  23.     list += (n + 1);
  24.   };
  25.   return false;
  26. }; // bool checkGLXExtension(const char* extName)

This function is case sensitive, I needed to pass "GLX_MESA_swap_control".

Now I can do:

  1. if (checkGLXExtension("GLX_MESA_swap_control"))
  2.   swapInterval = (void (*)(int)) glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");
  3. else if (checkGLXExtension("GLX_SGI_swap_control"))
  4.   swapInterval = (void (*)(int)) glXGetProcAddress((const GLubyte*) "glXSwapIntervalSGI");
  5. else
  6.   printf("no vsync?!\n");
  7.  
  8. swapInterval(1);
阅读(4139) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~