Offscreen rendering

That restriction doesn’t exist in GLX. You can create pbuffers without creating a window. At least, according to the GLX spec you can. I’ve never actually tried it.

I have not tried myself neither but I know someone who did and it works on linux. I am not sure to understand the issue Korval is pointing out, pbuffers in Windows don’t have the same purpose as in Linux?

They let you do off-screen rendering, yeah. But because of the way WGL is designed, you have to have a window before you can create them. I don’t know if you can leave that window un-mapped, though. If you can, it’s not really a problem.

Ok this is weird but I understand now. So Windows pbuffers are completely useless now, since the apparition of FBO.

Not entirely. Pbuffers let you do multisampling on hardware that doesn’t support the framebuffer_multisample and framebuffer_blit extensions (read: everyone but nvidia).

OK thanks for the precisions. :slight_smile:

Only Intel does not support it, ATI supports it on 9500+ which is interesting.

You use a Mac, don’t you?

Apple writes the GL drivers for Macs. ATI does not support the extension for Windows and Linux, at least not the last time a checked (a couple months ago).

Apple writes the GL drivers for Macs.

Apple writes much of the GL drivers for Macs. They basically use OpenGL the way Microsoft uses Direct3D: they write much of the client code, and then shell out to a much simpler API that ATi/nVidia then write a driver for.

Couldn’t this be done on Windows, too? ARB is responsible for writing the framework and defines the low-level driver API.

But wait, this would take another decade to happen based on the experience with OGL3… SCNR

FWIW, windowless FBOs work on the Mac, too. On all vendor’s drivers.

No, I use Windows and Linux. The extensions we’ve been talking about were added in May.

Hi

I need to do an offscreen hardware accelerated render in Linux using GLX (not GLUT) and pbuffers sound like exactly what I need based on what you said in this thread.

Thanks for mentioning about it.

Could you please point me to some sample code that uses pbuffers in GLX for offscreen rendering? (or would you have any code)

Thanks in advance

Srimal.

Ever since Framebuffer Objects (aka FBOs, spec: ARB_framebuffer_object) there’s been precious little reason to use PBuffers, particularly now that MSAA is supported in FBOs.

Are you sure you need PBuffers? One reason might be if your app doesn’t want to create an X window.

If you’re really sure, here’s some code. The first snippet just creates a GL 3.0 context using the new glXCreateContextAttribs call, targetting drawing to a window:


// GL 3.0 context creation example (Linux)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GL_GLEXT_PROTOTYPES 1
#define GLX_GLXEXT_PROTOTYPES 1
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>

#define GLX_CONTEXT_MAJOR_VERSION_ARB       0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB       0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);


