Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QGLWidget and fast offscreen rendering

Is it possible to render totally offscreen in a QGLWidget with Qt without the need to repaint the scene to screen thus avoiding totally the buffers flip on monitor?

I need to save every frame generated on the framebuffer but, since the sequence is made of 4000 frames and the time interval on the screen is 15ms I spend 4000*15ms=60s but I need to be much much faster than 60s (computations are not a bottleneck here, is just the update the problem).

Can rendering offscreen on a framebuffer be faster? Can I avoid the monitor refresh rate in my QGLWidget?

How do I render completely on framebuffer without the slow paintGL() calls?

like image 225
linello Avatar asked Nov 12 '13 16:11

linello


1 Answers

For now I'll assume we're talking Qt4.

Is it possible to render totally offscreen in a QGLWidget

Off-screen rendering isn't really a window-system-dependent task at all. The only problem with WGL (at least) and GLX in most toolkits is that you cannot have a surfaceless context, i.e. a context that's not bound to a drawable provided by the window-system. In other words, you'll always have window-system provided default framebuffer that immutable as long as the current context exists.

There are means to create a context that doesn't require a window manually with X11 but it's usually not worth the trouble. For EGL and OpenGL ES, for instance, this problem doesn't exist because there is an extension tending exactly to this problem, i.e. off-screen rendering.

You can, however, simply hide the QGLWidget after a valid context has been set up and use framebuffer objects to do everything without default framebuffer intervention.

Can I avoid the monitor refresh rate in my QGLWidget?

No, to my knowledge, the OpenGL module of Qt4 has no means to turn of vsync programmatically. You can turn to SDL or GLFW for something like that (not sure about FreeGLUT).

However, you can always turn stuff off in your driver settings. This will also affect QGLWidget (or better put, the swapping behavior of the underlying window-system.)

Can rendering offscreen on a framebuffer be faster?

It really shouldn't matter in the end. You're gonna want the image data some place else than VRAM, so after having rendered the current frame to a FBO, you need to get the image anyway. You either blit the results to the front buffer (or back buffer if you need double buffering and swap), or you need to read-back stuff prior to further processing your current frame.

However, as with anything OpenGL and performance related, don't guess - profile!

How do I render completely on framebuffer without the slow paintGL() calls?

Once a context is set up, you don't need the widget at all. You can do all the magic yourself without Qt's intervention. The only reason paintGL() exists is to provide the user with an easy to use interface that's guaranteed to be called when the widget needs to be updated.

EDIT: As to your query in the comments, see this minimal code example which should work cross-platform without change.

#include <iostream>
#include <QtOpenGL/QGLWidget>
#include <QtGui/QApplication>

void renderOffScreen ()
{
  std::cout << glGetString(GL_VENDOR)   << std::endl;
  std::cout << glGetString(GL_RENDERER) << std::endl;
  std::cout << glGetString(GL_VERSION)  << std::endl;

  // do whatever you want here, e.g. setup a FBO, 
  // render stuff, read the results back until you're done
  // pseudocode:
  //     
  //      setupFBO();
  //   
  //      while(!done)
  //      {
  //        renderFrame();
  //        readBackPixels();
  //        processImage();
  //      }
}

int main(int argc, char* argv[])
{
  QApplication app(argc, argv);
  QGLWidget gl;

  // after construction, you should have a valid context
  // however, it is NOT made current unless show() or
  // similar functions are called
  if(!gl.isValid ())
  {
    std::cout << "ERROR: No GL context!" << std::endl;
    return -1;
  }

  // do some off-screen rendering, the widget has never been made visible
  gl.makeCurrent (); // ABSOLUTELY CRUCIAL!
  renderOffScreen ();

  return 0;
}

On my current machine the programs prints:

ATI Technologies Inc.

AMD Radeon HD 7900 Series

1.4 (2.1 (4.2.12337 Compatibility Profile Context 13.101))

Please note how the QGLWidget is never actually made visible and no event processing takes place. The Qt OpenGL library is merely used for the context creation. Anything else is done without Qt intervention. Just don't forget to set the viewport and stuff according to your needs.

Please note: If all you need is some convenient way to setup a context, you might want to switch to some toolkit which is more lightweight than Qt4, like FreeGLUT. Personally I found FreeGLUT to be much more reliable when it comes to setting up a valid context exactly the way I want it on some hardware, e.g. Sandy Bridge CPUs.

like image 130
thokra Avatar answered Sep 30 '22 02:09

thokra