Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct
QWindow on a non-GUI thread
-
Hi guys,
I have a project where there is a subclass of QWindow rendering content on a thread. It runs well other than the assert error I get when rendering.:
Program: ..._0_MSVC2017_64bit-Debug\source\GLRenderer\debug\Qt5Cored.dll Module: 5.12.0 File: kernel\qcoreapplication.cpp Line: 578 ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x28a6e997e10. Receiver '' (of type 'OpenGLRenderWindow') was created in thread 0x0x28a7bc0d190", file kernel\qcoreapplication.cpp, line 578
Header file:
#ifndef OPENGLRENDERWINDOW_H #define OPENGLRENDERWINDOW_H #include <QWindow> #include <QOpenGLContext> class OpenGLRenderWindow : public QWindow { public: OpenGLRenderWindow(QScreen* outputScreen, const QSurfaceFormat& surfaceFormat, QOpenGLContext* sharedContext); virtual ~OpenGLRenderWindow(); bool event(QEvent *event) override; void exposeEvent(QExposeEvent* event) override; void resizeEvent(QResizeEvent *event) override; const QSurfaceFormat& getOpenGLFormat(); QOpenGLContext* getOpenGLContext(); protected: void swapSurfaceBuffers(); bool makeContextCurrent(); void doneContextCurrent(); QSurfaceFormat openGLFormat; QOpenGLContext* openGLContext; public slots: void renderFrame(); }; #endif // OPENGLRENDERWINDOW_H
CPP:
#include "openglrenderwindow.h" OpenGLRenderWindow::OpenGLRenderWindow( QScreen *outputScreen, const QSurfaceFormat &surfaceFormat, QOpenGLContext *sharedContext) : QWindow(outputScreen), openGLFormat(surfaceFormat), openGLContext(nullptr) { //Create surface setSurfaceType(QWindow::OpenGLSurface); setFormat(openGLFormat); //Allocate memory for the context object and prepare to create it openGLContext = new QOpenGLContext(this); openGLContext->setFormat(openGLFormat); if(sharedContext) openGLContext->setShareContext(sharedContext); //Make sure the context is created & is sharing resources with the shared context bool contextCreated = openGLContext->create(); assert(contextCreated); if(sharedContext) { bool sharing = QOpenGLContext::areSharing(openGLContext,sharedContext); assert(sharing); } } OpenGLRenderWindow::~OpenGLRenderWindow() { } bool OpenGLRenderWindow::event(QEvent *event) { switch (event->type()) { case QEvent::UpdateRequest: renderFrame(); return true; default: return QWindow::event(event); } } void OpenGLRenderWindow::exposeEvent(QExposeEvent *event) { if(isExposed()) renderFrame(); } void OpenGLRenderWindow::resizeEvent(QResizeEvent *event) { if(!makeContextCurrent()) return; unsigned int w = event->size().width(); unsigned int h = event->size().height(); QWindow::resize(QSize(w,h)); swapSurfaceBuffers(); doneContextCurrent(); } const QSurfaceFormat &OpenGLRenderWindow::getOpenGLFormat() { return openGLFormat; } QOpenGLContext *OpenGLRenderWindow::getOpenGLContext() { return openGLContext; } void OpenGLRenderWindow::swapSurfaceBuffers() { openGLContext->swapBuffers(this); } bool OpenGLRenderWindow::makeContextCurrent() { //Initialize OpenGL context & other resources return openGLContext->makeCurrent(this); } void OpenGLRenderWindow::doneContextCurrent() { openGLContext->doneCurrent(); } void OpenGLRenderWindow::renderFrame() { if(!isExposed()) return; if(!makeContextCurrent()) return; //Rendering code here swapSurfaceBuffers(); doneContextCurrent(); }
displayWindow = new OpenGLRenderWindow(mainOutputScreen,surfaceFormat,nullptr); displayWindow->show(); displayWindow->moveToThread(thread);
I have this exact same setup for an offscreen renderer subclassing QOffscreenSurface which works without issues (difference being the I call create() in the constructor of that class).
It seems like there is no way around getting resize and expose events for a QWindow, but I don't quite know how to fix this.
Is there something wrong with the order I create and move the resources?
Is there a way to disable events to this window? It renders pretty well despite of the pop-up error.
-
Hi,
IIRC, you can move your QOpenGLContext to a different thread but not the QWindow.
-
@SGaist Thanks for replying.
Are you aware of any alternatives to QWindow where using a thread is possible?
I do most of my rendering on a QOffscreenSurface subclass and the QWindow is only displaying the result. But since it sits on the GUI thread, any events there cause it to drop frames and stall.
-
Maybe the QQuickRenderControl example might help.
-
@SGaist Thanks! I will play around with that example