QCustomPlot Discussion and Comments

QCustomPlot OpenGL issues (setOpenGL true)Return to overview

Hello,
We are curently plotting up to 64 graphs in an ECG style (starting again after few seconds and replacing the previous data). Data is received at 2kHz via ethernet and inserted in a separate thread in batches (not one by one). We use a QTimer to replot every 50 ms. Some graphs have their own QCustomPlots (based on device setup).
We encountered some performance issues with the max number of graphs so we tried to use hardware acceleration with OpenGL to free up the CPU, but the actual plotting performances became much worse.

We noticed that

painter->drawImage(0, 0, mGlPBuffer->toImage());

takes around 7 ms for each buffer with OpenGL, and that QImages are quite worse than QPixmap for data visualisation.
After that we inspected
painter->drawPixmap(0, 0, mBuffer);

which takes around 0.6 ms for every buffer.

How could we efficiently visualize data by using or altering the QCustomPlot's OpenGL logic?
We also tried:
1. Putting our QCustomPlots with disabled OpenGL into QOpenGLWidgets, the performances are somewhat satisfying and the raster pixmaps are being visualized using hardware acceleration (correct me if I'm wrong), but our graphs are sometimes distorsed (probably caused by outer interference).
2. Putting QCustomPlots with enabled OpenGL into QOpenGLWidgets, and setting a shared QOpenGLContext between our widgets and QCustomPlot's mGlContext, which didn't improve any performaces to the basic setOpenGL inside a QWidget and even caused weird plot flickering when there is more than one plot on the screen.

The strange behavior when OpenGL is set for multiple QCustomPlot widgets in a single instance can be fixed as follows:

When we create multiple QCustomPlot Widgets in a single instance (or single process), somehow QOpenGLContext::currentContext() is getting other OpenGL context.

Each time when the widget has to draw, it is calling the QCPPaintBufferGlFbo::draw(QCPPainter *painter) function. Here, the QopenGL's current context is not checked with the widget's mGLContext like in other QCPPaintBufferGlFbo class functions. So adding this check and making the mGLContext as current Context solved the issue.

Change the following function in qcustomplot.cpp

void QCPPaintBufferGlFbo::draw(QCPPainter *painter) const
{
  if (!painter || !painter->isActive())
  {
    qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
    return;
  }
  if (!mGlFrameBuffer)
  {
    qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
    return;
  }
  painter->drawImage(0, 0, mGlFrameBuffer->toImage());
}

To

void QCPPaintBufferGlFbo::draw(QCPPainter *painter) const
{
  if (!painter || !painter->isActive())
  {
    qDebug() << Q_FUNC_INFO << "invalid or inactive painter passed";
    return;
  }
  if (!mGlFrameBuffer)
  {
    qDebug() << Q_FUNC_INFO << "OpenGL frame buffer object doesn't exist, reallocateBuffer was not called?";
    return;
  }

  //Add these 2 lines
  if (QOpenGLContext::currentContext() != mGlContext.data())
    mGlContext.data()->makeCurrent(mGlContext.data()->surface());

  painter->drawImage(0, 0, mGlFrameBuffer->toImage());
}

HI,

The Pramod patch seems to fix the visual artifact for me but doesn't change performance issue. On Windows, I tried with Nvidia, Amd and Intel graphic chipset. The result is worse with OpenGL at true (time x2 at least). I hope that DerManu or somebody with good understanding of OpenGL will fix this problem.