Opengl/windowless

From Sidvind
Jump to: navigation, search

In general it isn't possible to create an OpenGL context without having a window; Which can be quite annoying depending on what you want to archive. More than once have I wished for a way to either call non-rendering functions (like glGetString) or be able to render to a framebuffer and read the result back into a buffer.

Non-rendering context[edit]

A simple way to get an OpenGL context is to use the root window in GLX (DefaultRootWindow) or the desktop window (GetDesktopWindow) in Windows. While you're not allowed to do any rendering using this context it is enough to call functions like glGetString.

Code: windowless1.c (view, download)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <X11/X.h>
  4. #include <X11/Xlib.h>
  5. #include <GL/gl.h>
  6. #include <GL/glx.h>
  7.  
  8. int main(int argc, const char* argv[]){
  9.         Display *dpy;
  10.         Window root;
  11.         GLint attr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
  12.         XVisualInfo *vi;
  13.         GLXContext glc;
  14.  
  15.         /* open display */
  16.         if ( ! (dpy = XOpenDisplay(NULL)) ) {
  17.                 fprintf(stderr, "cannot connect to X server\n\n");
  18.                 exit(1);
  19.         }
  20.  
  21.         /* get root window */
  22.         root = DefaultRootWindow(dpy);
  23.  
  24.         /* get visual matching attr */
  25.         if( ! (vi = glXChooseVisual(dpy, 0, attr)) ) {
  26.                 fprintf(stderr, "no appropriate visual found\n\n");
  27.                 exit(1);
  28.         }
  29.  
  30.         /* create a context using the root window */
  31.         if ( ! (glc = glXCreateContext(dpy, vi, NULL, GL_TRUE)) ){
  32.                 fprintf(stderr, "failed to create context\n\n");
  33.                 exit(1);
  34.         }
  35.         glXMakeCurrent(dpy, root, glc);
  36.  
  37.         /* try it out, remember to *NOT* render to the default framebuffer! */
  38.         printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));
  39.  
  40.         return 0;
  41. }

Compile with:

 gcc -Wall -lX11 -lGL windowless1.c

Offscreen rendering only[edit]

Since OpenGL3 a new extension called ARB_create_context[1][2] gives a new API to create an OpenGL context; This is the API needed to actually create an OpenGL3 context and it also allows us not to pass a window to MakeCurrent. The description to MakeCurrent states that if you pass 0 as both read- and write-drawable "the context is made current without a default framebuffer".

Code: windowless2.c (view, download)

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <X11/X.h>
  4. #include <X11/Xlib.h>
  5. #include <GL/gl.h>
  6. #include <GL/glx.h>
  7.  
  8. typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
  9. typedef Bool (*glXMakeContextCurrentARBProc)(Display*, GLXDrawable, GLXDrawable, GLXContext);
  10. static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
  11. static glXMakeContextCurrentARBProc glXMakeContextCurrentARB = 0;
  12.  
  13. int main(int argc, const char* argv[]){
  14.         static int visual_attribs[] = {
  15.                 None
  16.         };
  17.         int context_attribs[] = {
  18.                 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
  19.                 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
  20.                 None
  21.         };
  22.  
  23.         Display* dpy = XOpenDisplay(0);
  24.         int fbcount = 0;
  25.         GLXFBConfig* fbc = NULL;
  26.         GLXContext ctx;
  27.         GLXPbuffer pbuf;
  28.  
  29.         /* open display */
  30.         if ( ! (dpy = XOpenDisplay(0)) ){
  31.                 fprintf(stderr, "Failed to open display\n");
  32.                 exit(1);
  33.         }
  34.  
  35.         /* get framebuffer configs, any is usable (might want to add proper attribs) */
  36.         if ( !(fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), visual_attribs, &fbcount) ) ){
  37.                 fprintf(stderr, "Failed to get FBConfig\n");
  38.                 exit(1);
  39.         }
  40.  
  41.         /* get the required extensions */
  42.         glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB");
  43.         glXMakeContextCurrentARB = (glXMakeContextCurrentARBProc)glXGetProcAddressARB( (const GLubyte *) "glXMakeContextCurrent");
  44.         if ( !(glXCreateContextAttribsARB && glXMakeContextCurrentARB) ){
  45.                 fprintf(stderr, "missing support for GLX_ARB_create_context\n");
  46.                 XFree(fbc);
  47.                 exit(1);
  48.         }
  49.  
  50.         /* create a context using glXCreateContextAttribsARB */
  51.         if ( !( ctx = glXCreateContextAttribsARB(dpy, fbc[0], 0, True, context_attribs)) ){
  52.                 fprintf(stderr, "Failed to create opengl context\n");
  53.                 XFree(fbc);
  54.                 exit(1);
  55.         }
  56.  
  57.         /* create temporary pbuffer */
  58.         int pbuffer_attribs[] = {
  59.                 GLX_PBUFFER_WIDTH, 800,
  60.                 GLX_PBUFFER_HEIGHT, 600,
  61.                 None
  62.         };
  63.         pbuf = glXCreatePbuffer(dpy, fbc[0], pbuffer_attribs);
  64.  
  65.         XFree(fbc);
  66.         XSync(dpy, False);
  67.  
  68.         /* try to make it the current context */
  69.         if ( !glXMakeContextCurrent(dpy, pbuf, pbuf, ctx) ){
  70.                 /* some drivers does not support context without default framebuffer, so fallback on
  71.                  * using the default window.
  72.                  */
  73.                 if ( !glXMakeContextCurrent(dpy, DefaultRootWindow(dpy), DefaultRootWindow(dpy), ctx) ){
  74.                         fprintf(stderr, "failed to make current\n");
  75.                         exit(1);
  76.                 }
  77.         }
  78.  
  79.         /* try it out */
  80.         printf("vendor: %s\n", (const char*)glGetString(GL_VENDOR));
  81.  
  82.         return 0;
  83. }

Compile with:

 gcc -Wall -lGL -lX11 windowless2.c