int main (int argc, char ** argv)
{
  Display *display = XOpenDisplay(0);

  if ( !display )
  {
    printf( "Failed to open X display
" );
    exit(1);
  }

  // Query/print GLX version
  int major, minor;

  if ( !glXQueryVersion( display, &major, &minor ) )
  {
    printf( "glXQueryVersion failed
" );
    exit(1);
  }
  printf( "GLX version = %d.%d
", major, minor );

  if ( major < 1 || major == 1 && minor < 3 )
  {
    printf( "GLX version is too old; must be > 1.3
" );
    exit(1);
  }

  // Print GLX extensions
  //const char *extensions = glXQueryExtensionsString( display, 
  //                                                DefaultScreen( display ) );
  //printf( "%s
", extensions );

  // Get a matching FB config
  static 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
    };

  printf( "Getting framebuffer configs
" );
  int fbcount;
  GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ), 
                                        visual_attribs, &fbcount );
  if ( !fbc || fbcount < 1 )
  {
    printf( "Failed to retrieve a framebuffer config
" );
    exit(1);
  }
  printf( "Found %d matching FB configs.
", fbcount );

  int fbc_id = 0;

  XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[ fbc_id ]  );
  printf( "Chosen visual ID = 0x%x
", vi->visualid );

  printf( "Creating colormap
" );
  XSetWindowAttributes swa;
  swa.colormap = XCreateColormap( display, RootWindow( display, vi->screen ), 
                                  vi->visual, AllocNone );
  swa.background_pixmap = None ;
  swa.border_pixel      = 0;
  swa.event_mask        = StructureNotifyMask;

  printf( "Creating window
" );
  Window win = XCreateWindow( display, RootWindow( display, vi->screen ), 
                              0, 0, 100, 100, 0, vi->depth, InputOutput, 
                              vi->visual, 
                              CWBorderPixel|CWColormap|CWEventMask, &swa );
  if ( !win )
  {
    printf( "Failed to create window.
" );
    exit(1);
  }

  XStoreName( display, win, "GL 3.0 Window");

  printf( "Mapping window
" );
  XMapWindow( display, win );

  // See if 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, vi, 0, True );
  glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
           glXGetProcAddress( (const GLubyte *) "glXCreateContextAttribsARB" );

  GLXContext ctx = 0;

  // If it doesn't, just use the old-style 2.x GLX context
  if ( !glXCreateContextAttribsARB )
  {
    printf( "glXCreateContextAttribsARB() not found"
            " ... using old-style GLX context
" );
    ctx = ctx_old;
  }

  // If it "does", try to get a GL 3.0 context!
  else
  {
    glXMakeCurrent( display, 0, 0 );
    glXDestroyContext( display, ctx_old );

    // NOTE: Early NVidia 3.x beta drivers tripped X errors in
    //   glXCreateContextAttribs (instead of returning NULL) on context
    //   creation if a 3.0 context wasn't supported on this GPU.  We don't
    //   trap/handle that here, bu

    static int context_attribs[] =
      {
        GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
        GLX_CONTEXT_MINOR_VERSION_ARB, 0,
        //GLX_CONTEXT_FLAGS_ARB        , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
        None
      };

    printf( "Creating context
" );
    ctx = glXCreateContextAttribsARB( display, fbc[ fbc_id ], 0, 
                                      True, context_attribs );

    if ( ctx )
      printf( "Created GL 3.0 context
" );
    else
    {
      // Couldn't create GL 3.0 context.  Fall back to old-style 2.x context.
      printf( "Failed to create GL 3.0 context"
              " ... using old-style GLX context
" );
      ctx = glXCreateContext( display, vi, 0, True );
    }
  }

  XFree( fbc );

  // Verifying that context is a direct context
  printf( "Verifying that context is direct
" );
  if ( ! glXIsDirect ( display, ctx ) )
  {
    printf( "Indirect GLX rendering context obtained
" );
    exit(1);
  }

  printf( "Making context current
" );
  glXMakeCurrent( display, win, ctx );

  glClearColor ( 0, 0.5, 1, 1 );
  glClear ( GL_COLOR_BUFFER_BIT );
  glXSwapBuffers ( display, win );

  sleep( 1 );

  glClearColor ( 1, 0.5, 0, 1 );
  glClear ( GL_COLOR_BUFFER_BIT );
  glXSwapBuffers ( display, win );

  sleep( 1 );

  ctx = glXGetCurrentContext(  );
  glXMakeCurrent( display, 0, 0 );
  glXDestroyContext( display, ctx );
}

If you want to retarget drawing to a PBUFFER, then change GLX_DRAWABLE_TYPE’s setting from GLX_WINDOW_BIT to GLX_PBUFFER_BIT, and flip in the PBuffer magic. I haven’t played with PBuffers in 5 years or so, but here’s some code I found lying around, archived from the distant past:


/*  http://groups.google.com/groups?th=fe10398b568c0b1e  */
/*  Works? */

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/gl.h>

#define WIDTH 300
#define HEIGHT 300

void fnRedraw(void);

Display     *dpy;
Window    win;
GLXContext PBufferCtx;
GLXContext WinCtx;
GLXPbuffer  PBuffer;

const int sbAttrib[] = {GLX_DOUBLEBUFFER,   0,   GLX_RED_SIZE, 
1,GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
   GLX_DEPTH_SIZE, 12,None};
const int pbAttrib[] = {GLX_PBUFFER_WIDTH, WIDTH,GLX_PBUFFER_HEIGHT,
HEIGHT,GLX_PRESERVED_CONTENTS, True,None };


static Bool WaitForNotify(Display *d, XEvent *e, char *arg) 
{
  return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
}

int main(int argc, char **argv)
{
  GLXFBConfig*     fbc;
  XVisualInfo*     vi = NULL;
  Colormap       cmap;
  XSetWindowAttributes swa;
  XEvent         event;
  Bool          bRedraw = False;
  int            dummy;
  int              nElements;
  int              nval;
  int              nCounter;

  if(!(dpy = XOpenDisplay(NULL)))
    {
      fprintf(stderr,"could not open display");
      exit(-1);
    }

  fprintf(stdout,"Info:GLX Extensions:%s
",glXQueryExtensionsString(dpy, DefaultScreen(dpy)));
  
  if(!glXQueryExtension(dpy, &dummy, &dummy))
    {
      fprintf(stderr,"Error:GLX extensions not supported");
      exit(-1);
    }

  fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), sbAttrib,
&nElements);
  fprintf(stdout,"Info:Number of FBConfigs: %d
",nElements);
  if(nElements == 0)
    {
      fprintf(stderr,"Error: No valid framebuffers configurations found
");
      exit(-1);
    }
  /* 
   * For simplicities sake, select the first. This however may not be
the right one
   * for the purpose of an example this will suffice.
   */
  vi = glXGetVisualFromFBConfig(dpy,fbc[0]);

  if(!(WinCtx = glXCreateContext(dpy, vi,
        None, /* no sharing of display lists */
        True /* direct rendering if possible */
        )))
    {
      fprintf(stderr,"Cound not create rendering context
");
      exit(-1);
    }

  PBuffer    = glXCreatePbuffer (dpy, fbc[0], pbAttrib);
  PBufferCtx = glXCreateNewContext( dpy, fbc[0], GLX_RGBA_TYPE, 0,
GL_TRUE);

  cmap             =
XCreateColormap(dpy,RootWindow(dpy,vi->screen),vi->visual,AllocNone);
  swa.colormap     = cmap;
  swa.border_pixel = 0;
  swa.event_mask   = ExposureMask | ButtonPressMask |
StructureNotifyMask;
  win = XCreateWindow(dpy,RootWindow(dpy,vi->screen),0,0,WIDTH,HEIGHT,
        0,vi->depth,InputOutput,vi->visual,
        CWBorderPixel | CWColormap | CWEventMask,
        &swa);
  
  glXMakeContextCurrent( dpy, PBuffer,PBuffer, PBufferCtx);
  
  XMapWindow(dpy, win);
  XIfEvent(dpy, &event, WaitForNotify, (char*)win);
  
  glEnable(GL_DEPTH_TEST);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-1.0,1.0,-1.0,1.0,1.0,10.0);
  
  while(1) 
    {
      do 
        {
          XNextEvent(dpy, &event);
          switch(event.type) 
            {
            case ConfigureNotify:
              glViewport(0,0,event.xconfigure.width,event.xconfigure.height);
              bRedraw = True;
              break;
            case Expose:
              bRedraw = True;
              break;
            }
        } 
      while(XPending(dpy)); /* loop to compress events */
      
      if(bRedraw) 
        {
          fnRedraw();
          bRedraw = False;
        }
    }
}

void fnRedraw(void)
{
  static Bool   bFirstPass=True;
  
  if(bFirstPass)
    {
      bFirstPass=False;
      glXMakeContextCurrent( dpy, PBuffer,PBuffer, PBufferCtx);
      glMatrixMode(GL_MODELVIEW); /* switch to model matrix stack */
      glLoadIdentity();   /* reset modelview matrix to identity */
      glTranslatef(0.0,0.0,-3.0); /* move camera back 3 units */
      glClearColor(1.0,0.0,0.0,0.0);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
      glBegin(GL_QUADS);
      {    
        glColor3f(0.0,0.7,0.1); 
        glVertex3f(-1.0, 1.0, 1.0);
        glVertex3f( 1.0, 1.0, 1.0);
        glVertex3f( 1.0,-1.0, 1.0);
        glVertex3f(-1.0,-1.0, 1.0);
      }
      glEnd();
      glReadBuffer(GL_FRONT);
    }
  glXMakeContextCurrent( dpy, win,PBuffer, WinCtx);
  
  glCopyPixels(0,0,WIDTH,HEIGHT,GL_COLOR);
  glFlush();  
}