C++ 2 QOpenGLWidget共享上下文导致崩溃

C++ 2 QOpenGLWidget共享上下文导致崩溃,c++,qt,opengl,C++,Qt,Opengl,我想解决我仍在处理的问题。。使用共享着色器程序等在不同的顶级窗口中同时渲染2个QopenglWidget 我的第一次尝试是使用一个上下文,但不起作用 目前QOpenGLWidget是否可能?或者我必须去老的QGLWidget?还是用别的 Qt::AA_ShareOpenGLContexts的testAttribute返回true,因此共享没有问题 甚至QOpenGLContext::areSharing也返回true。所以有些东西我遗漏了或者我不知道。不使用线程 调试输出: MapExplore

我想解决我仍在处理的问题。。使用共享着色器程序等在不同的顶级窗口中同时渲染2个QopenglWidget

我的第一次尝试是使用一个上下文,但不起作用

目前QOpenGLWidget是否可能?或者我必须去老的QGLWidget?还是用别的

Qt::AA_ShareOpenGLContexts的testAttribute返回true,因此共享没有问题 甚至QOpenGLContext::areSharing也返回true。所以有些东西我遗漏了或者我不知道。不使用线程

调试输出:

MapExplorer true QOpenGLShaderProgram::bind:程序不是 在当前上下文中有效。MapExlorer paintGL结束MapExplorer true true QOpenGLShaderProgram::bind:程序在中无效 当前上下文。MapExlorer画笔末端 QOpenGLFramebufferObject::bind()从不兼容的上下文调用 QOpenGLShaderProgram::bind:程序在当前 上下文QOpenGLShaderProgram::bind:程序在中无效 当前上下文。QOpenGLShaderProgram::bind:程序在中无效 当前环境。QOpenGLFramebufferObject::bind()从调用 从调用的不兼容上下文QOpenGLFramebufferObject::bind() 不兼容上下文

MapView初始值egl:

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);
}
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);
}
MapView paintGL:

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

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

    world->draw(...);
}
MapExplorer初始值egl:

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

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(...);
}
void MapExplorer::paintGL()
{
这个->makeCurrent();
qDebug()context())context());
QOpenGLShaderProgram*shader=world->getTerrainShader();
qDebug()创建();
着色器->绑定();//调试错误“QOpenGLShaderProgram::bind:程序在当前上下文中无效。”
//我们需要视口大小来计算细分级别,几何体着色器也需要视口矩阵
着色器->setUniformValue(“viewportSize”,viewportSize);
着色器->setUniformValue(“viewportMatrix”,viewportMatrix);
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
qDebug()抽屉浏览视图(…);
}

您的上下文让您感到悲伤的一个原因是,您正试图在MapExplorer::initializeGL中创建自己的上下文。QOpenGLWidget已经在其私有初始化函数中创建了自己的上下文。您需要使用它创建的一个。它自己的上下文在initializeGL、paintGL和resizeGL之前也是当前的。使您自己的当前可能会导致错误,而不是该小部件的设计使用方式


小部件之间的上下文共享需要使用Context.globalShareContext()完成。QOpenGLContext有一个静态成员,它在创建QGUI应用程序时被初始化。该静态成员和defaulFormat是QOpenGLWidgets上下文自动初始化的对象。

在您的代码中,我看不到您链接着色器程序的位置。你应该:

  • 从paintGL中删除着色器->create(),在其中一个视图的initializeGL函数中创建一次,并在其他视图中共享
  • 在绑定它之前,以这种方式在paintGL函数中链接它:

    if (!shader->isLinked())
        shader->link();
    
  • 着色器程序的链接状态取决于上下文(请参阅OpenGL并查看QOpenGLShaderProgram::link()源代码)

    在MapExplorer::initializeGL()删除上下文中(根本不使用它…)。同时删除此->上下文()->创建(这由QOpenGLWidget完成)

    在主函数中,将其放在第一行(或QApplication实例之前):


    我确实喜欢在多QOpenGLWidget应用程序中使用此功能,而且效果很好。

    嗨,我已经对它进行了两天的黑客攻击,终于找到了工作

    主要参考文献是

    基本上,我有一个带有自己上下文的QOpenglWidget,还有一个背景线程QOpenglWidget绘制到共享上下文的。后台线程绘制的帧缓冲区可直接由QOpenglWidget使用

    以下是让事情顺利进行的步骤:

  • 我有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 RenderWorker::initializeGL()
    {
        context->makeCurrent(surface);
        initializeOpenGLFunctions();
    }
    
  • 现在,在背景线程中绘制的任何帧缓冲区都可以由QOpenglWidget直接使用(作为纹理等),例如在
    paintGL()
    函数中


  • 据我所知,opengl上下文是绑定到线程的共享上下文并且必须在主线程中创建和设置相应的曲面,移动到另一个线程并在其中初始化,然后才能最终使用它。

    FBO不能跨上下文共享,因此这可能解释两个错误之一。该问题适用于OpenGL中的任何容器对象(因此,顶点数组对象也有相同的问题),并且只能共享存储实际数据的对象(例如渲染缓冲区、纹理、缓冲区)。至于着色器的错误,我真的不知道是怎么回事。啊,太令人失望了我想做一个世界的实例,只是画在多个不同的窗口上。你是说这不可能吧/@user1085907:以这种方式不可能。这就是为什么OOP包装OpenGL的尝试可能会在某个时候失败的原因。您需要一些上下文“容器包装器”,用于保存FBO、VAO等的多个实例(每个上下文一个实例),并保持它们的同步。或者在多个窗口中重复使用同一个OpenGL上下文,但Qt在这方面被打破了(告诉我吧……目前是我生活中的一大亮点)。好吧,无论如何,感谢您提供的这些知识,非常有用:)