QGLWidget and fast rendering

Is it possible to fully display the screen in QGLWidget using Qt without having to repaint the scene on the screen, while avoiding completely discarding the buffers on the monitor?

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

Is it possible to speed up frame-by-frame rendering? Can I avoid the monitor refresh rate in my QGLWidget?

How to fully render a framebuffer without slow paintGL() calls?

+6
source share
2 answers

For now, I assume we are talking about Qt4.

Is it possible to fully display the screen in a QGLWidget

Off-screen rendering is not a window system-specific task at all. The only problem with WGL (at least) and GLX in most toolboxes is that you cannot have a surfaceless context, i.e. A context that is not related to the drawing capability provided by the window system. In other words, you will always have a window system provided by default to the framebuffer, which is unchanged as long as the current context exists.

There are tools for creating a context that does not require a window manually with X11, but this is usually not worth the trouble. For example, for EGL and OpenGL ES this problem does not exist, because there is an extension that aims exactly at this problem, that is, off-screen rendering.

However, you can simply hide the QGLWidget after the actual context has been configured and use framebuffer objects to do everything without the intervention of the default fader.

Can I avoid the monitor refresh rate in my QGLWidget?

No, as far as I know, the Qt4 OpenGL module does not have any vsync programming tool. You can refer to SDL or GLFW for something similar (not sure about FreeGLUT).

However, you can always disable the material in the settings of your driver. This will also affect the QGLWidget (or better place, the swap behavior of the base window system).

Is it possible to speed up frame-by-frame rendering?

In the end, it shouldn't matter. You will want the image data to be somewhere else than VRAM, so after you have provided the current FBO frame, you need to get the image anyway. You either mix the results with the front buffer (or the rear buffer if you need double buffering and swap), or you need to reload the material before further processing your current frame.

However, like everything related to OpenGL and performance, do not guess - profile !

How to fully render a framebuffer without slow paintGL () calls?

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

EDIT . As for your request in the comments, see this minimal code example that should work cross-platform without changes.

 #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, eg 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 computer, the programs print:

ATI Technologies Inc.

AMD Radeon HD 7900 Series

1.4 (2.1 (4.2.12337 Context profile compatibility 13.101))

Note how QGLWidget never becomes visible and event processing does not occur. The Qt OpenGL library is used only to create context. Everything else is done without Qt's intervention. Just remember to set the viewport and more to suit your needs.

Please note:. If you need a convenient way of setting up the context, you can switch to some set of tools that will be easier than Qt4, for example FreeGLUT. Personally, I found that FreeGLUT will be much more reliable when it comes to setting the actual context exactly the way I want on some hardware, for example. Sandy Bridge processors.

+5
source

I found a solution using QGLFrameBuffer and glReadPixels .

First, I initialize my QGLFrameBuffer object to QGLWidget::initializeGL to have a valid GL context where the QGLFrameBuffer can "lie".

This is the first implementation. The frame rate is 10 times higher and does not update anything depending on VSync !!

 MyGLWidget::MyGLWidget(QWidget *parent) : // QGLWidget(parent) QGLWidget( QGLFormat(QGL::SampleBuffers), parent) //this format doesn't matter it the QGLWidget format on the monitor { //some initializations } void MyGLWidget::initializeGL() { qglClearColor(Qt::black); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0,0,-10); this->makeCurrent(); // Initializing frame buffer object // Here we create a framebuffer object with the smallest necessary precision, ie GL_LUMINANCE in order to make // the subsequent calls to glReadPixels MUCH faster because the internal format is simpler and no casts are needed QGLFramebufferObjectFormat fboFormat; fboFormat.setMipmap(false); fboFormat.setSamples(0); fboFormat.setInternalTextureFormat(GL_LUMINANCE); // Create the framebuffer object fbo = new QGLFramebufferObject(QSize(this->width(),this->height()),fboFormat); } void MyGLWidget::generateFrames() { //keep unsigned int because of possible integer overflow //when resizing the vector and consequent std::bad_alloc() exceptions unsigned int slicesNumber = 1000; unsigned int w = this->width(); unsigned int h = this->height(); // This vector contains all the frames generated as unsigned char. vector<unsigned char> allFrames; allFrames.resize(w*h*slicesNumber); fbo->bind(); // Inside this block the rendering is done on the framebuffer object instead of the MyGLWidget for ( int i=0; i<slicesNumber; i++ ) { this->paintGL(); // Read the current frame buffer object glReadPixels(0, 0, w, h, GL_LUMINANCE, GL_UNSIGNED_BYTE, allFrames.data()+i*w*h); // update scene() } fbo->release(); } 
0
source

Source: https://habr.com/ru/post/957935/


All Articles