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/
-
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!!!!
-
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.
-
By the way, what version of macOS are you running this on ?
-
10.14 (Mojave) but it also failed under High Sierra.
-
What is
windowPainter_
? -
It's the code that does our Rendering.
-
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!!!!