2 QOpenGLWidget共享上下文导致崩溃 [英] 2 QOpenGLWidget shared context causing crash

查看:1422
本文介绍了2 QOpenGLWidget共享上下文导致崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想解决我仍然要解决的问题.那就是使用共享的着色器程序等在不同的顶层窗口中同时渲染2个QOpenGLWidgets.

I would like to solve problem that I still deal with.. thats render 2 QOpenGLWidgets at same time in different top level windows with shared shader programs etc.

为什么我在这里而不是Qt论坛上发布它?我已经做过,但是没有人回应:/

Why do I post it here and not on Qt forums? I already did, but no one response :/

我的第一个尝试是使用一个上下文,没有用.

My first attempt was to use one context, wasnt working.

问题:QOpenGLWidget当前是否有可能?还是我必须去旧的QGLWidget?还是使用其他东西?

The question: Is it even possible currently with QOpenGLWidget? Or I have to go to older QGLWidget? Or use something else?

testAttribute返回true,因此共享没有问题 甚至QOpenGLContext :: areSharing也返回true.所以有一些我想念的东西或我不知道的东西.不使用线程.

testAttribute for Qt::AA_ShareOpenGLContexts returns true so there is not problem with sharing even QOpenGLContext::areSharing returns true. So there is something I missing or I dont know. Not using threads.

如果您还需要其他任何东西来调试此问题,请告诉我.

If you need anything more to debug this problem tell me.

调试输出:

MapExplorer是是是是QOpenGLShaderProgram :: bind:程序不是 在当前上下文中有效. MapExlorer paintGL结束MapExplorer true true true QOpenGLShaderProgram :: bind:程序在以下位置无效 当前的背景. MapExlorer paintGL结束 QOpenGLFramebufferObject :: bind()从不兼容的上下文中调用 QOpenGLShaderProgram :: bind:程序在当前无效 语境. QOpenGLShaderProgram :: bind:程序在以下位置无效 当前的背景. QOpenGLShaderProgram :: bind:程序在以下位置无效 当前上下文. QOpenGLFramebufferObject :: bind()从调用 从调用不兼容的上下文QOpenGLFramebufferObject :: bind() 不兼容的上下文

MapExplorer true true true QOpenGLShaderProgram::bind: program is not valid in the current context. MapExlorer paintGL ends MapExplorer true true true QOpenGLShaderProgram::bind: program is not valid in the current context. MapExlorer paintGL ends QOpenGLFramebufferObject::bind() called from incompatible context QOpenGLShaderProgram::bind: program is not valid in the current context. QOpenGLShaderProgram::bind: program is not valid in the current context. QOpenGLShaderProgram::bind: program is not valid in the current context. QOpenGLFramebufferObject::bind() called from incompatible context QOpenGLFramebufferObject::bind() called from incompatible context

MapView initializeGL:

MapView initializeGL:

void MapView::initializeGL()
{
    this->makeCurrent();

    initializeOpenGLFunctions();

    // Initialize World
    world->initialize(this->context(), size(), worldCoords);

    // Initialize camera shader
    camera->initialize();

    // Enable depth testing
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glDepthFunc(GL_LEQUAL); // just testing new depth func

    glClearColor(0.65f, 0.77f, 1.0f, 1.0f);
}

MapView paintGL:

MapView paintGL:

