Multithreading QThread中具有共享QOpenGLContext的qPaint-新版本上的seg故障

Multithreading QThread中具有共享QOpenGLContext的qPaint-新版本上的seg故障,multithreading,qt,opengl,qt5,Multithreading,Qt,Opengl,Qt5,我正在尝试学习如何使用Qt执行线程化gl,以便在一个单独的线程中卸载大量QPaint绘图。我在主gui线程中有一个QGLWidget,它从vbo中绘制一些线并显示纹理。在QGLWidget的initializeGL()函数中,我创建了一个QOffscreenSurface、QOpenGLContext和一个QThread,然后将QOpenGLContext移动到新的QThread。GLWidget的上下文和QOpenGLContext设置为共享。QThread启动后,它将创建一个QGLFrame

我正在尝试学习如何使用Qt执行线程化gl,以便在一个单独的线程中卸载大量QPaint绘图。我在主gui线程中有一个QGLWidget,它从vbo中绘制一些线并显示纹理。在QGLWidget的initializeGL()函数中,我创建了一个QOffscreenSurface、QOpenGLContext和一个QThread,然后将QOpenGLContext移动到新的QThread。GLWidget的上下文和QOpenGLContext设置为共享。QThread启动后,它将创建一个QGLFramebufferObject作为QPaint的绘制设备。当QPaint完成时,威胁会向QGLWidget发出信号,以使用fbo的完成纹理重新绘制

在英伟达开源Kuuntuu 14.04机上,如果有很多绘图,程序SEG故障,并可以删除视频驱动程序。如果使用QPainter绘制的图形很少,则一切正常。在Nexus 4、Kubuntu 14.04、英特尔第二代核心和英特尔82945G/GZ Kubuntu 14.04上看起来不错。我怀疑新潮只是对我未知的错误不那么宽容

nouveau: kernel rejected pushbuf: Invalid argument
nouveau: ch0: krec 0 pushes 3 bufs 12 relocs 0
nouveau: ch0: buf 00000000 00000002 00000004 00000004 00000000<\br>
nouveau: ch0: buf 00000001 00000013 00000002 00000000 00000002
nouveau: ch0: buf 00000002 00000016 00000002 00000002 00000000
nouveau: ch0: buf 00000003 00000007 00000002 00000002 00000000
nouveau: ch0: buf 00000004 0000000a 00000002 00000002 00000000
nouveau: ch0: buf 00000005 0000000b 00000002 00000002 00000000
nouveau: ch0: buf 00000006 00000008 00000002 00000002 00000000
nouveau: ch0: buf 00000007 00000006 00000004 00000000 00000004
nouveau: ch0: buf 00000008 00000003 00000004 00000004 00000000
nouveau: ch0: buf 00000009 0000000e 00000002 00000002 00000000
nouveau: ch0: buf 0000000a 00000017 00000002 00000000 00000002
nouveau: ch0: buf 0000000b 00000018 00000002 00000000 00000002
Segmentation fault (core dumped)
main.h

#include <QGLWidget>
#include <QGLFunctions>
#include <QGLShader>
#include <QTimer>
#include "textThread.h"

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:
    QTimer repaintTimer;
    QGLShaderProgram *program, *txtovlp;
    textThread *maketext;
    quint32 vbo_id[2];

private slots:
    void repaint(void);
};
#包括
#包括
#包括
#包括
#包括“textThread.h”
类glview:公共QGLWidget,受保护的QGLFunctions
{
Q_对象
公众:
显式glview(QWidget*parent=0);
~glview();
QSize sizeHint()常量;
受保护的:
void initializeGL();
无效尺寸(整数w,整数h);
void paintGL();
私人:
QTimer重绘定时器;
QGLShaderProgram*程序,*txtovlp;
textThread*maketext;
quint32 vbo_id[2];
专用插槽:
无效重新喷漆(无效);
};
main.cpp

#include <QApplication>
#include "main.h"

