Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Qt Academy Launch in California!

    Solved QOpenGlWidget's ::paintEngine being called from QCoreApplication::processEvents

    Game Development
    qopenglwidget paintengine
    2
    11
    1874
    Loading More Posts
    • 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.
    • M
      Michael Wilson last edited by

      I'm converting an OSX application from Qt 4/Carbon to Qt5.11 with the QOpenGLWidget.

      I've moved the drawing "calls" to my overridden QOpenGlWidget::paintGL().

      The problem is I'm still getting these messages on the console:

      QWidget::paintEngine: Should no longer be called

      Getting a stack trace, I've discovered that this is being called eventually from QCoreApplication::processEvents, which I'm calling from my own internal event loop.

      Here's a stack trace (edited for readability)

      thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
      frame #0: libQt5Widgets_debug.5.dylibQWidget::paintEngine()
      frame #1: libQt5Widgets_debug.5.dylibQOpenGLWidget::paintEngine(0) frame #2: libQt5Gui_debug.5.dylibQPainter::begin()
      frame #3: libQt5Gui_debug.5.dylibQPainter::QPainter() frame #4: libQt5Gui_debug.5.dylibQPainter::QPainter()
      frame #5: libQt5Widgets_debug.5.dylibQWidgetPrivate::drawWidget() frame #6: libQt5Widgets_debug.5.dylibQWidgetPrivate::repaint_sys()
      frame #7: libQt5Widgets_debug.5.dylibQWidgetPrivate::syncBackingStore() frame #8: libQt5Widgets_debug.5.dylibQWidgetWindow::handleExposeEvent()
      frame #9: libQt5Widgets_debug.5.dylibQWidgetWindow::event() frame #10: libQt5Widgets_debug.5.dylibQApplicationPrivate::notify_helper()
      frame #11: libQt5Widgets_debug.5.dylibQApplication::notify() frame #12: libQt5Core_debug.5.dylibQCoreApplication::notifyInternal2()
      frame #13: libQt5Gui_debug.5.dylibQCoreApplication::sendSpontaneousEvent() frame #14: libQt5Gui_debug.5.dylibQGuiApplicationPrivate::processExposeEvent()
      frame #15: libQt5Gui_debug.5.dylibQGuiApplicationPrivate::processWindowSystemEvent() frame #16: libQt5Gui_debug.5.dylibbool QWindowSystemInterfacePrivate::handleWindowSystemEventQWindowSystemInterface::SynchronousDelivery()
      frame #17: libQt5Gui_debug.5.dylibvoid QWindowSystemInterface::handleExposeEvent() frame #18: libqcocoa_debug.dylibQCocoaWindow::handleExposeEvent()
      frame #19: libqcocoa_debug.dylib::-[QNSView updateRegion:](self=0x000061200039fc40, _cmd="updateRegion:", dirtyRegion=QRegion @ 0x00007ffeefbf9b18) frame #20: libqcocoa_debug.dylib::-[QNSView updateLayer](self=0x000061200039fc40, _cmd="updateLayer")
      frame #21: AppKit_NSViewUpdateLayer + 45 frame #22: AppKit-[_NSViewBackingLayer display] + 495
      frame #23: QuartzCoreCA::Layer::display_if_needed(CA::Transaction*) + 634 frame #24: QuartzCoreCA::Context::commit_transaction(CA::Transaction*) + 319
      frame #25: QuartzCoreCA::Transaction::commit() + 576 frame #26: QuartzCoreCA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 66
      frame #27: CoreFoundationCFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23 frame #28: CoreFoundation__CFRunLoopDoObservers + 452
      frame #29: CoreFoundationCFRunLoopRunSpecific + 523 frame #30: HIToolboxRunCurrentEventLoopInMode + 293
      frame #31: HIToolboxReceiveNextEventCommon + 618 frame #32: HIToolbox_BlockUntilNextEventMatchingListInModeWithFilter + 64
      frame #33: AppKit_DPSNextEvent + 997 frame #34: AppKit-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1362
      frame #35: libqcocoa_debug.dylibQCocoaEventDispatcher::processEvents(this=0x00006040000dbdf0, flags=(i = 0)) at qcocoaeventdispatcher.mm:482 frame #36: libQt5Core_debug.5.dylib`QCoreApplication::processEvents(flags=(i = 0)) at qcoreapplication.cpp:1252
      The problem is that ::processEvents is eventually calling ::paintEngine for the QOpenGLWidget, OUTSIDE of ::paintGL, but it's totally out of my control.

      FWIW, the Event driving this is a QEvent::UpdateRequest.

      I tried overriding ::event in my QOpenGLWidget-inheriting class to call QOpenGlWidget::update when it receives a QEvent::UpdateRequest, but that just ended up making the app non-responsive.

      How should I handle ::processEvents attempting to draw QOpenGlWidgets?

      Thanks!

      P.S. Here's a link to the same question on Stack Overflow: https://stackoverflow.com/questions/51561062/

      1 Reply Last reply Reply Quote 0
      • M
        Michael Wilson last edited by

        Using the minimal example above, I fixed this by removing this call in our QOpenGlWidget subclass's constructor:

        setAttribute( Qt::WA_PaintOnScreen, true );

        Removing this got rid of the paintengine calls (and numerous other problems).

        Thanks!!!!

        1 Reply Last reply Reply Quote 1
        • SGaist
          SGaist Lifetime Qt Champion last edited by

          Hi and welcome to devnet,

          Can you share your widget's code ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply Reply Quote 0
          • M
            Michael Wilson last edited by

            Sure...here are the relevant QOpenGlWidget methods. I purposely have over-simplified them for now.

            Unfortunately, none of these methods are involved in code path being called. :-(.

            void
            UiEventSourceWidget::initializeGL()
            {
            // Set up the rendering context, load shaders and other resources, etc.:
            initializeOpenGLFunctions();
            bool result;
            uint error;

            error = glGetError();
            Log4(L"UiEventSourceWidget::initializeGL:%d glGetError %d", LINE, error);
            Assert(error == GL_NO_ERROR);

            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

            error = glGetError();
            Log4(L"UiEventSourceWidget::initializeGL:%d glGetError %d", LINE, error);
            Assert(error == GL_NO_ERROR);

            Log4(L"UiEventSourceWidget::initializeGL:%d context 0x%x, defaultFramebufferObject 0x%x",
            LINE, context(), defaultFramebufferObject());
            }

            void
            UiEventSourceWidget::resizeGL(int w, int h)
            {
            Log4(L"UiEventSourceWidget::resizeGL");
            update();
            }

            void
            UiEventSourceWidget::paintGL()
            {
            Log4(L"UiEventSourceWidget::paintGL QOpenGLContext::currentContext() 0x%x, "
            "defaultFramebufferObject() %d, isValid %s, glGetError() %d",
            QOpenGLContext::currentContext(),
            defaultFramebufferObject(),
            isValid() ? L"True" : L"False",
            glGetError());

            uint error;
            error = glGetError();
            Assert(error == GL_NO_ERROR);
            
            glClear(GL_COLOR_BUFFER_BIT);
            error = glGetError();
            Assert(error == GL_NO_ERROR);
            
            glClear(GL_COLOR_BUFFER_BIT);
            error = glGetError();
            Log4(L"UiEventSourceWidget::paintGL:%d glGetError %d", __LINE__, error);
            Assert(error == GL_NO_ERROR);
            
            windowPainter_->updateEntireWindow();
            
            error = glGetError();
            Log4(L"UiEventSourceWidget::paintGL:%d glGetError %d", __LINE__, error);
            Assert(error == GL_NO_ERROR);
            
            Log4(L"UiEventSourceWidget::paintGL ...exit");
            

            }

            1 Reply Last reply Reply Quote 0
            • M
              Michael Wilson last edited by

              FWIW, in QOpenGLWidget::paintEngine(), d->inBackingStorePaint is True.

              1 Reply Last reply Reply Quote 0
              • SGaist
                SGaist Lifetime Qt Champion last edited by

                By the way, what version of macOS are you running this on ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply Reply Quote 0
                • M
                  Michael Wilson last edited by

                  10.14 (Mojave) but it also failed under High Sierra.

                  1 Reply Last reply Reply Quote 0
                  • SGaist
                    SGaist Lifetime Qt Champion last edited by

                    What is windowPainter_ ?

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply Reply Quote 0
                    • M
                      Michael Wilson last edited by

                      It's the code that does our Rendering.

                      1 Reply Last reply Reply Quote 0
                      • SGaist
                        SGaist Lifetime Qt Champion last edited by

                        Would it be possible to also see that ?

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply Reply Quote 0
                        • M
                          Michael Wilson last edited by

                          Well, considering that it's rendering an entire Virtual World (There.com) I'm pretty sure it wouldn't fit in one post :-).

                          But, I can replace it with this and get the same problem.

                          glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
                          
                          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
                          
                          AssertNoGlError();
                          
                          GLint drawFboId = 0, readFboId = 0, drawBoId = 0;
                          glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFboId);
                          glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFboId);
                          glGetIntegerv(GL_DRAW_BUFFER, &drawBoId);
                          
                          Log4(L"PoWglPlatform::openPlatform:%d, drawFboId %d, readFboId %d, drawBoId %d",
                               __LINE__, drawFboId, readFboId, drawBoId);
                          
                          AssertNoGlError();
                          
                          glColor3d(0.0,1.0,0.0);
                          // Draw something static to the back buffer.
                          glBegin(GL_QUADS);
                                  glVertex2d(0.0,0.0);glVertex2d(0.10,0.0);glVertex2d(0.10,0.10);glVertex2d(0.0,0.10);
                          glEnd();
                          glFlush();
                          
                          // If this line is uncommented, it proves that
                          // glDrawBuffer(GL_FRONT) is not working!!!!!!!!!!!!
                          //glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
                          
                          //glDrawBuffer(GL_FRONT);
                          
                          float angle=0;
                          for( angle=0;angle<360.0;angle+=2.0)
                          {
                              // This should restore our static drawing.
                              glFlush();
                          
                              float x=sin(angle*M_PI/180.0);
                              float y=cos(angle*M_PI/180.0);
                              glColor3d(1.0,1.0,1.0);
                              glBegin(GL_LINES);
                                  glVertex2d(0.0,0.0);
                                  glVertex2d(x,y);
                              glEnd();
                          
                              glFinish();
                          }
                          
                          AssertNoGlError();
                          

                          Also, here's ::initializeGL

                          // Set up the rendering context, load shaders and other resources, etc.:
                          initializeOpenGLFunctions();

                          AssertNoGlError();

                          glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

                          FWIW, the screen stays blue ( glClearColor(0.0f, 0.0f, 1.0f, 1.0f); ), and never turns red or draws anything we see in ::paintGL.

                          1 Reply Last reply Reply Quote 0
                          • M
                            Michael Wilson last edited by

                            Using the minimal example above, I fixed this by removing this call in our QOpenGlWidget subclass's constructor:

                            setAttribute( Qt::WA_PaintOnScreen, true );

                            Removing this got rid of the paintengine calls (and numerous other problems).

                            Thanks!!!!

                            1 Reply Last reply Reply Quote 1
                            • First post
                              Last post