PDA

View Full Version : Offscreen rendering



enigmagame
08-21-2008, 03:06 AM
Hi to all!
For my project I need to implement a offscreen rendering method, I've some OpenGL code and I want to rendering the result to an image without create and open a window.
I've tried Mesa3D Off-screen rendering, it's works correctly, but without hardware acceleration, so the result is bad...
There are other solutions for this problem?
Thanks!

Zengar
08-21-2008, 03:08 AM
You have to create a window to get an OpenGL accelerated context. For offscreen rednering, just make the window invisible and use the framebuffer object extension.

babis
08-21-2008, 03:13 AM
Just create a dummy glut window & run your rendering method. One example I've found in the forums is here :

http://www.vis.uni-stuttgart.de/~klein/fboCheckSupported.tar.gz

dletozeun
08-21-2008, 03:37 AM
You can also look at pBuffers. I think it is exactly what you need.

You have one extension for windows here (http://www.opengl.org/registry/specs/ARB/wgl_pbuffer.txt)

And it is available with glx on Linux.

enigmagame
08-21-2008, 04:10 AM
You can also look at pBuffers. I think it is exactly what you need.

An information, to do this, I need to create a window (for example with GLUT) or isn't necessary?

Zengar
08-21-2008, 04:31 AM
If I understand correctly and you are on linux, you don't need to create a window. Please refer to the GLX documentation.

enigmagame
08-21-2008, 04:37 AM
If I understand correctly and you are on linux, you don't need to create a window. Please refer to the GLX documentation.
In reality I need a cross platform code, and at this moment I'm working on Windows. If the only (and simple) solution, is a hide GLUT window + FBO, I use this...

Zengar
08-21-2008, 04:46 AM
If you want cross-platform, a hidden GLUT window with FBO would work fine

enigmagame
08-21-2008, 04:54 AM
If you want cross-platform, a hidden GLUT window with FBO would work fine
Perfect, I take this solution! If I've problems, I post here.
Thanks to all!

dletozeun
08-21-2008, 06:01 AM
pbuffers are exactly designed for offscreen rendering, it enables you to create a rendering context like a window but without drawing on the screen.

The problem is that on windows, you have to use thee WGL_EXT_pbuffer extension and on linux, you have to use glx to create a pbuffer.

The hidden glut window is the easiest way to do it since it is not platform specific unlike pbuffers

Zengar
08-21-2008, 09:24 AM
Yes, but pbuffers are also de-facto deprecated, after FBO has appeared. Also, FBO is much easier to use.

Keith Z. Leonard
08-21-2008, 11:06 AM
There was some discussion at the Siggraph BOF about allocating a context without a window in gl 3.0 as well. If you are being progressive about it, there will be an interface there in a few months. If not, I probably agree with Zengar, FBO is a lot easier to use than pbuffers. The only issue is if you need to share your results with other contexts.

dletozeun
08-21-2008, 11:28 AM
Yes that's correct. Now pbuffers would be useful just for creating a independant rendering context for a little program which don't have access to window management, I think about plugins for example... until the interface Keith is talking about is released.

enigmagame
08-21-2008, 11:32 AM
I've tried, but there is a problem with the FBO.
Only using the glGenRenderbuffersEXT() function, the application crash. For the extensions, I use glew library.

dletozeun
08-21-2008, 11:34 AM
Did you check if GL_EXT_frame_buffer_object extension is supported by your hardware?

enigmagame
08-21-2008, 11:41 AM
Did you check if GL_EXT_frame_buffer_object extension is supported by your hardware?
Yes, it's supported, this is the response: (from glewinfo)


GL_EXT_framebuffer_object: OK
--------------------------
glBindFramebufferEXT: OK
glBindRenderbufferEXT: OK
glCheckFramebufferStatusEXT: OK
glDeleteFramebuffersEXT: OK
glDeleteRenderbuffersEXT: OK
glFramebufferRenderbufferEXT: OK
glFramebufferTexture1DEXT: OK
glFramebufferTexture2DEXT: OK
glFramebufferTexture3DEXT: OK
glGenFramebuffersEXT: OK
glGenRenderbuffersEXT: OK
glGenerateMipmapEXT: OK
glGetFramebufferAttachmentParameterivEXT: OK
glGetRenderbufferParameterivEXT: OK
glIsFramebufferEXT: OK
glIsRenderbufferEXT: OK
glRenderbufferStorageEXT: OK

PaladinOfKaos
08-21-2008, 11:43 AM
You did rember to call glewInit() after creating your context, right? If you didn't, you're trying to call an uninitialized function pointer.

enigmagame
08-21-2008, 11:47 AM
:o :o :o mmmm... no... :o :o :o
Ok, it's runs!

dletozeun
08-21-2008, 11:50 AM
:D We all do this error once!

Korval
08-21-2008, 12:42 PM
There was some discussion at the Siggraph BOF about allocating a context without a window in gl 3.0 as well.

You can't. Well, not really.

See, the Microsoft Win32 library requires that context creation take a HDC, which requires a HWND of some kind. It's an issue that's discussed in the ARB_context_create extension.

After creating the context, you can make it current without a HDC (if it is a 3.0 or greater context); that is the clue to the context that you don't want a default framebuffer.

PaladinOfKaos
08-21-2008, 01:16 PM
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.

dletozeun
08-21-2008, 01:23 PM
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?

PaladinOfKaos
08-21-2008, 01:29 PM
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.

dletozeun
08-21-2008, 02:01 PM
Ok this is weird but I understand now. So Windows pbuffers are completely useless now, since the apparition of FBO.

PaladinOfKaos
08-21-2008, 02:04 PM
Not entirely. Pbuffers let you do multisampling on hardware that doesn't support the framebuffer_multisample and framebuffer_blit extensions (read: everyone but nvidia).

dletozeun
08-21-2008, 02:19 PM
OK thanks for the precisions. :)