struct vrtx {
    GLfloat x;
    GLfloat y;
    GLfloat z;
    GLfloat r;
    GLfloat g;
    GLfloat b;
}__attribute__((packed)) line_geo[] = {
//   x, y, z, r, g, b
    {1, 1, 0, 1, 0, 0},
    {1, 2, 0, 0, 1, 0},
    {1, 2, 0, 0, 1, 0},
    {2, 2, 0, 1, 0, 0},
    {2, 2, 0, 1, 0, 0},
    {2, 1, 0, 0, 1, 0},
    {2, 1, 0, 0, 1, 0},
    {1, 1, 0, 1, 0, 0},
};

struct txtr_vrtx {
    GLfloat   x;
    GLfloat   y;
    GLfloat   z;
    GLfloat   tx;
    GLfloat   ty;
}__attribute__((packed)) txtr_geo[] = {
//   x, y, z, tx,ty
    {3, 1, 0, 0, 0},
    {3, 2, 0, 0, 1},
    {4, 2, 0, 1, 1},
    {4, 1, 0, 1, 0},
};

glview::glview(QWidget *parent) : QGLWidget(parent)
{
    connect(&repaintTimer, SIGNAL(timeout()), this, SLOT(repaint()));
    repaintTimer.start(20);
}

glview::~glview()
{
    delete maketext->context;
    delete maketext->offscrnsf;
    delete maketext;
    delete program;
    delete txtovlp;
}

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

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

    QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
    const char *vsrc =
        "attribute highp vec4 vertex;\n"
        "attribute mediump vec4 colour;\n"
        "varying mediump vec4 f_colour;\n"
        "uniform mediump mat4 matrix;\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = matrix * vertex;\n"
        "    f_colour = colour;\n"
        "}\n";
    vshader->compileSourceCode(vsrc);

    QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
    const char *fsrc =
        "varying mediump vec4 f_colour;\n"
        "void main(void)\n"
        "{\n"
        "    gl_FragColor = f_colour;\n"
        "}\n";
    fshader->compileSourceCode(fsrc);

    program = new QGLShaderProgram(this);
    program->addShader(vshader);
    program->addShader(fshader);
    program->link();

    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(2, vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(line_geo), line_geo, GL_STATIC_DRAW);

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

    glEnable(GL_DEPTH_TEST);
    doneCurrent();

    maketext = new textThread;
    maketext->offscrnsf = new QOffscreenSurface();
    maketext->offscrnsf->create();
    if (!maketext->offscrnsf->isValid()) {
        qDebug() << "Surface Failed";
        exit(1);
    }

    maketext->context = new QOpenGLContext();
    maketext->context->setShareContext(this->context()->contextHandle());
    maketext->context->create();
    if (!maketext->context->isValid()) {
        qDebug() << "Context Failed";
        exit(1);
    }
    if (!maketext->context->areSharing(this->context()->contextHandle(), maketext->context)) {
        qDebug() << "Sharing Failed";
        exit(1);
    }
    maketext->context->moveToThread(maketext);

    //connect(maketext, SIGNAL(finished()), this, SLOT(repaint()));
    connect(maketext, SIGNAL(finished()), this, SLOT(repaint()), Qt::QueuedConnection);
    maketext->start();
}

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

void glview::repaint(void)
{
    repaintTimer.start(20);
    updateGL();
}

