QPainter与共享QOpenGLContext在QThread - seg_fault on nouveau



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

在Kubuntu 14.04机器上的nvidia开源nouveau驱动程序上,如果进行多次绘图,程序隔离故障并可以吐出视频驱动程序的东西。如果使用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)

test.pro

QT += core gui widgets opengl
TARGET = test
TEMPLATE = app
SOURCES = main.cpp textThread.cpp
HEADERS = main.h textThread.h

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);
};

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("intn");
}
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
    QApplication app(argc, argv);
    glview widget;
    widget.show();
    return app.exec();
}

textThread.h

#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

textThread.cpp

#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();
}

我切换到这段代码段故障所在的同一台机器上的闭源nvidia驱动程序,它工作正常。我也在窗户上试过,效果很好。我很确定问题是开源的nouveau驱动程序。

相关内容

  • 没有找到相关文章

最新更新