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 UPDATE I must have made a mistake when testing glFlush()
es and glFinish()
es - no impact (either on FPS or flickering.)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):
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.)