void glview::paintGL()
{
    static quint32 i;

    i++;

    printf("Pa");
    makeCurrent();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 matrix;
    matrix.ortho(0, 5, 0, 3, -1, 1);

    program->bind();
    program->setUniformValue("matrix", matrix);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    int vertexLocation = program->attributeLocation("vertex");
    program->enableAttributeArray(vertexLocation);
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct vrtx), 0);

    int colourLocation = program->attributeLocation("colour");
    program->enableAttributeArray(colourLocation);
    glVertexAttribPointer(colourLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct vrtx), ((char*)NULL + 12));

    glDrawArrays(GL_LINES, 0, sizeof(line_geo) / sizeof(struct vrtx));

    txtovlp->bind();
    txtovlp->setUniformValue("matrix", matrix);

    maketext->textLock.lock();
    if (maketext->done) {
        maketext->textLock.unlock();
        //qDebug() << "Painting with text" << i;
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
        glEnable(GL_TEXTURE_2D);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
        glBindTexture(GL_TEXTURE_2D, maketext->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);
    }
    else {
        maketext->textLock.unlock();
        //qDebug() << "Painting" << i;
    }

    glFlush();
    printf("int\n");
}

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();
}
#包括
#包括“main.h”
结构vrtx{
GLX;
GLY;
GLZ;
GLR;
GLG;
GLB;
}__属性uuu((压缩))行_geo[]={
//x,y,z,r,g,b
{1, 1, 0, 1, 0, 0},
{1, 2, 0, 0, 1, 0},
{1, 2, 0, 0, 1, 0},
{2, 2, 0, 1, 0, 0},
{2, 2, 0, 1, 0, 0},
{2, 1, 0, 0, 1, 0},
{2, 1, 0, 0, 1, 0},
{1, 1, 0, 1, 0, 0},
};
结构txtr\U vrtx{
GLX;
GLY;
GLZ;
GLTX;
GLTY;
}__属性(压缩)txtr\u geo[]={
//x,y,z,tx,ty
{3, 1, 0, 0, 0},
{3, 2, 0, 0, 1},
{4, 2, 0, 1, 1},
{4, 1, 0, 1, 0},
};
glview::glview(QWidget*父项):QGLWidget(父项)
{
连接(&重新绘制计时器,信号(超时()),此,插槽(重新绘制());
重新绘制计时器。启动(20);
}
glview::~glview()
{
删除maketext->context;
删除maketext->offscrnsf;
删除maketext;
删除程序;
删除txtovlp;
}
QSize glview::sizeHint()常量
{
返回QSize(500300);
}
void glview::initializeGL()
{
initializeGLFunctions();
qglClearColor(Qt::白色);
QGLShader*vshader=新的QGLShader(QGLShader::Vertex,this);
常量字符*vsrc=
“属性highp vec4顶点;\n”
“属性mediump vec4 color;\n”
“不同的mediump vec4 f_颜色;\n”
“统一mediump mat4矩阵;\n”
“作废主(作废)\n”
“{\n”
“gl_位置=矩阵*顶点;\n”
“f_color=color;\n”
“}\n”;
vshader->compileSourceCode(vsrc);
QGLShader*fshader=新的QGLShader(QGLShader::Fragment,this);
常量字符*fsrc=
“不同的mediump vec4 f_颜色;\n”
“作废主(作废)\n”
“{\n”
“gl\u FragColor=f\u color;\n”
“}\n”;
fshader->compileSourceCode(fsrc);
程序=新的QGLShaderProgram(本程序);
程序->添加着色器(vshader);
程序->添加着色器(fshader);
程序->链接();
QGLShader*txtovlp_vshader=新的QGLShader(QGLShader::Vertex,this);
常量字符*txtovlp\u vsrc=
“属性highp vec4顶点;\n”
“属性mediump vec2 texCoord;\n”
“可变介质矢量2 texc;\n”
“统一mediump mat4矩阵;\n”
“作废主(作废)\n”
“{\n”
“gl_位置=矩阵*顶点;\n”
“texc=texCoord;\n”
“}\n”;
txtovlp_vshader->编译源代码(txtovlp_vsrc);
QGLShader*txtovlp_fshader=新的QGLShader(QGLShader::Fragment,this);
常量字符*txtovlp_fsrc=
“二维纹理的均匀采样;\n”
“可变介质矢量2 texc;\n”
“作废主(作废)\n”
“{\n”
gl_FragColor=texture2D(纹理,texc.st);\n
“}\n”;
txtovlp_fshader->编译资源代码(txtovlp_fsrc);
txtovlp=新的QGLShaderProgram(本程序);
txtovlp->addShader(txtovlp_vshader);
txtovlp->addShader(txtovlp_fshader);
txtovlp->link();
glGenBuffers(2,vbo_id);
glBindBuffer(GL_数组_BUFFER,vbo_id[0]);
glBufferData(GL_数组_缓冲区、sizeof(line_geo)、line_geo、GL_静态_绘图);
glBindBuffer(GL_数组_BUFFER,vbo_id[1]);
glBufferData(GL_数组_缓冲区、sizeof(txtr_geo)、txtr_geo、GL_静态_绘图);
glEnable(GLU深度试验);
doneCurrent();
maketext=新的textThread;
maketext->offscrnsf=新QOffscreenSurface();
maketext->offscrnsf->create();
如果(!maketext->offscrnsf->isValid()){
qDebug()上下文=新的QOpenGLContext();
maketext->context->setShareContext(此->context()->contextHandle());
maketext->context->create();
如果(!maketext->context->isValid()){
qDebug()context->areSharing(此->context()->contextHandle(),maketext->context)){
qDebug()上下文->移动到线程(maketext);
//连接(maketext,信号(finished()),此,插槽(repaint());
连接(maketext,SIGNAL(finished()),this,SLOT(repaint()),Qt::QueuedConnection);
maketext->start();
}
void glview::resizeGL(int w,int h)
{
makeCurrent();
glViewport(0,0,w,h);
}
void glview::重新绘制(void)
{
重新绘制计时器。启动(20);
updateGL();
}
void glview::paintGL()
{
静态电压;
i++;
printf(“Pa”);
makeCurrent();
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
QMatrix4x4矩阵;
矩阵正交(0,5,0,3,-1,1);
程序->绑定();
程序->设置统一值(“矩阵”,矩阵);
#include <QApplication>
#include "main.h"

struct vrtx {
    GLfloat x;
    GLfloat y;
    GLfloat z;
    GLfloat r;
    GLfloat g;
    GLfloat b;
}__attribute__((packed)) line_geo[] = {
//   x, y, z, r, g, b
    {1, 1, 0, 1, 0, 0},
    {1, 2, 0, 0, 1, 0},
    {1, 2, 0, 0, 1, 0},
    {2, 2, 0, 1, 0, 0},
    {2, 2, 0, 1, 0, 0},
    {2, 1, 0, 0, 1, 0},
    {2, 1, 0, 0, 1, 0},
    {1, 1, 0, 1, 0, 0},
};

struct txtr_vrtx {
    GLfloat   x;
    GLfloat   y;
    GLfloat   z;
    GLfloat   tx;
    GLfloat   ty;
}__attribute__((packed)) txtr_geo[] = {
//   x, y, z, tx,ty
    {3, 1, 0, 0, 0},
    {3, 2, 0, 0, 1},
    {4, 2, 0, 1, 1},
    {4, 1, 0, 1, 0},
};

glview::glview(QWidget *parent) : QGLWidget(parent)
{
    connect(&repaintTimer, SIGNAL(timeout()), this, SLOT(repaint()));
    repaintTimer.start(20);
}

glview::~glview()
{
    delete maketext->context;
    delete maketext->offscrnsf;
    delete maketext;
    delete program;
    delete txtovlp;
}

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

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

    QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
    const char *vsrc =
        "attribute highp vec4 vertex;\n"
        "attribute mediump vec4 colour;\n"
        "varying mediump vec4 f_colour;\n"
        "uniform mediump mat4 matrix;\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = matrix * vertex;\n"
        "    f_colour = colour;\n"
        "}\n";
    vshader->compileSourceCode(vsrc);

    QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
    const char *fsrc =
        "varying mediump vec4 f_colour;\n"
        "void main(void)\n"
        "{\n"
        "    gl_FragColor = f_colour;\n"
        "}\n";
    fshader->compileSourceCode(fsrc);

    program = new QGLShaderProgram(this);
    program->addShader(vshader);
    program->addShader(fshader);
    program->link();

    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(2, vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(line_geo), line_geo, GL_STATIC_DRAW);

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

    glEnable(GL_DEPTH_TEST);
    doneCurrent();

    maketext = new textThread;
    maketext->offscrnsf = new QOffscreenSurface();
    maketext->offscrnsf->create();
    if (!maketext->offscrnsf->isValid()) {
        qDebug() << "Surface Failed";
        exit(1);
    }

    maketext->context = new QOpenGLContext();
    maketext->context->setShareContext(this->context()->contextHandle());
    maketext->context->create();
    if (!maketext->context->isValid()) {
        qDebug() << "Context Failed";
        exit(1);
    }
    if (!maketext->context->areSharing(this->context()->contextHandle(), maketext->context)) {
        qDebug() << "Sharing Failed";
        exit(1);
    }
    maketext->context->moveToThread(maketext);

    //connect(maketext, SIGNAL(finished()), this, SLOT(repaint()));
    connect(maketext, SIGNAL(finished()), this, SLOT(repaint()), Qt::QueuedConnection);
    maketext->start();
}

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

void glview::repaint(void)
{
    repaintTimer.start(20);
    updateGL();
}

void glview::paintGL()
{
    static quint32 i;

    i++;

    printf("Pa");
    makeCurrent();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 matrix;
    matrix.ortho(0, 5, 0, 3, -1, 1);

    program->bind();
    program->setUniformValue("matrix", matrix);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
    int vertexLocation = program->attributeLocation("vertex");
    program->enableAttributeArray(vertexLocation);
    glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct vrtx), 0);

    int colourLocation = program->attributeLocation("colour");
    program->enableAttributeArray(colourLocation);
    glVertexAttribPointer(colourLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct vrtx), ((char*)NULL + 12));

    glDrawArrays(GL_LINES, 0, sizeof(line_geo) / sizeof(struct vrtx));

    txtovlp->bind();
    txtovlp->setUniformValue("matrix", matrix);

    maketext->textLock.lock();
    if (maketext->done) {
        maketext->textLock.unlock();
        //qDebug() << "Painting with text" << i;
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
        glEnable(GL_TEXTURE_2D);

        glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]);
        glBindTexture(GL_TEXTURE_2D, maketext->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);
    }
    else {
        maketext->textLock.unlock();
        //qDebug() << "Painting" << i;
    }

    glFlush();
    printf("int\n");
}

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();
}
#ifndef textThread_h
#define textThread_h

