QOpenGLFramebufferObject renders only first frame



  • HI!

    I am trying to use OpenGL with QtQuick, with use of QQuickFramebufferObject. Generally, everything seems to be working, but only on the first frame. Every other redraw (resizing window or calling 'update()') gives empty widget filled with color set by glClearColor(...). I was trying to manipulate with OpenGL's state, disabling everything that could potentially make scene invisible, but nothing solved the problem. I can't find similar problem in web so i'm asking for help here.

    I'm guessing the problem can be with context state after Qt done some stuff on other widgets but i have no idea what could go wrong with this code :/

    Or maybe I am trying something very weird here? I don't know. I have seen couple of ways to use OpenGL with Qt but do not exacly know which way is the preffered one.

    I will be grateful for any kind of help.

    first frame
    c0190420-540d-455b-aabf-a4322c2f49ea-image.png

    redrawed window after resize (update() gives same effect)
    23c015b2-d9da-45d3-a6a2-7035685be17b-image.png

    qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    
    import OpenGLItem 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        OpenGLItem {
            anchors.fill: parent
        }
    }
    

    createRenderer()

    QQuickFramebufferObject::Renderer *OpenGLItem::createRenderer() const
    {
        return new OpenGLRenderer();
    }
    

    Renderer

    #include "openglitem.h"
    
    #include <QOpenGLFramebufferObjectFormat>
    #include <QOpenGLFunctions>
    #include <QQuickWindow>
    
    class OpenGLRenderer : public QQuickFramebufferObject::Renderer
    {
    private:
        GLuint m_VBO;
        GLuint m_ShaderProgram;
        QQuickWindow *m_Window = nullptr;
    
    public:
        OpenGLRenderer()
        {
            QOpenGLFunctions *ogl = QOpenGLContext::currentContext()->functions();
    
            float verts[] = {
                -1.0f, -1.0f, 0.0f,
                1.0f, -1.0f, 0.0f,
                0.0f, 1.0f, 0.0f
            };
    
            const char *vertexShaderSource =
                    "#version 330 core\n"
                    "layout(location=0) in vec3 a_Position;\n"
                    "void main() {\n"
                    " gl_Position = vec4(a_Position, 1.0);\n"
                    "}\n\0";
    
            const char *fragmentShaderSource =
                    "#version 330 core\n"
                    "out vec4 FragColor;\n"
                    "void main() {\n"
                    " FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
                    "}\n\0";
    
            char infoLog[1024];
    
            ogl->glGenBuffers(1, &m_VBO);
            ogl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
            ogl->glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
            ogl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
            ogl->glEnableVertexAttribArray(0);
            ogl->glBindBuffer(GL_ARRAY_BUFFER, 0);
    
            m_ShaderProgram = ogl->glCreateProgram();
    
            GLuint vertexShader = ogl->glCreateShader(GL_VERTEX_SHADER);
            ogl->glShaderSource(vertexShader, 1, &vertexShaderSource, 0);
            ogl->glCompileShader(vertexShader);
            ogl->glAttachShader(m_ShaderProgram, vertexShader);
            ogl->glGetShaderInfoLog(vertexShader, 1024, 0, infoLog);
            qDebug() << infoLog;
            ogl->glDeleteShader(vertexShader);
    
            GLuint fragmentShader = ogl->glCreateShader(GL_FRAGMENT_SHADER);
            ogl->glShaderSource(fragmentShader, 1, &fragmentShaderSource, 0);
            ogl->glCompileShader(fragmentShader);
            ogl->glAttachShader(m_ShaderProgram, fragmentShader);
            ogl->glGetShaderInfoLog(fragmentShader, 1024, 0, infoLog);
            qDebug() << infoLog;
            ogl->glDeleteShader(fragmentShader);
    
            ogl->glLinkProgram(m_ShaderProgram);
            ogl->glGetProgramInfoLog(m_ShaderProgram, 1024, 0, infoLog);
            qDebug() << infoLog;
    
            ogl->glUseProgram(m_ShaderProgram);
        }
    
        virtual void render() override
        {
            static bool firstTime = true;
    
            QOpenGLFunctions *ogl = QOpenGLContext::currentContext()->functions();
    
            ogl->glDisable(GL_DEPTH_TEST);
            ogl->glDisable(GL_CULL_FACE);
            ogl->glDisable(GL_SCISSOR_TEST);
            ogl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
            ogl->glDisable(GL_BLEND);
            ogl->glDisable(GL_TEXTURE_2D);
    
            if(firstTime) {
                firstTime = false;
                ogl->glClearColor(1.0f, 1.0f,0.0f,1.0f);
            }
            else
                ogl->glClearColor(1.0f, 0.0f,1.0f,1.0f);
            ogl->glClear(GL_COLOR_BUFFER_BIT);
    
            ogl->glUseProgram(m_ShaderProgram);
            ogl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
            ogl->glDrawArrays(GL_TRIANGLES, 0, 3);
            ogl->glBindBuffer(GL_ARRAY_BUFFER, 0);
    
            ogl->glFlush();
            ogl->glFinish();
    
            ogl->glUseProgram(0);
    
            update();
            if(m_Window)
                m_Window->resetOpenGLState();
    
        }
    
        virtual QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override
        {
            QOpenGLFramebufferObjectFormat format;
            format.setAttachment(QOpenGLFramebufferObject::Attachment::Depth);
            format.setSamples(1);
            return new QOpenGLFramebufferObject(size, format);
        }
    
        virtual void synchronize(QQuickFramebufferObject *item) override
        {
            m_Window = item->window();
        }
    };
    

    main

    #include "openglitem.h"
    
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<OpenGLItem>("OpenGLItem", 1, 0, "OpenGLItem");
    
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    


  • 'Client vertex and index arrays - all vertex array attribute and element array
    index pointers must refer to buffer objects. The default vertex array object
    (the name zero) is also deprecated
    . Calling VertexAttribPointer when no
    buffer object or no vertex array object is bound will generate an INVALID_-
    OPERATION error, as will calling any array drawing command when no vertex array object is bound.'

    source: https://www.khronos.org/registry/OpenGL/specs/gl/glspec33.core.pdf
    page 344