Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Incorrect rendering using QSGRenderNode and QQuickItem



  • I am trying to use QSGRenderNode in order to render custom OpenGL commands using a QQuickItem. To do so I have subclassed QQuickItem and implemented its updatePaintNode virtual function. However, my code produces very strange behaviour: when the qml window is first shown everything is rendered somewhat correctly (although still wrongly) but when I resize the window my QQuickItem renders incorrectly (it shifts position unexpectdly) and other qml items like Rectangle also shift and scale unpredicatbly. The code below (which draws a line from (0,0) to (400,400) ) demonstrates my problem:

    RenderItem.h:

    #pragma once
    
    #include <QQuickItem>
    #include <QQuickWindow>
    #include <QSGRenderNode>
    #include <QOpenGLPaintDevice>
    #include <QPainter>
    #include <QOpenGLFunctions>
    
    class RenderNode : public QSGRenderNode, QOpenGLFunctions{
    public:
        RenderNode() {
            initializeOpenGLFunctions();
        }
        StateFlags changedStates() const override{
            return BlendState;
        }
        void render(const RenderState *state) override{
            Q_UNUSED(state);
            QOpenGLPaintDevice device(width, height);
            QPainter painter;
            painter.begin(&device);
            painter.drawLine(QLineF(0,0,400,400));
    
            if(window) window->resetOpenGLState();
        };
        int width = 0;
        int height = 0;
        QQuickWindow* window;
    };
    
    class RenderItem : public QQuickItem
    {
        Q_OBJECT
    public:
        RenderItem() {
            setFlag(ItemHasContents, true);
        }
    protected:
        void itemChange(ItemChange change, const ItemChangeData &changeData) override{
            update();
            QQuickItem::itemChange(change, changeData);
        }
        QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *nodeData) override{
            Q_UNUSED(nodeData);
            auto renderNode = static_cast<RenderNode*>(node);
            if(!renderNode){
                renderNode = new RenderNode;
            }
            renderNode->width = width();
            renderNode->height = height();
            renderNode->window = window();
            renderNode->markDirty(QSGNode::DirtyMaterial);
            return renderNode;
        }
    };
    

    My qml file:

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import RenderItem 1.0
    
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    
        RenderItem{
            id: renderItem
            width: 500; height: 500
        }
        Rectangle{
            id: renderRect
            color: "red"
            opacity: 0.2
            width: 500; height: 500
        }
        MouseArea{
            anchors.fill: parent
            onClicked: renderItem.update()
        }
    }
    

    This is a screenshot of the window as it first appears QML Window and this is a screenshot of the window after it has been resized enter image description here.

    What is the root of this issue? I suspect it has something to do with OpenGL, but I cannot figure out what it is.



  • I have just noticed that adding ViewportState to changedStates():

        return BlendState | ViewportState;
    

    fixes the issue of the rectangle being incorrectly scaled, but the line is still draw with an incorrect offset.


Log in to reply