Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QOpenGLWidget and Threads
Forum Updated to NodeBB v4.3 + New Features

QOpenGLWidget and Threads

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 4 Posters 2.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R rtavakko

    @Kent-Dorfman Thanks for your reply! That does make sense and looking at the QOpenGLWidget threaded example it looks like that is what they're doing there using a worker thread. I think another alternative is to have multiple contexts on different threads sharign textures. Do you know by any chance how that could be done?

    Cheers!

    Kent-DorfmanK Offline
    Kent-DorfmanK Offline
    Kent-Dorfman
    wrote on last edited by
    #4

    @rtavakko Unfortunately my opengl experience is old school immediate mode programming. I have yet to do anything real using the modern shaper/pipeline architecture. I think it's a given that the framework properly handles multiple QOpenGLWidgets, but as you've discovered, when you try to offload to worker threads there are some gotchas: the big one being that you now have to explicitly give the correct worker thread the context (and it probably cannot be simultaneously shared). I suspect that the modern pipeline architecture cannot handle multiple threads using the pipeline concurrently.

    1 Reply Last reply
    0
    • W Offline
      W Offline
      wesblake
      wrote on last edited by
      #5

      I've got a similar question. I am trying to get our current (threaded) QGLWidget migrated to a QOpenGLWidget. So far based on an example it's successfully working meaning it runs, the glClear is working from the other thread, as is the "WTF" message so I know it's rendering at X fps.
      What I can't figure out is how to get a QPainter to work!! I've tried everything. Our current QGLWidget based class renders QIMages at about 60 fps threaded, np using QPainter. I've read many things that seem to indicate I can still use QPainter in a separate thread as we are doing with QGLWidget, but I just can't get it to work. No matter how/where I create QPainter, it crashes. (cpp line 197)
      Am I forced to use opengl directly? How would I draw a QImage like that? Thanks!

      #ifndef GLWIDGET_H
      #define GLWIDGET_H
      
      #include "framequeue.h"
      
      #include <QOpenGLWidget>
      #include <QOpenGLContext>
      #include <QImage>
      #include <QThread>
      #include <QMutex>
      #include <QList>
      #include <QWaitCondition>
      
      class GLWidget;
      
      class Renderer : public QObject
      {
          Q_OBJECT
      
      public:
          Renderer(GLWidget *);
          ~Renderer();
          void lockRenderer() { m_renderMutex.lock(); }
          void unlockRenderer() { m_renderMutex.unlock(); }
          QMutex *grabMutex() { return &m_grabMutex; }
          QWaitCondition *grabCond() { return &m_grabCond; }
          void prepareExit() { m_exiting = true; m_grabCond.wakeAll(); }
      
          FrameQueue *selfView;
          QList<FrameQueue*> remoteViewList;
      
      signals:
          void contextWanted();
      
      public slots:
          void start();
          void stop();
          void pause();
          void resume();
          void resumeToClose();
          void render();
      
      private:
          static const int animationFPS = 30;
          static const int pipWidth = 160;
          static const int pipHeight = 120;
      
          bool m_inited;
          GLWidget *m_glwidget;
          QMutex m_renderMutex;
          QMutex m_grabMutex;
          QWaitCondition m_grabCond;
          bool m_exiting;
      
          bool pauseRendering;
      };
      
      class GLWidget : public QOpenGLWidget
      {
          Q_OBJECT
      public:
          GLWidget(QWidget *parent);
          ~GLWidget();
          void stopRendering();
          void startRendering();
          void pauseRendering();
          void resumeRendering();
          void resumeForClose();
          bool isStarted();
      
      protected:
          void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE { }
      
      signals:
          void renderRequested();
      
      public slots:
          void grabContext();
      
      private slots:
          void onAboutToCompose();
          void onFrameSwapped();
          void onAboutToResize();
          void onResized();
      
      private:
          QThread *m_thread;
          Renderer *m_renderer;
          bool m_isStarted;
      };
      
      #endif // GLWIDGET_H
      
      
      #include "glwidget.h"
      
      #include <QGuiApplication>
      #include <QPainter>
      #include <QDebug>
      
      //Leak detection
      #ifdef Q_OS_WIN32
      #ifdef QT_DEBUG
      #include "debugtools/reportinghook.h"
      #include "debugtools/setdebugnew.h"
      #define new DEBUG_NEW
      #endif
      #endif
      
      GLWidget::GLWidget(QWidget *parent)
          : QOpenGLWidget(parent)
          , m_isStarted(false)
      {
          connect(this, &QOpenGLWidget::aboutToCompose, this, &GLWidget::onAboutToCompose);
          connect(this, &QOpenGLWidget::frameSwapped, this, &GLWidget::onFrameSwapped);
          connect(this, &QOpenGLWidget::aboutToResize, this, &GLWidget::onAboutToResize);
          connect(this, &QOpenGLWidget::resized, this, &GLWidget::onResized);
      
          m_thread = new QThread;
          m_renderer = new Renderer(this);
          m_renderer->moveToThread(m_thread);
          connect(m_thread, &QThread::finished, m_renderer, &QObject::deleteLater);
      
          connect(this, &GLWidget::renderRequested, m_renderer, &Renderer::render);
          connect(m_renderer, &Renderer::contextWanted, this, &GLWidget::grabContext);
      }
      
      GLWidget::~GLWidget()
      {
      //    stopRendering();
      }
      
      void GLWidget::stopRendering()
      {
          m_renderer->prepareExit();
          m_thread->quit();
          m_thread->wait();
          delete m_thread;
      }
      
      void GLWidget::startRendering()
      {
          m_thread->start();
          m_isStarted = true;
          QMetaObject::invokeMethod(m_renderer, "start");
      }
      
      void GLWidget::pauseRendering()
      {
          QMetaObject::invokeMethod(m_renderer, "pause");
      }
      
      void GLWidget::resumeRendering()
      {
          QMetaObject::invokeMethod(m_renderer, "resume");
      }
      
      void GLWidget::resumeForClose()
      {
          QMetaObject::invokeMethod(m_renderer, "resumeToClose");
      }
      
      bool GLWidget::isStarted()
      {
          return m_isStarted;
      }
      
      void GLWidget::onAboutToCompose()
      {
          //We are on the gui thread here. Composition is about to begin, wait until the render thread finishes.
          m_renderer->lockRenderer();
      }
      
      void GLWidget::onFrameSwapped()
      {
          m_renderer->unlockRenderer();
          //Assuming a blocking swap, our animation is driven purely by the vsync in this example.
          emit renderRequested();
      }
      
      void GLWidget::onAboutToResize()
      {
          m_renderer->lockRenderer();
      }
      
      void GLWidget::onResized()
      {
          m_renderer->unlockRenderer();
      }
      
      void GLWidget::grabContext()
      {
          m_renderer->lockRenderer();
          QMutexLocker lock(m_renderer->grabMutex());
          context()->moveToThread(m_thread);
          m_renderer->grabCond()->wakeAll();
          m_renderer->unlockRenderer();
      }
      
      Renderer::Renderer(GLWidget *w)
          : m_inited(false),
            m_glwidget(w),
            m_exiting(false),
            pauseRendering(false)
      {
          selfView = new FrameQueue("selfView");
          long lineCount = 4;
          int iRet = HAPIGetPropertyInt(catPhone, propPhoneCallsLimit, &lineCount);
          QString remoteName;
          for(int i=0; i<lineCount; i++){
              remoteViewList.append(new FrameQueue(remoteName.sprintf("remoteView%i",i)));
          }
      }
      
      Renderer::~Renderer()
      {
          if(selfView)
              delete selfView;
          for(int i=0; i<remoteViewList.size(); i++){
              FrameQueue *curQueue = remoteViewList.at(i);
              if(curQueue)
                  delete curQueue;
          }
      }
      
      void Renderer::start()
      {
          HAPIRegisterSelfView(selfView);
      }
      
      void Renderer::stop()
      {
          HAPIUnregisterSelfView(selfView);
      }
      
      void Renderer::pause()
      {
          pauseRendering = true;
          HAPIUnregisterSelfView(selfView);
      }
      
      void Renderer::resume()
      {
          pauseRendering = false;
          HAPIRegisterSelfView(selfView);
      }
      
      void Renderer::resumeToClose()
      {
          pauseRendering = false;
      }
      
      void Renderer::render()
      {
          if(m_exiting)
              return;
      
          QOpenGLContext *ctx = m_glwidget->context();
          if(!ctx)//QOpenGLWidget not yet initialized
              return;
      
          //Grab the context.
          m_grabMutex.lock();
          emit contextWanted();
          m_grabCond.wait(&m_grabMutex);
          QMutexLocker lock(&m_renderMutex);
          m_grabMutex.unlock();
      
          if(m_exiting)
              return;
      
          Q_ASSERT(ctx->thread() == QThread::currentThread());
      
          //Make the context (and an offscreen surface) current for this thread.
          //The QOpenGLWidget's fbo is bound in the context.
          m_glwidget->makeCurrent();
      
          if(!m_inited) {
              m_inited = true;
      //        initializeOpenGLFunctions();
          }
      
          glClearColor(0.27f, 0.26f, 0.26f, 1.0f);
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
          if(pauseRendering){
              return;
          } else {
              //TODO HERE
              //How do I get QPainter here?! The context is moved yet I'm getting errors!
      //            QPainter p(m_glwidget);
      
              qDebug() << "WTF";
          }
      
          //Make no context current on this thread and move the QOpenGLWidget's context back to the gui thread.
          m_glwidget->doneCurrent();
          ctx->moveToThread(qGuiApp->thread());
      
          //Schedule composition. Note that this will use QueuedConnection, meaning that update() will be invoked on the gui thread.
          QMetaObject::invokeMethod(m_glwidget, "update");
      }
      
      
      1 Reply Last reply
      0
      • W Offline
        W Offline
        wesblake
        wrote on last edited by
        #6

        Bump. I've done everything and can't figure this out. I'm about to try a non-threaded QOpenGLWidget because it's my only choice at this point but I'm afraid it will impact performance too much.

        R 1 Reply Last reply
        0
        • W wesblake

          Bump. I've done everything and can't figure this out. I'm about to try a non-threaded QOpenGLWidget because it's my only choice at this point but I'm afraid it will impact performance too much.

          R Offline
          R Offline
          rtavakko
          wrote on last edited by
          #7

          @wesblake The topics are not directly related so it would've probably helped to start a new one.

          What error are you getting?

          I'm coming more and more to the conclusion that a single thread is the way to go most of the time.

          W 1 Reply Last reply
          0
          • R rtavakko

            @wesblake The topics are not directly related so it would've probably helped to start a new one.

            What error are you getting?

            I'm coming more and more to the conclusion that a single thread is the way to go most of the time.

            W Offline
            W Offline
            wesblake
            wrote on last edited by
            #8

            @rtavakko said in QOpenGLWidget and Threads:

            @wesblake The topics are not directly related so it would've probably helped to start a new one.

            What error are you getting?

            I'm coming more and more to the conclusion that a single thread is the way to go most of the time.

            Sorry, seemed similar but I can move it. Here is the error:
            QGL-Thread-error.png

            1 Reply Last reply
            0
            • R Offline
              R Offline
              rtavakko
              wrote on last edited by
              #9

              @wesblake said in QOpenGLWidget and Threads:

              QPainter p(m_glwidget);

              Try replacing:

              QPainter p(m_glwidget);

              with:

              QPainter p(this);

              1 Reply Last reply
              0
              • W Offline
                W Offline
                wesblake
                wrote on last edited by
                #10

                Thanks. I found a known bug in QOpenGLWidget now preventing me from using it. :( So, starting over. New trial, a regular QWidget, worker thread to resize and composite frames first.

                R 1 Reply Last reply
                0
                • W wesblake

                  Thanks. I found a known bug in QOpenGLWidget now preventing me from using it. :( So, starting over. New trial, a regular QWidget, worker thread to resize and composite frames first.

                  R Offline
                  R Offline
                  rtavakko
                  wrote on last edited by
                  #11

                  @wesblake Hmm. Which bug is this?

                  1 Reply Last reply
                  0
                  • W Offline
                    W Offline
                    wesblake
                    wrote on last edited by
                    #12

                    https://bugreports.qt.io/browse/QTBUG-49657
                    Duplicated ticket says fixed but it's not. It occurs exactly as described.

                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #13

                      I'm pretty sure this is not your bug as long as you don't use qt5.6 and fullscreen mode. Please provide a compilable, minimal example to show your problem.

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved