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
 

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