OpenGL in Qt 5.1 – Part 3

This article continues our series on what is new in Qt 5.1 with respect to OpenGL. If you haven’t already seen them, you may be interested in reading Part 1 and Part 2.

Timer Queries

OpenGL on the desktop exposes a very useful tool in the shape of timer query objects. These can be used to record the amount of time taken by the GPU to process sequences of commands. If we couple this with the usual CPU profiling techniques then we can get a very complete understanding of the bottlenecks in our rendering code.

One obvious place that could take advantage of this is the Qt Quick 2 renderer. Although the Qt Quick 2 renderer does have options to enable timings of various stages of rendering, this only tells us half of the story. Namely, the CPU half. Using OpenGL timer queries would allow us to fill in the gap and gain an understanding of how the GPU is performing.

Another common use for OpenGL timer queries is to provide feedback to adaptive rendering routines in order to maintain more consistent frame rates. For example, if we instrument our rendering function and find at runtime that our application is rendering too slowly, we can perhaps increase the frame rate by using less complex shaders or by using lower resolution meshes etc. Conversely, if we find that we have GPU cycles to spare then we could improve rendering quality by perhaps using higher levels of tessellation.

Qt 5.1 will make such tasks much easier with the introduction of two new classes developed by KDAB engineers: QOpenGLTimerQuery and QOpenGLTimeMonitor. The QOpenGLTimerQuery class is a simple wrapper around a single OpenGL timer query object and can be used if you wish to have total control. It is expected that QOpenGLTimeMonitor will be the more commonly used class as this is a wrapper around a sequence of timer query objects and makes it trivial to measure the GPU time of the various stages of our rendering functions:

void Scene::initialize()
{
    // Create a timer query object
    m_timeMonitor = new QOpenGLTimeMonitor( this );
    m_timeMonitor->setSampleCount( 5 );
    if ( !m_timeMonitor->create() )
        qWarning() << &quot;Failed to create timer query object&quot;;

    // Generate some names for the various stages of rendering
    m_renderStages << &quot;Clear Buffer&quot; << &quot;VAO Binding&quot;
                   << &quot;Shader Program Binding&quot; << &quot;Drawing&quot;;
}

void Scene::render()
{
    // Start the timer query
    m_timeMonitor->recordSample();

    // Do some rendering
    m_funcs->glClear( GL_COLOR_BUFFER_BIT );
    m_timeMonitor->recordSample();
    m_vao.bind();
    m_timeMonitor->recordSample();
    m_shaderProgram.bind();
    m_timeMonitor->recordSample();
    m_funcs->glDrawArrays( GL_TRIANGLES, 0, 3 );

    // End the timer query
    m_timeMonitor->recordSample();

    // Block until the results are available
    QVector<GLuint64> timeSamples = m_timeMonitor->waitForSamples();
    qDebug() << &quot;timeSamples =&quot; << timeSamples;

    QVector<GLuint64> intervals = m_timeMonitor->waitForIntervals();
    for ( int i = 0; i <= intervals.count(); ++i )
        qDebug() << i << m_renderStages.at( i ) 
                 << double( intervals.at( i ) ) / 1.0e6 << &quot;msecs&quot;;

    // Clear the query results ready for the next frame
    m_timeMonitor->reset();
}

This is obviously a trivial example but gives an idea of the usage. Note that the timer intervals and timestamps are recorded in nanoseconds. Sample output from this is:

 timeSamples = QVector(5850713788736, 5850713794176, 5850713794848, 5850713795552, 5850713801952) 
 0 "Clear Buffer" 0.00544 msecs 
 1 "VAO Binding" 0.000672 msecs 
 2 "Shader Program Binding" 0.000704 msecs 
 3 "Drawing" 0.0064 msecs

So here we see in this trivial example (which just draws a single large triangle) that the GPU is using only a fraction of a millisecond. This means that we could easily ask the GPU to do more work per-frame (as we would certainly hope!).

There is much more to say about the nuances of using timer queries but we’ll leave that to a future more in-depth article.

Read Part 4…

 

Share on FacebookTweet about this on TwitterShare on Google+

10 thoughts on “OpenGL in Qt 5.1 – Part 3

  1. One thing that is sorely needed in the Qt5 OpenGL world is a good set of compilable examples. The existing ones appear to be ports of the Qt4 OGL ones and don’t illustrate the use of the new stuff. I know it’s all documented but having something you can step through with a debugger is a much easier way to learn and/or build upon.

    Another thing that might be worth mentioning is the usage of QWidget::createWindowContainer in order to create something analogous to QGLWidget from a GL backed QWindow. It took me many hours or googling and some IRCing to figure this out. Granted it is a very new feature so won’t have percolated up to the surface yet, but being able to have a GL “subwindow” seems like such a fundamental feature I’m surprised its usage hasn’t been made more obvious or documented.

    Anyway, it looks like you’ve been doing a great job making OpenGL less of a pain with Qt5; long may it continue!

    • Yes, I have plans to add a new set of OpenGL examples to Qt5 very shortly. Are there any in particular that you would like to see?

      • I think the instanced rendering demo from your QtDD talk probably covers all the bases; i.e. a bunch of phong-lit meshes in space with basic camera manipulation.

        Thanks.

          • How about examples of how to initialize and use OpenGL with Qt/QtQuick? In your talk you show how to use it as an underlay but you also mention that it can be used as overlay, inside of QML element, etc.

          • OK but have you looked at the examples in qtdeclarative/examples/scenegraph/?

          • Did these examples ever make it into Qt5? I’m trying to find them in the dev tree but failing.

  2. Did these examples ever make it into Qt5? I’m trying to find them in the dev tree, but failing. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *


7 − two =