3
\$\begingroup\$

I have a Qt (5.9.1) app that on Windows many of the geometries I'm drawing flickers. My problem description is vague because I'm at a complete loss.

Does anyone know if there's an issue with flickering on Windows with OpenGL (I think Qt uses ANGLE for OpenGL) that would be different than in Linux? My app on Linux seems to work perfectly.

Specifically, my app draws LIDAR ground points (GL_POINTS), and boxes around objects (GL_LINES), and range marker circles (GL_LINE_LOOP). These are all drawn to the same context. I also set up double buffering. All the rendering takes place on a render thread. This is done in the style of Scene Graph - Rendering FBOs in a thread (so, no Qt3D)

When the app starts, initially it seems fine, but after a couple seconds, different geometries, say, the boxes around objects, and/or the range marker circles, start flickering. Although they're all on the same context, all of the same geometries (say the range markers) will flicker at the same rate (independent of the other geometry types), or all the boxes.

While this is happening, my measured FPS does slow down, but the flickering still occurs even when the FPS is up at 58+. I've even inserted some glFlush()es and glFinish()es - no impact (either on FPS or flickering.) UPDATE I must have made a mistake when testing glFinish() or something changed, because now glFinish() removes the flicking (and kills my FPS.)

The structure of my renderers is that I have one class that sets up the viewports, calls glClear, and then invokes render() on each renderer. Those renderers have a buffer setup with vertex array buffers, I set some uniforms, and call glDrawArrays. I don't think I'm doing anything unconventional. e.g.

opengl_safety_buffer_.bind();

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

QOpenGLVertexArrayObject::Binder vaoBinder(&safety_vao_);
render_safety_program_->bind();

glLineWidth(safety_ranges_config_["lineWidth"].value<GLfloat>());
render_safety_program_->setUniformValue("col", vcol_);

glUniformMatrix4fv(render_safety_program_->uniformLocation("mvp"), static_cast<GLsizei>(mvp_matrices_.size()), GL_TRUE, reinterpret_cast<GLfloat*>(&(mvp_matrices_[0])));
glDrawArrays(GL_LINE_LOOP, 0, opengl_safety_buffer_.CountVertices());

glDisable(GL_BLEND);

render_safety_program_->release();
opengl_safety_buffer_.release();

My vertex and fragment shaders are very simple.

I don't have great profiling data right now, but the little I do have shows that all my renderers combined don't take even half of the 1/60s time per frame I need.

The flickering started when I moved away from using a Scene Graph Under QML mixed with Qt3D, towards the threaded FBO example - so I figure there's nothing intrisic in my geometries that should be causing the flickering.

UPDATE

Posting my top level render code. Basically I have a loop that calls all my individual renderers sequentially, all on the same thread and on the same context.

Top level render code:

// ...

render_fbo_->bind();

// Clear
context_->functions()->glClearColor(0.039f, 0.055f, 0.10f, 1.0f);
context_->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Render only the faces closest to you
context_->functions()->glEnable(GL_DEPTH_TEST);
context_->functions()->glDepthMask(GL_TRUE);

{
    // Configure out viewport (x,y, width, height)
    unsigned int i = 0;
    foreach (const auto v, scene_graph_->viewports())
    {
        // Make sure that the viewports cameras are updated
        v->camera()->calculatePosition();

        auto vs = v->paddedRect();
        context_->versionFunctions<QOpenGLFunctions_4_3_Core>()->glViewportIndexedf(i, vs.x(), vs.y(), vs.width(), vs.height());
        i++;
    }
}

foreach (const auto model, scene_graph_->models())
{
    if (model->isDirty())
    {
        model->renderer()->synchronize(model);
        model->dataSynced();
    }
    model->renderer()->render();
}

// Reset OpenGL state
context_->functions()->glDisable(GL_DEPTH_TEST);

// We need to flush the contents to the FBO before posting
// the texture to the other thread, otherwise, we might
// get unexpected results.
context_->functions()->glFlush();

// FPS
recalculateFPS();

render_fbo_->bindDefault();
render_fbo_.swap(display_fbo_);

emit textureReady(display_fbo_->texture(), size_);

When I include glFlush glFinish() after model->renderer()->render(), I can see that some of my renders, specially my GroundRenderer is taking waay too much time (the black line represents the amx time for 1 frame):

Profile of my renders

So, my goal now is to figure out why GroundRenderer takes so much time. It basically just writes to a large circular buffer. I'm not experienced enough yet though to know what "large" is, but I haven't really observed a sensitivity to the specific size of the buffer (I cut it's size by a few orders of magnitude, and didn't see any real difference.)

\$\endgroup\$
  • \$\begingroup\$ You have a problem in the handling of multiple contexts and lack of synchronization. Post the details of your code treating the threads and contexts. \$\endgroup\$ – Andreas Sep 15 '17 at 19:12
  • \$\begingroup\$ Unless I'm misunderstanding something, I think I'm writing everything to the same context sequentially all in the same thread. So I think it's really that a single renderer is taking up too much time. I posted a graph showing the time taken by each renderer. \$\endgroup\$ – Matt Sep 15 '17 at 19:55
  • 1
    \$\begingroup\$ "// We need to flush the contents to the FBO before posting // the texture to the other thread, otherwise, we might // get unexpected results. context_->functions()->glFlush();" glFlush tells the driver "now is a good time to start working with the command queue" which can be good for performance if there are large gaps between the last draw call and usage of the result such as buffer swap. You are not in sync after invoking it. If you want sync without locks checkout sync objects: khronos.org/opengl/wiki/Sync_Object \$\endgroup\$ – Andreas Sep 16 '17 at 9:41
  • \$\begingroup\$ @Andreas I think you're right, but ultimately I'm pretty confident that my issue is that one of my renderers is simply taking too much time. So if I properly sync, I won't see any flicking but my FPS will be cut in half. Thanks though. \$\endgroup\$ – Matt Sep 16 '17 at 17:48
1
\$\begingroup\$

The problem is that my renders are taking too long, which is "solved" with a glFinish(). My understanding however is that glFinish() should only be used to debug, so this is not a solution, but it does point me in a better direction to ultimately solving my problem. (and tells me that my profiling attempts wasn't working as well as I thought.)

I've left this question up in case any one else experiences similar issues to me, but I want this answer to "close" this question as the question is pretty vague and I have a new direction to pursue.

\$\endgroup\$
  • \$\begingroup\$ Just an ammendment, very particular to the Scene Graph - Rendering FBOs in a thread, reversing the order of the bindDefault and the qSswap call seemed to make a huge difference. The right there was the effective ultimate fix, but I don't understand it well enough to compose a proper answer based on it. \$\endgroup\$ – Matt Oct 20 '17 at 17:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.