Eosie
08-21-2008, 04:50 PM
Not entirely. Pbuffers let you do multisampling on hardware that doesn't support the framebuffer_multisample and framebuffer_blit extensions (read: everyone but nvidia).
Only Intel does not support it, ATI supports it on 9500+ which is interesting.

PaladinOfKaos
08-21-2008, 07:19 PM
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).

Korval
08-21-2008, 11:20 PM
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.

Hampel
08-22-2008, 12:28 AM
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

arekkusu
08-22-2008, 12:48 AM
FWIW, windowless FBOs work on the Mac, too. On all vendor's drivers.

Eosie
08-22-2008, 07:59 PM
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).

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

srimalj
12-13-2009, 10:09 PM
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.

Dark Photon
12-15-2009, 11:18 AM
I need to do an offscreen hardware accelerated render in Linux using GLX (not GLUT) and pbuffers sound like exactly what I need ... Could you please point me to some sample code that uses pbuffers in GLX for offscreen rendering?
Ever since Framebuffer Objects (aka FBOs, spec: ARB_framebuffer_object (http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt)) 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\n" );
exit(1);
}

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

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

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

// Print GLX extensions
//const char *extensions = glXQueryExtensionsString( display,
// DefaultScreen( display ) );
//printf( "%s\n", 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\n" );
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ),
visual_attribs, &amp;fbcount );
if ( !fbc || fbcount < 1 )
{
printf( "Failed to retrieve a framebuffer config\n" );
exit(1);
}
printf( "Found %d matching FB configs.\n", fbcount );

int fbc_id = 0;

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

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

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

printf( "Mapping window\n" );
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\n" );
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\n" );
ctx = glXCreateContextAttribsARB( display, fbc[ fbc_id ], 0,
True, context_attribs );

if ( ctx )
printf( "Created GL 3.0 context\n" );
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\n" );
ctx = glXCreateContext( display, vi, 0, True );
}
}

XFree( fbc );

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

printf( "Making context current\n" );
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) &amp;&amp; (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\n",glXQueryExtensionsString(dpy, DefaultScreen(dpy)));

if(!glXQueryExtension(dpy, &amp;dummy, &amp;dummy))
{
fprintf(stderr,"Error:GLX extensions not supported");
exit(-1);
}

fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), sbAttrib,
&amp;nElements);
fprintf(stdout,"Info:Number of FBConfigs: %d\n",nElements);
if(nElements == 0)
{
fprintf(stderr,"Error: No valid framebuffers configurations found\n");
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\n");
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,
&amp;swa);

glXMakeContextCurrent( dpy, PBuffer,PBuffer, PBufferCtx);

XMapWindow(dpy, win);
XIfEvent(dpy, &amp;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, &amp;event);
switch(event.type)
{
case ConfigureNotify:
glViewport(0,0,event.xconfigure.width,event.xconfi gure.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();
}