Drawing in QQuickFramebufferObject via texture taken from an Item. It fails unless I repaint/update constantly



  • What my code does, in short:

    • Create a simple Rectangle named rect, with layer.enabled: true.
    • Pass rect to an instance of my QQuickFramebufferObject subclass called itemSnapshotter
    • In synchronize, take a copy of the texture provided by rect
    • In render, draw a rectangle textured with the texture I took
    • When main.qml finishes loading, call itemSnapshotter.update(); for the first and only time.

    The problem is that the QQFBO draws nothing, unless I uncomment the update call at the end of render(). Any idea why?

    My code:

    main.cpp:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include <QQuickFramebufferObject>
    #include <QOpenGLFramebufferObject>
    #include <QSGTextureProvider>
    #include <QObject>
    #include <QOpenGLFunctions>
    #include <QOpenGLShaderProgram>
    #include <QOpenGLBuffer>
    #include <QQuickWindow>
    #include <QOpenGLFunctions>
    // propertyhelper.h is from http://syncor.blogspot.bg/2014/11/qt-auto-property.html
    #include "propertyhelper.h"
    
    class ItemSnapshotter : public QQuickFramebufferObject {
        Q_OBJECT
    
        AUTO_PROPERTY(QQuickItem*, sourceItem)
    
    public:
        Renderer *createRenderer() const;
    };
    
    class ItemSnapshotterRenderer
        : public QObject
        , public QQuickFramebufferObject::Renderer
        , protected QOpenGLFunctions
    {
        Q_OBJECT
    
    public:
        ItemSnapshotterRenderer() {
            initializeOpenGLFunctions();
            initShader();
            createGeometry();
        }
    
        void createGeometry() {
            m_vertices << QVector2D(0, 0) << QVector2D(0, 1) << QVector2D(1, 1);
            m_vertices << QVector2D(0, 0) << QVector2D(1, 0) << QVector2D(1, 1);
        }
    
        void initShader() {
            m_shaderProgram.addShaderFromSourceFile(
                QOpenGLShader::Vertex, ":/PassThrough.vert.glsl");
            m_shaderProgram.addShaderFromSourceFile(
                QOpenGLShader::Fragment, ":/PassThrough.frag.glsl");
            m_shaderProgram.link();
            m_shaderProgram.bind();
    
            glActiveTexture(GL_TEXTURE0);
            m_shaderProgram.setUniformValue("uTex", 0);
        }
    
        void prepareShader() {
            m_shaderProgram.enableAttributeArray("aPos");
            m_shaderProgram.setAttributeArray("aPos", m_vertices.constData());
            m_shaderProgram.bind();
        }
    
        void render() {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
            prepareShader();
            m_tex->bind();
            glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    
            glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
    
            m_window->resetOpenGLState();
            //update();
        }
    
        void synchronize(QQuickFramebufferObject* qqfbo){
            auto parentItem = (ItemSnapshotter*)qqfbo;
    
            m_window = parentItem->window();
            copyTexture(*parentItem);
        }
    
        void copyTexture(const ItemSnapshotter &srcItem) {
            QQuickItem* sourceItem = srcItem.sourceItem();
            QSGTextureProvider* sourceTexProvider = sourceItem->textureProvider();
            m_tex = sourceTexProvider->texture();
            GLenum err;
            while ((err = glGetError()) != GL_NO_ERROR) {
                qDebug("\tgl error: 0x%x", err, 0, 16);
            }
        }
    
        QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) {
            QOpenGLFramebufferObjectFormat format;
            format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); // TODO simpler format
            return new QOpenGLFramebufferObject(size, format);
        }
    
    private:
        QOpenGLShaderProgram m_shaderProgram;
        QQuickWindow* m_window;
        QSGTexture* m_tex;
        QVector<QVector2D> m_vertices;
    };
    
    QQuickFramebufferObject::Renderer *ItemSnapshotter::createRenderer() const {
        return new ItemSnapshotterRenderer();
    }
    
    int main(int argc, char *argv[]) {
        qmlRegisterType<ItemSnapshotter>("ItemSnapshotter", 1, 0, "ItemSnapshotter");
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        return app.exec();
    }
    
    #include "main.moc"
    

    main.qml:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    import ItemSnapshotter 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
    
        Row {
            Rectangle {
                layer.enabled: true
                id: rect
                width: 100
                height: 100
                color: "red"
                border.color: "black"
            }
    
            ItemSnapshotter {
                id: itemSnapshotter
                sourceItem: rect
                width: sourceItem.width
                height: sourceItem.height
            }
        }
    
        Component.onCompleted: {
            itemSnapshotter.update();
        }
    }
    

    PassThrough.frag.glsl:

    varying highp vec2 vTexCoord;
    uniform sampler2D uTex;
    
    void main() {
        gl_FragColor = texture2D(uTex, vTexCoord);
    }
    

    PassThrough.vert.glsl:

    attribute highp vec2 aPos;
    varying highp vec2 vTexCoord;
    
    void main() {
        gl_Position = vec4(aPos, 0.0, 1.0);
        vTexCoord = aPos;
    }

Log in to reply
 

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