Using Scene3D and Surface3D in the same .qml object results in a warning on program exit



  • Hello everyone!

    I have Scene3D and Surface3D elements on my main.qml. When program exits I get warning: "Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.". Everything else is OK.

    The warning disappears when I comment out either Scene3D {...} or Surface3D {...}. I suppose the reason is the sequence of thread destruction (?) or something like that. Google says nothing about that, except the source code of Qt:

    qoffscreensurface.cpp:

    ...
    if (QThread::currentThread() != qGuiApp->thread())
                    qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.");
    
    ...
    

    I do not create any additional threads in my application, so I suppose the reason is that either QThread::currentThread() or qGuiApp->thread() is 0 at that moment (when program exits).

    How to avoid this warning?


  • Qt Champions 2016

    Please attach how you set up your code (the C++ part) and perhaps also a stripped down version of your QML file.



  • main.cpp

    #include <QtWidgets/QApplication>
    #include <QtQml/QQmlContext>
    #include <QtQuick/QQuickView>
    #include <QtQml/QQmlEngine>
    #include <QtCore/QDir>
    #include <QNetworkInterface>
    #include <QComboBox>
    #include <QObject>
    #include "datasource.h"
    #include "tssocket.h"
    #include "address_provider.h"
    #include "intercom.h"
    #include "ipslistmodel.h"
    #include "interfacehelper.h"
    #include "measurementmodel.h"
    
    #include <QtQml>
    
    #include "timeline3d.h"
    
    int main(int argc, char *argv[])
    {
        qDebug() << QThread::currentThreadId();
        // Qt Charts uses Qt Graphics View Framework for drawing, therefore QApplication must be used.
        QApplication app(argc, argv);
    
        qmlRegisterType<IPsListModel>("IPsListModel", 1, 0, "IPsListModel");
    
        qmlRegisterType<Timeline3D>("com.example.Timeline3D", 1, 0, "Timeline3D");
    
        QQuickView viewer;
    
        // The following are needed to make examples run without having to install the module
        // in desktop environments.
    #ifdef Q_OS_WIN
        QString extraImportPath(QStringLiteral("%1/../../../../%2"));
    #else
        QString extraImportPath(QStringLiteral("%1/../../../%2"));
    #endif
        viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
                                          QString::fromLatin1("qml")));
        QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close);
    
        viewer.setTitle(QStringLiteral("Scan Tube v0.0"));
    
        DataSource dataSource(&viewer);
        viewer.rootContext()->setContextProperty("dataSource", &dataSource);
    
        intercom *_intercom = new intercom(&viewer);
    
        _intercom->setDataSource(&dataSource);
    
        viewer.rootContext()->setContextProperty("_intercom", _intercom);
    
        InterfaceHelper *_interfaceHelper = new InterfaceHelper();
        viewer.rootContext()->setContextProperty("_interfaceHelper", _interfaceHelper);
    
        IPsListModel myIPsListModel;
    
        foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
            if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost) && !address.isLoopback()){
                qDebug() << address.toString();
                myIPsListModel.add(address.toString());
            }
        }
        viewer.rootContext()->setContextProperty("myIPsListModel", &myIPsListModel);
    
        MeasurementModel measurementModel;
        viewer.rootContext()->setContextProperty("measurementModel", &measurementModel);
        dataSource.setMeasurementModel(&measurementModel);
    
    
        viewer.setSource(QUrl("qrc:/qml/qmloscilloscope/main.qml"));
        viewer.setResizeMode(QQuickView::SizeRootObjectToView);
        viewer.setColor(QColor("#404040"));
        viewer.show();
    
         auto ret = app.exec();
        _intercom->off();
        return ret;
    }
    

    timeline3d.h

    #ifndef TIMELINE3D_H
    #define TIMELINE3D_H
    
    #include <QObject>
    #include <Qt3DCore>
    #include <Qt3DRender>
    #include <Qt3DExtras>
    
    #include "datasource.h"
    
    using namespace Qt3DCore;
    using namespace Qt3DRender;
    using namespace Qt3DExtras;
    
    class Timeline3D : public QEntity
    {
        Q_OBJECT
    public:
        Timeline3D(QNode *parent = 0);
        Q_INVOKABLE void addScan();
        Q_INVOKABLE void connectDataSource(DataSource *dataSource);
    private:
        DataSource *dataSource {nullptr};
    
        QCamera *m_camera;
    
        Qt3DCore::QTransform *lightTransform;
    
        int m_count;
        float x,y;
    
        void onTimerUpdate();
    
        //QPlaneMesh* m_planeMesh;
        QPhongAlphaMaterial *m_planeMaterial;
    
        Qt3DRender::QBuffer *vertexBuffer;
        QAttribute *positionAttribute;
    
        //todo temporary, remove
        QGeometryRenderer* m_geometryRenderer;
    
        void addPoint();
    };
    
    #endif // TIMELINE3D_H
    

    timeline3d.cpp

    #include <Qt3DInput>
    
    #include "timeline3d.h"
    
    #define ANGLE 13
    #define COUNT 8
    
    Timeline3D::Timeline3D(QNode *parent)
        : QEntity(parent)
        , m_camera(new QCamera())
        , m_count(0)
        , y(0.0f)
        , x(0.0f)
    {
        m_camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
    
        // FrameGraph
        QRenderSettings *renderSettings = new QRenderSettings();
        QRenderSurfaceSelector *renderSurfaceSelector = new QRenderSurfaceSelector();
        
        QViewport *viewport = new QViewport();
        viewport->setNormalizedRect(QRectF(0.0f, 0.0f, 1.0f, 1.0f));
        
        QLayerFilter *layerFilter = new QLayerFilter();
        layerFilter->setEnabled(false);
        QCameraSelector *cameraSelector = new QCameraSelector();
        cameraSelector->setCamera(m_camera);
        
        QClearBuffers *clearBuffer = new QClearBuffers();
        clearBuffer->setBuffers(QClearBuffers::ColorDepthStencilBuffer);
        clearBuffer->setClearColor("black");
        
        clearBuffer->setParent(cameraSelector);
        cameraSelector->setParent(layerFilter);
        layerFilter->setParent(renderSurfaceSelector);
        
        renderSurfaceSelector->setParent(viewport);
        
        renderSettings->setActiveFrameGraph(viewport);
        this->addComponent(renderSettings);
           
        m_camera->setPosition(QVector3D(0.0f,5.0f,0.0f) +
                              QVector3D(-25.0f,0.0f,0.0f));
        m_camera->setViewCenter(QVector3D(0.0f,0.0f,0.0f));
        m_camera->setUpVector(QVector3D(0.0f,1.0f,0.0f));
    
        //phong alpha 0.3 material
        m_planeMaterial = new QPhongAlphaMaterial();
        m_planeMaterial->setAmbient(QColor(100,100,100));
        m_planeMaterial->setDiffuse(QColor(255,255,255));
        m_planeMaterial->setAlpha(0.3f);
        
        QTimer *timer = new QTimer();
        QObject::connect(timer, &QTimer::timeout,this,&Timeline3D::onTimerUpdate);
    
        timer->start(100);
    
        Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(this);
        Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
        light->setColor("yellow");
        light->setIntensity(1000);
        lightEntity->addComponent(light);
        lightTransform = new Qt3DCore::QTransform(lightEntity);
        lightTransform->setTranslation(QVector3D(0, 0, 0));
        lightEntity->addComponent(lightTransform);
    
        //m_camera->setPosition(QVector3D(y,sinf(M_PI/12)*30.0f,x+50.0f));
        //m_camera->setViewCenter(QVector3D(y,0.0f,x));
    }
    
    void Timeline3D::addScan()
    {
        if (!dataSource)
            return;
    
        auto scan_data = dataSource->getScanData();
    
        if (!scan_data)
            return;
    }
    
    void Timeline3D::connectDataSource(DataSource *dataSource)
    {
        this->dataSource = dataSource;
    }
    
    void Timeline3D::addPoint() {
        float* reVertexArray;
    
        x -= 5.0f;
        y += qrand() % 2 - 1;
    
        if (!(m_count % 100)) {
            //every 100-th timer tick:
            m_geometryRenderer = new QGeometryRenderer();
            QGeometry* meshGeometry = new QGeometry(m_geometryRenderer);
    
            QByteArray vertexArray;
            vertexArray.resize(200*3*sizeof(float));
            reVertexArray = reinterpret_cast<float*>(vertexArray.data());
    
            //coordinates of left vertex
            reVertexArray[0] = y-5.0f;
            reVertexArray[1] = 0.0f;
            reVertexArray[2] = x;
    
            //coordinates of right vertex
            reVertexArray[3] = y+5.0f;
            reVertexArray[4] = 0.0f;
            reVertexArray[5] = x;
    
            vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer,meshGeometry);
            vertexBuffer->setUsage(Qt3DRender::QBuffer::DynamicDraw);
            vertexBuffer->setData(vertexArray);
    
            // Attributes
            positionAttribute = new QAttribute(meshGeometry);
            positionAttribute->setAttributeType(QAttribute::VertexAttribute);
            positionAttribute->setBuffer(vertexBuffer);
            positionAttribute->setDataType(QAttribute::Float);
            positionAttribute->setDataSize(3);
            positionAttribute->setByteOffset(0);
            positionAttribute->setByteStride(3*sizeof(float));
            positionAttribute->setCount(2);
            positionAttribute->setName(QAttribute::defaultPositionAttributeName());
    
            meshGeometry->addAttribute(positionAttribute);
    
            m_geometryRenderer->setInstanceCount(1);
            m_geometryRenderer->setFirstVertex(0);
            m_geometryRenderer->setFirstInstance(0);
            m_geometryRenderer->setPrimitiveType(QGeometryRenderer::TriangleStrip);
            m_geometryRenderer->setGeometry(meshGeometry);
    
            QEntity* entity = new QEntity(this);
            entity->addComponent(m_geometryRenderer);
            entity->addComponent(m_planeMaterial);
    
    
    
            return;
        }
    
    
        //update geometry
        QByteArray appendVertexArray;
        appendVertexArray.resize(2*3*sizeof(float));
        reVertexArray = reinterpret_cast<float*>(appendVertexArray.data());
    
        //coordinates of left vertex
        reVertexArray[0] = y-5.0f;
        reVertexArray[1] = 0.0f;
        reVertexArray[2] = x;
    
        //coordinates of right vertex
        reVertexArray[3] = y+5.0f;
        reVertexArray[4] = 1.0f;
        reVertexArray[5] = x;
    
        uint vertexCount = positionAttribute->count();
        vertexBuffer->updateData(vertexCount*3*sizeof(float),appendVertexArray);
        positionAttribute->setCount(vertexCount+2);
    }
    
    void Timeline3D::onTimerUpdate()
    {   
        addPoint();
    
        m_camera->setPosition(QVector3D(y,sinf(M_PI/12)*30.0f,x+50.0f));
        m_camera->setViewCenter(QVector3D(y,0.0f,x));
    
        qDebug() << "x=" << x << "; y=" << y;
    
        lightTransform->setTranslation(QVector3D(y, 10.0f, x));
    
        m_count++;
    }
    
    
    

    main.qml

    ...
    StackLayout {
                        width: parent.width
                        height: parent.height - tabBar.height
                        currentIndex: tabBar.currentIndex
                        Item {...}
                        Item {...}
                        Item {
                            id: timeline_3d
                            anchors.fill: parent
                            Scene3D {
                                anchors.fill: parent
                                focus: true
                                Timeline3D {
                                    id: timeline_3d_object
                                }
                        }
                        Item {
                            id: timeline_3d_surface
                            anchors.fill: parent
    
                            Surface3D {
                                id: timeline_3d_surface_object
                                anchors.fill: parent
                                axisX.min: 0.0
                                axisX.max: 100.0
                                axisX.title: "Scan"
                                axisX.titleVisible: true
    
                                axisZ.min: 0.0
                                axisZ.max: 727.0
                                axisZ.title: "Distance"
                                axisZ.titleVisible: true
    
                                axisY.min: -1024
                                axisY.max: 1024
                                axisY.title: "Signal level"
                                axisY.titleVisible: true
    
                                horizontalAspectRatio: 2
                            }
                      }
    }
    ...
    

  • Qt Champions 2016

    I couldn't see anything obvious, but you really should've included only the essential c++ code ...
    Anyway, my best advice is to cut away everything that's not directly related to the problem, which would include all your custom classes, models and so on and see if it continues to manifest itself. Also take a look at the comments of this ticket, which may be related. It might also be helpful to get the stack trace (at the moment the warning's emitted) and see where all this started.


  • Moderators

    Hi! Does this also happen when you put the items in a RowLayout, so that they are both visible?



  • @Wieland yes, it doesn't matter if one of them is invisible or not



  • How to get the stack trace at the moment the warning' emitted? The code with the warning is in qt's source files, I use dll's, I cannot just put breakpoint there.


Log in to reply
 

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