void MapView::paintGL()
{
    this->makeCurrent();

    glDrawBuffer(GL_FRONT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    world->draw(...);
}

MapExplorer initializeGL:

MapExplorer initializeGL:

void MapExplorer::initializeGL()
{
    this->makeCurrent();

    QOpenGLContext* _context = _mapView->context();
    _context->setShareContext(this->context());
    _context->create();

    this->context()->create();
    this->makeCurrent();

    initializeOpenGLFunctions();

    // Enable depth testing
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glDepthFunc(GL_LEQUAL); // just testing new depth func

    glClearColor(0.65f, 0.77f, 1.0f, 1.0f);
}

MapExplorer paintGL:

MapExplorer paintGL:

void MapExplorer::paintGL()
{
    this->makeCurrent();

    qDebug() << "MapExplorer" << QOpenGLContext::areSharing(this->context(), _mapView->context()) << (QOpenGLContext::currentContext() == this->context());

    QOpenGLShaderProgram* shader = world->getTerrainShader();
    qDebug() << shader->create();
    shader->bind(); // debug error "QOpenGLShaderProgram::bind: program is not valid in the current context."

    // We need the viewport size to calculate tessellation levels and the geometry shader also needs the viewport matrix
    shader->setUniformValue("viewportSize",   viewportSize);
    shader->setUniformValue("viewportMatrix", viewportMatrix);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    qDebug() << "MapExlorer paintGL ends";

    //world->drawExplorerView(...);
}

谢谢.

关于,格拉兰.

推荐答案

我已经破解了2天,终于有了一些工作.

Hi I've been hacking this for 2 days, and finally got something to work.

主要参考文献是 qt的threadrenderer示例.

基本上,我有一个 QOpenglWidget 及其自己的上下文,还有一个后台线程 QOpenglWidget 绘制到共享的上下文强>. QOpenglWidget 可以直接使用由后台线程绘制的帧缓冲区.

Basically I have a QOpenglWidget with its own context, and a background thread drawing to the context shared from QOpenglWidget. The framebuffer drawn by the background thread can be directly used by the QOpenglWidget.

以下是使事情正常进行的步骤:

Here's the steps to make things work:

  1. 我有 QOpenglWidget RenderEngine后台线程 RenderWorker

// the worker is a thread
class RenderWorker : public QThread, protected QOpenGLFunctions
{
    // the background thread's context and surface
    QOffscreenSurface *surface = nullptr;
    QOpenGLContext *context = nullptr;

    RenderWorker::RenderWorker()
    {
        context = new QOpenGLContext();
        surface = new QOffscreenSurface();
    }

    ...
}

// the engine is a QOpenglWidget
class RenderEngine : public QOpenGLWidget, protected QOpenGLFunctions
{
protected:
    // overwrite
    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL() override;

private:
    // the engine has a background worker
    RenderWorker *m_worker = nullptr;

    ...
}

  • QOpenglWidget initializeGL()

    void RenderEngine::initializeGL()
    {
        initializeOpenGLFunctions();
    
        // done with current (QOpenglWidget's) context
        QOpenGLContext *current = context();
        doneCurrent();
    
        // create the background thread
        m_worker = new RenderWorker();
    
        // the background thread's context is shared from current
        QOpenGLContext *shared = m_worker->context;
        shared->setFormat(current->format());
        shared->setShareContext(current);
        shared->create();
    
        // must move the shared context to the background thread
        shared->moveToThread(m_worker);
    
        // setup the background thread's surface
        // must be created here in the main thread
        QOffscreenSurface *surface = m_worker->surface;
        surface->setFormat(shared->format());
        surface->create();
    
        // worker signal
        connect(m_worker, SIGNAL(started()), m_worker, SLOT(initializeGL()));
    
        // must move the thread to itself
        m_worker->moveToThread(m_worker);
    
        // the worker can finally start
        m_worker->start();
    }
    

  • 后台线程必须在其自己的线程中初始化共享上下文

  • The background thread have to initialize the shared context in its own thread

    void RenderWorker::initializeGL()
    {
        context->makeCurrent(surface);
        initializeOpenGLFunctions();
    }
    

  • 现在, QOpenglWidget 可以直接使用(在后台线程中绘制的任何帧缓冲区)(作为纹理等),例如在paintGL()函数中.

  • Now any framebuffer drawn in the background thread can be directly used (as texture, etc.) by the QOpenglWidget, e.g. in the paintGL() function.

    据我所知,opengl上下文是绑定到线程的一种.必须先在主线程中创建共享上下文和相应的表面,并将其设置为移动,然后在其中进行初始化.终于用了.

    As far as I know, an opengl context is kind of binded to a thread. Shared context and the corresponding surface must be created and setup in the main thread, moved to another thread and initialized in it, before it can be finally used.

    这篇关于2 QOpenGLWidget共享上下文导致崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