#include <QThread>
#include <QMutex>
#include <QOpenGLContext>
#include <QOffscreenSurface>
#include <QGLFramebufferObject>
#include <QFont>
#include <QDebug>

class textThread : public QThread
{
    Q_OBJECT

public:
    textThread();
    ~textThread();
    QMutex textLock;
    QOffscreenSurface *offscrnsf;
    QOpenGLContext *context;
    bool done;
    quint32 texture_id;

signals:
    void finished(void);

protected:
    void run();

private:
    QGLFramebufferObject *fbo;
    QFont font;
};

#endif
#include <QPainter>
#include "textThread.h"

#define QPAINT_A_LOT

textThread::textThread()
{
    done = 0;
    fbo = NULL;
    font.setFamily("Helvetica");
}

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

void textThread::run()
{
    context->makeCurrent(offscrnsf);
    qDebug() << "Thread";

    if (!fbo)
        fbo = new QGLFramebufferObject(100, 100, GL_TEXTURE_2D);
    fbo->bind();
    texture_id = fbo->texture();

    QPainter painter(fbo);
    font.setPointSize(20);
    painter.setFont(font);
    painter.eraseRect(0,0,100,100);
    painter.setPen(Qt::blue);
#ifdef  QPAINT_A_LOT
    quint32 i;
    for (i=0; i<140000; i++) {
        //if (!(i%32768))
        if (!(i%1024))
            qDebug() << i;
        painter.drawText(0, 60, "FBO");
    }
#else
    painter.drawText(0, 60, "FBO");
    sleep(1);
#endif
    painter.end();
    fbo->release();

    context->doneCurrent();
    textLock.lock();
    done = 1;
    textLock.unlock();
    emit finished();
}