QOpenGLWidget在另一个线程中绘制2D纹理

时间:2017-09-12 11:03:10

标签: c++ multithreading qt opengl

我试图在另一个帖子中绘制QOpenGLWidget,这是我的代码:

// widget.h
class QGLCanvas;

class FrameRenderer: public QThread
{
    Q_OBJECT
public:
    FrameRenderer(QGLCanvas *parent);
    void run() Q_DECL_OVERRIDE;
    void stop();
    void initialize();
    void updateFrame(std::shared_ptr<cv::Mat> frame);

    QGLCanvas *parent_;
    std::atomic<bool> thread_run_;
    bool initialize_;
    GLuint texture_;
    std::shared_ptr<cv::Mat> frame_;    
    QMutex mutex_;
};

class QGLCanvas : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    QGLCanvas(QWidget* parent = NULL);

    virtual void initializeGL();
    virtual void paintGL();
    virtual void resizeGL(int width, int height);

    void ShowImage(std::shared_ptr<cv::Mat> frame);

    // for opengl rendering thread
    FrameRenderer* render_thread_;
    QTimer* render_timer_;

private slots:
    void StartRendering();
};


//widget.cpp
#include "widget.h"
FrameRenderer::FrameRenderer(QGLCanvas* parent):
QThread(), parent_(parent)
{
    thread_run_ = true;
    initialize_ = false;

    frame_ = std::make_shared<cv::Mat>();
    cv::Mat img = cv::imread("./res/no_image.jpg");
    *frame_ = img;
}

void FrameRenderer::stop()
{
    thread_run_ = false;
}

void FrameRenderer::initialize()
{
    if(initialize_)
        return;

    glGenTextures(1, &texture_);
    glBindTexture(GL_TEXTURE_2D, texture_);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frame_->cols,
         frame_->rows, 0, GL_RGB, GL_UNSIGNED_BYTE,
         NULL);
    glBindTexture(GL_TEXTURE_2D, 0);

    initialize_ = true;
}

void FrameRenderer::run()
{
    while(true)
    {
        QMutexLocker lock(&mutex_);
        if(!thread_run_)
            break;

        parent_->makeCurrent();
       if(!initialize_)
           initialize();

        int width = parent_->width(), height = parent_->height();
        glViewport(0, 0, width, height);
        glClearColor(0, 0, 1, 1);
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, texture_);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame_->cols,
                   frame_->rows,  GL_RGB, GL_UNSIGNED_BYTE,
                   frame_->data);

        glBegin(GL_QUADS);
          glTexCoord2f(0.0f, 1.0f); glVertex3f(0, 0, 0.0f);
          glTexCoord2f(1.0f, 1.0f); glVertex3f(width, 0.0f, 0.0f);
          glTexCoord2f(1.0f, 0.0f); glVertex3f(width, height,  0.0f);
          glTexCoord2f(0.0f, 0.0f); glVertex3f(0,  height,  0.0f);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        parent_->doneCurrent();
        QMetaObject::invokeMethod(parent_, "update");
        msleep(40);
    }
}

void FrameRenderer::updateFrame(std::shared_ptr<cv::Mat> frame)
{
    QMutexLocker lock(&mutex_);
    frame_ = frame;
}




QGLCanvas::QGLCanvas(QWidget* parent)
    : QOpenGLWidget(parent)
{
    render_timer_ = new QTimer(this);
    QObject::connect(render_timer_, SIGNAL(timeout()), this, SLOT(StartRendering()));
    render_timer_->start(1000);
}

void QGLCanvas::initializeGL()
{

}

void QGLCanvas::resizeGL(int width, int height)
{
   //stop QGLWidget standard behavior
}

void QGLCanvas::paintGL()
{

}

void QGLCanvas::StartRendering()
{
    doneCurrent();
    render_thread_ = new FrameRenderer(this);
    context()->moveToThread(render_thread_);
    render_thread_->start();
}

void QGLCanvas::ShowImage(std::shared_ptr<cv::Mat> frame)
{
    if(render_thread_)
        render_thread_->updateFrame(frame);
}


// main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    // Check that the threaded OpenGL is supported.
    if (!QOpenGLContext::supportsThreadedOpenGL())
    {
        std::cerr << "Threaded OpenGL is not supported" << std::endl;
        return EXIT_FAILURE;
    }

    // Set the wanted surface format.
    QSurfaceFormat format;
    format.setDepthBufferSize(16);
    format.setVersion(4, 4);
    format.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(format);

    // Calculate the position of the widget. The widget should be
    // located so that the center is also at the center of desktop.
    const QDesktopWidget* desktop = QApplication::desktop();
    const QSize size(720, 576);
    const QPoint position(
        desktop->width()  / 2 - size.width()  / 2,
        desktop->height() / 2 - size.height() / 2);

    // Create the OpenGL widget
    std::shared_ptr<QGLCanvas> widget = std::make_shared<QGLCanvas>();
    widget->resize(size);
    widget->move(position);
    widget->show();
    return app.exec();
}

问题是我收到了这个错误:

无法让QOpenglContext在另一个帖子中保持最新状态。

我使用QGLWidget有类似的代码结构。但是当更改为QOpenGLWidget时,它无法正常工作。

0 个答案:

没有答案