使用来自其他线程的qglcontext



是否有方法从其他线程使用glwidget的qglcontext。因为我需要从其他线程上传一些纹理。然而,在纹理上传之后,甚至在上传期间,上下文也必须在我的渲染glwidget的服务中。是否有文件或可靠的(无假设的)答案?

OpenGL不支持多线程渲染,所有OpenGL调用都必须从创建上下文的线程执行。但是,如果你只想加载纹理,你可以从其他线程加载它,而不是将结果从OpenGL上下文创建的线程发布到glTexImage2D,作为图像信息。要做到这一点,必须添加一些线程管理(信号e.t.c…)

有关更多信息,请参阅并发和OpenGL。

还有QGLWidget多线程示例?。

要在其他线程中工作,必须与它们创建单独的上下文或执行一些共享上下文管理。


来自官方Qt文档:

从Qt 4.8版本开始,对执行线程GL渲染的支持得到了改进。我们目前支持三种场景:

  1. 线程中的缓冲区交换。在双缓冲上下文中交换缓冲区可能是一种同步锁定调用,在某些GL实现中,这可能是一项成本高昂的操作。尤其是嵌入式设备。当GPU进行缓冲区交换时,让CPU空闲并不是最佳选择。在这些情况下,可以在主线程中进行渲染,并在单独的线程中进行实际的缓冲区交换。这可以通过以下步骤完成:

    1. 渲染完成后,在主线程中调用doneCurrent()

    2. 调用QGLContext::moveToThread(swapThread)将上下文的所有权转移到交换线程。

    3. 通知交换线程它可以获取上下文。

    4. 使用makeCurrent()在交换线程中使渲染上下文为当前上下文,然后调用swapBuffers()

    5. 在交换线程中调用doneCurrent()

    6. 调用QGLContext::moveToThread(qApp->thread())并通知主线程交换已完成。

这样做将释放主线程,以便它可以继续处理例如UI事件或网络请求。即使涉及上下文交换,与在GPU完成交换操作时让主线程等待相比,这可能是优选的。请注意,这高度依赖于实现。

  1. 线程中的纹理上传。在线程中进行纹理上传对于处理需要显示的大量图像的应用程序(例如照片库应用程序)可能非常有用。这是通过现有的bindTexture() API在Qt中支持的。一个简单的方法是创建两个共享QGLWidgets。一个在主GUI线程中是最新的,而另一个在纹理上传线程中是当前的。上传线程中的小部件从未显示,它只用于与主线程共享纹理。对于通过bindTexture()绑定的每个纹理,通知主线程,以便它可以开始使用该纹理。

  2. 使用QPainter绘制线程中的QGLWidget。在Qt 4.8中,可以在单独的线程中使用QPainter来绘制QGLWidget。注意,这对于QGLPixelBuffersQGLFramebufferObjects也是可能的。由于这仅在GL 2绘制引擎中受支持,因此需要OpenGL 2.0或OpenGL ES 2.0。

QGLWidgets只能在主GUI线程中创建。这意味着需要调用doneCurrent()才能从主线程释放GL上下文,然后才能由另一个线程将小部件引入。然后,您需要调用QGLContext::moveToThread()来将上下文的所有权转移到要使其成为当前线程的线程。此外,当小部件被调整大小,或者它的一部分被暴露或需要重新绘制时,主GUI线程将向QGLWidget调度调整大小和绘制事件。因此,有必要处理这些事件,因为QGLWidget中的默认实现将尝试使QGLWidget的上下文成为当前上下文,这将再次干扰呈现到小部件中的任何线程。重新实现QGLWidget::paintEvent()QGLWidget::resizeEvent(),以通知渲染线程需要调整大小或更新,并注意不要调用基类实现。如果正在渲染动画,则可能根本不需要处理绘制事件,因为渲染线程正在进行定期更新。那么重新实现QGLWidget::paintEvent()就足够了,什么都不做。

执行线程渲染时的一般规则是:请注意,不同线程中的绑定和释放上下文必须由用户同步。GL呈现上下文在任何时候都只能是一个线程中的当前上下文。如果您尝试在QGLWidget上打开QPainter,而小部件的呈现上下文在另一个线程中是当前的,那么它将失败。

除此之外,还支持在单独的线程中使用原始GL调用进行渲染。

相关内容

  • 没有找到相关文章

最新更新