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

QOpenGLFramebufferObject not working when it is larger than viewport?



  • I'm using QOpenGLFramebufferObject as a QPaint device, then drawing a texture from the fbo in the QGLWidget. A QOpenGLFramebufferObject and QPainter are created and destroyed each time make_text() is called. The example below creates a 600x600 fbo with a 300x300 viewport. The first call to make_text() is fine, all calls after the first mess up the projection. If I limit the fbo to the viewport size there is no issue. The corruption seams to happen at the first use of the QPainter eraseRect(). I have no idea why this is breaking.

    main.h
    @
    #include <QGLWidget>
    #include <QGLFunctions>
    #include <QGLFramebufferObject>
    #include <QFont>
    #include <QGLShader>

    class glview : public QGLWidget, protected QGLFunctions
    {
    Q_OBJECT

    public:
    explicit glview(QWidget *parent = 0);
    ~glview();
    QSize sizeHint() const;

    protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

    private:
    void make_text(void);
    QGLFramebufferObject *fbo;
    QFont font;
    quint32 vbo_id[1], texture_id;
    QGLShaderProgram *txtovlp;
    QTimer *delay;

    private slots:
    void refresh(void);
    };
    @

    main.cpp
    @
    #include <QApplication>
    #include <QPainter>
    #include <QTimer>
    #include "main.h"

    struct txtr_vrtx {
    GLfloat x;
    GLfloat y;
    GLfloat z;
    GLfloat tx;
    GLfloat ty;
    }attribute((packed)) txtr_geo[] = {
    // x, y, z, tx,ty
    {0, 0, 0, 0, 0},
    {0, 6, 0, 0, 1},
    {6, 6, 0, 1, 1},
    {6, 0, 0, 1, 0},
    };

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();
    }

    glview::glview(QWidget *parent) : QGLWidget(parent)
    {
    fbo = NULL;
    font.setFamily("Helvetica");
    delay = new QTimer;
    delay->start(2000);
    connect(delay, SIGNAL(timeout()), this, SLOT(refresh()));
    }

    glview::~glview()
    {
    delete fbo;
    }

    void glview::refresh(void)
    {
    delay->stop();
    qDebug() << "refresh fired";
    make_text();
    updateGL();
    }

    void glview::make_text(void)
    {
    glBindBuffer(GL_ARRAY_BUFFER, 0); // must unbind for QPainter

    glEnable(GL_TEXTURE_2D);
    if (fbo)
    delete fbo;
    fbo = new QGLFramebufferObject(600, 600, GL_TEXTURE_2D);
    fbo->bind();
    texture_id = fbo->texture();

    QPainter painter(fbo);
    font.setPointSize(20);
    painter.setFont(font);
    painter.eraseRect(0,0,600,600);
    painter.setPen(Qt::blue);
    painter.drawText(250, 310, "FBO");
    painter.setPen(Qt::red);
    painter.drawText(100, 310, "FBO");
    painter.setPen(Qt::green);
    painter.drawText(250, 510, "FBO");
    painter.end();

    fbo->release();
    }

    QSize glview::sizeHint() const
    {
    return QSize(300, 300);
    }

    void glview::initializeGL()
    {
    initializeGLFunctions();
    qglClearColor(Qt::white);

    QGLShader *txtovlp_vshader = new QGLShader(QGLShader::Vertex, this);
    const char *txtovlp_vsrc =
    "attribute highp vec4 vertex;\n"
    "attribute mediump vec2 texCoord;\n"
    "varying mediump vec2 texc;\n"
    "uniform mediump mat4 matrix;\n"
    "void main(void)\n"
    "{\n"
    " gl_Position = matrix * vertex;\n"
    " texc = texCoord;\n"
    "}\n";
    txtovlp_vshader->compileSourceCode(txtovlp_vsrc);

    QGLShader *txtovlp_fshader = new QGLShader(QGLShader::Fragment, this);
    const char *txtovlp_fsrc =
    "uniform sampler2D texture;\n"
    "varying mediump vec2 texc;\n"
    "void main(void)\n"
    "{\n"
    " gl_FragColor = texture2D(texture, texc.st);\n"
    "}\n";
    txtovlp_fshader->compileSourceCode(txtovlp_fsrc);

    txtovlp = new QGLShaderProgram(this);
    txtovlp->addShader(txtovlp_vshader);
    txtovlp->addShader(txtovlp_fshader);
    txtovlp->link();

    glGenBuffers(1, vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(txtr_geo), txtr_geo, GL_STATIC_DRAW);

    make_text();

    glEnable(GL_DEPTH_TEST);
    }

    void glview::resizeGL(int w, int h)
    {
    glViewport(0, 0, w, h);
    }

    void glview::paintGL()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 matrix;
    matrix.ortho(1.5, 4.5, 1.5, 4.5, -1, 1);
    //matrix.translate(1,1,0);

    txtovlp->bind();
    txtovlp->setUniformValue("matrix", matrix);
    //txtovlp->setUniformValue("texture", 0);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBindTexture(GL_TEXTURE_2D, texture_id);

    int txtr_vertexLocation = txtovlp->attributeLocation("vertex");
    txtovlp->enableAttributeArray(txtr_vertexLocation);
    glVertexAttribPointer(txtr_vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct txtr_vrtx), 0);

    int texCoordLocation = txtovlp->attributeLocation("texCoord");
    txtovlp->enableAttributeArray(texCoordLocation);
    glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(struct txtr_vrtx), ((char*)NULL + 12));

    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    glFlush();
    }

    @



  • Is the correct context current when calling make_text from refresh? Try doing a makeCurrent in refresh() before calling make_text.



  • I tried calling makeCurrent() before make_text(), no change. Also tried putting a makeCurrent() in the beginning of the paintGL(). Also tried both places at the same time. It feels like the matrix is getting messed up but qDebug() << matrix in paintGL() shows it is the same the first and last paint event. Maybe there is a bug in my shader programs?



  • QPainter trashes the GL context and I've learned that also includes the viewport. By adding glViewport(0, 0, width(), height()); at the end of make_text() (after QPainter is finished) restores the viewport for the next paint event.


Log in to reply