gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:19:22 26 4
gpt4 key购买 nike

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

我的第一次尝试是使用一个上下文,但没有成功。

目前 QOpenGLWidget 甚至可能吗?或者我必须去旧的 QGLWidget?还是用别的东西?

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

调试输出:

MapExplorer true true true QOpenGLShaderProgram::bind: program is notvalid in the current context. MapExlorer paintGL ends MapExplorer truetrue true QOpenGLShaderProgram::bind: program is not valid in thecurrent context. MapExlorer paintGL endsQOpenGLFramebufferObject::bind() called from incompatible contextQOpenGLShaderProgram::bind: program is not valid in the currentcontext. QOpenGLShaderProgram::bind: program is not valid in thecurrent context. QOpenGLShaderProgram::bind: program is not valid inthe current context. QOpenGLFramebufferObject::bind() called fromincompatible context QOpenGLFramebufferObject::bind() called fromincompatible context

map View 初始化GL:

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

map View 绘制GL:

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

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

world->draw(...);
}

MapExplorer 初始化GL:

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

最佳答案

嗨,我已经破解了 2 天了,终于找到了可以工作的东西。

主要引用是qt's threadrenderer example .

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

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

  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;

    ...
    }
  2. QOpenglWidgetinitializeGL() 中创建和设置后台线程

    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();
    }
  3. 后台线程必须在自己的线程中初始化共享上下文

    void RenderWorker::initializeGL()
    {
    context->makeCurrent(surface);
    initializeOpenGLFunctions();
    }
  4. 现在后台线程中绘制的任何帧缓冲区都可以被QOpenglWidget直接使用(作为纹理等),例如在paintGL()功能。

据我所知,opengl 上下文有点绑定(bind)到线程。 Shared context和相应的surface必须在主线程中创建和设置,移动到另一个线程并在其中初始化,然后才可以终于用上了。

关于c++ - 2 QOpenGLWidget 共享上下文导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28787728/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com