从另一个线程渲染到 QWindow

Posted

技术标签:

【中文标题】从另一个线程渲染到 QWindow【英文标题】:Rendering to QWindow from another thread 【发布时间】:2014-03-21 20:06:19 【问题描述】:

我一直在尝试解决我的问题一段时间,但到目前为止我没有找到解决方案

我有一个 QT 应用程序,现在我需要在其中添加一个 QWindow 以使用 opengl 进行绘制。

我知道我需要调用 QWidget::createWindowContainer() 来创建可以插入到另一个小部件或主窗口中的 QWidget。 现在,我在我拥有的子类 QWindow 类中创建了一个上下文。当窗户暴露时我会这样做。然后我在我的渲染类所在的地方创建了另一个线程,将 QOpenGLContext 传递给它,使其成为当前的,但无论我尝试什么,它都不起作用。

QWindow 的子类我只是初始化上下文,仅此而已(我在构造函数中设置了表面类型):

void OpenGLWindow::initialize()

    if (!m_context) 
        m_context = new QOpenGLContext();
        m_context->setFormat(requestedFormat());
        m_context->create();
    

    if(!isRunning) 
    thread = new ThreadHelper(m_context, this);
    thread->start();
    
 

然后是线程助手:

ThreadHelper::ThreadHelper(QOpenGLContext *context, OpenGLWindow *window) : 
m_window(window),
m_context(context)




void ThreadHelper::run()

    m_context->makeCurrent(m_window);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    glClearColor(1.0, 0.0, 0.0, 0.5);

    // the rendering is done here, it's a loop, where I loop 
    // over classes and call the render method


void ThreadHelper::swapOpenGLBuffers()
    m_context->swapBuffers(m_window);

它在 m_context->makeCurrent(m_window) 行崩溃。

还尝试将上下文移动到另一个线程,但没有成功,我收到一个运行时错误,提示它无法移动。

【问题讨论】:

比赛条件可能吗? 我不这么认为,但我不知道QT的内部细节。但是据我所知,我不会做任何可能导致比赛条件的事情 对于现在阅读本文的任何人,都无需将上下文移动到渲染线程,您可以避免关联问题以及以后与锁定有关的任何事情。在那里(在渲染线程中)创建它,因为你的表面只关心绘画,唯一应该绑定这些类的是 QWindow 传递和 swapBuffers(...) 【参考方案1】:

来自文档:

QOpenGLContext 可以使用 moveToThread() 移动到不同的线程。 不要从与要调用的线程不同的线程调用 makeCurrent() QOpenGLContext 对象属于哪个。上下文只能是当前的 一次在一个螺纹中并靠在一个表面上,并且一个螺纹只有一个 一次只有一个上下文。

所以你需要在启动线程之前调用m_context->moveToThread(thread) 之类的东西。这可能对你不起作用,因为你试图在另一个线程中调用它。 moveToThread 必须在当前拥有该对象的线程(即创建它的线程)中调用。

【讨论】:

我是这样做的,而且效果不错。问题是我必须拨打 2 次 gl... 才能生效,这真的很奇怪。我在渲染线程(也是拥有上下文的线程)中使上下文处于当前状态,但是当我调用 glClear* 时,它第一次被完全忽略,只有第​​二次它实际清除屏幕并设置颜色。我将接受这个解决方案,并就这个不同的问题提出另一个问题。

以上是关于从另一个线程渲染到 QWindow的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UI 与 C# 中的渲染分开?

使用 ZeroMQ Socket 时,我可以从一个线程 send() 并从另一个线程发送 recv() 到同一个套接字吗?

从另一个局部视图渲染局部视图

Gtkmm:如何从另一个线程更新 UI?连续不断

从另一个线程更改按钮图标/切换按钮

有没有办法从另一个进程向线程发送信号?