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



  • 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/


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Can you share your widget's code ?



  • 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");
    

    }



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


  • Lifetime Qt Champion

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



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


  • Lifetime Qt Champion

    What is windowPainter_ ?



  • It's the code that does our Rendering.


  • Lifetime Qt Champion

    Would it be possible to also see that ?



  • 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.



  • 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!!!!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.