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. [SOLVED] QOpenGLWidget 's surface not written by QOpenGLContext living in another thread

[SOLVED] QOpenGLWidget 's surface not written by QOpenGLContext living in another thread

Scheduled Pinned Locked Moved General and Desktop
multithreadsqopenglwidgetqsurface
3 Posts 2 Posters 4.4k Views
  • 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.
  • U Offline
    U Offline
    ucmar
    wrote on 15 Mar 2015, 16:27 last edited by ucmar
    #1

    Hi all!
    I am writing a multi-threaded QtGUI application making use of a QOpenGLWidget derived class. My GL widget is used to show resources (VBOs and shaders) allocated in additional QOpenGLContexts (representing distinct "views"), shared with the widget's context(). Each time the user chooses a specific view from a combo list, I want the widget to make the appropriate context current in its own worker thread and draw the widget's surface from there.
    I attach some relevant portions of my classes here, where for testing purposes I am using only one shared context and triggering widget updates for clearing the background with another color on mouse move.

    class glview : public QOpenGLWidget
    {
        Q_OBJECT
    public:
        explicit glview();
        ...
        void initializeGL();
        void paintEvent(QPaintEvent* e);
        void mouseMoveEvent(QMouseEvent *e);
        QOpenGLContext *m_context;
        QSurface *m_surf;
        bool m_isrendering;
    signals:
        void requestDraw();
    public slots:
        void provideUpdate();
    };
    
    glview::glview()
    {
        setMouseTracking(true);
        m_isrendering = false;
    }
    
    void glview::initializeGL()
    {
        m_context = context()->currentContext();
        m_surf = context()->currentContext()->surface();
        QOpenGLFunctions f;
        f.initializeOpenGLFunctions();
        f.glClearColor(0.0,0.0,1.0,1.0);
    }
    
    void glview::paintEvent(QPaintEvent *e)
    {
    }
    
    void glview::mouseMoveEvent(QMouseEvent *e)
    {
        if (!m_isrendering)
        {
            m_context->doneCurrent();
            m_isrendering = true;
            emit requestDraw();
        }
    }
    
    void glview::provideUpdate()
    {
        m_isrendering = false;
        context()->makeCurrent(m_surf);
        emit update();
    }
    
    class objview : public QObject
    {
        Q_OBJECT
    public:
        objview(QOpenGLContext* c, QSurface* s, QSurfaceFormat format);
        ...
        QOpenGLContext* m_glcontext;
        QSurface* m_surf;
    public slots:
        void provideDraw();
    private:
        QSurfaceFormat m_format;
    signals:
        void requestUpdate();
    };
    
    objview::objview(QOpenGLContext* c, QSurface* s, QSurfaceFormat format)
        : m_format(format)
        , m_surf(s)
    {
        m_glcontext = new QOpenGLContext(this);
        m_glcontext->setShareContext(c);
        m_glcontext->setFormat(m_format);
        if (m_glcontext->create())
            qDebug() << "shared glcontext correcty created";
    }
    
    void objview::provideDraw()
    {
        if (!m_glcontext->makeCurrent(m_surf))
            return;
        QOpenGLFunctions f;
        f.initializeOpenGLFunctions();
        f.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        f.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        m_glcontext->doneCurrent();
        emit requestUpdate();
    }
    

    To facilitate things, I create a glcontroller class endowing a QThread and a QOpenGLContext member variables. After creating the shared context in the main thread, I use the function moveToThread() to move the controller's context in the other thread event loop.

    class glcontroller : public QObject
    {
        Q_OBJECT
    public:
        glcontroller(QOpenGLContext* c, QSurface* s, QSurfaceFormat sf);
    ...    
        QThread m_thread;
        objview *m_ov;
    signals:
        void requestUpdate();
        void requestDraw();
    };
    
    glcontroller::glcontroller(QOpenGLContext* c, QSurface* s, QSurfaceFormat sf)
    {
        m_ov = new objview(c,s,sf);    
        m_ov->moveToThread(&m_thread);    
        emit m_thread.start();
        connect(this,&glcontroller::requestDraw,
                m_ov,&objview::provideDraw);
        connect(m_ov,&objview::requestUpdate,
                this,&glcontroller::requestUpdate);
    }
    

    I define, implement and connect what I believe is an appropriate set of Signals and Slots to sync the worker thread and the main thread. Anyway, it seems that my widget is always showing a plain fill based on the glClearColor() I used in initializedGL().

    Originally, I thought the problem was caused by the use of paintGL in my main thread calling makeCurrent() asynchronously while my worker thread was still rendering the frame buffer. Therefore, as suggested on the QOpenGLWidget's reference page, I reimplemented paintEvent(QPaintEvent*) to do nothing and now the debugger shows a correct processing sequence of my update and rendering slots.
    Anyway, the widget's framebuffer doesn't seem to be touched in anyway by my worker thread. Could it be that I have to bind a QOffscreeenSurface and the perform some kind of swapBuffer (although I read that the new QOpenGL* classes do not require nor allow framebuffer swapping)?

    I have been struggling for several days on this problem and I would be very happy if anyone could explain me why my code is not working! Thank you very much! :-)

    Mario

    U 1 Reply Last reply 16 Mar 2015, 01:13
    0
    • U ucmar
      15 Mar 2015, 16:27

      Hi all!
      I am writing a multi-threaded QtGUI application making use of a QOpenGLWidget derived class. My GL widget is used to show resources (VBOs and shaders) allocated in additional QOpenGLContexts (representing distinct "views"), shared with the widget's context(). Each time the user chooses a specific view from a combo list, I want the widget to make the appropriate context current in its own worker thread and draw the widget's surface from there.
      I attach some relevant portions of my classes here, where for testing purposes I am using only one shared context and triggering widget updates for clearing the background with another color on mouse move.

      class glview : public QOpenGLWidget
      {
          Q_OBJECT
      public:
          explicit glview();
          ...
          void initializeGL();
          void paintEvent(QPaintEvent* e);
          void mouseMoveEvent(QMouseEvent *e);
          QOpenGLContext *m_context;
          QSurface *m_surf;
          bool m_isrendering;
      signals:
          void requestDraw();
      public slots:
          void provideUpdate();
      };
      
      glview::glview()
      {
          setMouseTracking(true);
          m_isrendering = false;
      }
      
      void glview::initializeGL()
      {
          m_context = context()->currentContext();
          m_surf = context()->currentContext()->surface();
          QOpenGLFunctions f;
          f.initializeOpenGLFunctions();
          f.glClearColor(0.0,0.0,1.0,1.0);
      }
      
      void glview::paintEvent(QPaintEvent *e)
      {
      }
      
      void glview::mouseMoveEvent(QMouseEvent *e)
      {
          if (!m_isrendering)
          {
              m_context->doneCurrent();
              m_isrendering = true;
              emit requestDraw();
          }
      }
      
      void glview::provideUpdate()
      {
          m_isrendering = false;
          context()->makeCurrent(m_surf);
          emit update();
      }
      
      class objview : public QObject
      {
          Q_OBJECT
      public:
          objview(QOpenGLContext* c, QSurface* s, QSurfaceFormat format);
          ...
          QOpenGLContext* m_glcontext;
          QSurface* m_surf;
      public slots:
          void provideDraw();
      private:
          QSurfaceFormat m_format;
      signals:
          void requestUpdate();
      };
      
      objview::objview(QOpenGLContext* c, QSurface* s, QSurfaceFormat format)
          : m_format(format)
          , m_surf(s)
      {
          m_glcontext = new QOpenGLContext(this);
          m_glcontext->setShareContext(c);
          m_glcontext->setFormat(m_format);
          if (m_glcontext->create())
              qDebug() << "shared glcontext correcty created";
      }
      
      void objview::provideDraw()
      {
          if (!m_glcontext->makeCurrent(m_surf))
              return;
          QOpenGLFunctions f;
          f.initializeOpenGLFunctions();
          f.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
          f.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          m_glcontext->doneCurrent();
          emit requestUpdate();
      }
      

      To facilitate things, I create a glcontroller class endowing a QThread and a QOpenGLContext member variables. After creating the shared context in the main thread, I use the function moveToThread() to move the controller's context in the other thread event loop.

      class glcontroller : public QObject
      {
          Q_OBJECT
      public:
          glcontroller(QOpenGLContext* c, QSurface* s, QSurfaceFormat sf);
      ...    
          QThread m_thread;
          objview *m_ov;
      signals:
          void requestUpdate();
          void requestDraw();
      };
      
      glcontroller::glcontroller(QOpenGLContext* c, QSurface* s, QSurfaceFormat sf)
      {
          m_ov = new objview(c,s,sf);    
          m_ov->moveToThread(&m_thread);    
          emit m_thread.start();
          connect(this,&glcontroller::requestDraw,
                  m_ov,&objview::provideDraw);
          connect(m_ov,&objview::requestUpdate,
                  this,&glcontroller::requestUpdate);
      }
      

      I define, implement and connect what I believe is an appropriate set of Signals and Slots to sync the worker thread and the main thread. Anyway, it seems that my widget is always showing a plain fill based on the glClearColor() I used in initializedGL().

      Originally, I thought the problem was caused by the use of paintGL in my main thread calling makeCurrent() asynchronously while my worker thread was still rendering the frame buffer. Therefore, as suggested on the QOpenGLWidget's reference page, I reimplemented paintEvent(QPaintEvent*) to do nothing and now the debugger shows a correct processing sequence of my update and rendering slots.
      Anyway, the widget's framebuffer doesn't seem to be touched in anyway by my worker thread. Could it be that I have to bind a QOffscreeenSurface and the perform some kind of swapBuffer (although I read that the new QOpenGL* classes do not require nor allow framebuffer swapping)?

      I have been struggling for several days on this problem and I would be very happy if anyone could explain me why my code is not working! Thank you very much! :-)

      Mario

      U Offline
      U Offline
      ucmar
      wrote on 16 Mar 2015, 01:13 last edited by
      #2

      Ok after several readings and tests, I found a solution myself. I simply had to bind the widget's framebuffer's when repainting from the worker thread and call glFlush().

      I hope it helps others dealing with the same or similar issues.

      Mario

      1 Reply Last reply
      0
      • SightlineS Offline
        SightlineS Offline
        Sightline
        wrote on 12 Apr 2016, 14:03 last edited by
        #3

        I have followed your solution but still have the same problem. I am binding the defaultFrameBufferObject() accessed via the shared context in my rendering class but it's still not drawing on-screen. Could you please update the code to include your implementation of the binding operation?

        1 Reply Last reply
        0

        • Login

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